Disabling auto-refresh of game list by default, as it is causing bugs sometimes
[open-ps2-loader.git] / modules / ps2fs / pfs_fio.c
blob6283dca9fbdb38d8e4fdd907c51bdb6de4097905
1 /*
2 # _____ ___ ____ ___ ____
3 # ____| | ____| | | |____|
4 # | ___| |____ ___| ____| | \ PS2DEV Open Source Project.
5 #-----------------------------------------------------------------------
6 # Copyright 2001-2004, ps2dev - http://www.ps2dev.org
7 # Licenced under Academic Free License version 2.0
8 # Review ps2sdk README & LICENSE files for further details.
10 # $Id: pfs_fio.c 1491 2009-01-04 23:46:22Z oopo $
11 # PFS I/O manager related routines
14 #include "pfs.h"
16 ///////////////////////////////////////////////////////////////////////////////
17 // Globals
19 u8 openFlagArray[] = { 0, 4, 2, 6, 0, 0, 0, 0 };
20 int symbolicLinks = 0;
21 int pfsFioSema = 0;
22 pfs_file_slot_t *fileSlots;
24 ///////////////////////////////////////////////////////////////////////////////
25 // Function defenitions
27 int checkForLastError(pfs_mount_t *pfsMount, int rv)
29 return pfsMount->lastError ? pfsMount->lastError : rv;
32 int checkFileSlot(pfs_file_slot_t *fileSlot)
34 WaitSema(pfsFioSema);
36 if(fileSlot->clink==NULL)
38 SignalSema(pfsFioSema);
39 return -EBADF;
42 return 0;
45 void closeFileSlot(pfs_file_slot_t *fileSlot)
47 pfs_mount_t *pfsMount=fileSlot->clink->pfsMount;
49 if(fileSlot->fd->mode & O_WRONLY)
51 if(fileSlot->restsInfo.dirty!=0)
53 pfsMount->blockDev->transfer(pfsMount->fd, fileSlot->restsBuffer,
54 fileSlot->restsInfo.sub, fileSlot->restsInfo.sector, 1, IOCTL2_TMODE_WRITE);
56 inodeUpdateTime(fileSlot->clink); // set time :P
57 fileSlot->clink->u.inode->attr|=FIO_ATTR_CLOSED;
58 if(pfsMount->flags & FIO_ATTR_WRITEABLE)
59 cacheFlushAllDirty(pfsMount);
61 cacheAdd(fileSlot->block_pos.inode);
62 cacheAdd(fileSlot->clink);
63 memset(fileSlot, 0, sizeof(pfs_file_slot_t));
66 pfs_mount_t *fioGetMountedUnit(int unit)
68 pfs_mount_t *pfsMount;
70 WaitSema(pfsFioSema);
71 if((pfsMount=getMountedUnit(unit))==NULL)
72 SignalSema(pfsFioSema);
73 return pfsMount;
76 int mountDevice(block_device *blockDev, int fd, int unit, int flag)
78 u32 i;
79 int rv;
81 if((u32)unit >= pfsConfig.maxMount)
82 return -EMFILE;
84 if(pfsMountBuf[unit].flags & MOUNT_BUSY)
85 return -EBUSY;
87 for(i = 0; i < pfsConfig.maxMount; i++)
88 if((pfsMountBuf[i].flags & MOUNT_BUSY) &&
89 (blockDev == pfsMountBuf[i].blockDev) &&
90 (fd == pfsMountBuf[i].fd)) // Cant mount the same partition more than once
91 return -EBUSY;
93 // dprintf("ps2fs: Found free mount buffer!\n");
95 pfsMountBuf[unit].blockDev = blockDev;
96 pfsMountBuf[unit].fd = fd;
97 pfsMountBuf[unit].flags = flag;
99 rv = mountSuperBlock(&pfsMountBuf[unit]);
100 if(rv < 0)
101 return rv;
103 pfsMountBuf[unit].flags |= MOUNT_BUSY;
104 dprintf("ps2fs: mount successfull!\n");
106 return 0;
109 int openFile(pfs_mount_t *pfsMount, pfs_file_slot_t *freeSlot, const char *filename, int openFlags, int mode)
111 char file[256];
112 int result, result2, result3, result4;
113 pfs_cache_t *parentInode, *fileInode, *cached;
116 result = 0; //no error
117 // Get the inode for the directory which contains the file (dir) in filename
118 // After this call, 'file' will contain the name of the file we're operating on.
119 if ((parentInode=inodeGetParent(pfsMount, NULL, filename, file, &result))==0)
121 dprintf("ps2fs: Failed to get parent inode\n");
122 return result;
125 // dprintf("ps2fs: Got parent inode!\n");
126 // inodePrint(parentInode->u.inode);
128 // Get the inode for the actual file/directory contained in the parent dir
129 fileInode=inodeGetFileInDir(parentInode, file, &result);
131 // dprintf("ps2fs: got file inode! (file: %s)\n", file);
132 // inodePrint(fileInode->u.inode);
134 // If file already exists..
135 if (fileInode)
137 u32 flags;
138 u32 count;
140 dprintf("ps2fs: File inode already exists\n");
142 // Setup flags
143 flags=openFlagArray[openFlags & O_RDWR];
144 if (openFlags & O_TRUNC) flags |= 2;
145 if (openFlags & FDIRO) flags |= 4;
146 if ((mode & 0x10000) ||
147 ((openFlags & (O_CREAT|O_EXCL)) == (O_CREAT|O_EXCL))){
148 result=-EEXIST;
150 else
152 count = 0;
154 // Resolve actual file from a symlink
155 while ((fileInode->u.inode->mode & FIO_S_IFMT) == FIO_S_IFLNK)
157 dprintf("ps2fs: Resolving symlink..\n");
159 if (count++>=4)
161 result=-ELOOP;
162 goto label;
165 parentInode=inodeGetParent(pfsMount, parentInode, (char*)&fileInode->u.inode->data[1],
166 file, &result);
167 cacheAdd(fileInode);
168 if ((parentInode==0) ||
169 ((fileInode=inodeGetFileInDir(parentInode, file, &result))==0))
170 goto label;
173 // Make sure that if a file is being opened, then inode does not point
174 // to a directory, and vice versa.
175 if ((openFlags & FDIRO) == 0)
177 if ((fileInode->u.inode->mode & FIO_S_IFMT) == FIO_S_IFDIR)
178 result=-EISDIR;
179 }else{
180 if ((fileInode->u.inode->mode & FIO_S_IFMT) != FIO_S_IFDIR)
181 result=-ENOTDIR;
184 // Truncate file if required
185 if ((result==0) &&
186 ((result=checkAccess(fileInode, flags & 0xFFFF))==0) &&
187 (openFlags & O_TRUNC))
190 dprintf("ps2fs: Truncating file..\n");
192 cached=cacheGetData(fileInode->pfsMount, fileInode->sub, fileInode->sector+1, CACHE_FLAG_NOLOAD | CACHE_FLAG_NOTHING, &result2);
193 if (cached)
195 memset(cached->u.aentry, 0, sizeof(pfs_inode)); //1024
196 cached->u.aentry->aLen=sizeof(pfs_inode);
197 cached->flags |= CACHE_FLAG_DIRTY;
198 cacheAdd(cached);
200 if ((result!=result2))
202 fileInode->u.inode->size = 0;
203 fileInode->u.inode->attr &= ~FIO_ATTR_CLOSED; //~0x80==0xFF7F
204 fileInode->flags |= CACHE_FLAG_DIRTY;
205 ioctl2Free(fileInode);
210 // Otherwise, if file doesnt already exist..
211 }else{
213 dprintf("ps2fs: File inode does not exist..\n");
215 if ((openFlags & O_CREAT) && (result==-ENOENT) &&
216 ((result=checkAccess(parentInode, 2))==0) &&
217 (fileInode=inodeCreateNewFile(parentInode, mode, pfsMount->uid,
218 pfsMount->gid, &result)))
220 if ((mode & FIO_S_IFMT) == FIO_S_IFLNK)
222 strcpy((char*)&fileInode->u.inode->data[1], (char*)freeSlot);
223 freeSlot=NULL;
226 // If new file is a directory, the fill self and parent entries
227 if ((mode & FIO_S_IFMT) == FIO_S_IFDIR)
229 cached=cacheGetData(fileInode->pfsMount, fileInode->u.inode->data[1].subpart,
230 fileInode->u.inode->data[1].number << fileInode->pfsMount->inode_scale,
231 CACHE_FLAG_NOLOAD | CACHE_FLAG_NOTHING, &result3);
232 if (cached)
234 fillSelfAndParentDentries(cached,
235 &fileInode->u.inode->inode_block,
236 &parentInode->u.inode->inode_block);
237 cached->flags |= CACHE_FLAG_DIRTY;
238 cacheAdd(cached);
240 result=result3;
241 // Otherwise if its just a regular file, just zero its attribute entry
242 }else{
243 cached=cacheGetData(fileInode->pfsMount, fileInode->sub, fileInode->sector+1,
244 CACHE_FLAG_NOLOAD | CACHE_FLAG_NOTHING, &result4);
245 if (cached)
247 memset(cached->u.aentry, 0, sizeof(pfs_inode));
248 cached->u.aentry->aLen=sizeof(pfs_inode);
249 cached->flags |= CACHE_FLAG_DIRTY;
250 cacheAdd(cached);
252 result=result4;
255 // Link new file with parent directory
256 if ((result==0) && (cached=dirAddEntry(parentInode, file, &fileInode->u.inode->inode_block,
257 mode, &result)))
259 inodeUpdateTime(parentInode);
260 cached->flags|=CACHE_FLAG_DIRTY;
261 cacheAdd(cached);
265 label:
266 cacheAdd(parentInode);
267 if ((result==0) && freeSlot && fileInode)
270 // dprintf("ps2fs: Setup file slot sizes\n");
272 freeSlot->clink=fileInode;
273 if (openFlags & O_APPEND)
274 freeSlot->position = fileInode->u.inode->size;
275 else
276 freeSlot->position = 0;
278 result=blockInitPos(freeSlot->clink, &freeSlot->block_pos, freeSlot->position);
279 if (result==0)
281 if ((openFlags & O_WRONLY) &&
282 (fileInode->u.inode->attr & FIO_ATTR_CLOSED)){
283 fileInode->u.inode->attr &= ~FIO_ATTR_CLOSED;
284 fileInode->flags |= CACHE_FLAG_DIRTY;
285 if (pfsMount->flags & FIO_ATTR_WRITEABLE)
286 cacheFlushAllDirty(pfsMount);
288 if ((result=checkForLastError(pfsMount, result))==0)
289 return 0;
291 freeSlot->clink=NULL;
294 if(fileInode) cacheAdd(fileInode);
296 return checkForLastError(pfsMount, result);
299 // Reads unaligned data, or remainder data (size < 512)
300 int fileTransferRemainder(pfs_file_slot_t *fileSlot, void *buf, int size, int operation)
302 u32 sector, pos;
303 int result;
304 pfs_blockpos_t *blockpos = &fileSlot->block_pos;
305 pfs_mount_t *pfsMount = fileSlot->clink->pfsMount;
306 pfs_restsInfo_t *info = &fileSlot->restsInfo;
307 pfs_blockinfo *bi = blockGetCurrent(blockpos);
309 sector = ((bi->number+blockpos->block_offset) << pfsMount->sector_scale) +
310 (blockpos->byte_offset >> 9);
311 pos = blockpos->byte_offset & 0x1FF;
313 if((info->sector != sector) || (info->sub!=bi->subpart))
315 if (fileSlot->restsInfo.dirty)
317 result=pfsMount->blockDev->transfer(pfsMount->fd, fileSlot->restsBuffer, info->sub, info->sector, 1, 1);
318 if(result)
319 return result;
320 fileSlot->restsInfo.dirty=0;
323 info->sub=bi->subpart;
324 info->sector=sector;
326 if(pos || (fileSlot->position != fileSlot->clink->u.inode->size))
328 result = pfsMount->blockDev->transfer(pfsMount->fd, fileSlot->restsBuffer, info->sub, info->sector, 1, 0);
329 if(result)
330 return result | 0x10000;
334 if (operation==0)
335 memcpy(buf, fileSlot->restsBuffer+pos, size=min(size, 512-(int)pos));
336 else
337 memcpy(fileSlot->restsBuffer+pos, buf, size=min(size, 512-(int)pos));
339 if (operation == 1)
341 if (pfsMount->flags & FIO_ATTR_WRITEABLE)
343 if ((result=pfsMount->blockDev->transfer(pfsMount->fd, fileSlot->restsBuffer, info->sub,
344 info->sector, operation, operation)))
345 return result;
347 else
348 info->dirty=operation;
350 return size;
353 // Does actual read/write of data from file
354 int fileTransfer(pfs_file_slot_t *fileSlot, u8 *buf, int size, int operation)
356 int result=0;
357 pfs_blockpos_t *blockpos=&fileSlot->block_pos;
358 pfs_mount_t *pfsMount=fileSlot->clink->pfsMount;
359 u32 bytes_remain;
360 u32 total = 0;
362 // dprintf2("ps2fs CALL: fileTransfer( , ,%d,%d)\n", size, operation);
364 // If we're writing and there is less free space in the last allocated block segment
365 // than can hold the data being written, then try and expand the block segment
366 if ((operation==1) &&
367 (fileSlot->clink->u.inode->number_data - 1 == blockpos->block_segment))
369 bytes_remain = (blockGetCurrent(blockpos)->count - blockpos->block_offset) * pfsMount->zsize - blockpos->byte_offset;//u32
371 if (bytes_remain < size)
373 blockExpandSegment(fileSlot->clink, blockpos,
374 ((size-bytes_remain+pfsMount->zsize-1) & (~(pfsMount->zsize-1))) / pfsMount->zsize);
378 while (size)
380 pfs_blockinfo *bi;
381 u32 sectors;
383 // Get block info for current file position
384 bi=blockGetCurrent(blockpos);
386 // Get amount of remaining data in current block
387 bytes_remain=(bi->count - blockpos->block_offset) * pfsMount->zsize - blockpos->byte_offset;
389 // If there is no space/data left in the current block segment, then we need to move onto the next
390 if (bytes_remain==0)
392 // If we're at the end of allocated block segments, then allocate a new block segment
393 if (blockpos->block_segment == fileSlot->clink->u.inode->number_data-1){
394 if (operation==0){
395 printf("ps2fs: Panic: This is a bug!\n");
396 return 0;
399 result = blockAllocNewSegment(fileSlot->clink, blockpos,
400 (size - 1 + pfsMount->zsize) / pfsMount->zsize);
401 if(result<0)
402 break;
404 // Otherwise, move to the next block segment
405 }else
406 if ((result=blockSeekNextSegment(fileSlot->clink, blockpos)))
408 dprintf("ps2fs: Failed to seek to next block segment!\n");
409 return result;
412 bi=blockGetCurrent(blockpos);
413 bytes_remain=(bi->count - blockpos->block_offset) * pfsMount->zsize - blockpos->byte_offset;
416 if (bytes_remain==0)
418 printf("ps2fs: Panic: There is no zone.\n");
419 return 0;
422 // If we are transferring size not a multiple of 512, under 512, or to
423 // an unaligned buffer we need to use a special function rather than
424 // just doing a ATA sector transfer.
425 if ((blockpos->byte_offset & 0x1FF) || (size < 512) || ((u32)buf & 3))
427 dprintf("ps2fs: Transfer unaligned (size = %d, op = %d)\n", size, operation);
428 if ((result=fileTransferRemainder(fileSlot, buf, size, operation)) < 0)
429 break;
431 else
433 sectors = bytes_remain / 512;
434 if ((size / 512) < sectors) sectors = size / 512; //sectors=min(size/512, sectors)
436 // Do the ATA sector transfer
437 result=pfsMount->blockDev->transfer(pfsMount->fd, buf, bi->subpart,
438 ((bi->number + blockpos->block_offset) << pfsMount->sector_scale)+(blockpos->byte_offset / 512),
439 sectors, operation);
440 if (result < 0)
442 result |= 0x10000; // TODO: EIO define
443 break;
445 result = sectors * 512;
448 size -= result;
449 fileSlot->position += result;
450 buf += result;
451 total += result;
453 // If file has grown, need to mark inode as dirty
454 if(fileSlot->clink->u.inode->size < fileSlot->position)
456 fileSlot->clink->u.inode->size = fileSlot->position;
457 fileSlot->clink->flags |= CACHE_FLAG_DIRTY;
460 blockpos->block_offset+=blockSyncPos(blockpos, result);
462 return result < 0 ? result : total;
465 void pfsPowerOffHandler(void* data)
467 printf("pfs close all\n");
468 devctlCloseAll();
471 int pfsInit(iop_device_t *f)
473 iop_sema_t sema;
475 sema.attr = 1;
476 sema.option = 0;
477 sema.initial = 1;
478 sema.max = 1;
480 pfsFioSema = CreateSema(&sema);
482 AddPowerOffHandler(pfsPowerOffHandler, 0);
483 return 0;
486 int pfsDeinit(iop_device_t *f)
488 devctlCloseAll();
490 DeleteSema(pfsFioSema);
492 return 0;
495 int pfsFormat(iop_file_t *t, const char *dev, const char *blockdev, void *args, size_t arglen)
497 int *arg = (int *)args;
498 int fragment = 0;
499 int fd;
500 block_device *blockDev;
501 int rv;
503 // Has a fragment bit pattern been specified ?
504 if((arglen == (3 * sizeof(int))) && (arg[1] == 0x2D66))
505 fragment = arg[2];
507 if((blockDev = getDeviceTable(blockdev)) == 0)
508 return -ENXIO;
510 WaitSema(pfsFioSema);
512 fd = open(blockdev, O_RDWR, 0644);
514 dprintf("ps2fs: Format: fragment = 0x%X\n", fragment);
516 if(fd < 0)
517 rv = fd;
518 else {
519 rv = _format(blockDev, fd, arg[0], fragment);
520 close(fd);
523 SignalSema(pfsFioSema);
525 return rv;
528 int pfsOpen(iop_file_t *f, const char *name, int flags, int mode)
530 int rv = 0;
531 u32 i;
532 pfs_file_slot_t *freeSlot;
533 pfs_mount_t *pfsMount;
535 if(!name)
536 return -ENOENT;
538 if(!(pfsMount = fioGetMountedUnit(f->unit)))
540 dprintf("Couldnt get mounted unit!\n");
541 return -ENODEV;
544 // Find free file slot
545 for(i = 0; i < pfsConfig.maxOpen; i++)
547 if(!fileSlots[i].fd) {
548 freeSlot = &fileSlots[i];
549 goto pfsOpen_slotFound;
553 printf("ps2fs: Error: There are no free file slots!\n");
554 freeSlot = NULL;
556 pfsOpen_slotFound:
558 if(!freeSlot) {
559 rv = -EMFILE;
560 goto pfsOpen_end;
563 // Do actual open
564 if((rv = openFile(pfsMount, freeSlot, name, f->mode, (mode & 0xfff) | FIO_S_IFREG)))
565 goto pfsOpen_end;
567 dprintf("ps2fs: File opened successfully!\n");
569 freeSlot->fd = f;
570 f->privdata = freeSlot;
572 pfsOpen_end:
574 SignalSema(pfsFioSema);
576 return rv;
579 int pfsClose(iop_file_t *f)
581 pfs_file_slot_t *fileSlot = (pfs_file_slot_t *)f->privdata;
582 int rv;
584 rv = checkFileSlot(fileSlot);
585 if(rv)
586 return rv;
588 closeFileSlot(fileSlot);
590 SignalSema(pfsFioSema);
592 return rv;
595 int pfsRead(iop_file_t *f, void *buf, int size)
597 pfs_file_slot_t *fileSlot = (pfs_file_slot_t*)f->privdata;
598 int result = checkFileSlot(fileSlot);
600 if (result)
602 dprintf("ps2fs: bad file slot on read\n");
603 return result;
606 // Check bounds, adjust size if necessary
607 if(fileSlot->clink->u.inode->size < (fileSlot->position + size))
608 size = fileSlot->clink->u.inode->size - fileSlot->position;
610 result = size ? fileTransfer(fileSlot, buf, size, 0) : 0;
611 result = checkForLastError(fileSlot->clink->pfsMount, result);
613 SignalSema(pfsFioSema);
614 return result;
617 int pfsWrite(iop_file_t *f, void *buf, int size)
619 pfs_mount_t *pfsMount;
620 pfs_file_slot_t *fileSlot = (pfs_file_slot_t*)f->privdata;
621 int result = checkFileSlot(fileSlot);
623 if(result)
624 return result;
626 pfsMount = fileSlot->clink->pfsMount;
628 result = fileTransfer(fileSlot, buf, size, 1);
630 if (pfsMount->flags & FIO_ATTR_WRITEABLE)
631 cacheFlushAllDirty(pfsMount);
633 result = checkForLastError(pfsMount, result);
634 SignalSema(pfsFioSema);
635 return result;
638 s64 _seek(pfs_file_slot_t *fileSlot, s64 offset, int whence, int mode)
640 int rv;
641 s64 startPos, newPos;
643 if (mode & O_DIROPEN)
645 dprintf("ps2fs: Cant seek: directory\n");
646 return -EISDIR;
649 switch (whence)
651 case SEEK_SET:
652 startPos = 0;
653 break;
654 case SEEK_CUR:
655 startPos= fileSlot->position;
656 break;
657 case SEEK_END:
658 startPos = fileSlot->clink->u.inode->size;
659 break;
660 default:
661 return -EINVAL;
663 newPos = startPos + offset;
665 if (((offset < 0) && (startPos < newPos)) ||
666 ((offset > 0) && (startPos > newPos)) ||
667 (fileSlot->clink->u.inode->size < newPos))
669 dprintf("ps2fs: Cant seek: invalid args\n");
670 return -EINVAL;
673 cacheAdd(fileSlot->block_pos.inode);
674 rv=blockInitPos(fileSlot->clink, &fileSlot->block_pos, newPos);
675 if (rv==0)
676 fileSlot->position = newPos;
677 else {
678 fileSlot->position = 0;
679 blockInitPos(fileSlot->clink, &fileSlot->block_pos, 0);
682 if (rv)
684 dprintf("ps2fs: Cant seek: failed to blockInitPos\n");
685 return rv;
688 dprintf("ps2fs: Seek successfull! newPos = %ld\n", (u32)newPos);
690 return newPos;
693 int pfsLseek(iop_file_t *f, unsigned long pos, int whence)
695 pfs_file_slot_t *fileSlot = (pfs_file_slot_t*)f->privdata;
696 int result = checkFileSlot(fileSlot);
698 if (result)
699 return result;
701 result = (u32)_seek(fileSlot, (s64)pos, whence, f->mode);
703 SignalSema(pfsFioSema);
704 return result;
707 s64 pfsLseek64(iop_file_t *f, s64 offset, int whence)
709 printf("ps2fs: Error: Operation currently unsupported.\n");
711 return -1;
713 /*pfs_file_slot_t *fileSlot = (pfs_file_slot_t *)f->privdata;
714 u64 rv;
716 rv=checkFileSlot(fileSlot);
717 if(!rv)
719 rv=_seek(fileSlot, offset, whence, f->mode);
720 SignalSema(pfsFioSema);
722 return rv;*/
725 int _remove(pfs_mount_t *pfsMount, const char *path, int mode)
727 char szPath[256];
728 int rv=0;
729 pfs_cache_t *parent;
730 pfs_cache_t *file;
732 if((parent=inodeGetParent(pfsMount, NULL, path, szPath, &rv))==NULL)
733 return rv;
735 if((file=inodeGetFileInDir(parent, szPath, &rv))!=NULL)
737 if(mode!=0)
738 {// remove dir
739 if((file->u.inode->mode & FIO_S_IFMT) != FIO_S_IFDIR)
740 rv=-ENOTDIR;
741 else if(checkDirForFiles(file)==0)
742 rv=-ENOTEMPTY;
743 else if(((u16)file->u.inode->inode_block.number==pfsMount->root_dir.number) &&
744 ((u16)file->u.inode->inode_block.subpart==pfsMount->root_dir.subpart))
745 rv=-EBUSY;
746 else if(((u16)file->u.inode->inode_block.number==pfsMount->current_dir.number) &&
747 ((u16)file->u.inode->inode_block.subpart==pfsMount->current_dir.subpart))
748 rv=-EBUSY;
750 else// just a file
751 if((file->u.inode->mode & FIO_S_IFMT)==FIO_S_IFDIR)
752 rv=-EISDIR;
754 if(rv==0)
756 if(file->u.inode->uid!=0)
757 rv=checkAccess(file, 2);
758 if(file->nused>=2)
759 rv=-EBUSY;
760 if(rv==0)
761 return inodeRemove(parent, file, szPath);
763 cacheAdd(file);
765 cacheAdd(parent);
766 return checkForLastError(pfsMount, rv);
770 int pfsRemove(iop_file_t *f, const char *name)
772 pfs_mount_t *pfsMount;
773 int rv;
775 if(!(pfsMount = fioGetMountedUnit(f->unit)))
776 return -ENODEV;
778 rv = _remove(pfsMount, name, 0);
780 SignalSema(pfsFioSema);
782 return rv;
785 int pfsMkdir(iop_file_t *f, const char *path, int mode)
787 pfs_mount_t *pfsMount;
788 int rv;
790 mode = (mode & 0xfff) | 0x10000 | FIO_S_IFDIR; // TODO: change to some constant/macro
792 if(!(pfsMount = fioGetMountedUnit(f->unit)))
793 return -ENODEV;
795 rv = openFile(pfsMount, NULL, path, O_CREAT | O_WRONLY, mode);
797 SignalSema(pfsFioSema);
799 return rv;
802 int pfsRmdir(iop_file_t *f, const char *path)
804 pfs_mount_t *pfsMount;
805 const char *temp;
806 int rv;
808 temp = path + strlen(path);
809 if(*temp == '.')
810 return -EINVAL;
812 if(!(pfsMount = fioGetMountedUnit(f->unit)))
813 return -ENODEV;
815 rv = _remove(pfsMount, path, 0x01); // TODO: constant for 0x01 ?
817 SignalSema(pfsFioSema);
819 return rv;
822 int pfsDopen(iop_file_t *f, const char *name)
824 return pfsOpen(f, name, 0, 0);
827 int pfsDread(iop_file_t *f, iox_dirent_t *dirent)
829 pfs_file_slot_t *fileSlot = (pfs_file_slot_t *)f->privdata;
830 pfs_mount_t *pfsMount;
831 pfs_cache_t *clink;
832 pfs_blockinfo bi;
833 int result;
834 int rv;
836 // dprintf2("ps2fs CALL: pfsDread();\n");
838 rv = checkFileSlot(fileSlot);
839 if(rv < 0)
840 return rv;
842 pfsMount = fileSlot->clink->pfsMount;
844 if((fileSlot->clink->u.inode->mode & FIO_S_IFMT) != FIO_S_IFDIR)
846 dprintf("ps2fs: dread error: not directory!\n");
847 rv = -ENOTDIR;
849 else
850 if((rv = getNextDentry(fileSlot->clink, &fileSlot->block_pos, (u32 *)&fileSlot->position,
851 dirent->name, &bi)) > 0)
854 clink = inodeGetData(pfsMount, bi.subpart, bi.number, &result);
855 if(clink != NULL)
857 fioStatFiller(clink, &dirent->stat);
858 cacheAdd(clink);
861 if(result)
862 rv = result;
865 rv = checkForLastError(pfsMount, rv);
866 SignalSema(pfsFioSema);
868 return rv;
871 void fioStatFiller(pfs_cache_t *clink, iox_stat_t *stat)
873 stat->mode = clink->u.inode->mode;
874 stat->attr = clink->u.inode->attr;
875 stat->size = (u32)clink->u.inode->size;
876 stat->hisize = (u32)(clink->u.inode->size >> 32);
877 memcpy(&stat->ctime, &clink->u.inode->ctime, sizeof(pfs_datetime));
878 memcpy(&stat->atime, &clink->u.inode->atime, sizeof(pfs_datetime));
879 memcpy(&stat->mtime, &clink->u.inode->mtime, sizeof(pfs_datetime));
880 stat->private_0 = clink->u.inode->uid;
881 stat->private_1 = clink->u.inode->gid;
882 stat->private_2 = clink->u.inode->number_blocks;
883 stat->private_3 = clink->u.inode->number_data;
884 stat->private_4 = 0;
885 stat->private_5 = 0;
888 int pfsGetstat(iop_file_t *f, const char *name, iox_stat_t *stat)
890 pfs_mount_t *pfsMount;
891 pfs_cache_t *clink;
892 int rv=0;
894 if(!(pfsMount = fioGetMountedUnit(f->unit)))
895 return -ENODEV;
897 clink=inodeGetFile(pfsMount, NULL, name, &rv);
898 if(clink!=NULL)
900 fioStatFiller(clink, stat);
901 cacheAdd(clink);
904 SignalSema(pfsFioSema);
905 return checkForLastError(pfsMount, rv);
908 int pfsChstat(iop_file_t *f, const char *name, iox_stat_t *stat, unsigned int statmask)
910 pfs_mount_t *pfsMount;
911 pfs_cache_t *clink;
912 int rv = 0;
914 if(!(pfsMount = fioGetMountedUnit(f->unit)))
915 return -ENODEV;
917 clink = inodeGetFile(pfsMount, NULL, name, &rv);
918 if(clink != NULL) {
920 rv = checkAccess(clink, 0x02);
921 if(rv == 0) {
923 clink->flags |= 0x01;
925 if((statmask & FIO_CST_MODE) && ((clink->u.inode->mode & FIO_S_IFMT) != FIO_S_IFLNK))
926 clink->u.inode->mode = (clink->u.inode->mode & FIO_S_IFMT) | (stat->mode & 0xfff);
927 if(statmask & FIO_CST_ATTR)
928 clink->u.inode->attr = (clink->u.inode->attr & 0xA0) | (stat->attr & 0xFF5F);
929 if(statmask & FIO_CST_SIZE)
930 rv = -EACCES;
931 if(statmask & FIO_CST_CT)
932 memcpy(&clink->u.inode->ctime, stat->ctime, sizeof(pfs_datetime));
933 if(statmask & FIO_CST_AT)
934 memcpy(&clink->u.inode->atime, stat->atime, sizeof(pfs_datetime));
935 if(statmask & FIO_CST_MT)
936 memcpy(&clink->u.inode->mtime, stat->mtime, sizeof(pfs_datetime));
937 if(statmask & FIO_CST_PRVT) {
938 clink->u.inode->uid = stat->private_0;
939 clink->u.inode->gid = stat->private_1;
942 if(pfsMount->flags & FIO_ATTR_WRITEABLE)
943 cacheFlushAllDirty(pfsMount);
946 cacheAdd(clink);
950 SignalSema(pfsFioSema);
951 return checkForLastError(pfsMount, rv);
954 int pfsRename(iop_file_t *ff, const char *old, const char *new)
956 char path1[256], path2[256];
957 int result=0;
958 pfs_mount_t *pfsMount;
959 int f;
960 pfs_cache_t *parentOld=NULL, *parentNew=NULL;
961 pfs_cache_t *removeOld=NULL, *removeNew=NULL;
962 pfs_cache_t *iFileOld=NULL, *iFileNew=NULL;
963 pfs_cache_t *newParent=NULL,*addNew=NULL;
965 pfsMount=fioGetMountedUnit(ff->unit);
966 if (pfsMount==0) return -ENODEV;
968 parentOld=inodeGetParent(pfsMount, NULL, old, path1, &result);
969 if (parentOld){
970 u32 nused=parentOld->nused;
972 if (nused != 1){
973 result=-EBUSY;
974 goto exit;
977 if ((iFileOld=inodeGetFileInDir(parentOld, path1, &result))==0) goto exit;
979 if ((parentNew=inodeGetParent(pfsMount, NULL, new, path2, &result))==0) goto exit;
981 f=(iFileOld->u.inode->mode & FIO_S_IFMT) == FIO_S_IFDIR;
983 if ((parentNew->nused != nused) && ((parentOld!=parentNew) || (parentNew->nused!=2))){
984 result=-EBUSY;
985 goto exit;
988 iFileNew=inodeGetFileInDir(parentNew, path2, &result);
989 if (iFileNew){
990 if (f){
991 if ((iFileNew->u.inode->mode & FIO_S_IFMT) != FIO_S_IFDIR)
992 result=-ENOTDIR;
993 else
994 if (checkDirForFiles(iFileNew)){
995 if (iFileNew->nused >= 2)
996 result=-EBUSY;
997 else{
998 if (iFileOld==iFileNew)
999 goto exit;
1001 }else
1002 result=-ENOTEMPTY;
1003 }else
1004 if ((iFileNew->u.inode->mode & FIO_S_IFMT) == FIO_S_IFDIR)
1005 result=-EISDIR;
1006 else
1007 if (iFileNew->nused >= 2)
1008 result=-EBUSY;
1009 else{
1010 if (iFileOld==iFileNew)
1011 goto exit;
1013 }else
1014 if (result==-ENOENT)
1015 result=0;
1017 if (result) goto exit;
1019 if (f && (parentOld!=parentNew)){
1020 pfs_cache_t *parent;
1022 parent=cacheUsedAdd(parentNew);
1024 pfs_cache_t *tmp;
1026 if (parent==iFileOld){
1027 result=-EINVAL;
1028 break;
1030 tmp=inodeGetFileInDir(parent, "..", &result);
1031 cacheAdd(parent);
1032 if (tmp==parent)break;
1033 parent=tmp;
1034 }while(parent);
1035 cacheAdd(parent);
1038 if (result==0){
1039 if (strcmp(path1, ".") && strcmp(path1, "..") &&
1040 strcmp(path2, ".") && strcmp(path2, "..")){
1041 result=checkAccess(parentOld, 3);
1042 if (result==0)
1043 result=checkAccess(parentNew, 3);
1044 }else
1045 result=-EINVAL;
1047 if (result==0){
1048 if (iFileNew && ((removeNew=dirRemoveEntry(parentNew, path2))==NULL))
1049 result=-ENOENT;
1050 else{
1051 removeOld=dirRemoveEntry(parentOld, path1);
1052 if (removeOld==0)
1053 result=-ENOENT;
1054 else{
1055 addNew=dirAddEntry(parentNew, path2, &iFileOld->u.inode->inode_block, iFileOld->u.inode->mode, &result);
1056 if (addNew && f && (parentOld!=parentNew))
1057 newParent=setParent(iFileOld, &parentNew->u.inode->inode_block, &result);
1063 if (result){
1064 if (removeNew) removeNew->pfsMount=NULL;
1065 if (removeOld) removeOld->pfsMount=NULL;
1066 if (addNew) addNew->pfsMount=NULL;
1067 if (iFileNew) iFileNew->pfsMount=NULL;
1068 parentOld->pfsMount=NULL;
1069 parentNew->pfsMount=NULL;
1070 }else{
1071 if (parentOld==parentNew){
1072 if (removeOld!=addNew)
1073 removeOld->flags |= CACHE_FLAG_DIRTY;
1074 }else
1076 inodeUpdateTime(parentOld);
1077 removeOld->flags|=CACHE_FLAG_DIRTY;
1079 inodeUpdateTime(parentNew);
1080 addNew->flags|=CACHE_FLAG_DIRTY;
1082 if (newParent){
1083 inodeUpdateTime(iFileOld);
1084 newParent->flags|=CACHE_FLAG_DIRTY;
1085 cacheAdd(newParent);
1088 if (iFileNew){
1089 iFileNew->flags &= ~CACHE_FLAG_DIRTY;
1090 bitmapFreeInodeBlocks(iFileNew);
1093 if (pfsMount->flags & FIO_ATTR_WRITEABLE)
1094 cacheFlushAllDirty(pfsMount);
1096 if (removeOld) cacheAdd(removeOld);
1097 if (addNew) cacheAdd(addNew);
1098 if (removeNew) cacheAdd(removeNew);
1099 exit:
1100 if (iFileNew) cacheAdd(iFileNew);
1101 cacheAdd(iFileOld);
1102 cacheAdd(parentOld);
1103 cacheAdd(parentNew);
1105 SignalSema(pfsFioSema);
1106 return checkForLastError(pfsMount, result);
1109 int pfsChdir(iop_file_t *f, const char *name)
1111 pfs_mount_t *pfsMount;
1112 pfs_cache_t *clink;
1113 int result = 0;
1115 if(!(pfsMount = fioGetMountedUnit(f->unit)))
1116 return -ENODEV;
1118 clink = inodeGetFile(pfsMount, 0, name, &result);
1119 if(clink != NULL) {
1120 if((clink->u.inode->mode & FIO_S_IFMT) != FIO_S_IFDIR)
1121 result = -ENOTDIR;
1122 else {
1124 result = checkAccess(clink, 0x01);
1126 if(result == 0)
1127 memcpy(&pfsMount->current_dir, &clink->u.inode->inode_block, sizeof(pfs_blockinfo));
1130 cacheAdd(clink);
1133 SignalSema(pfsFioSema);
1134 return checkForLastError(pfsMount, result);
1137 void _sync()
1139 u32 i;
1140 for(i=0;i<pfsConfig.maxOpen;i++)
1142 pfs_restsInfo_t *info=&fileSlots[i].restsInfo;
1143 if(info->dirty) {
1144 pfs_mount_t *pfsMount=fileSlots[i].clink->pfsMount;
1145 pfsMount->blockDev->transfer(pfsMount->fd, &fileSlots[i].restsBuffer,
1146 info->sub, info->sector, 1, IOCTL2_TMODE_WRITE);
1147 fileSlots[i].restsInfo.dirty=0;
1152 int pfsSync(iop_file_t *f, const char *dev, int flag)
1154 pfs_mount_t *pfsMount;
1156 if(!(pfsMount = fioGetMountedUnit(f->unit)))
1157 return -ENODEV;
1159 _sync();
1160 cacheFlushAllDirty(pfsMount);
1161 hddFlushCache(pfsMount->fd);
1163 SignalSema(pfsFioSema);
1164 return checkForLastError(pfsMount, 0);
1167 int pfsMount(iop_file_t *f, const char *fsname, const char *devname, int flag, void *arg, size_t arglen)
1169 int rv;
1170 int fd;
1171 block_device *blockDev;
1173 if(!(blockDev = getDeviceTable(devname)))
1174 return -ENXIO;
1176 WaitSema(pfsFioSema);
1178 fd = open(devname, (flag & O_RDONLY) ? O_RDONLY : O_RDWR, 0644); // ps2hdd.irx fd
1179 if(fd < 0)
1180 rv = fd;
1181 else {
1182 dprintf("ps2fs: Mounting device..\n");
1183 if((rv=mountDevice(blockDev, fd, f->unit, flag)) < 0)
1184 close(fd);
1186 SignalSema(pfsFioSema);
1187 return rv;
1190 void _umount(pfs_mount_t *pfsMount)
1192 u32 i;
1194 cacheFlushAllDirty(pfsMount);
1195 for(i=1; i < numBuffers+1;i++){
1196 if(cacheBuf[i].pfsMount==pfsMount)
1197 cacheBuf[i].pfsMount=NULL;
1200 hddFlushCache(pfsMount->fd);
1203 int pfsUmount(iop_file_t *f, const char *fsname)
1205 u32 i;
1206 int rv=0;
1207 int busy_flag=0;
1208 pfs_mount_t *pfsMount;
1210 if((pfsMount = fioGetMountedUnit(f->unit))==NULL)
1211 return -ENODEV;
1213 for(i = 0; i < pfsConfig.maxOpen; i++)
1215 if((fileSlots[i].clink!=NULL) && (fileSlots[i].clink->pfsMount==pfsMount))
1217 busy_flag=1;
1218 break;
1221 if(busy_flag==0)
1223 _umount(pfsMount);
1224 close(pfsMount->fd);
1225 clearMount(pfsMount);
1227 else
1228 rv=-EBUSY; // Mount device busy
1230 SignalSema(pfsFioSema);
1231 return rv;
1234 int pfsSymlink(iop_file_t *f, const char *old, const char *new)
1236 int rv;
1237 pfs_mount_t *pfsMount;
1238 int mode=0x141FF;
1240 if(old==NULL || new==NULL)
1241 return -ENOENT;
1243 if(!(pfsMount=fioGetMountedUnit(f->unit)))
1244 return -ENODEV;
1246 rv = openFile(pfsMount, (pfs_file_slot_t *)old, (const char *)new, O_CREAT|O_WRONLY, mode);
1247 SignalSema(pfsFioSema);
1248 return rv;
1251 int pfsReadlink(iop_file_t *f, const char *path, char *buf, int buflen)
1253 int rv=0;
1254 pfs_mount_t *pfsMount;
1255 pfs_cache_t *clink;
1257 if(buflen < 0)
1258 return -EINVAL;
1259 if(!(pfsMount=fioGetMountedUnit(f->unit)))
1260 return -ENODEV;
1262 if((clink=inodeGetFile(pfsMount, NULL, path, &rv))!=NULL)
1264 if((clink->u.inode->mode & FIO_S_IFMT) == FIO_S_IFLNK)
1265 rv=-EINVAL;
1266 else
1268 rv=strlen((char *)&clink->u.inode->data[1]);
1269 if(buflen < rv)
1270 rv=buflen;
1271 memcpy(buf, &clink->u.inode->data[1], rv);
1273 cacheAdd(clink);
1275 SignalSema(pfsFioSema);
1277 return checkForLastError(pfsMount, rv);
1280 int pfsUnsupported()
1282 printf("ps2fs: Error: Operation currently unsupported.\n");
1284 return -1;