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;
}