feat: extend vfs with vfsRmdir and vfsOwnerOrRoot
This commit is contained in:
1 parent
4640fb5eb5
commit
5b5b0203dd
1 file changed
+173
@@ -1364,6 +1364,179 @@ int vfsUnlink(const char* path)
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Real rmdir(2): the counterpart vfsUnlink above deliberately refuses. Only
|
||||
ever removes a directory, and only an EMPTY one (ENOTDIR/ENOTEMPTY in
|
||||
real errno terms, both collapsed to -1 here like every other vfs.c entry
|
||||
point). root itself can never be removed -- root is created non-writable
|
||||
(nodeAlloc("/", ...) in vfsInit), so the same `!node->writable` check
|
||||
every other mutating entry point already relies on covers it for free,
|
||||
no separate identity check needed. */
|
||||
int vfsRmdir(const char* path)
|
||||
{
|
||||
char resolvedPath[fsPathMax];
|
||||
vfsResolvePath(path, resolvedPath, sizeof(resolvedPath));
|
||||
path = resolvedPath;
|
||||
|
||||
const char* rel;
|
||||
if (isSfsPath(path, &rel)) {
|
||||
int32 inodeNum = sfsLookup(rel);
|
||||
if (inodeNum < 0 || sfsTypeOf(inodeNum) != sfsTypeDir)
|
||||
return -1;
|
||||
/* sfsRemove's own `inode.type == sfsTypeDir && inode.size > 0`
|
||||
check (sfs.c) still refuses a non-empty directory -- kept as
|
||||
defense in depth rather than duplicated here. */
|
||||
return sfsRemove(rel) ? 0 : -1;
|
||||
}
|
||||
|
||||
VfsNode* node = lookupNode(path);
|
||||
if (!node || !node->writable || node->type != fsTypeDir || node->firstChild)
|
||||
return -1;
|
||||
|
||||
/* Same parent-directory write check as vfsUnlink above -- removing a
|
||||
directory ENTRY needs write permission on the PARENT, not the
|
||||
directory being removed itself. */
|
||||
VfsNode* parent = node->parent;
|
||||
if (!vfsPermitted(parent->mode, parent->uid, parent->gid, currentThreadUid(), currentThreadGid(), fsModeOwnerWrite))
|
||||
return -1;
|
||||
|
||||
VfsNode** link = &parent->firstChild;
|
||||
while (*link && *link != node)
|
||||
link = &(*link)->nextSibling;
|
||||
if (*link)
|
||||
*link = node->nextSibling;
|
||||
|
||||
kfree(node);
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool vfsOwnerOrRoot(uint32 ownerUid, uint32 callerUid)
|
||||
{
|
||||
return callerUid == 0 || callerUid == ownerUid;
|
||||
}
|
||||
|
||||
int vfsChmod(const char* path, uint32 mode)
|
||||
{
|
||||
char resolvedPath[fsPathMax];
|
||||
vfsResolvePath(path, resolvedPath, sizeof(resolvedPath));
|
||||
path = resolvedPath;
|
||||
|
||||
const char* rel;
|
||||
if (isSfsPath(path, &rel)) {
|
||||
int32 inodeNum = sfsLookup(rel);
|
||||
if (inodeNum < 0)
|
||||
return -1;
|
||||
if (!vfsOwnerOrRoot(sfsUidOf(inodeNum), currentThreadUid()))
|
||||
return -1;
|
||||
return sfsChmod(inodeNum, mode) ? 0 : -1;
|
||||
}
|
||||
|
||||
VfsNode* node = lookupNode(path);
|
||||
if (!node || !node->writable)
|
||||
return -1;
|
||||
if (!vfsOwnerOrRoot(node->uid, currentThreadUid()))
|
||||
return -1;
|
||||
node->mode = mode;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int vfsChown(const char* path, uint32 newUid)
|
||||
{
|
||||
if (currentThreadUid() != 0)
|
||||
return -1;
|
||||
|
||||
char resolvedPath[fsPathMax];
|
||||
vfsResolvePath(path, resolvedPath, sizeof(resolvedPath));
|
||||
path = resolvedPath;
|
||||
|
||||
const char* rel;
|
||||
if (isSfsPath(path, &rel)) {
|
||||
int32 inodeNum = sfsLookup(rel);
|
||||
if (inodeNum < 0)
|
||||
return -1;
|
||||
return sfsChown(inodeNum, newUid) ? 0 : -1;
|
||||
}
|
||||
|
||||
VfsNode* node = lookupNode(path);
|
||||
if (!node || !node->writable)
|
||||
return -1;
|
||||
node->uid = newUid;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int vfsChgrp(const char* path, uint32 newGid)
|
||||
{
|
||||
uint32 callerUid = currentThreadUid();
|
||||
bool isRoot = callerUid == 0;
|
||||
/* Non-root: only the CALLER's own current gid may ever be assigned
|
||||
(this kernel's one-gid-per-thread "membership"), and only by the
|
||||
file's own owner -- both conditions checked up front so neither
|
||||
branch below needs to repeat them. */
|
||||
if (!isRoot && newGid != currentThreadGid())
|
||||
return -1;
|
||||
|
||||
char resolvedPath[fsPathMax];
|
||||
vfsResolvePath(path, resolvedPath, sizeof(resolvedPath));
|
||||
path = resolvedPath;
|
||||
|
||||
const char* rel;
|
||||
if (isSfsPath(path, &rel)) {
|
||||
int32 inodeNum = sfsLookup(rel);
|
||||
if (inodeNum < 0)
|
||||
return -1;
|
||||
if (!isRoot && sfsUidOf(inodeNum) != callerUid)
|
||||
return -1;
|
||||
return sfsChgrp(inodeNum, newGid) ? 0 : -1;
|
||||
}
|
||||
|
||||
VfsNode* node = lookupNode(path);
|
||||
if (!node || !node->writable)
|
||||
return -1;
|
||||
if (!isRoot && node->uid != callerUid)
|
||||
return -1;
|
||||
node->gid = newGid;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int vfsSymlink(const char* path, const char* target)
|
||||
{
|
||||
/* Only `path` (where the symlink itself is created) is resolved against
|
||||
the calling thread's cwd -- `target` (the string stored INSIDE it) is
|
||||
kept exactly as given, never resolved, matching real symlink(2)
|
||||
(a relative target is only ever interpreted later, at traversal
|
||||
time, relative to the symlink's own directory -- not the creating
|
||||
process's cwd at creation time). */
|
||||
char resolvedPath[fsPathMax];
|
||||
vfsResolvePath(path, resolvedPath, sizeof(resolvedPath));
|
||||
|
||||
const char* rel;
|
||||
if (!isSfsPath(resolvedPath, &rel))
|
||||
return -1;
|
||||
return sfsCreateSymlink(rel, target) >= 0 ? 0 : -1;
|
||||
}
|
||||
|
||||
int64 vfsReadlink(const char* path, char* buffer, uint64 cap)
|
||||
{
|
||||
char resolvedPath[fsPathMax];
|
||||
vfsResolvePath(path, resolvedPath, sizeof(resolvedPath));
|
||||
path = resolvedPath;
|
||||
|
||||
const char* rel;
|
||||
if (!isSfsPath(path, &rel))
|
||||
return -1;
|
||||
|
||||
int32 inodeNum = sfsLookupNoFollow(rel);
|
||||
if (inodeNum < 0 || sfsTypeOf(inodeNum) != sfsTypeSymlink)
|
||||
return -1;
|
||||
if (!sfsReadlink(inodeNum, buffer, cap))
|
||||
return -1;
|
||||
return (int64)strlen(buffer);
|
||||
}
|
||||
|
||||
int vfsLink(const char* existingPath, const char* newPath)
|
||||
{
|
||||
char resolvedExisting[fsPathMax];
|
||||
}
|
||||
|
||||
VfsNode* vfsLookup(const char* path)
|
||||
{
|
||||
return lookupNode(path);
|
||||
|
||||
Reference in new issue
Block a user