// vfs.c // Author: Josh Holtrop // Date: 08/22/04 // Modified: 12/21/04 #include "hos_defines.h" #include "kout.h" #include "fs/vfs.h" #include "fs/ext2.h" #include "kernel.h" #include "mm/vmm.h" #include "lang/lang.h" vfs_fs_t *fses[VFS_MAX_FS]; // a vfs_fs structure for every filesystem we support vfs_mount_node_t *mounts; // basic initialization routine, init all filesystem drivers int vfs_init() { k_check(ext2_init(FS_EXT2), "ext2_init() failed!"); return 0; } // called by a filesystem driver to let us know that it is ready to handle fs requests int vfs_register_fs(int fsn, vfs_fs_t *fs) { if (fsn < 0 || fsn >= VFS_MAX_FS || fses[fsn]) { kprintf("Invalid filesystem register: %d\n", fsn); return -1; } fses[fsn] = fs; return 0; } // called to mount a block device with a certain filesystem to a part of our VFS Mount Tree int vfs_mount(major_t maj, minor_t min, int fsType, char *mountPoint) { if (fsType < 0 || fsType >= VFS_MAX_FS || !fses[fsType]) return -1; // invalid filesystem type if (!strcmp("/", mountPoint)) { if (mounts) return -2; // root already mounted void *super = fses[fsType]->mount_super(maj, min); vfs_mount_t *mnt = New(vfs_mount_t); mnt->refs = 0; mnt->fs = fsType; mnt->major = maj; mnt->minor = min; mnt->super = super; vfs_mount_node_t *node = New(vfs_mount_node_t); mount = node; node->next = NULL; node->mount = mnt; node->vfs_inode = 0; return 0; } if (mountPoint[0] != '/') return -3; // mount point must be absolute int l = strlen(mountPoint); if (l < 2) return -4; // mount point must be non-null string return -5; } vfs_inode_t vfs_get_inode_number(char *path) { if (path[0] != '/') return 0; vfs_file_addr_t file_addr; file_addr.mount = mounts->mount; file_addr.inode = fses[file_addr.mount->fsType]->get_root_inode(file_addr.mount); } // stat a file, fills a vfs_stat_t structure with stat information and returns standard status int vfs_stat(char *file, vfs_stat_t *stat) { vfs_mount_match_t match = vfs_get_rel_path(file); if (match.mount == NULL) return -256; if (fses[match.mount->fs]->stat) return fses[match.mount->fs]->stat(match.mount, file + match.length - 1, stat); return -257; } vfs_open_file_t *vfs_open_dir(vfs_inode_t inode) { vfs_open_file_t *open_dir = New(vfs_open_file_t); if (fses[match.mount->fs]->open_dir && !(fses[match.mount->fs]->open_dir(match.mount, file + match.length - 1, open_dir))) { open_dir->mount = match.mount; return open_dir; } kfree(open_dir); return NULL; } int vfs_read_dir(vfs_open_file_t *open_dir, vfs_dir_entry_t *dentry) { return !(fses[open_dir->mount->fs]->read_dir && !(fses[open_dir->mount->fs]->read_dir(open_dir->mount, open_dir, dentry))); } int vfs_close_dir(vfs_open_file_t *open_dir) { int status = 0; if (fses[open_dir->mount->fs]->close_dir) status = fses[open_dir->mount->fs]->close_dir(open_dir->mount, open_dir); kfree(open_dir); return status; } vfs_open_file_t *vfs_open_block_file(char *file) { vfs_mount_match_t match = vfs_get_rel_path(file); if (match.mount == NULL) return NULL; vfs_open_file_t *open_file = New(vfs_open_file_t); if (fses[match.mount->fs]->open_block_file && !(fses[match.mount->fs]->open_block_file(match.mount, file + match.length - 1, open_file))) { open_file->mount = match.mount; return open_file; } kfree(open_file); return NULL; } int vfs_read_block_file(vfs_open_file_t *open_file, void *buffer) { if (fses[open_file->mount->fs]->read_block_file) return fses[open_file->mount->fs]->read_block_file(open_file->mount, open_file, buffer); return 0; } int vfs_block_file_seek(vfs_open_file_t *open_file, u32_t block_number) { if (fses[open_file->mount->fs]->block_file_seek) return fses[open_file->mount->fs]->block_file_seek(open_file->mount, open_file, block_number); return -1; } int vfs_close_block_file(vfs_open_file_t *open_file) { int status = 0; if (fses[open_file->mount->fs]->close_block_file) status = fses[open_file->mount->fs]->close_block_file(open_file->mount, open_file); kfree(open_file); return status; } // DEBUG routines to draw the VFS Mount Tree /******************************************/ void vfs_dump_tree() { if (!vfsMountTree) kprintf("vfsMountTree == NULL!\n"); else vfs_dump_node(vfsMountTree, 0); } void vfs_dump_node(vfs_node_t *node, int level) { int i; for (i = 0; i < level; i++) { putc(' '); } kprintf("%c (0x%x) mount: 0x%x, up: 0x%x, next:0x%x, down:0x%x\n", node->chr, node, node->mount, node->up, node->next, node->down); node = node->down; if (!node) return; while (node) { vfs_dump_node(node, level + 1); node = node->next; } } /******************************************/