feat: add splitPath and dirFind to sfs

This commit is contained in:
dualfroz committed 2026-09-07 17:13:24 +02:00
1 parent c13e57d322
commit 39520e6183
1 file changed
+157
+157
View File
@@ -636,3 +636,160 @@ static bool sfsTruncateInode(SfsInode* inode, int32 inodeNum, uint32 newSize)
inode->blockCount--; inode->blockCount--;
} }
if (neededBlocks <= sfsDirectBlocks + sfsPtrsPerBlock && inode->doubleIndirect != 0) {
uint8 outerBuf[sfsBlockSize];
if (blockRead(inode->doubleIndirect, outerBuf)) {
uint32* outerPtrs = (uint32*)outerBuf;
for (uint32 j = 0; j < sfsPtrsPerBlock; j++) {
if (outerPtrs[j] != 0) {
freeDataBlockAbs(outerPtrs[j]);
inode->blockCount--;
}
}
}
freeDataBlockAbs(inode->doubleIndirect);
inode->doubleIndirect = 0;
inode->blockCount--;
}
if (neededBlocks <= sfsDirectBlocks && inode->indirect != 0) {
freeDataBlockAbs(inode->indirect);
inode->indirect = 0;
inode->blockCount--;
}
inode->size = newSize;
inode->mtime = inode->ctime = (uint32)rtcNow();
return writeInodeRaw(inodeNum, inode);
}
static bool splitPath(const char* path, char* parentOut, uint64 parentCap, char* leafOut, uint64 leafCap)
{
uint64 len = strlen(path);
while (len > 0 && path[len - 1] == '/')
len--;
if (len == 0)
return false;
int64 slash = -1;
for (int64 i = (int64)len - 1; i >= 0; i--)
if (path[i] == '/') {
slash = i;
break;
}
uint64 leafStart, leafLen;
if (slash < 0) {
parentOut[0] = 0;
leafStart = 0;
leafLen = len;
} else {
uint64 plen = (uint64)slash;
if (plen >= parentCap)
plen = parentCap - 1;
memcpy(parentOut, path, plen);
parentOut[plen] = 0;
leafStart = (uint64)slash + 1;
leafLen = len - leafStart;
}
if (leafLen == 0 || leafLen >= leafCap)
return false;
memcpy(leafOut, path + leafStart, leafLen);
leafOut[leafLen] = 0;
return true;
}
static int32 dirFind(int32 dirInode, const char* name, uint64 nameLen)
{
SfsDirEntry entry;
uint64 pos = 0;
for (;;) {
int64 got = sfsReadAt(dirInode, pos, &entry, sizeof(entry));
if (got != (int64)sizeof(entry))
break;
if (strlen(entry.name) == nameLen && memcmp(entry.name, name, nameLen) == 0)
return (int32)entry.inode;
pos += sizeof(entry);
}
return -1;
}
static bool dirAdd(int32 dirInode, const char* name, uint64 nameLen, int32 childInode, uint32 type)
{
if (nameLen == 0 || nameLen >= sfsNameMax)
return false;
if (dirFind(dirInode, name, nameLen) >= 0)
return false;
SfsDirEntry entry;
memset(&entry, 0, sizeof(entry));
entry.inode = (uint32)childInode;
entry.type = type;
memcpy(entry.name, name, nameLen);
entry.name[nameLen] = 0;
uint64 size = sfsSizeOf(dirInode);
return sfsWriteAt(dirInode, size, &entry, sizeof(entry)) == (int64)sizeof(entry);
}
static bool dirRemove(int32 dirInode, const char* name, uint64 nameLen)
{
SfsDirEntry entry;
uint64 pos = 0;
int64 foundPos = -1;
for (;;) {
int64 got = sfsReadAt(dirInode, pos, &entry, sizeof(entry));
if (got != (int64)sizeof(entry))
break;
if (strlen(entry.name) == nameLen && memcmp(entry.name, name, nameLen) == 0) {
foundPos = (int64)pos;
break;
}
pos += sizeof(entry);
}
if (foundPos < 0)
return false;
uint64 size = sfsSizeOf(dirInode);
uint64 lastPos = size - sizeof(SfsDirEntry);
if ((uint64)foundPos != lastPos) {
SfsDirEntry last;
if (sfsReadAt(dirInode, lastPos, &last, sizeof(last)) != (int64)sizeof(last))
return false;
if (sfsWriteAt(dirInode, (uint64)foundPos, &last, sizeof(last)) != (int64)sizeof(last))
return false;
}
SfsInode inode;
if (!readInode(dirInode, &inode))
return false;
return sfsTruncateInode(&inode, dirInode, (uint32)lastPos);
}
static int32 createNode(const char* path, uint32 type)
{
if (!isMounted)
return -1;
char parentBuf[256];
char leaf[sfsNameMax];
if (!splitPath(path, parentBuf, sizeof(parentBuf), leaf, sizeof(leaf)))
return -1;
int32 parentInode = sfsLookup(parentBuf);
if (parentInode < 0 || sfsTypeOf(parentInode) != sfsTypeDir)
return -1;
/* Real Unix directory-write semantics: creating a NEW entry needs
write permission on the PARENT directory, mirroring vfs.c's
vfsMkdir/resolveOpen create-branch's own equivalent tmpfs check. */
if (!vfsPermitted(sfsModeOf(parentInode), sfsUidOf(parentInode), sfsGidOf(parentInode),
currentThreadUid(), currentThreadGid(), fsModeOwnerWrite))
return -1;
if (dirFind(parentInode, leaf, strlen(leaf)) >= 0)
return -1;
int32 newInode = allocInodeNum();
if (newInode < 0)
return -1;