diff --git a/include/functions.h b/include/functions.h index d2eee60615..0970b330c5 100644 --- a/include/functions.h +++ b/include/functions.h @@ -246,7 +246,7 @@ void Sleep_Msec(u32 ms); void Sleep_Sec(u32 sec); // void __osSetCause(void); s32 osSendMesg(OSMesgQueue* mq, OSMesg msg, s32 flags); -// void osPfsFreeBlocks(void); +s32 osPfsFreeBlocks(OSPfs* pfs, s32* leftoverBytes); void osViExtendVStart(u32 param_1); void osStopThread(OSThread* t); s32 osRecvMesg(OSMesgQueue* mq, OSMesg* msg, s32 flags); @@ -325,8 +325,9 @@ void osViSetMode(OSViMode* modep); // void __osSetConfig(void); void guLookAtF(float mf[4][4], f32 xEye, f32 yEye, f32 zEye, f32 xAt, f32 yAt, f32 zAt, f32 xUp, f32 yUp, f32 zUp); void guLookAt(Mtx* m, f32 xEye, f32 yEye, f32 zEye, f32 xAt, f32 yAt, f32 zAt, f32 xUp, f32 yUp, f32 zUp); -// void osPfsAllocateFile(UNK_TYPE1 param_1, UNK_TYPE1 param_2, UNK_TYPE1 param_3, UNK_TYPE1 param_4, UNK_TYPE4 param_5, UNK_TYPE4 param_6, UNK_TYPE4 param_7); -// void __osPfsDeclearPage(UNK_TYPE1 param_1, UNK_TYPE1 param_2, UNK_TYPE1 param_3, UNK_TYPE1 param_4, UNK_TYPE1 param_5, UNK_TYPE4 param_6, UNK_TYPE4 param_7); +s32 osPfsAllocateFile(OSPfs* pfs, u16 companyCode, u32 gameCode, u8* gameName, u8* extName, s32 fileSize, s32* fileNo); +s32 __osPfsDeclearPage(OSPfs* pfs, __OSInode* inode, s32 fileSizeInPages, s32* startPage, u8 bank, s32* decleared, + s32* finalPage); s32 osStopTimer(OSTimer* t); u32 __osProbeTLB(void* param_1); void osCreatePiManager(OSPri pri, OSMesgQueue* cmdQ, OSMesg* cmdBuf, s32 cmdMsgCnt); diff --git a/src/libultra/io/pfsallocatefile.c b/src/libultra/io/pfsallocatefile.c index fd7bdeef3f..821568b87d 100644 --- a/src/libultra/io/pfsallocatefile.c +++ b/src/libultra/io/pfsallocatefile.c @@ -1,5 +1,138 @@ +#include "ultra64.h" #include "global.h" -#pragma GLOBAL_ASM("asm/non_matchings/boot/pfsallocatefile/osPfsAllocateFile.s") +s32 osPfsAllocateFile(OSPfs* pfs, u16 companyCode, u32 gameCode, u8* gameName, u8* extName, s32 fileSize, s32* fileNo) { + s32 startPage; + s32 decleared; + s32 prevPage; + s32 oldPrevPage = 0; + s32 ret = 0; + s32 fileSizeInPages; + __OSInode inode; + __OSInode backupInode; + __OSDir dir; + u8 bank; + u8 prevBank = 0; + s32 firsttime = 0; + s32 bytes; + __OSInodeUnit fpage; -#pragma GLOBAL_ASM("asm/non_matchings/boot/pfsallocatefile/__osPfsDeclearPage.s") + if ((companyCode == 0) || (gameCode == 0)) { + return PFS_ERR_INVALID; + } + + fileSizeInPages = (fileSize + PFS_PAGE_SIZE - 1) / PFS_PAGE_SIZE; + + if (((ret = osPfsFindFile(pfs, companyCode, gameCode, gameName, extName, fileNo)) != 0) && + (ret != PFS_ERR_INVALID)) { + return ret; + } + if (*fileNo != -1) { + return PFS_ERR_EXIST; + } + + ret = osPfsFreeBlocks(pfs, &bytes); + if (fileSize > bytes) { + return PFS_DATA_FULL; + } + + if (fileSizeInPages == 0) { + return (PFS_ERR_INVALID); + } + + if (((ret = osPfsFindFile(pfs, 0, 0, NULL, NULL, fileNo)) != 0) && (ret != PFS_ERR_INVALID)) { + return ret; + } + if (*fileNo == -1) { + return PFS_DIR_FULL; + } + + for (bank = PFS_ID_BANK_256K; bank < pfs->banks; bank++) { + if ((ret = __osPfsRWInode(pfs, &inode, PFS_READ, bank)) != 0) { + return ret; + } + ret = __osPfsDeclearPage(pfs, &inode, fileSizeInPages, &startPage, bank, &decleared, &prevPage); + if (ret) { + return ret; + } + if (startPage != -1) { /* There is free space */ + if (firsttime == 0) { + fpage.inode_t.page = (u8)startPage; + fpage.inode_t.bank = bank; + } else { /* Writing previous bank inode */ + backupInode.inodePage[oldPrevPage].inode_t.bank = bank; + backupInode.inodePage[oldPrevPage].inode_t.page = (u8)startPage; + if ((ret = __osPfsRWInode(pfs, &backupInode, PFS_WRITE, prevBank)) != 0) { + return ret; + } + } + if (fileSizeInPages > decleared) { + bcopy(&inode, &backupInode, sizeof(__OSInode)); + oldPrevPage = prevPage; + prevBank = bank; + fileSizeInPages -= decleared; + firsttime++; + } else { + fileSizeInPages = 0; + if ((ret = __osPfsRWInode(pfs, &inode, PFS_WRITE, bank)) != 0) { + return ret; + } + break; + } + } + } + if ((fileSizeInPages > 0) || (startPage == -1)) { + return PFS_ERR_INCONSISTENT; + } + + dir.start_page = fpage; + dir.company_code = companyCode; + dir.game_code = gameCode; + dir.data_sum = 0; + + bcopy(gameName, dir.game_name, PFS_FILE_NAME_LEN); + bcopy(extName, dir.ext_name, PFS_FILE_EXT_LEN); + + return __osContRamWrite(pfs->queue, pfs->channel, pfs->dir_table + *fileNo, (u8*)&dir, 0); +} + +s32 __osPfsDeclearPage(OSPfs* pfs, __OSInode* inode, s32 fileSizeInPages, s32* startPage, u8 bank, s32* decleared, + s32* finalPage) { + s32 j; + s32 spage, prevPage; + s32 ret = 0; + s32 offset = ((bank > PFS_ID_BANK_256K) ? 1 : pfs->inodeStartPage); + + for (j = offset; j < PFS_INODE_SIZE_PER_PAGE; j++) { + if (inode->inodePage[j].ipage == PFS_PAGE_NOT_USED) { + break; + } + } + if (j == PFS_INODE_SIZE_PER_PAGE) { + *startPage = -1; + return ret; + } + + spage = j; + *decleared = 1; + prevPage = j; + j++; + while ((fileSizeInPages > *decleared) && (j < PFS_INODE_SIZE_PER_PAGE)) { + if (inode->inodePage[j].ipage == PFS_PAGE_NOT_USED) { + inode->inodePage[prevPage].inode_t.bank = bank; + inode->inodePage[prevPage].inode_t.page = j; + prevPage = j; + (*decleared)++; + } + j++; + } + + *startPage = spage; + if ((j == (PFS_INODE_SIZE_PER_PAGE)) && (fileSizeInPages > *decleared)) { + *finalPage = prevPage; + } else { + inode->inodePage[prevPage].ipage = PFS_EOF; + *finalPage = 0; + } + return ret; +}