hos/kernel/fs/vfs.c

207 lines
5.1 KiB
C

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