BarryServer : Git

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

// Related

Nucleus

Barry FS Object wrapper functions 77a8df8 (3 years, 3 months ago)
diff --git a/vfs/direntry.c b/vfs/direntry.c
index a8a0110..7a0b559 100644
--- a/vfs/direntry.c
+++ b/vfs/direntry.c
@@ -16,6 +16,7 @@ static void direntry_delete(Object *);
 
 /* Directory Entry object type */
 ObjectType dirEntryType = {
+	.name = "DIRECTORY ENTRY",
 	.size = sizeof(DirEntry),
 	.delete = direntry_delete,
 };
@@ -44,9 +45,11 @@ direntry_delete(Object *obj)
 static int
 compare_direntry_name(void *addr, void *data)
 {
-	DirEntry *entry = (void *) addr;
+	DirEntry *entry = addr;
 	struct FindData *find = data;
 	uint32_t hash = name_hash(find->name);
+	if (__builtin_expect(!(entry->hash), 0))
+		entry->hash = name_hash(entry->name);
 	if (entry->hash != hash)
 		return 0;
 	if (strcmp(entry->name, find->name))
@@ -59,13 +62,11 @@ compare_direntry_name(void *addr, void *data)
 DirEntry *
 find_direntry(ObjectList *list, const char *name)
 {
-	lock(list);
 	struct FindData data = {
 		.name = name,
 		.result = NULL,
 	};
 	iterate(list, compare_direntry_name, &data);
-	unlock(list);
 	return data.result;
 }
 
diff --git a/vfs/file.c b/vfs/file.c
index 8aef18f..f73c8e1 100644
--- a/vfs/file.c
+++ b/vfs/file.c
@@ -7,6 +7,7 @@
  * generic version.
  */
 
+#include <errno.h>
 #include <nucleus/object.h>
 #include <nucleus/vfs.h>
 
@@ -14,6 +15,7 @@ static void file_delete(Object *);
 
 /* File object type */
 ObjectType fileType = {
+	.name = "FILE",
 	.size = sizeof(File),
 	.delete = file_delete,
 };
@@ -28,3 +30,36 @@ file_delete(Object *obj)
 	if (file->path)
 		destroy_list(file->path);
 }
+
+/* Open a file */
+int
+file_open(File *file)
+{
+	if (!file->ops || !file->ops->open)
+		return -EINVAL;
+	return file->ops->open(file);
+}
+
+/* Read a file */
+size_t
+file_read(File *file, char *buf, size_t size)
+{
+	size_t count = 0;
+	if (!file->ops || !file->ops->read)
+		return count;
+	count = file->ops->read(file, buf, size, file->pos);
+	file->pos += count;
+	return count;
+}
+
+/* Write a file */
+size_t
+file_write(File *file, char *buf, size_t size)
+{
+	size_t count = 0;
+	if (!file->ops || !file->ops->write)
+		return count;
+	count = file->ops->write(file, buf, size, file->pos);
+	file->pos += count;
+	return count;
+}
diff --git a/vfs/fstype.c b/vfs/fstype.c
index 73d28c8..9043ba4 100644
--- a/vfs/fstype.c
+++ b/vfs/fstype.c
@@ -11,6 +11,7 @@
 
 /* Structure for a File System Type */
 struct FSType {
+	Object obj;
 	const char *name;
 	Inode *(*mount)(FSType *, int, const char *, void *);
 };
@@ -23,6 +24,7 @@ struct FindData {
 
 /* File System Type object type */
 ObjectType fstypeType = {
+	.name = "FILE SYSTEM TYPE",
 	.size = sizeof(FSType),
 };
 
diff --git a/vfs/inode.c b/vfs/inode.c
index 6f49c67..c64542d 100644
--- a/vfs/inode.c
+++ b/vfs/inode.c
@@ -7,8 +7,12 @@
  * operation can be called on the particular inode.
  */
 
+#include <string.h>
+#include <sys/stat.h>
+#include <errno.h>
 #include <nucleus/object.h>
 #include <nucleus/memory.h>
+#include <nucleus/task.h>
 #include <nucleus/vfs.h>
 
 static void inode_new(Object *);
@@ -16,6 +20,7 @@ static void inode_delete(Object *);
 
 /* Inode object type */
 ObjectType inodeType = {
+	.name = "INODE",
 	.size = sizeof(Inode),
 	.new = inode_new,
 	.delete = inode_delete,
@@ -26,6 +31,7 @@ static void
 inode_new(Object *obj)
 {
 	Inode *inode = (void *) obj;
+	inode->dirEntries = create_list(&dirEntryType);
 	inode->pages = create_list(&pageType);
 }
 
@@ -36,9 +42,90 @@ inode_delete(Object *obj)
 	Inode *inode = (void *) obj;
 
 	/* Remove inode from the SuperBlock's list */
-//	if (inode->super)
+	if (inode->super) {
 //		super_remove_inode(inode->super, inode);
+		put(inode->super);
+	}
 
 	/* Clean cache */
 	destroy_list(inode->pages);
 }
+
+/* Check if a process has permission to access an inode */
+int
+permission(Inode *inode, int mask)
+{
+	if (!inode)
+		return 0;
+
+	int mode = inode->mode;
+	if (current->euid == inode->uid)
+		mode >>= 6;
+	else if (current->egid == inode->gid)
+		mode >>= 3;
+
+	if (((mode & mask & 0007) == mask) || super_user())
+		return 1;
+	return 0;
+}
+
+/* Create an inode wrapper */
+int
+inode_create(Inode *inode, DirEntry *entry, mode_t mode)
+{
+	if (!inode->ops || !inode->ops->create)
+		return -EINVAL;
+	lock(inode);
+	int err = inode->ops->create(inode, entry, mode);
+	if (!err) {
+		add(inode->dirEntries, entry);
+		entry->inode = super_alloc_inode(inode->super);
+		entry->inode->mode = mode | S_IFREG;
+	}
+	unlock(inode);
+	return err;
+}
+
+/* Find a named entry in a directory inode */
+DirEntry *
+inode_lookup(Inode *inode, const char *name)
+{
+	if (!S_ISDIR(inode->mode))
+		return NULL;
+	lock(inode);
+
+	/* Check cache first */
+	DirEntry *entry = find_direntry(inode->dirEntries, name);
+	if (entry) {
+		get(entry);
+		if (entry->inode)
+			goto end;
+	}
+	/* Try file system lookup */
+	if (!inode->ops || !inode->ops->lookup) {
+		entry = NULL;
+		goto end;
+	}
+	Inode *child = inode->ops->lookup(inode, name);
+
+	/* The file doesn't exist */
+	if (!child) {
+		if (entry)
+			remove(inode->dirEntries, entry);
+		entry = NULL;
+		goto end;
+	}
+
+	/* Fill in DirEntry */
+	if (!entry) {
+		entry = new(&dirEntryType);
+		strncpy(entry->name, name, NAME_MAX);
+		entry->super = inode->super;
+		add(inode->dirEntries, entry);
+	}
+	entry->inode = get(child);
+
+end:
+	unlock(inode);
+	return entry;
+}
diff --git a/vfs/mount.c b/vfs/mount.c
index 472b30f..53bdab2 100644
--- a/vfs/mount.c
+++ b/vfs/mount.c
@@ -3,7 +3,9 @@
  * mount system call.
  */
 
+#include <string.h>
 #include <errno.h>
+#include <nucleus/memory.h>
 #include <nucleus/task.h>
 #include <nucleus/vfs.h>
 #include "namespace.h"
@@ -16,6 +18,13 @@ int
 mount(const char *src, const char *target, const char *type,
       unsigned long flags, void *data)
 {
+	if (!verify_access(src, strnlen(src, PATH_MAX), PROT_READ))
+		return -EFAULT;
+	if (!verify_access(target, strnlen(target, PATH_MAX), PROT_READ))
+		return -EFAULT;
+	if (!verify_access(type, strnlen(type, 16), PROT_READ))
+		return -EFAULT;
+
 	Inode *mnt = NULL;
 	int res = mount_fstype(type, flags, src, data, &mnt);
 	if (res < 0)
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;
+}
diff --git a/vfs/superblock.c b/vfs/superblock.c
index 657ddc7..4d90e3d 100644
--- a/vfs/superblock.c
+++ b/vfs/superblock.c
@@ -17,11 +17,12 @@ struct FindData {
 
 /* Super Block object type */
 ObjectType superBlockType = {
+	.name = "SUPER BLOCK",
 	.size = sizeof(SuperBlock),
 };
 
 /* Find an Inode by ino value */
-int
+static int
 compare_inode_ino(void *addr, void *data)
 {
 	Inode *inode = addr;