Shipwright/soh/src/libultra/io/pfsallocatefile.c

140 lines
4.1 KiB
C

#include "ultra64.h"
#include "global.h"
#include "ultra64/pfs.h"
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;
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, 0, 0, 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 = (u8)bank;
inode->inodePage[prevPage].inode_t.page = (u8)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;
}