diff options
Diffstat (limited to 'src/kernel/fs/vfs')
-rw-r--r-- | src/kernel/fs/vfs/vfs.c | 371 | ||||
-rw-r--r-- | src/kernel/fs/vfs/vfs.h | 149 |
2 files changed, 520 insertions, 0 deletions
diff --git a/src/kernel/fs/vfs/vfs.c b/src/kernel/fs/vfs/vfs.c new file mode 100644 index 0000000..bbc3912 --- /dev/null +++ b/src/kernel/fs/vfs/vfs.c @@ -0,0 +1,371 @@ +#include <kernel/system.h> +#include <kernel/fs/ext2/ext2.h> +#include <kernel/fs/vfs/vfs.h> +#include <kernel/lib/data/list.h> +#include <kernel/lib/data/generic_tree.h> +#include <kernel/memory/alloc.h> +#include <kernel/lib/stdlib.h> +#include <kernel/lib/lib.h> + +gtree_t *vfs_tree; +vfs_node_t *vfs_root; + +uint32_t vfs_get_file_size(vfs_node_t *node) +{ + if (node && node->get_file_size) { + return node->get_file_size(node); + } + return 0; +} + +void vfs_db_listdir(char *name) +{ + vfs_node_t *n = file_open(name, 0); + if (!n) { + log("Could not list a directory that does not exist\n"); + return; + } + if (!n->listdir) + return; + char **files = n->listdir(n); + char **save = files; + while (*files) { + log("%s ", *files); + kfree(*files); + files++; + } + kfree(save); + log("\n"); +} + +void print_vfstree_recur(gtreenode_t *node, int parent_offset) +{ + if (!node) + return; + char *tmp = kmalloc(512); + int len = 0; + memset(tmp, 0, 512); + for (int i = 0; i < parent_offset; ++i) { + strcat(tmp, " "); + } + char *curr = tmp + strlen(tmp); + struct vfs_entry *fnode = (struct vfs_entry *)node->value; + if (fnode->file) { + log(curr, "%s(0x%x, %s)", fnode->name, (uint32_t)fnode->file, fnode->file->name); + } else { + log(curr, "%s(empty)", fnode->name); + } + log("%s\n", tmp); + len = strlen(fnode->name); + kfree(tmp); + foreach(child, node->children) + { + print_vfstree_recur(child->val, parent_offset + len + 1); + } +} + +void print_vfstree() +{ + print_vfstree_recur(vfs_tree->root, 0); +} + +uint32_t vfs_read(vfs_node_t *node, uint32_t offset, uint32_t size, char *buffer) +{ + if (node && node->read) { + uint32_t ret = node->read(node, offset, size, buffer); + return ret; + } + return -1; +} + +uint32_t vfs_write(vfs_node_t *node, uint32_t offset, uint32_t size, char *buffer) +{ + if (node && node->write) { + uint32_t ret = node->write(node, offset, size, buffer); + return ret; + } + return -1; +} + +void vfs_open(struct vfs_node *node, uint32_t flags) +{ + if (!node) + return; + if (node->refcount >= 0) + node->refcount++; + node->open(node, flags); +} + +void vfs_close(vfs_node_t *node) +{ + if (!node || node == vfs_root || node->refcount == -1) + return; + node->refcount--; + if (node->refcount == 0) + node->close(node); +} + +void vfs_chmod(vfs_node_t *node, uint32_t mode) +{ + if (node->chmod) + return node->chmod(node, mode); +} + +struct dirent *vfs_readdir(vfs_node_t *node, uint32_t index) +{ + if (node && (node->flags & FS_DIRECTORY) && node->readdir) + return node->readdir(node, index); + return NULL; +} + +vfs_node_t *vfs_finddir(vfs_node_t *node, char *name) +{ + if (node && (node->flags & FS_DIRECTORY) && node->finddir) + return node->finddir(node, name); + return NULL; +} + +int vfs_ioctl(vfs_node_t *node, int request, void *argp) +{ + if (!node) + return -1; + if (node->ioctl) + return node->ioctl(node, request, argp); + return -1; // ENOTTY +} + +void vfs_mkdir(char *name, unsigned short permission) +{ + // Find parent directory + int i = strlen(name); + char *dirname = strdup(name); + char *save_dirname = dirname; + char *parent_path = "/"; + while (i >= 0) { + if (dirname[i] == '/') { + if (i != 0) { + dirname[i] = '\0'; + parent_path = dirname; + } + dirname = &dirname[i + 1]; + break; + } + i--; + } + + // Open file + vfs_node_t *parent_node = file_open(parent_path, 0); + if (!parent_node) { + kfree(save_dirname); + } + + // mkdir + if (parent_node->mkdir) + parent_node->mkdir(parent_node, dirname, permission); + kfree(save_dirname); + + vfs_close(parent_node); +} + +int vfs_create_file(char *name, unsigned short permission) +{ + // Find parent directory + int i = strlen(name); + char *dirname = strdup(name); + char *save_dirname = dirname; + char *parent_path = "/"; + while (i >= 0) { + if (dirname[i] == '/') { + if (i != 0) { + dirname[i] = '\0'; + parent_path = dirname; + } + dirname = &dirname[i + 1]; + break; + } + i--; + } + + // Open file + vfs_node_t *parent_node = file_open(parent_path, 0); + if (!parent_node) { + kfree(save_dirname); + return -1; + } + if (parent_node->create) + parent_node->create(parent_node, dirname, permission); + kfree(save_dirname); + vfs_close(parent_node); + return 0; +} + +void vfs_unlink(char *name) +{ + // Find parent directory + int i = strlen(name); + char *dirname = strdup(name); + char *save_dirname = dirname; + char *parent_path = "/"; + while (i >= 0) { + if (dirname[i] == '/') { + if (i != 0) { + dirname[i] = '\0'; + parent_path = dirname; + } + dirname = &dirname[i + 1]; + break; + } + i--; + } + + // Open file + vfs_node_t *parent_node = file_open(parent_path, 0); + if (!parent_node) { + kfree(save_dirname); + } + if (parent_node->unlink) + parent_node->unlink(parent_node, dirname); + kfree(save_dirname); + vfs_close(parent_node); +} + +char *expand_path(char *input) +{ + list_t *input_list = str_split(input, "/", NULL); + char *ret = list2str(input_list, "/"); + return ret; +} + +vfs_node_t *get_mountpoint_recur(char **path, gtreenode_t *subroot) +{ + int found = 0; + char *curr_token = strsep(path, "/"); + if (curr_token == NULL || !strcmp(curr_token, "")) { + struct vfs_entry *ent = (struct vfs_entry *)subroot->value; + return ent->file; + } + foreach(child, subroot->children) + { + gtreenode_t *tchild = (gtreenode_t *)child->val; + struct vfs_entry *ent = (struct vfs_entry *)(tchild->value); + if (strcmp(ent->name, curr_token) == 0) { + found = 1; + subroot = tchild; + break; + } + } + + if (!found) { + *path = curr_token; + return ((struct vfs_entry *)(subroot->value))->file; + } + return get_mountpoint_recur(path, subroot); +} +vfs_node_t *get_mountpoint(char **path) +{ + if (strlen(*path) > 1 && (*path)[strlen(*path) - 1] == '/') + *(path)[strlen(*path) - 1] = '\0'; + if (!*path || *(path)[0] != '/') + return NULL; + if (strlen(*path) == 1) { + *path = '\0'; + struct vfs_entry *ent = (struct vfs_entry *)vfs_tree->root->value; + return ent->file; + } + (*path)++; + return get_mountpoint_recur(path, vfs_tree->root); +} + +vfs_node_t *file_open(const char *file_name, uint32_t flags) +{ + char *curr_token = NULL; + char *filename = strdup(file_name); + char *free_filename = filename; + char *save = strdup(filename); + char *original_filename = filename; + char *new_start = NULL; + vfs_node_t *nextnode = NULL; + vfs_node_t *startpoint = get_mountpoint(&filename); + if (!startpoint) + return NULL; + if (filename) + new_start = strstr(save + (filename - original_filename), filename); + while (filename != NULL && ((curr_token = strsep(&new_start, "/")) != NULL)) { + nextnode = vfs_finddir(startpoint, curr_token); + if (!nextnode) + return NULL; + startpoint = nextnode; + } + if (!nextnode) + nextnode = startpoint; + vfs_open(nextnode, flags); + kfree(save); + kfree(free_filename); + return nextnode; +} + +void vfs_init() +{ + vfs_tree = tree_create(); + struct vfs_entry *root = kmalloc(sizeof(struct vfs_entry)); + root->name = strdup("root"); + root->file = NULL; + tree_insert(vfs_tree, NULL, root); +} + +void vfs_mount_dev(char *mountpoint, vfs_node_t *node) +{ + vfs_mount(mountpoint, node); +} + +void vfs_mount_recur(char *path, gtreenode_t *subroot, vfs_node_t *fs_obj) +{ + int found = 0; + char *curr_token = strsep(&path, "/"); + + if (curr_token == NULL || !strcmp(curr_token, "")) { + struct vfs_entry *ent = (struct vfs_entry *)subroot->value; + if (ent->file) { + log("The path is already mounted, plz unmount before mounting again\n"); + return; + } + if (!strcmp(ent->name, "/")) + vfs_root = fs_obj; + ent->file = fs_obj; + return; + } + + foreach(child, subroot->children) + { + gtreenode_t *tchild = (gtreenode_t *)child->val; + struct vfs_entry *ent = (struct vfs_entry *)(tchild->value); + if (strcmp(ent->name, curr_token) == 0) { + found = 1; + subroot = tchild; + } + } + + if (!found) { + struct vfs_entry *ent = kcalloc(sizeof(struct vfs_entry), 1); + ent->name = strdup(curr_token); + subroot = tree_insert(vfs_tree, subroot, ent); + } + vfs_mount_recur(path, subroot, fs_obj); +} + +void vfs_mount(char *path, vfs_node_t *fs_obj) +{ + fs_obj->refcount = -1; + fs_obj->fs_type = 0; + if (path[0] == '/' && strlen(path) == 1) { + struct vfs_entry *ent = (struct vfs_entry *)vfs_tree->root->value; + if (ent->file) { + log("The path is already mounted, plz unmount before mounting again\n"); + return; + } + vfs_root = fs_obj; + ent->file = fs_obj; + return; + } + vfs_mount_recur(path + 1, vfs_tree->root, fs_obj); +}
\ No newline at end of file diff --git a/src/kernel/fs/vfs/vfs.h b/src/kernel/fs/vfs/vfs.h new file mode 100644 index 0000000..b31767e --- /dev/null +++ b/src/kernel/fs/vfs/vfs.h @@ -0,0 +1,149 @@ +#ifndef MELVIX_VFS_H +#define MELVIX_VFS_H + +#include <stdint.h> + +#define PATH_SEPARATOR '/' +#define PATH_SEPARATOR_STRING "/" +#define PATH_UP ".." +#define PATH_DOT "." +#define VFS_EXT2_MAGIC 0xeeee2222 + +#define O_RDONLY 0x0000 +#define O_WRONLY 0x0001 +#define O_RDWR 0x0002 +#define O_APPEND 0x0008 +#define O_CREAT 0x0200 +#define O_TRUNC 0x0400 +#define O_EXCL 0x0800 +#define O_NOFOLLOW 0x1000 +#define O_PATH 0x2000 + +#define FS_FILE 0x01 +#define FS_DIRECTORY 0x02 +#define FS_CHARDEVICE 0x04 +#define FS_BLOCKDEVICE 0x08 +#define FS_PIPE 0x10 +#define FS_SYMLINK 0x20 +#define FS_MOUNTPOINT 0x40 + +#define _IFMT 0170000 /* type of file */ +#define _IFDIR 0040000 /* directory */ +#define _IFCHR 0020000 /* character special */ +#define _IFBLK 0060000 /* block special */ +#define _IFREG 0100000 /* regular */ +#define _IFLNK 0120000 /* symbolic link */ +#define _IFSOCK 0140000 /* socket */ +#define _IFIFO 0010000 /* fifo */ + +struct vfs_node; + +typedef uint32_t (*get_file_size_callback)(struct vfs_node *node); +typedef uint32_t (*read_callback)(struct vfs_node *, uint32_t, uint32_t, char *); +typedef uint32_t (*write_callback)(struct vfs_node *, uint32_t, uint32_t, char *); +typedef void (*open_callback)(struct vfs_node *, uint32_t flags); +typedef void (*close_callback)(struct vfs_node *); +typedef struct dirent *(*readdir_callback)(struct vfs_node *, uint32_t); +typedef struct vfs_node *(*finddir_callback)(struct vfs_node *, char *name); +typedef void (*create_callback)(struct vfs_node *, char *name, uint16_t permission); +typedef void (*unlink_callback)(struct vfs_node *, char *name); +typedef void (*mkdir_callback)(struct vfs_node *, char *name, uint16_t permission); +typedef int (*ioctl_callback)(struct vfs_node *, int request, void *argp); +typedef int (*get_size_callback)(struct vfs_node *); +typedef void (*chmod_callback)(struct vfs_node *, uint32_t mode); +typedef char **(*listdir_callback)(struct vfs_node *); + +typedef struct vfs_node { + char name[256]; + void *device; + uint32_t mask; + uint32_t uid; + uint32_t gid; + uint32_t flags; + uint32_t inode_num; + uint32_t size; + uint32_t fs_type; + uint32_t open_flags; + uint32_t create_time; + uint32_t access_time; + uint32_t modified_time; + + uint32_t offset; + unsigned nlink; + int refcount; + + // File operations + read_callback read; + write_callback write; + open_callback open; + close_callback close; + readdir_callback readdir; + finddir_callback finddir; + create_callback create; + unlink_callback unlink; + mkdir_callback mkdir; + ioctl_callback ioctl; + get_size_callback get_size; + chmod_callback chmod; + get_file_size_callback get_file_size; + + listdir_callback listdir; +} vfs_node_t; + +struct dirent { + char name[256]; + uint32_t inode_num; +}; + +typedef struct vfs_entry { + char *name; + vfs_node_t *file; +} vfs_entry_t; + +uint32_t vfs_get_file_size(vfs_node_t *node); + +uint32_t vfs_read(vfs_node_t *node, uint32_t offset, uint32_t size, char *buffer); + +uint32_t vfs_write(vfs_node_t *node, uint32_t offset, uint32_t size, char *buffer); + +void vfs_open(struct vfs_node *node, uint32_t flags); + +void vfs_close(vfs_node_t *node); + +vfs_node_t *vfs_finddir(vfs_node_t *node, char *name); + +void vfs_mkdir(char *name, uint16_t permission); + +void vfs_mkfile(char *name, uint16_t permission); + +int vfs_create_file(char *name, uint16_t permission); + +vfs_node_t *file_open(const char *file_name, uint32_t flags); + +char *expand_path(char *input); + +int vfs_ioctl(vfs_node_t *node, int request, void *argp); + +void vfs_chmod(vfs_node_t *node, uint32_t mode); + +void vfs_unlink(char *name); + +int vfs_symlink(char *value, char *name); + +int vfs_readlink(vfs_node_t *node, char *buf, uint32_t size); + +void vfs_init(); + +void vfs_mount(char *path, vfs_node_t *local_root); + +typedef vfs_node_t *(*vfs_mount_callback)(char *arg, char *mountpoint); + +void vfs_register(char *name, vfs_mount_callback callme); + +void vfs_mount_dev(char *mountpoint, vfs_node_t *node); + +void print_vfstree(); + +void vfs_db_listdir(char *name); + +#endif
\ No newline at end of file |