feat: add sfsWriteRaw and sfsTruncateInode to sfs

This commit is contained in:
dualfroz committed 2026-09-07 17:12:31 +02:00
1 parent 1203e0880e
commit c13e57d322
1 file changed
+168
+168
View File
@@ -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--;
}