hos/kernel/fs/vfs.c

187 lines
3.5 KiB
C

// vfs.c
// Author: Josh Holtrop
// Date: 08/22/04
// Modified: 12/20/04
#include "hos_defines.h"
#include "kout.h"
#include "fs/vfs.h"
#include "fs/ext2.h"
#include "kernel.h"
#include "mm/vmm.h"
vfs_fs_t *fses[VFS_MAX_FS];
vfs_node_t *vfsMountTree;
int vfs_init()
{
k_check(ext2_init(FS_EXT2), "ext2_init() failed!");
return 0;
}
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;
}
int vfs_mount(major_t maj, minor_t min, int fsType, char *mountPoint)
{
if (mountPoint[0] != '/')
return -1; // mount point must be absolute
if (fsType < 0 || fsType >= VFS_MAX_FS || !fses[fsType])
return -2; // invalid filesystem type
if (vfs_find_mount(mountPoint))
{
return -5; // mount point already mounted
}
void *super = fses[fsType]->mount_super(maj, min);
if (!super)
return -6; // filesystem superblock not correctly identified
vfs_mount_t *mnt = New(vfs_mount_t);
if (!mnt)
return -3; // could not allocate memory
mnt->refs = 0;
mnt->major = maj;
mnt->minor = min;
mnt->super = super;
if (vfs_add_mount(mnt, mountPoint))
{
kfree(mnt);
return -4; // could not add mount
}
return 0;
}
int vfs_add_mount(vfs_mount_t *mnt, char *mountPoint)
{
vfs_node_t *node = vfsMountTree;
char *mp = mountPoint;
if (!vfsMountTree)
{
vfsMountTree = New(vfs_node_t);
node = vfsMountTree;
node->chr = *mp;
node->up = NULL;
node->next = NULL;
node->down = NULL;
node->mount = NULL;
}
for (;;)
{
if (node->chr == *mp) // got a match
{
mp++;
if (*mp == 0)
{
if (node->mount)
return -1; // mount point already taken
node->mount = mnt;
return 0;
}
if (node->down)
node = node->down;
else
{
node->down = New(vfs_node_t);
node->down->up = node;
node = node->down;
node->next = NULL;
node->down = NULL;
node->mount = NULL;
node->chr = *mp;
}
}
else if (node->next)
{
node = node->next;
}
else // add a node for this character
{
node->next = New(vfs_node_t);
node->next->up = node->up;
node = node->next;
node->next = NULL;
node->down = NULL;
node->mount = NULL;
node->chr = *mp;
}
}
}
vfs_mount_match_t vfs_get_rel_path(char *path)
{
vfs_mount_match_t matched;
char *pp = path;
int length = 0;
vfs_node_t *node = vfsMountTree;
while (*pp)
{
if (!node)
break;
if (node->chr == *pp) // got a character match
{
if (node->mount) // and there is something mounted here
{
matched.major = node->mount->major;
matched.minor = node->mount->minor;
matched.length = length;
}
pp++;
length++;
node = node->down;
}
else
node = node->next;
}
return matched;
}
vfs_mount_t *vfs_find_mount(char *mountPoint)
{
char *mp = mountPoint;
vfs_node_t *node = vfsMountTree;
while (node)
{
if (node->chr == *mp)
{
mp++;
if (*mp == 0) // we matched the whole mount point string
return node->mount;
node = node->down;
}
else
node = node->next;
}
return NULL;
}
/*void vfs_dump_tree()
{
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;
}
}*/