Nucleus
Barry More VFS functions and structure d3f787c (3 years, 2 months ago)
diff --git a/include/nucleus/vfs.h b/include/nucleus/vfs.h
index 97ebf54..2ab824c 100644
--- a/include/nucleus/vfs.h
+++ b/include/nucleus/vfs.h
@@ -30,6 +30,7 @@ struct SuperBlock {
SuperOps *ops;
Inode *root;
ObjectList *inodes; /* List of cached inodes */
+ File *back;
void *data;
};
struct SuperOps {
@@ -85,6 +86,7 @@ struct FileOps {
size_t (*read)(File *, char *, size_t, off_t);
size_t (*write)(File *, char *, size_t, off_t);
int (*open)(File *);
+ int (*ioctl)(File *, unsigned long, uintptr_t);
void (*mmap)(File *, void *, size_t, off_t);
};
@@ -101,6 +103,7 @@ File *create_anonymous_file(void);
void register_fstype(const char *name, mount_callback_t mount);
int mount(const char *src, const char *target, const char *type,
unsigned long flags, void *data);
+Inode *lookup(const char *path, ObjectList *newcustody);
/* Super Block functions */
Inode *super_alloc_inode(SuperBlock *sb);
@@ -118,6 +121,7 @@ DirEntry *find_direntry(ObjectList *list, const char *name);
int file_open(File *file);
size_t file_read(File *file, char *buf, size_t count);
size_t file_write(File *file, char *buf, size_t count);
+int file_ioctl(File *file, unsigned long request, uintptr_t arpg);
void file_mmap(File *file, void *addr, size_t len, off_t offset);
/* Files namespace functions */
File *get_file_by_fd(int fd);
diff --git a/vfs/file.c b/vfs/file.c
index 0d0f31d..bca19dc 100644
--- a/vfs/file.c
+++ b/vfs/file.c
@@ -146,6 +146,17 @@ end:
return count;
}
+/* I/O Control */
+int
+file_ioctl(File *file, unsigned long request, uintptr_t argp)
+{
+ if (!file->ops)
+ return -EINVAL;
+ if (!file->ops->ioctl)
+ return -ENOTTY;
+ return file->ops->ioctl(file, request, argp);
+}
+
/* Map a file into memory */
void
file_mmap(File *file, void *addr, size_t len, off_t offset)
diff --git a/vfs/files.c b/vfs/files.c
index fffbc42..b830e40 100644
--- a/vfs/files.c
+++ b/vfs/files.c
@@ -101,6 +101,8 @@ close(int fd)
int
read(int fd, void *buf, size_t count)
{
+ if (!buf)
+ return -EFAULT;
if (!verify_access(buf, count, PROT_WRITE))
return -EFAULT;
@@ -121,6 +123,8 @@ read(int fd, void *buf, size_t count)
int
write(int fd, void *buf, size_t count)
{
+ if (!buf)
+ return -EFAULT;
if (!verify_access(buf, count, PROT_READ))
return -EFAULT;
@@ -163,3 +167,22 @@ lseek(int fd, off_t offset, int whence)
unlock(file);
return file->pos;
}
+
+/* Perform I/O control on a file */
+int
+ioctl(int fd, unsigned long request, ...)
+{
+ File *file = get_file_by_fd(fd);
+ if (!file)
+ return -EBADF;
+
+ va_list args;
+ va_start(args, request);
+ uintptr_t argp = va_arg(args, uintptr_t);
+ va_end(args);
+
+ lock(file);
+ int ret = file_ioctl(file, request, argp);
+ unlock(file);
+ return ret;
+}
diff --git a/vfs/mount.c b/vfs/mount.c
index 53bdab2..a321d34 100644
--- a/vfs/mount.c
+++ b/vfs/mount.c
@@ -4,12 +4,14 @@
*/
#include <string.h>
+#include <sys/stat.h>
#include <errno.h>
#include <nucleus/memory.h>
#include <nucleus/task.h>
#include <nucleus/vfs.h>
#include "namespace.h"
+Inode *lookup(const char *path, ObjectList *newcustody);
int mount_fstype(const char *name, int flags, const char *src, void *data,
Inode **root);
@@ -18,6 +20,8 @@ int
mount(const char *src, const char *target, const char *type,
unsigned long flags, void *data)
{
+ if (!src || !type)
+ return -EFAULT;
if (!verify_access(src, strnlen(src, PATH_MAX), PROT_READ))
return -EFAULT;
if (!verify_access(target, strnlen(target, PATH_MAX), PROT_READ))
@@ -39,5 +43,23 @@ mount(const char *src, const char *target, const char *type,
return 0;
}
+ /* Find target's directory entry */
+ ObjectList *custody = create_list(&dirEntryType, LIST_NORMAL);
+ Inode *root = lookup(target, custody);
+ if (!root) {
+ destroy_list(custody);
+ return -ENOENT;
+ }
+ if (!S_ISDIR(root->mode)) {
+ put(root);
+ destroy_list(custody);
+ return -ENOTDIR;
+ }
+ DirEntry *de = get_nth_item(custody, count(custody) - 1);
+ de->mnt = de->inode;
+ de->inode = get(mnt);
+ put(root);
+ destroy_list(custody);
+
return 0;
}
diff --git a/vfs/namespace.c b/vfs/namespace.c
index 1b102af..1d560a9 100644
--- a/vfs/namespace.c
+++ b/vfs/namespace.c
@@ -3,7 +3,12 @@
* task's file system. It tracks a task's root and current working directory.
*/
+#include <string.h>
+#include <sys/stat.h>
+#include <errno.h>
+#include <nucleus/memory.h>
#include <nucleus/object.h>
+#include <nucleus/task.h>
#include <nucleus/vfs.h>
#include "namespace.h"
@@ -47,3 +52,94 @@ file_system_copy(Object *a, Object *b)
child->cwdPath = copy_list(parent->cwdPath);
child->root = get(parent->root);
}
+
+/* Change the current working directory */
+int
+chdir(const char *path)
+{
+ if (!path)
+ return -EFAULT;
+ if (!verify_access(path, strnlen(path, PATH_MAX), PROT_READ))
+ return -EFAULT;
+ ObjectList *custody = create_list(&dirEntryType, LIST_NORMAL);
+ Inode *inode = lookup(path, custody);
+ if (!inode) {
+ destroy_list(custody);
+ return -ENOENT;
+ }
+ if (!S_ISDIR(inode->mode)) {
+ destroy_list(custody);
+ put(inode);
+ return -ENOTDIR;
+ }
+ if (!permission(inode, PROT_READ)) {
+ destroy_list(custody);
+ put(inode);
+ return -EACCES;
+ }
+ put(current->fs->cwd);
+ current->fs->cwd = inode;
+ destroy_list(current->fs->cwdPath);
+ current->fs->cwdPath = custody;
+ return 0;
+}
+
+/* Change the current root */
+int
+chroot(const char *path)
+{
+ if (!path)
+ return -EFAULT;
+ if (!verify_access(path, strnlen(path, PATH_MAX), PROT_READ))
+ return -EFAULT;
+ Inode *inode = lookup(path, NULL);
+ if (!inode)
+ return -ENOENT;
+ if (!S_ISDIR(inode->mode)) {
+ put(inode);
+ return -ENOTDIR;
+ }
+ if (!permission(inode, PROT_READ)) {
+ put(inode);
+ return -EACCES;
+ }
+ put(current->fs->root);
+ current->fs->root = inode;
+ return 0;
+}
+
+/* Get the current working directory's path */
+char *
+getcwd(char *buf, size_t size)
+{
+ if (!buf || !size)
+ return (char *) -EINVAL;
+ if (!verify_access(buf, size, PROT_WRITE))
+ return (char *) -EFAULT;
+ size_t i = 0, len;
+ char path[PATH_MAX];
+ memset(path, 0, PATH_MAX);
+
+ /* Empty path */
+ if (count(current->fs->cwdPath) == 0) {
+ buf[0] = '/';
+ buf[1] = '\0';
+ return buf;
+ }
+ /* Iterate directory entries */
+ DirEntry *de;
+ foreach (current->fs->cwdPath, de) {
+ len = strlen(de->name);
+ if (i + 1 + len >= PATH_MAX)
+ return (char *) -ENAMETOOLONG;
+ if (i + 1 + len >= size)
+ return (char *) -ERANGE;
+ path[i++] = '/';
+ strcpy(path + i, de->name);
+ i += len;
+ }
+ /* Copy to user buffer */
+ strcpy(buf, path);
+ buf[i] = '\0';
+ return buf;
+}
diff --git a/vfs/open.c b/vfs/open.c
index 9dd8978..cac1512 100644
--- a/vfs/open.c
+++ b/vfs/open.c
@@ -116,6 +116,8 @@ end:
int
open(const char *name, int flags, ...)
{
+ if (!name)
+ return -EFAULT;
if (!verify_access(name, strnlen(name, PATH_MAX), PROT_READ))
return -EFAULT;