summaryrefslogtreecommitdiff
path: root/kernel/fs/vfs.c
diff options
context:
space:
mode:
authorAnton Kling <anton@kling.gg>2023-10-30 22:12:14 +0100
committerAnton Kling <anton@kling.gg>2023-10-31 00:18:38 +0100
commit8a9208612eec8ddae4c418485d848ecfa0613699 (patch)
tree2f4b29200c2f0c19ae52f45bdb9b38a41b356e30 /kernel/fs/vfs.c
parentca76600acc8bf7a02346efa5bd8f17072210ec01 (diff)
Meta: Move kernel and userland to their own folders.
This is to allow both the kernel and the userland to share certain header files and to make the folder structure a bit more clear.
Diffstat (limited to 'kernel/fs/vfs.c')
-rw-r--r--kernel/fs/vfs.c318
1 files changed, 318 insertions, 0 deletions
diff --git a/kernel/fs/vfs.c b/kernel/fs/vfs.c
new file mode 100644
index 0000000..0c616a2
--- /dev/null
+++ b/kernel/fs/vfs.c
@@ -0,0 +1,318 @@
+#include <assert.h>
+#include <errno.h>
+#include <fs/vfs.h>
+#include <mmu.h>
+#include <poll.h>
+
+vfs_inode_t *root_dir;
+vfs_mounts_t mounts[10];
+int num_mounts = 0;
+
+vfs_fd_t *get_vfs_fd(int fd) {
+ if (fd >= 100) {
+ klog("get_vfs_fd(): Tried to get out of range fd", LOG_WARN);
+ dump_backtrace(12);
+ return NULL;
+ }
+ if (fd < 0) {
+ klog("get_vfs_fd(): Tried to get out of range fd", LOG_WARN);
+ dump_backtrace(12);
+ return NULL;
+ }
+ return get_current_task()->file_descriptors[fd];
+}
+
+vfs_inode_t *vfs_create_inode(
+ int inode_num, int type, uint8_t has_data, uint8_t can_write,
+ uint8_t is_open, void *internal_object, uint64_t file_size,
+ vfs_inode_t *(*open)(const char *path),
+ int (*create_file)(const char *path, int mode),
+ int (*read)(uint8_t *buffer, uint64_t offset, uint64_t len, vfs_fd_t *fd),
+ int (*write)(uint8_t *buffer, uint64_t offset, uint64_t len, vfs_fd_t *fd),
+ void (*close)(vfs_fd_t *fd),
+ int (*create_directory)(const char *path, int mode),
+ vfs_vm_object_t *(*get_vm_object)(uint64_t length, uint64_t offset,
+ vfs_fd_t *fd),
+ int (*truncate)(vfs_fd_t *fd, size_t length)) {
+ vfs_inode_t *r = kmalloc(sizeof(inode_t));
+ r->inode_num = inode_num;
+ r->type = type;
+ r->has_data = has_data;
+ r->can_write = can_write;
+ r->is_open = is_open;
+ r->internal_object = internal_object;
+ r->file_size = file_size;
+ r->open = open;
+ r->create_file = create_file;
+ r->read = read;
+ r->write = write;
+ r->close = close;
+ r->create_directory = create_directory;
+ r->get_vm_object = get_vm_object;
+ r->truncate = truncate;
+ return r;
+}
+
+int vfs_create_fd(int flags, int mode, vfs_inode_t *inode, vfs_fd_t **fd) {
+ process_t *p = (process_t *)get_current_task();
+ int i;
+ for (i = 0; i < 100; i++)
+ if (!p->file_descriptors[i])
+ break;
+ if (p->file_descriptors[i])
+ return -1;
+ vfs_fd_t *r = kmalloc(sizeof(vfs_fd_t));
+ r->flags = flags;
+ r->mode = mode;
+ r->inode = inode;
+ r->reference_count = 1;
+ p->file_descriptors[i] = r;
+ if (fd)
+ *fd = r;
+ return i;
+}
+
+int vfs_create_file(const char *file) {
+ vfs_mounts_t *file_mount = 0;
+ int length = 0;
+ for (int i = 0; i < num_mounts; i++) {
+ int path_len = strlen(mounts[i].path);
+ if (path_len <= length)
+ continue;
+
+ if (isequal_n(mounts[i].path, file, path_len)) {
+ length = path_len;
+ file_mount = &mounts[i];
+ }
+ }
+ if (1 != length)
+ file += length;
+
+ if (!file_mount) {
+ kprintf("vfs_internal_open could not find mounted path for file : %s\n",
+ file);
+ return 0;
+ }
+ // ext2_create_file("/etc/oscreated", 0);
+ assert(file_mount->local_root->create_file);
+ kprintf("Creating a file\n");
+ return file_mount->local_root->create_file(file, 0);
+}
+
+vfs_inode_t *vfs_internal_open(const char *file) {
+ vfs_mounts_t *file_mount = 0;
+ int length = 0;
+ for (int i = 0; i < num_mounts; i++) {
+ int path_len = strlen(mounts[i].path);
+ if (path_len <= length)
+ continue;
+
+ if (isequal_n(mounts[i].path, file, path_len)) {
+ length = path_len;
+ file_mount = &mounts[i];
+ }
+ }
+ if (1 != length)
+ file += length;
+
+ if (!file_mount) {
+ kprintf("vfs_internal_open could not find mounted path for file : %s\n",
+ file);
+ return NULL;
+ }
+
+ vfs_inode_t *ret = file_mount->local_root->open(file);
+ return ret;
+}
+
+char *vfs_clean_path(const char *path, char *resolved_path) {
+ // char *const clean = kmalloc(strlen(path) + 1);
+ char *clean = resolved_path;
+ int prev_slash = 0;
+ char *ptr = clean;
+ for (; *path; path++) {
+ if (prev_slash && '/' == *path) {
+ continue;
+ }
+ prev_slash = ('/' == *path);
+ *ptr = *path;
+ ptr++;
+ }
+ *ptr = '\0';
+ return clean;
+}
+
+char *vfs_resolve_path(const char *file, char *resolved_path) {
+ if ('/' == *file) {
+ return vfs_clean_path(file, resolved_path);
+ }
+ const char *cwd = get_current_task()->current_working_directory;
+ size_t l = strlen(cwd);
+ assert(l > 0);
+ assert('/' == cwd[l - 1]);
+ // char *r = kmalloc(l + strlen(file) + 1);
+ char r[256];
+ strcpy(r, cwd);
+ strcat(r, file);
+ char *final = vfs_clean_path(r, resolved_path);
+ // kfree(r);
+ return final;
+}
+
+int vfs_mkdir(const char *path, int mode) {
+ vfs_mounts_t *file_mount = 0;
+ int length = 0;
+ for (int i = 0; i < num_mounts; i++) {
+ int path_len = strlen(mounts[i].path);
+ if (path_len <= length)
+ continue;
+
+ if (isequal_n(mounts[i].path, path, path_len)) {
+ length = path_len;
+ file_mount = &mounts[i];
+ }
+ }
+ if (1 != length)
+ path += length;
+
+ if (!file_mount) {
+ kprintf("vfs_internal_open could not find mounted path for file : %s\n",
+ path);
+ return 0;
+ }
+ assert(file_mount->local_root->create_directory);
+ // TODO: Error checking, don't just assume it is fine
+ file_mount->local_root->create_directory(path, mode);
+ return 0;
+}
+
+int vfs_open(const char *file, int flags, int mode) {
+ char resolved_path[256] = {0};
+ vfs_resolve_path(file, resolved_path);
+ vfs_inode_t *inode = vfs_internal_open(resolved_path);
+ if (0 == inode) {
+ if (mode & O_CREAT) {
+ if (vfs_create_file(resolved_path)) {
+ klog("VFS: File created", LOG_NOTE);
+ return vfs_open(file, flags, mode);
+ }
+ klog("VFS: Could not create file", LOG_WARN);
+ }
+ return -ENOENT;
+ }
+ if (inode->type == FS_TYPE_UNIX_SOCKET) {
+ return uds_open(resolved_path);
+ }
+
+ return vfs_create_fd(flags, mode, inode, NULL);
+}
+
+int vfs_close(int fd) {
+ vfs_fd_t *fd_ptr = get_vfs_fd(fd);
+ if (NULL == fd_ptr) {
+ return -1;
+ }
+ assert(0 < fd_ptr->reference_count);
+ // Remove process reference
+ fd_ptr->reference_count--;
+ get_current_task()->file_descriptors[fd] = 0;
+ // If no references left then free the contents
+ if (0 == fd_ptr->reference_count) {
+ if (fd_ptr->inode->close)
+ fd_ptr->inode->close(fd_ptr);
+
+ kfree(fd_ptr);
+ }
+ return 0;
+}
+
+int raw_vfs_pread(vfs_fd_t *vfs_fd, void *buf, uint64_t count,
+ uint64_t offset) {
+ if (!(vfs_fd->flags & O_READ))
+ return -EBADF;
+ return vfs_fd->inode->read(buf, offset, count, vfs_fd);
+}
+
+int vfs_pread(int fd, void *buf, uint64_t count, uint64_t offset) {
+ if (fd >= 100) {
+ kprintf("EBADF : %x\n", fd);
+ return -EBADF;
+ }
+ if (fd < 0) {
+ dump_backtrace(12);
+ kprintf("EBADF : %x\n", fd);
+ return -EBADF;
+ }
+ vfs_fd_t *vfs_fd = get_current_task()->file_descriptors[fd];
+ if (!vfs_fd)
+ return -EBADF;
+ int rc = raw_vfs_pread(vfs_fd, buf, count, offset);
+ if (-EAGAIN == rc && count > 0) {
+ if (!(vfs_fd->flags & O_NONBLOCK)) {
+ struct pollfd fds;
+ fds.fd = fd;
+ fds.events = POLLIN;
+ fds.revents = 0;
+ poll(&fds, 1, 0);
+ return vfs_pread(fd, buf, count, offset);
+ }
+ }
+ return rc;
+}
+
+int raw_vfs_pwrite(vfs_fd_t *vfs_fd, void *buf, uint64_t count,
+ uint64_t offset) {
+ assert(vfs_fd);
+ assert(vfs_fd->inode);
+ assert(vfs_fd->inode->write);
+ return vfs_fd->inode->write(buf, offset, count, vfs_fd);
+}
+
+int vfs_pwrite(int fd, void *buf, uint64_t count, uint64_t offset) {
+ vfs_fd_t *vfs_fd = get_vfs_fd(fd);
+ if (!vfs_fd)
+ return -EBADF;
+ if (!(vfs_fd->flags & O_WRITE)) {
+ return -EBADF;
+ }
+ return raw_vfs_pwrite(vfs_fd, buf, count, offset);
+}
+
+vfs_vm_object_t *vfs_get_vm_object(int fd, uint64_t length, uint64_t offset) {
+ vfs_fd_t *vfs_fd = get_vfs_fd(fd);
+ if (!vfs_fd)
+ return NULL;
+ vfs_vm_object_t *r = vfs_fd->inode->get_vm_object(length, offset, vfs_fd);
+ return r;
+}
+
+int vfs_dup2(int org_fd, int new_fd) {
+ get_current_task()->file_descriptors[new_fd] =
+ get_current_task()->file_descriptors[org_fd];
+ get_current_task()->file_descriptors[new_fd]->reference_count++;
+ return 1;
+}
+
+int vfs_ftruncate(int fd, size_t length) {
+ vfs_fd_t *fd_ptr = get_vfs_fd(fd);
+ if (!fd_ptr)
+ return -EBADF;
+ if (!(fd_ptr->flags & O_READ))
+ return -EINVAL;
+ vfs_inode_t *inode = fd_ptr->inode;
+ if (!inode)
+ return -EINVAL;
+ if (!inode->truncate)
+ return -EINVAL;
+
+ return inode->truncate(fd_ptr, length);
+}
+
+void vfs_mount(char *path, vfs_inode_t *local_root) {
+ int len = strlen(path);
+ mounts[num_mounts].path = kmalloc_eternal(len + 1);
+ memcpy(mounts[num_mounts].path, path, len);
+ mounts[num_mounts].path[len] = '\0';
+ mounts[num_mounts].local_root = local_root;
+ num_mounts++;
+}