feat: add sfsReadlink and sfsLink to sfs

This commit is contained in:
dualfroz committed 2026-09-07 18:03:50 +02:00
1 parent b92f439ebc
commit 58b615e840
1 file changed
+160
+160
View File
@@ -1106,3 +1106,163 @@ int32 sfsCreateSymlink(const char* path, const char* target)
if (newInode < 0) if (newInode < 0)
return -1; 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;
}