feat: extend vfs with vfsChdir and vfsGetcwd
This commit is contained in:
1 parent
5b5b0203dd
commit
4dee5e3009
1 file changed
+106
@@ -1535,6 +1535,62 @@ int64 vfsReadlink(const char* path, char* buffer, uint64 cap)
|
||||
int vfsLink(const char* existingPath, const char* newPath)
|
||||
{
|
||||
char resolvedExisting[fsPathMax];
|
||||
char resolvedNew[fsPathMax];
|
||||
vfsResolvePath(existingPath, resolvedExisting, sizeof(resolvedExisting));
|
||||
vfsResolvePath(newPath, resolvedNew, sizeof(resolvedNew));
|
||||
existingPath = resolvedExisting;
|
||||
newPath = resolvedNew;
|
||||
|
||||
const char* existingRel;
|
||||
const char* newRel;
|
||||
/* Cross-filesystem hardlinks (one path under /mnt, the other not) are
|
||||
not supported -- same scope limit as a real link(2) across different
|
||||
mounted filesystems (EXDEV), just expressed as a flat rejection since
|
||||
this kernel has exactly one linkable filesystem. */
|
||||
if (!isSfsPath(existingPath, &existingRel) || !isSfsPath(newPath, &newRel))
|
||||
return -1;
|
||||
return sfsLink(existingRel, newRel) >= 0 ? 0 : -1;
|
||||
}
|
||||
|
||||
int vfsChdir(const char* path)
|
||||
{
|
||||
char resolvedPath[fsPathMax];
|
||||
vfsResolvePath(path, resolvedPath, sizeof(resolvedPath));
|
||||
|
||||
const char* rel;
|
||||
if (isSfsPath(resolvedPath, &rel)) {
|
||||
int32 inodeNum = sfsLookup(rel);
|
||||
if (inodeNum < 0 || sfsTypeOf(inodeNum) != sfsTypeDir)
|
||||
return -1;
|
||||
/* No parent-walk primitive exists for sfs.h inodes (unlike vfsPath
|
||||
below for the VfsNode tree), so the /mnt branch stores exactly
|
||||
what vfsResolvePath produced -- the one honestly-scoped gap
|
||||
vfsChdir's own doc comment (vfs.h) calls out. */
|
||||
return currentThreadSetCwd(resolvedPath) ? 0 : -1;
|
||||
}
|
||||
|
||||
VfsNode* node = lookupNode(resolvedPath);
|
||||
if (!node || node->type != fsTypeDir)
|
||||
return -1;
|
||||
|
||||
/* Canonicalizes away any "."/".." components the caller typed by
|
||||
walking the resolved node's REAL parent chain (vfsPath), rather than
|
||||
storing vfsResolvePath's own plain string join verbatim -- shell.c's
|
||||
old changeDir already did exactly this before this subsystem
|
||||
existed, so this keeps that behavior for the VfsNode-tree case. */
|
||||
char canonical[fsPathMax];
|
||||
vfsPath(node, canonical, sizeof(canonical));
|
||||
return currentThreadSetCwd(canonical) ? 0 : -1;
|
||||
}
|
||||
|
||||
int64 vfsGetcwd(char* out, uint64 cap)
|
||||
{
|
||||
const char* cwd = currentThreadCwd();
|
||||
uint64 len = strlen(cwd);
|
||||
if (len >= cap)
|
||||
return -1;
|
||||
memcpy(out, cwd, len + 1);
|
||||
return (int64)len;
|
||||
}
|
||||
|
||||
VfsNode* vfsLookup(const char* path)
|
||||
@@ -1567,6 +1623,56 @@ uint64 vfsSize(VfsNode* node)
|
||||
return node->size;
|
||||
}
|
||||
|
||||
uint32 vfsMode(VfsNode* node)
|
||||
{
|
||||
return node->mode;
|
||||
}
|
||||
|
||||
uint32 vfsUid(VfsNode* node)
|
||||
{
|
||||
return node->uid;
|
||||
}
|
||||
|
||||
uint32 vfsGid(VfsNode* node)
|
||||
{
|
||||
return node->gid;
|
||||
}
|
||||
|
||||
/* Real Unix owner/other permission algorithm, the one real choke-point
|
||||
piece of logic resolveOpen's two branches (tmpfs, SFS) and syscall.c's
|
||||
loadImageByPath/jobctl.c's jobctlSpawn all now share instead of each
|
||||
re-deriving it -- previously all four sites just tested a single bit
|
||||
unconditionally (`mode & fsModeOwnerWrite`), honest only because there
|
||||
was no uid model yet to make owner-vs-other meaningful. Deliberately a
|
||||
pure function of its four arguments, not of "whoever is currently
|
||||
running" -- every real call site passes currentThreadUid() in explicitly
|
||||
for `callerUid`, so this stays testable against arbitrary uid/mode/owner
|
||||
combinations without ever touching a live thread's own credential (see
|
||||
coreTest.c's own KTEST coverage). `wantOwnerBit` is always one of
|
||||
fs.h's fsModeOwner* constants; the matching "other" bit is derived by
|
||||
shifting it right 6 (fsModeOther*'s own doc comment explains why that is
|
||||
exact, not approximate) rather than requiring a second argument.
|
||||
|
||||
Deliberately NO uid-0-bypasses-everything superuser rule, unlike real
|
||||
Unix's root: every boot-time process starts at uid 0 (sched.h's
|
||||
Thread.uid doc comment), so a blanket bypass would have silently undone
|
||||
the entire pre-existing "chmod denies write even to the file's own
|
||||
creator" contract every current permission test (this file's own
|
||||
resolveOpen tests, permtest.c's live demo) already relies on -- caught
|
||||
by exactly those tests going red the first time this function existed
|
||||
with a bypass in it. uid 0 is simply this kernel's default starting
|
||||
identity, gated by the same owner/other bits as any other uid; its only
|
||||
real asymmetry is currentThreadSetUid's own one-way privilege-drop rule
|
||||
(sched.h), not a free pass here. */
|
||||
bool vfsPermitted(uint32 mode, uint32 ownerUid, uint32 ownerGid, uint32 callerUid, uint32 callerGid, uint32 wantOwnerBit)
|
||||
{
|
||||
if (callerUid == ownerUid)
|
||||
return (mode & wantOwnerBit) != 0;
|
||||
if (callerGid == ownerGid)
|
||||
return (mode & (wantOwnerBit >> 3)) != 0;
|
||||
return (mode & (wantOwnerBit >> 6)) != 0;
|
||||
}
|
||||
|
||||
const void* vfsFileData(VfsNode* node)
|
||||
{
|
||||
if (!node)
|
||||
|
||||
Reference in new issue
Block a user