feat: add inodeLocation and inodeNumInRange to sfs

This commit is contained in:
dualfroz committed 2026-09-07 15:04:25 +02:00
1 parent 3dfdda8771
commit 8f2ecdb2d4
1 file changed
+151
+151
View File
@@ -156,3 +156,154 @@ static bool flushSuperblock(void)
return blockWrite(0, buf); return blockWrite(0, buf);
} }
static void inodeLocation(int32 inodeNum, uint32* blockAbs, uint32* index)
{
uint32 perBlock = sfsBlockSize / sizeof(SfsInode);
*blockAbs = sb.inodeTableStart + (uint32)inodeNum / perBlock;
*index = (uint32)inodeNum % perBlock;
}
/* Shared bound check for readInode/writeInodeRaw below: every REAL inode
number allocInodeNum ever hands out satisfies 1 <= n < sb.inodeCount (the
loop above never even considers slot 0, reserved as an eternal sentinel).
Every one of this file's own internal callers already passes a value it
got from allocInodeNum/sfsLookup/dirFind, so this never rejects a
legitimate call -- it exists to stop an out-of-range inodeNum (a caller
bug, or a deliberately-invalid probe like sfsModeOf(9999)) from silently
computing a block address past the real inode table and reading/writing
whatever data block happens to live there instead of failing cleanly. */
static bool inodeNumInRange(int32 inodeNum)
{
return inodeNum > 0 && (uint32)inodeNum < sb.inodeCount;
}
static bool readInode(int32 inodeNum, SfsInode* out)
{
if (!inodeNumInRange(inodeNum))
return false;
uint32 blk, idx;
inodeLocation(inodeNum, &blk, &idx);
uint8 buf[sfsBlockSize];
if (!blockRead(blk, buf))
return false;
memcpy(out, buf + (uint64)idx * sizeof(SfsInode), sizeof(SfsInode));
return true;
}
static bool writeInodeRaw(int32 inodeNum, const SfsInode* in)
{
if (!inodeNumInRange(inodeNum))
return false;
uint32 blk, idx;
inodeLocation(inodeNum, &blk, &idx);
uint8 buf[sfsBlockSize];
if (!blockRead(blk, buf))
return false;
memcpy(buf + (uint64)idx * sizeof(SfsInode), in, sizeof(SfsInode));
return blockWrite(blk, buf);
}
static int32 allocInodeNum(void)
{
for (uint32 i = 1; i < sb.inodeCount; i++) {
if (!bitTest(inodeBitmap, i)) {
bitSet(inodeBitmap, i);
flushInodeBitmap();
return (int32)i;
}
}
return -1;
}
static void freeInodeNum(int32 inodeNum)
{
bitClear(inodeBitmap, (uint32)inodeNum);
flushInodeBitmap();
}
static int32 allocDataBlockAbs(void)
{
uint32 dataBlockCount = sb.totalBlocks - sb.dataStart;
for (uint32 i = 0; i < dataBlockCount; i++) {
if (!bitTest(blockBitmap, i)) {
bitSet(blockBitmap, i);
flushBlockBitmap();
uint32 abs = sb.dataStart + i;
uint8 zero[sfsBlockSize];
memset(zero, 0, sizeof(zero));
blockWrite(abs, zero);
return (int32)abs;
}
}
return -1;
}
static void freeDataBlockAbs(uint32 blockAbs)
{
bitClear(blockBitmap, blockAbs - sb.dataStart);
flushBlockBitmap();
}
/* Allocates (if needed) blockAbs's holderAbs on first use and returns the
holder block's contents in buf, zeroed for a fresh allocation. Shared by
the single-indirect and each level of the double-indirect path below, so
the "allocate a pointer block, zero it, write it back" dance is written
once. *holderAbs is updated (and inode->blockCount bumped) when a new
block is allocated. */
static bool loadOrAllocPointerBlock(SfsInode* inode, uint32* holderAbs, uint8* buf)
{
if (*holderAbs == 0) {
int32 nb = allocDataBlockAbs();
if (nb < 0)
return false;
*holderAbs = (uint32)nb;
inode->blockCount++;
memset(buf, 0, sfsBlockSize);
return blockWrite(*holderAbs, buf);
}
return blockRead(*holderAbs, buf);
}
static bool getOrAllocBlockForWrite(SfsInode* inode, uint32 logicalIndex, uint32* outAbs)
{
if (logicalIndex < sfsDirectBlocks) {
if (inode->direct[logicalIndex] == 0) {
int32 nb = allocDataBlockAbs();
if (nb < 0)
return false;
inode->direct[logicalIndex] = (uint32)nb;
inode->blockCount++;
}
*outAbs = inode->direct[logicalIndex];
return true;
}
uint32 indIndex = logicalIndex - sfsDirectBlocks;
if (indIndex < sfsPtrsPerBlock) {
uint8 indBuf[sfsBlockSize];
if (!loadOrAllocPointerBlock(inode, &inode->indirect, indBuf))
return false;
uint32* ptrs = (uint32*)indBuf;
if (ptrs[indIndex] == 0) {
int32 nb = allocDataBlockAbs();
if (nb < 0)
return false;
ptrs[indIndex] = (uint32)nb;
inode->blockCount++;
if (!blockWrite(inode->indirect, indBuf))
return false;
}
*outAbs = ptrs[indIndex];
return true;
}
uint32 doubleIndex = indIndex - sfsPtrsPerBlock;
if (doubleIndex < sfsPtrsPerBlock * sfsPtrsPerBlock) {
uint32 outerIndex = doubleIndex / sfsPtrsPerBlock;
uint32 innerIndex = doubleIndex % sfsPtrsPerBlock;
uint8 outerBuf[sfsBlockSize];
if (!loadOrAllocPointerBlock(inode, &inode->doubleIndirect, outerBuf))
return false;