BarryServer : Git

All the code for all my projects
// BarryServer : Git / Nucleus / commit / 77a8df88b03707e14f840df6b0daeb9fa081f613 / vfs / open.c

// Related

Nucleus

Barry FS Object wrapper functions 77a8df8 (3 years, 3 months ago)
diff --git a/vfs/open.c b/vfs/open.c
new file mode 100644
index 0000000..cf03a24
--- /dev/null
+++ b/vfs/open.c
@@ -0,0 +1,189 @@
+/*
+ * This file contains the open system call.  It handles creating missing files,
+ * and installing the file descriptor.  Most of the actual code to find the
+ * inode by name is in the lookup() routine.
+ */
+
+#include <stdarg.h>
+#include <string.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <nucleus/memory.h>
+#include <nucleus/object.h>
+#include <nucleus/task.h>
+#include <nucleus/vfs.h>
+#include "namespace.h"
+
+/* Lookup a file path */
+Inode *
+lookup(const char *path, ObjectList *newcustody)
+{
+	if (!current->fs->root)
+		return NULL;
+
+	char buf[PATH_MAX], *p = buf;
+	strncpy(buf, path, PATH_MAX);
+	Inode *inode;
+	DirEntry *entry;
+	ObjectList *custody;
+
+	/* Resolve to absolute/relative root */
+	if (*p == '/') {
+		inode = current->fs->root;
+		while (*++p == '/');
+		custody = create_list(&dirEntryType);
+	} else {
+		inode = current->fs->cwd;
+		custody = copy_list(current->fs->cwdPath);
+	}
+
+	/* Drop through directories */
+	char *curr, *prev = p;
+	for (curr = p; *curr; curr++) {
+		if (*curr != '/')
+			continue;
+		*curr = '\0';
+
+		/* Path part */
+		if (!strcmp(prev, ".")) {
+			entry = NULL;
+		} else if (!strcmp(prev, "..")) {
+			entry = NULL;
+			if (inode != current->fs->root) {
+				entry = pop_from_end(custody);
+				if (!entry)
+					inode = current->fs->root;
+				else
+					put(entry);
+			}
+		} else {
+			entry = inode_lookup(inode, prev);
+			if (!entry) {
+				inode = NULL;
+				goto end;
+			}
+			add(custody, entry);
+			put(entry);
+		}
+
+		if (entry)
+			inode = entry->inode;
+
+		while (*++curr == '/');
+		prev = curr;
+	}
+
+	/* Base name */
+	if (!strcmp(prev, ".") || !strcmp(prev, "")) {
+		if (!S_ISDIR(inode->mode)) {
+			inode = NULL;
+			entry = NULL;
+		}
+	} else if (!strcmp(prev, "..")) {
+		if (inode != current->fs->root) {
+			entry = pop_from_end(custody);
+			if (!entry)
+				inode = current->fs->root;
+			else
+				put(entry);
+		}
+	} else {
+		entry = inode_lookup(inode, prev);
+		if (!entry) {
+			entry = new(&dirEntryType);
+			strncpy(entry->name, prev, NAME_MAX);
+			entry->super = inode->super;
+		}
+		add(custody, entry);
+		put(entry);
+	}
+	if (entry) {
+		inode = entry->inode;
+		if (inode)
+			get(inode);
+	}
+
+	/* Copy path */
+	if (newcustody)
+		concat_list(custody, newcustody);
+end:
+	destroy_list(custody);
+	return inode;
+}
+
+/* Open a file */
+int
+open(const char *name, int flags, ...)
+{
+	if (!verify_access(name, strnlen(name, PATH_MAX), PROT_READ))
+		return -EFAULT;
+
+	/* Allocate a file descriptor */
+	int fd = allocate_fd();
+	if (fd < 0)
+		return -EMFILE;
+
+	/* Find inode */
+	ObjectList *custody = create_list(&dirEntryType);
+	Inode *inode = lookup(name, custody);
+	DirEntry *entry;
+	va_list args;
+	if (!inode) {
+		if (!(flags & O_CREATE)) {
+			destroy_list(custody);
+			return -ENOENT;
+		}
+		/* Create file */
+		if (!count(custody)) {
+			destroy_list(custody);
+			return -ENOENT;
+		}
+		entry = get_nth_item(custody, count(custody) - 2);
+		if (entry)
+			inode = entry->inode;
+		else
+			inode = current->fs->root;
+		if (!permission(inode, PROT_WRITE)) {
+			destroy_list(custody);
+			return -EACCES;
+		}
+		va_start(args, flags);
+		inode_create(inode, get_nth_item(custody, count(custody) - 1),
+		             va_arg(args, mode_t));
+		inode = lookup(name, NULL);
+		va_end(args);
+	}
+
+	/* Check permissions */
+	int perm = 0;
+	if ((flags & O_ACCMODE) == O_RDONLY)
+		perm = PROT_READ;
+	else if ((flags & O_ACCMODE) == O_WRONLY)
+		perm = PROT_WRITE;
+	else if ((flags & O_ACCMODE) == O_RDWR)
+		perm = PROT_READ | PROT_WRITE;
+	if (!permission(inode, perm)) {
+		put(inode);
+		destroy_list(custody);
+		return -EACCES;
+	}
+
+	/* Open file */
+	File *file = new(&fileType);
+	file->inode = get(inode);
+	file->flags = flags;
+	file->ops = inode->fileOps;
+	file->path = custody;
+
+	int err = file_open(file);
+	if (err) {
+		put(file);
+		put(inode);
+		return err;
+	}
+
+	install_fd(fd, file);
+	put(inode);
+	return fd;
+}