From 58b615e840834c23d70feb2a3204e812f2fa3412 Mon Sep 17 00:00:00 2001 From: DualFroz Date: Mon, 7 Sep 2026 18:03:50 +0200 Subject: [PATCH] feat: add sfsReadlink and sfsLink to sfs --- src/sfs.c | 160 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 160 insertions(+) diff --git a/src/sfs.c b/src/sfs.c index 573460f..a003d7e 100644 --- a/src/sfs.c +++ b/src/sfs.c @@ -1106,3 +1106,163 @@ int32 sfsCreateSymlink(const char* path, const char* target) if (newInode < 0) return -1; + if (sfsWriteAt(newInode, 0, target, targetLen) != (int64)targetLen) { + char parentBuf[256]; + char leaf[sfsNameMax]; + if (splitPath(path, parentBuf, sizeof(parentBuf), leaf, sizeof(leaf))) { + int32 parentInode = sfsLookup(parentBuf); + if (parentInode >= 0) + dirRemove(parentInode, leaf, strlen(leaf)); + } + freeInodeNum(newInode); + return -1; + } + return newInode; +} + +bool sfsReadlink(int32 inodeNum, char* buf, uint64 cap) +{ + if (!isMounted || inodeNum <= 0) + return false; + return readSymlinkTarget(inodeNum, buf, cap); +} + +int32 sfsLink(const char* existingPath, const char* newPath) +{ + if (!isMounted) + return -1; + + int32 target = sfsLookup(existingPath); + if (target < 0) + return -1; + + SfsInode inode; + if (!readInode(target, &inode)) + return -1; + if (inode.type == sfsTypeDir) + return -1; + + char parentBuf[256]; + char leaf[sfsNameMax]; + if (!splitPath(newPath, parentBuf, sizeof(parentBuf), leaf, sizeof(leaf))) + return -1; + + int32 parentInode = sfsLookup(parentBuf); + if (parentInode < 0 || sfsTypeOf(parentInode) != sfsTypeDir) + return -1; + /* Same parent-directory write check as createNode/sfsRemove above -- + adding a new hardlink NAME needs write permission on the PARENT of + the new name, not on the existing target being linked to. */ + if (!vfsPermitted(sfsModeOf(parentInode), sfsUidOf(parentInode), sfsGidOf(parentInode), + currentThreadUid(), currentThreadGid(), fsModeOwnerWrite)) + return -1; + if (dirFind(parentInode, leaf, strlen(leaf)) >= 0) + return -1; + + inode.linkCount++; + inode.ctime = (uint32)rtcNow(); + if (!writeInodeRaw(target, &inode)) + return -1; + + if (!dirAdd(parentInode, leaf, strlen(leaf), target, inode.type)) { + inode.linkCount--; + writeInodeRaw(target, &inode); + return -1; + } + return target; +} + +uint32 sfsLinkCountOf(int32 inodeNum) +{ + if (!isMounted || inodeNum <= 0) + return 0; + SfsInode inode; + if (!readInode(inodeNum, &inode)) + return 0; + return inode.linkCount; +} + +bool sfsRemove(const char* path) +{ + if (!isMounted) + return false; + + char parentBuf[256]; + char leaf[sfsNameMax]; + if (!splitPath(path, parentBuf, sizeof(parentBuf), leaf, sizeof(leaf))) + return false; + + int32 parentInode = sfsLookup(parentBuf); + if (parentInode < 0) + return false; + /* Same parent-directory write check as createNode above -- removing an + entry needs write permission on the PARENT, not the entry itself, + mirroring vfs.c's vfsUnlink/vfsRmdir's own equivalent tmpfs check. */ + if (!vfsPermitted(sfsModeOf(parentInode), sfsUidOf(parentInode), sfsGidOf(parentInode), + currentThreadUid(), currentThreadGid(), fsModeOwnerWrite)) + return false; + int32 target = dirFind(parentInode, leaf, strlen(leaf)); + if (target < 0) + return false; + + SfsInode inode; + if (!readInode(target, &inode)) + return false; + if (inode.type == sfsTypeDir && inode.size > 0) + return false; + + if (!dirRemove(parentInode, leaf, strlen(leaf))) + return false; + + if (inode.linkCount > 1) { + inode.linkCount--; + inode.ctime = (uint32)rtcNow(); + return writeInodeRaw(target, &inode); + } + + if (!sfsTruncateInode(&inode, target, 0)) + return false; + freeInodeNum(target); + return true; +} + +uint64 sfsSizeOf(int32 inodeNum) +{ + if (!isMounted || inodeNum <= 0) + return 0; + SfsInode inode; + if (!readInode(inodeNum, &inode)) + return 0; + return inode.size; +} + +uint32 sfsTypeOf(int32 inodeNum) +{ + if (!isMounted || inodeNum <= 0) + return sfsTypeFree; + SfsInode inode; + if (!readInode(inodeNum, &inode)) + return sfsTypeFree; + return inode.type; +} + +uint64 sfsMtimeOf(int32 inodeNum) +{ + if (!isMounted || inodeNum <= 0) + return 0; + SfsInode inode; + if (!readInode(inodeNum, &inode)) + return 0; + return inode.mtime; +} + +uint64 sfsCtimeOf(int32 inodeNum) +{ + if (!isMounted || inodeNum <= 0) + return 0; + SfsInode inode; + if (!readInode(inodeNum, &inode)) + return 0; + return inode.ctime; +} +