// 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_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); if (!super) return -3; // didn't mount superblock vfs_mount_t *mnt = New(vfs_mount_t); mnt->refs = 0; mnt->fs = fsType; mnt->major = maj; mnt->minor = min; mnt->super = super; mnt->next = NULL; mnt->prev = NULL; node->vfs_mount_inode = 0; // root not mounted on another fs node->vfs_up_inode = 0; mounts = mnt; return 0; // successfully mounted root } if (mountPoint[0] != '/') return -3; // mount point must be absolute int l = strlen(mountPoint); if (l < 2) return -4; // mount point is too short return -5; } vfs_inode_t vfs_get_inode_number(char *path) { if (path[0] != '/') return 0; vfs_inode_t vfs_inode = 0; } // look for entry in dir_inode, return the vfs_inode for the entry vfs_inode_t vfs_entry_lookup(vfs_inode_t dir_inode, char *entry) { vfs_open_file_t *open_dir = vfs_open_dir_inode(dir_inode); if (!open_dir) return 0x8000000000000001ULL; vfs_dir_entry_t dentry; vfs_inode_t vfs_inode = 0; while (!vfs_read_dir(open_dir, &dentry)) { if (!strcmp(dentry.name, entry)) { vfs_inode = (dir_inode & 0xFFFFFFFF00000000ULL) | dentry.inode_number; break; } } vfs_close_dir(open_dir); return vfs_inode; } // 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; } } /******************************************/