feat: build out vfs
This commit is contained in:
1 parent
3124635682
commit
4640fb5eb5
1 file changed
+140
-18
@@ -1122,15 +1122,17 @@ int64 vfsRead(int fd, void* buffer, uint64 length)
|
|||||||
return sfsFdRead(d, buffer, length);
|
return sfsFdRead(d, buffer, length);
|
||||||
|
|
||||||
if (d->kind == fdConsole) {
|
if (d->kind == fdConsole) {
|
||||||
char* text = (char*)buffer;
|
/* Non-blocking, like every other real fd kind above: -1 (queue
|
||||||
uint64 count = 0;
|
currently empty) is the "would block" signal syscall.c's sysRead
|
||||||
while (count < length) {
|
retries via vfsBlockingChannel's channel + the restart-syscall
|
||||||
char c = keyboardReadChar();
|
trick, instead of this function looping/halting in place the way
|
||||||
text[count++] = c;
|
the old single-global-buffer keyboardReadChar() used to. Returns
|
||||||
if (c == '\n')
|
whatever is queued right now (possibly fewer than length bytes,
|
||||||
break;
|
same partial-read contract pipeRead already has) rather than
|
||||||
}
|
insisting on a full line -- nothing in this kernel relied on the
|
||||||
return (int64)count;
|
old line-buffering behavior (grep shows no caller ever read fd 0
|
||||||
|
before this wave). */
|
||||||
|
return keyboardReaderRead(d->pipeHandle, buffer, length);
|
||||||
}
|
}
|
||||||
|
|
||||||
VfsNode* node = d->node;
|
VfsNode* node = d->node;
|
||||||
@@ -1149,7 +1151,7 @@ int64 vfsRead(int fd, void* buffer, uint64 length)
|
|||||||
int64 vfsLseek(int fd, int64 offset, int whence)
|
int64 vfsLseek(int fd, int64 offset, int whence)
|
||||||
{
|
{
|
||||||
FileDescriptor* d = fdAt(fd);
|
FileDescriptor* d = fdAt(fd);
|
||||||
if (!d || d->kind != fdFile)
|
if (!d || (d->kind != fdFile && d->kind != fdBlockDev && d->kind != fdSfs))
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
int64 base;
|
int64 base;
|
||||||
@@ -1157,9 +1159,14 @@ int64 vfsLseek(int fd, int64 offset, int whence)
|
|||||||
base = 0;
|
base = 0;
|
||||||
else if (whence == seekCur)
|
else if (whence == seekCur)
|
||||||
base = (int64)d->offset;
|
base = (int64)d->offset;
|
||||||
else if (whence == seekEnd)
|
else if (whence == seekEnd) {
|
||||||
base = (int64)d->node->size;
|
if (d->kind == fdBlockDev)
|
||||||
else
|
base = (int64)blockDevTotalBytes();
|
||||||
|
else if (d->kind == fdSfs)
|
||||||
|
base = (int64)sfsSizeOf(d->pipeHandle);
|
||||||
|
else
|
||||||
|
base = (int64)d->node->size;
|
||||||
|
} else
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
int64 target = base + offset;
|
int64 target = base + offset;
|
||||||
@@ -1171,20 +1178,75 @@ int64 vfsLseek(int fd, int64 offset, int whence)
|
|||||||
|
|
||||||
int vfsStat(const char* path, FbStat* out)
|
int vfsStat(const char* path, FbStat* out)
|
||||||
{
|
{
|
||||||
|
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;
|
||||||
|
out->size = sfsSizeOf(inodeNum);
|
||||||
|
out->type = sfsTypeToFsType(sfsTypeOf(inodeNum));
|
||||||
|
out->mode = sfsModeOf(inodeNum);
|
||||||
|
out->uid = sfsUidOf(inodeNum);
|
||||||
|
out->gid = sfsGidOf(inodeNum);
|
||||||
|
out->mtime = sfsMtimeOf(inodeNum);
|
||||||
|
out->ctime = sfsCtimeOf(inodeNum);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (strcmp(path, blockDevPath) == 0) {
|
||||||
|
out->size = blockDevTotalBytes();
|
||||||
|
out->type = fsTypeFile;
|
||||||
|
out->mode = 0666;
|
||||||
|
out->uid = 0;
|
||||||
|
out->gid = 0;
|
||||||
|
out->mtime = 0;
|
||||||
|
out->ctime = 0;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
VfsNode* node = lookupNode(path);
|
VfsNode* node = lookupNode(path);
|
||||||
if (!node)
|
if (!node)
|
||||||
return -1;
|
return -1;
|
||||||
out->size = node->size;
|
out->size = node->size;
|
||||||
out->type = node->type;
|
out->type = node->type;
|
||||||
out->mode = node->writable ? 0666 : 0444;
|
out->mode = node->mode;
|
||||||
|
out->uid = node->uid;
|
||||||
|
out->gid = node->gid;
|
||||||
|
out->mtime = 0;
|
||||||
|
out->ctime = 0;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int64 vfsGetdents(int fd, void* buffer, uint64 length)
|
int64 vfsGetdents(int fd, void* buffer, uint64 length)
|
||||||
{
|
{
|
||||||
FileDescriptor* d = fdAt(fd);
|
FileDescriptor* d = fdAt(fd);
|
||||||
if (!d || d->kind != fdFile)
|
if (!d || (d->kind != fdFile && d->kind != fdSfs))
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
|
if (d->kind == fdSfs) {
|
||||||
|
if (sfsTypeOf(d->pipeHandle) != sfsTypeDir)
|
||||||
|
return -1;
|
||||||
|
FbDirent* out = (FbDirent*)buffer;
|
||||||
|
uint64 written = 0;
|
||||||
|
char name[fsNameMax];
|
||||||
|
uint32 type;
|
||||||
|
while (written + sizeof(FbDirent) <= length &&
|
||||||
|
sfsReaddirAt(d->pipeHandle, (uint32)d->offset, name, sizeof(name), &type)) {
|
||||||
|
uint64 nameLen = strlen(name);
|
||||||
|
out->type = sfsTypeToFsType(type);
|
||||||
|
out->nameLength = (unsigned int)nameLen;
|
||||||
|
memcpy(out->name, name, nameLen + 1);
|
||||||
|
out++;
|
||||||
|
written += sizeof(FbDirent);
|
||||||
|
d->offset++;
|
||||||
|
}
|
||||||
|
return (int64)written;
|
||||||
|
}
|
||||||
|
|
||||||
VfsNode* node = d->node;
|
VfsNode* node = d->node;
|
||||||
if (node->type != fsTypeDir)
|
if (node->type != fsTypeDir)
|
||||||
return -1;
|
return -1;
|
||||||
@@ -1214,28 +1276,88 @@ int64 vfsGetdents(int fd, void* buffer, uint64 length)
|
|||||||
|
|
||||||
int vfsMkdir(const char* path)
|
int vfsMkdir(const char* path)
|
||||||
{
|
{
|
||||||
|
char resolvedPath[fsPathMax];
|
||||||
|
vfsResolvePath(path, resolvedPath, sizeof(resolvedPath));
|
||||||
|
path = resolvedPath;
|
||||||
|
|
||||||
|
const char* rel;
|
||||||
|
if (isSfsPath(path, &rel))
|
||||||
|
return sfsCreateDir(rel) >= 0 ? 0 : -1;
|
||||||
|
|
||||||
if (lookupNode(path))
|
if (lookupNode(path))
|
||||||
return -1;
|
return -1;
|
||||||
char leaf[fsNameMax];
|
char leaf[fsNameMax];
|
||||||
VfsNode* parent = splitParent(path, leaf, sizeof(leaf));
|
VfsNode* parent = splitParent(path, leaf, sizeof(leaf));
|
||||||
if (!parent || parent->type != fsTypeDir || !parent->writable)
|
if (!parent || parent->type != fsTypeDir || !parent->writable
|
||||||
|
|| !vfsPermitted(parent->mode, parent->uid, parent->gid, currentThreadUid(), currentThreadGid(), fsModeOwnerWrite))
|
||||||
return -1;
|
return -1;
|
||||||
return makeChildDir(parent, leaf, strlen(leaf), true) ? 0 : -1;
|
return makeChildDir(parent, leaf, strlen(leaf), true, fsModeDefaultDir) ? 0 : -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
int vfsUnlink(const char* path)
|
int vfsUnlink(const char* path)
|
||||||
{
|
{
|
||||||
|
char resolvedPath[fsPathMax];
|
||||||
|
vfsResolvePath(path, resolvedPath, sizeof(resolvedPath));
|
||||||
|
path = resolvedPath;
|
||||||
|
|
||||||
|
const char* rel;
|
||||||
|
if (isSfsPath(path, &rel)) {
|
||||||
|
int32 inodeNum = sfsLookup(rel);
|
||||||
|
/* Real unlink(2) semantics: EISDIR on a directory, even an empty
|
||||||
|
one -- rmdir(2) (vfsRmdir below) is the only sanctioned way to
|
||||||
|
remove one. sfsRemove itself has no opinion here (it is the raw
|
||||||
|
on-disk primitive, also used by vfsRmdir below), so the type
|
||||||
|
check has to happen at this dispatch layer, matching the tmpfs
|
||||||
|
branch below which has always refused a directory this way. */
|
||||||
|
if (inodeNum < 0 || sfsTypeOf(inodeNum) == sfsTypeDir)
|
||||||
|
return -1;
|
||||||
|
/* Only the LAST directory entry pointing at a persistent fifo's
|
||||||
|
inode should ever tear down its live pipe.h binding (see
|
||||||
|
sfsFifoForget above) -- a hardlinked fifo (sfsLink does not
|
||||||
|
special-case sfsTypeFifo, unlike sfsTypeDir) losing one of
|
||||||
|
several names must leave any live session alone, exactly like
|
||||||
|
sfsRemove itself only actually frees the inode once linkCount
|
||||||
|
drops to 0. Checked and captured BEFORE sfsRemove, since a
|
||||||
|
successful removal may itself free the inode (readInode on it
|
||||||
|
afterwards would read whatever unrelated data now occupies that
|
||||||
|
slot, if anything). */
|
||||||
|
bool lastLinkOfFifo = sfsTypeOf(inodeNum) == sfsTypeFifo &&
|
||||||
|
sfsLinkCountOf(inodeNum) <= 1;
|
||||||
|
if (!sfsRemove(rel))
|
||||||
|
return -1;
|
||||||
|
if (lastLinkOfFifo)
|
||||||
|
sfsFifoForget(inodeNum);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
VfsNode* node = lookupNode(path);
|
VfsNode* node = lookupNode(path);
|
||||||
if (!node || node->type != fsTypeFile || !node->writable)
|
if (!node || !node->writable || (node->type != fsTypeFile && node->type != fsTypeFifo))
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
|
/* Real unlink(2) semantics: removing a directory ENTRY needs write
|
||||||
|
permission on the PARENT directory, not on the entry itself -- a
|
||||||
|
real Unix caller can delete a read-only file it can write into the
|
||||||
|
containing directory of, matching real Unix's own "the file's own
|
||||||
|
mode is irrelevant to unlink" rule. */
|
||||||
VfsNode* parent = node->parent;
|
VfsNode* parent = node->parent;
|
||||||
|
if (!vfsPermitted(parent->mode, parent->uid, parent->gid, currentThreadUid(), currentThreadGid(), fsModeOwnerWrite))
|
||||||
|
return -1;
|
||||||
|
|
||||||
VfsNode** link = &parent->firstChild;
|
VfsNode** link = &parent->firstChild;
|
||||||
while (*link && *link != node)
|
while (*link && *link != node)
|
||||||
link = &(*link)->nextSibling;
|
link = &(*link)->nextSibling;
|
||||||
if (*link)
|
if (*link)
|
||||||
*link = node->nextSibling;
|
*link = node->nextSibling;
|
||||||
|
|
||||||
|
/* Any fd already opened on this fifo (fdPipeRead/fdPipeWrite) keeps
|
||||||
|
working off its own copy of node->pipeHandle -- it never dereferences
|
||||||
|
this node again, so freeing it here does not disturb a live reader or
|
||||||
|
writer, matching real unlink-while-open semantics. Only reclaim the
|
||||||
|
underlying pipe slot if nobody ever actually opened it; otherwise the
|
||||||
|
still-open ends must keep it alive until their own vfsClose. */
|
||||||
|
if (node->type == fsTypeFifo)
|
||||||
|
pipeDestroyIfUnattached(node->pipeHandle);
|
||||||
|
|
||||||
if (node->rwData)
|
if (node->rwData)
|
||||||
kfree(node->rwData);
|
kfree(node->rwData);
|
||||||
kfree(node);
|
kfree(node);
|
||||||
|
|||||||
Reference in new issue
Block a user