From 39520e618391ac07a2c804f5c6cdf582a45fa5b6 Mon Sep 17 00:00:00 2001 From: DualFroz Date: Mon, 7 Sep 2026 17:13:24 +0200 Subject: [PATCH] feat: add splitPath and dirFind to sfs --- src/sfs.c | 157 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 157 insertions(+) diff --git a/src/sfs.c b/src/sfs.c index a4a2a68..bc7c4aa 100644 --- a/src/sfs.c +++ b/src/sfs.c @@ -636,3 +636,160 @@ static bool sfsTruncateInode(SfsInode* inode, int32 inodeNum, uint32 newSize) 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; +