/* * 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 #include #include #include #include #include #include #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; }