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

194 lines
6.4 KiB
C

#include "ultra64.h"
#include "global.h"
#include "ultra64/pfs.h"
#define CHECK_IPAGE(p) \
(((p).ipage >= pfs->inodeStartPage) && ((p).inode_t.bank < pfs->banks) && ((p).inode_t.page >= 0x01) && \
((p).inode_t.page < 0x80))
s32 osPfsChecker(OSPfs* pfs) {
s32 j;
s32 ret;
__OSInodeUnit next;
__OSInode checkedInode;
__OSInode tempInode;
__OSDir tempDir;
__OSInodeUnit nextNodeInFile[16];
__OSInodeCache cache;
s32 fixed = 0;
u8 bank, prevBank = 254;
s32 cc, cl;
s32 offset;
ret = __osCheckId(pfs);
if (ret == PFS_ERR_NEW_PACK) {
ret = __osGetId(pfs);
}
if (ret) {
return ret;
}
if ((ret = func_80105788(pfs, &cache)) != 0) {
return ret;
}
for (j = 0; j < pfs->dir_size; j++) {
if ((ret = __osContRamRead(pfs->queue, pfs->channel, pfs->dir_table + j, (u8*)&tempDir)) != 0) {
return ret;
}
if ((tempDir.company_code != 0) || (tempDir.game_code != 0)) {
if ((tempDir.company_code == 0) || (tempDir.game_code == 0)) {
cc = -1;
} else {
next = tempDir.start_page;
cl = cc = 0;
bank = 255;
while (CHECK_IPAGE(next)) {
if (bank != next.inode_t.bank) {
bank = next.inode_t.bank;
if (prevBank != bank) {
ret = __osPfsRWInode(pfs, &tempInode, PFS_READ, bank);
prevBank = bank;
}
if ((ret != 0) && (ret != PFS_ERR_INCONSISTENT)) {
return ret;
}
}
if ((cc = func_80105A60(pfs, next, &cache) - cl) != 0) {
break;
}
cl = 1;
next = tempInode.inodePage[next.inode_t.page];
}
}
if ((cc != 0) || (next.ipage != PFS_EOF)) {
bzero(&tempDir, sizeof(__OSDir));
if (pfs->activebank != 0) {
if ((ret = __osPfsSelectBank(pfs, 0)) != 0) {
return ret;
}
}
if ((ret = __osContRamWrite(pfs->queue, pfs->channel, pfs->dir_table + j, (u8*)&tempDir, 0)) != 0) {
return ret;
}
fixed++;
}
}
}
for (j = 0; j < pfs->dir_size; j++) {
if ((ret = __osContRamRead(pfs->queue, pfs->channel, pfs->dir_table + j, (u8*)&tempDir)) != 0) {
return ret;
}
if ((tempDir.company_code != 0) && (tempDir.game_code != 0) &&
(tempDir.start_page.ipage >= (u16)pfs->inodeStartPage)) { // cast required
nextNodeInFile[j].ipage = tempDir.start_page.ipage;
} else {
nextNodeInFile[j].ipage = 0;
}
}
for (bank = 0; bank < pfs->banks; bank++) {
ret = __osPfsRWInode(pfs, &tempInode, PFS_READ, bank);
if ((ret != 0) && (ret != PFS_ERR_INCONSISTENT)) {
return (ret);
}
offset = ((bank > PFS_ID_BANK_256K) ? 1 : pfs->inodeStartPage);
for (j = 0; j < offset; j++) {
checkedInode.inodePage[j].ipage = tempInode.inodePage[j].ipage;
}
for (; j < PFS_INODE_SIZE_PER_PAGE; j++) {
checkedInode.inodePage[j].ipage = PFS_PAGE_NOT_USED;
}
for (j = 0; j < pfs->dir_size; j++) {
while (nextNodeInFile[j].inode_t.bank == bank &&
nextNodeInFile[j].ipage >= (u16)pfs->inodeStartPage) { // cast required
u8 val;
val = nextNodeInFile[j].inode_t.page;
nextNodeInFile[j] = checkedInode.inodePage[val] = tempInode.inodePage[val];
}
}
if ((ret = __osPfsRWInode(pfs, &checkedInode, PFS_WRITE, bank)) != 0) {
return ret;
}
}
if (fixed != 0) {
pfs->status |= PFS_CORRUPTED;
} else {
pfs->status &= ~PFS_CORRUPTED;
}
return 0;
}
// Original name: corrupted_init (probably needs better name)
s32 func_80105788(OSPfs* pfs, __OSInodeCache* cache) {
s32 i;
s32 n;
s32 offset;
u8 bank;
__OSInodeUnit tpage;
__OSInode tempInode;
s32 ret;
for (i = 0; i < PFS_INODE_DIST_MAP; i++) {
cache->map[i] = 0;
}
cache->bank = 255;
for (bank = PFS_ID_BANK_256K; bank < pfs->banks; bank++) {
offset = ((bank > PFS_ID_BANK_256K) ? 1 : pfs->inodeStartPage);
ret = __osPfsRWInode(pfs, &tempInode, PFS_READ, bank);
if ((ret != 0) && (ret != PFS_ERR_INCONSISTENT)) {
return ret;
}
for (i = offset; i < PFS_INODE_SIZE_PER_PAGE; i++) {
tpage = tempInode.inodePage[i];
if ((tpage.ipage >= pfs->inodeStartPage) && (tpage.inode_t.bank != bank)) {
n = ((tpage.inode_t.page & 0x7F) / PFS_SECTOR_SIZE) +
PFS_SECTOR_PER_BANK * (tpage.inode_t.bank % PFS_BANK_LAPPED_BY);
cache->map[n] |= (1 << (bank % PFS_BANK_LAPPED_BY));
}
}
}
return 0;
}
// original name: corrupted (probably needs a better name)
s32 func_80105A60(OSPfs* pfs, __OSInodeUnit fpage, __OSInodeCache* cache) {
s32 j;
s32 n;
s32 hit = 0;
u8 bank;
s32 offset;
s32 ret = 0;
n = (fpage.inode_t.page / PFS_SECTOR_SIZE) + PFS_SECTOR_PER_BANK * (fpage.inode_t.bank % PFS_BANK_LAPPED_BY);
for (bank = PFS_ID_BANK_256K; bank < pfs->banks; bank++) {
offset = ((bank > PFS_ID_BANK_256K) ? 1 : pfs->inodeStartPage);
if ((bank == fpage.inode_t.bank) || (cache->map[n] & (1 << (bank % PFS_BANK_LAPPED_BY))) != 0) {
if (bank != cache->bank) {
ret = __osPfsRWInode(pfs, &(cache->inode), PFS_READ, bank);
if (ret && (ret != PFS_ERR_INCONSISTENT)) {
return ret;
}
cache->bank = bank;
}
for (j = offset; ((hit < 2) && (j < PFS_INODE_SIZE_PER_PAGE)); j++) {
if (cache->inode.inodePage[j].ipage == fpage.ipage) {
hit++;
}
}
if (hit >= 2) {
return 2;
}
}
}
return hit;
}