From c13e57d322ff39d0f357aa333e82f3711c23a8f0 Mon Sep 17 00:00:00 2001 From: DualFroz Date: Mon, 7 Sep 2026 17:12:31 +0200 Subject: [PATCH] feat: add sfsWriteRaw and sfsTruncateInode to sfs --- src/sfs.c | 168 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 168 insertions(+) diff --git a/src/sfs.c b/src/sfs.c index 00d1770..a4a2a68 100644 --- a/src/sfs.c +++ b/src/sfs.c @@ -468,3 +468,171 @@ static bool getBlockForRead(const SfsInode* inode, uint32 logicalIndex, uint32* if (midPtrs[midIndex] == 0) return false; + uint8 leafBuf[sfsBlockSize]; + if (!blockRead(midPtrs[midIndex], leafBuf)) + return false; + uint32* leafPtrs = (uint32*)leafBuf; + *outAbs = leafPtrs[leafIndex]; + return *outAbs != 0; +} + +static bool sfsWriteRaw(SfsInode* inode, int32 inodeNum, uint64 position, const void* data, uint64 length) +{ + if (length == 0) + return true; + + const uint8* src = (const uint8*)data; + uint64 done = 0; + while (done < length) { + uint64 pos = position + done; + uint32 logicalBlock = (uint32)(pos / sfsBlockSize); + uint32 within = (uint32)(pos % sfsBlockSize); + uint32 chunk = sfsBlockSize - within; + if ((uint64)chunk > length - done) + chunk = (uint32)(length - done); + + uint32 blockAbs; + if (!getOrAllocBlockForWrite(inode, logicalBlock, &blockAbs)) + return false; + + uint8 blockBuf[sfsBlockSize]; + if (chunk == sfsBlockSize) { + if (src) + memcpy(blockBuf, src + done, sfsBlockSize); + else + memset(blockBuf, 0, sfsBlockSize); + } else { + if (!blockRead(blockAbs, blockBuf)) + return false; + if (src) + memcpy(blockBuf + within, src + done, chunk); + else + memset(blockBuf + within, 0, chunk); + } + if (!blockWrite(blockAbs, blockBuf)) + return false; + + done += chunk; + } + + uint64 newSize = position + length; + if (newSize > inode->size) + inode->size = (uint32)newSize; + inode->mtime = inode->ctime = (uint32)rtcNow(); + return writeInodeRaw(inodeNum, inode); +} + +static bool sfsTruncateInode(SfsInode* inode, int32 inodeNum, uint32 newSize) +{ + uint32 oldBlocks = inode->size ? (inode->size + sfsBlockSize - 1) / sfsBlockSize : 0; + uint32 neededBlocks = newSize ? (newSize + sfsBlockSize - 1) / sfsBlockSize : 0; + + for (uint32 i = neededBlocks; i < oldBlocks; i++) { + uint32 abs = 0; + if (i < sfsDirectBlocks) { + abs = inode->direct[i]; + inode->direct[i] = 0; + } else { + uint32 indIndex = i - sfsDirectBlocks; + if (indIndex < sfsPtrsPerBlock) { + if (inode->indirect == 0) + continue; + uint8 indBuf[sfsBlockSize]; + if (!blockRead(inode->indirect, indBuf)) + continue; + uint32* ptrs = (uint32*)indBuf; + abs = ptrs[indIndex]; + ptrs[indIndex] = 0; + blockWrite(inode->indirect, indBuf); + } else { + uint32 doubleIndex = indIndex - sfsPtrsPerBlock; + if (doubleIndex < sfsPtrsPerBlock * sfsPtrsPerBlock) { + uint32 outerIndex = doubleIndex / sfsPtrsPerBlock; + uint32 innerIndex = doubleIndex % sfsPtrsPerBlock; + if (inode->doubleIndirect == 0) + continue; + uint8 outerBuf[sfsBlockSize]; + if (!blockRead(inode->doubleIndirect, outerBuf)) + continue; + uint32* outerPtrs = (uint32*)outerBuf; + if (outerPtrs[outerIndex] == 0) + continue; + uint8 innerBuf[sfsBlockSize]; + if (!blockRead(outerPtrs[outerIndex], innerBuf)) + continue; + uint32* innerPtrs = (uint32*)innerBuf; + abs = innerPtrs[innerIndex]; + innerPtrs[innerIndex] = 0; + blockWrite(outerPtrs[outerIndex], innerBuf); + } else { + uint32 tripleIndex = doubleIndex - sfsPtrsPerBlock * sfsPtrsPerBlock; + uint32 topIndex = tripleIndex / (sfsPtrsPerBlock * sfsPtrsPerBlock); + uint32 midIndex = (tripleIndex / sfsPtrsPerBlock) % sfsPtrsPerBlock; + uint32 leafIndex = tripleIndex % sfsPtrsPerBlock; + if (inode->tripleIndirect == 0 || topIndex >= sfsPtrsPerBlock) + continue; + uint8 topBuf[sfsBlockSize]; + if (!blockRead(inode->tripleIndirect, topBuf)) + continue; + uint32* topPtrs = (uint32*)topBuf; + if (topPtrs[topIndex] == 0) + continue; + uint8 midBuf[sfsBlockSize]; + if (!blockRead(topPtrs[topIndex], midBuf)) + continue; + uint32* midPtrs = (uint32*)midBuf; + if (midPtrs[midIndex] == 0) + continue; + uint8 leafBuf[sfsBlockSize]; + if (!blockRead(midPtrs[midIndex], leafBuf)) + continue; + uint32* leafPtrs = (uint32*)leafBuf; + abs = leafPtrs[leafIndex]; + leafPtrs[leafIndex] = 0; + blockWrite(midPtrs[midIndex], leafBuf); + } + } + } + if (abs != 0) { + freeDataBlockAbs(abs); + inode->blockCount--; + } + } + + /* Pointer-holder blocks themselves (the indirect block, every inner + indirect block plus the outer double-indirect block, and every + top/mid/leaf-pointer block of the triple-indirect chain) are + reclaimed all-or-nothing once nothing addressed through them is + needed anymore -- the loop above already frees every leaf data block + that was in range, so by this point each holder either still guards + live data (neededBlocks reaches into its range: leave it alone) or is + entirely spent (free it, and everything it pointed at). Checked + highest level first (triple, then double, then single) so a shrink + that drops the whole file frees every level in one pass. */ + if (neededBlocks <= sfsDirectBlocks + sfsPtrsPerBlock + sfsPtrsPerBlock * sfsPtrsPerBlock + && inode->tripleIndirect != 0) { + uint8 topBuf[sfsBlockSize]; + if (blockRead(inode->tripleIndirect, topBuf)) { + uint32* topPtrs = (uint32*)topBuf; + for (uint32 j = 0; j < sfsPtrsPerBlock; j++) { + if (topPtrs[j] == 0) + continue; + uint8 midBuf[sfsBlockSize]; + if (blockRead(topPtrs[j], midBuf)) { + uint32* midPtrs = (uint32*)midBuf; + for (uint32 k = 0; k < sfsPtrsPerBlock; k++) { + if (midPtrs[k] != 0) { + freeDataBlockAbs(midPtrs[k]); + inode->blockCount--; + } + } + } + freeDataBlockAbs(topPtrs[j]); + inode->blockCount--; + } + } + freeDataBlockAbs(inode->tripleIndirect); + inode->tripleIndirect = 0; + inode->blockCount--; + } +