BarryServer : Git

All the code for all my projects
// BarryServer : Git / Nucleus / blob / master / vfs / namespace.c

// Related

Nucleus

Barry System headers (remove libc dependency) 18495cf (3 years, 2 months ago)
/*
 * This file implements the File System object, which is the namespace for a
 * task's file system.  It tracks a task's root and current working directory.
 */

#include <sys/errno.h>
#include <sys/stat.h>
#include <nucleus/lib.h>
#include <nucleus/memory.h>
#include <nucleus/object.h>
#include <nucleus/task.h>
#include <nucleus/vfs.h>
#include "namespace.h"

static void file_system_new(Object *);
static void file_system_delete(Object *);
static void file_system_copy(Object *, Object *);

/* File System object type */
ObjectType fsType = {
	.name = "FILE SYSTEM",
	.size = sizeof(FileSystem),
	.new = file_system_new,
	.delete = file_system_delete,
	.copy = file_system_copy,
};

/* Create a new File System object */
static void
file_system_new(Object *obj)
{
	FileSystem *fs = (void *) obj;
	fs->cwdPath = create_list(&dirEntryType, LIST_NORMAL);
}

/* Destory a File System object */
static void
file_system_delete(Object *obj)
{
	FileSystem *fs = (void *) obj;
	put(fs->cwd);
	destroy_list(fs->cwdPath);
	put(fs->root);
}

/* Copy a File System object */
static void
file_system_copy(Object *a, Object *b)
{
	FileSystem *parent = (void *) a, *child = (void *) b;
	child->cwd = get(parent->cwd);
	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;
}