nshell/src/vfs/vfs.c

249 lines
6.3 KiB
C

#include "vfs.h"
#include <stdlib.h>
#include <string.h>
#include <gint/bfile.h>
#include <gint/cpu.h>
#include <gint/drivers.h>
#include <gint/keyboard.h>
#include <gint/kmalloc.h>
#include <printf.h>
#include "../term.h"
extern void _name_to_str(char *dest, const uint16_t *source, int n);
extern void _str_to_name(uint16_t *dest, const char *source, int n);
extern int _find_first(const uint16_t *pathname, int *FindHandle, const uint16_t *foundfile, struct BFile_FileInfo *fileinfo);
extern int _find_next(int FindHandle, const uint16_t *foundfile, struct BFile_FileInfo *fileinfo);
extern int _open_file_os(const unsigned short *filename, int mode, int zero);
extern int _close_file_os(int handle);
extern int _readfile_os(int handle, void *buf, int size, int pos);
static vfs_entry_t *vfs_root;
static vfs_entry_t *vfs_alloc_entry(const char *name) {
vfs_entry_t *entry = kmalloc(sizeof(vfs_entry_t), NULL);
entry->name = kmalloc(strlen(name) + 1, NULL);
strcpy(entry->name, name);
return entry;
}
static vfs_entry_t *vfs_new_dir(const char *name, vfs_entry_t *parent) {
vfs_entry_t *newdir = vfs_alloc_entry(name);
newdir->parent = parent;
newdir->type = vfs_dir;
newdir->driver = (parent == NULL) ? vfs_drv_none : parent->driver;
newdir->childs = NULL;
newdir->next = NULL;
newdir->next = parent->childs;
parent->childs = newdir;
return newdir;
}
static vfs_entry_t *vfs_new_file(const char *name, vfs_entry_t *parent) {
vfs_entry_t *newfile = vfs_alloc_entry(name);
newfile->parent = parent;
newfile->type = vfs_file;
newfile->driver = (parent == NULL) ? vfs_drv_none : parent->driver;
newfile->childs = NULL;
newfile->next = NULL;
newfile->next = parent->childs;
parent->childs = newfile;
return newfile;
}
static void vfs_debug_tree_(int indent, vfs_entry_t *subtree) {
vfs_entry_t *child = subtree->childs;
while (child != NULL) {
for (int i = 0; i < indent; i++)
term_print(" ");
if (child->type == vfs_file)
term_printf("%s\n", child->name);
else if (child->type == vfs_dir) {
term_printf("%s/\n", child->name);
vfs_debug_tree_(indent + 1, child);
}
child = child->next;
}
}
static void vfs_debug_tree(void) {
term_print("/\n");
vfs_debug_tree_(1, vfs_root);
}
static int shandle;
static void populate_vfs_fls(const char *path, vfs_entry_t *dir) {
char glob[64];
strcpy(glob, path);
strcat(glob, "\\*");
uint16_t glob_c16[64];
_str_to_name(glob_c16, glob, 64);
uint16_t foundfile[64];
struct BFile_FileInfo fileinfo;
int ret = _find_first(glob_c16, &shandle, foundfile, &fileinfo);
while (ret == 0) {
char foundfile_str[64];
_name_to_str(foundfile_str, foundfile, 64);
if (foundfile_str[0] != '@' && strcmp(foundfile_str, ".") != 0 && strcmp(foundfile_str, "..") != 0) {
vfs_entry_t *e;
if (fileinfo.type == BFile_Type_Directory) {
e = vfs_new_dir(foundfile_str, dir);
} else {
e = vfs_new_file(foundfile_str, dir);
}
// embed full path str
char data_str[64];
strcpy(data_str, path);
strcat(data_str, foundfile_str);
e->data = kmalloc(64, NULL);
_str_to_name((uint16_t *)e->data, data_str, 64);
}
ret = _find_next(shandle, foundfile, &fileinfo);
}
BFile_FindClose(shandle);
// we do the recursive search when the search handle
// has been closed to avoid using too much handles
vfs_entry_t *child = dir->childs;
while (child != NULL) {
if (child->type == vfs_dir) {
char new_path[64];
sprintf(new_path, "%s\\%s", path, child->name);
populate_vfs_fls(new_path, child);
}
child = child->next;
}
}
void vfs_init(void) {
vfs_root = vfs_alloc_entry("");
vfs_root->parent = NULL;
vfs_root->type = vfs_dir;
vfs_root->driver = vfs_drv_builtin;
vfs_root->childs = NULL;
vfs_root->next = NULL;
vfs_entry_t *sysfs = vfs_new_dir("sys", vfs_root);
sysfs->driver = vfs_drv_sysfs;
vfs_entry_t *media = vfs_new_dir("media", vfs_root);
vfs_entry_t *fls0 = vfs_new_dir("fls0", media);
fls0->driver = vfs_drv_fls;
cpu_atomic_start();
populate_vfs_fls("\\\\fls0", fls0);
cpu_atomic_end();
vfs_entry_t *res = vfs_new_dir("res", media);
res->driver = vfs_drv_res;
vfs_debug_tree();
}
static vfs_entry_t *vfs_find_child(vfs_entry_t *parent, const char *child_name) {
if (parent == NULL)
return NULL;
if (parent->type != vfs_dir)
return NULL;
if (child_name[0] == '\0')
return parent;
vfs_entry_t *fe = parent->childs;
while (1) {
if (fe == NULL)
return NULL;
if (strcmp(child_name, fe->name) == 0)
break;
fe = fe->next;
}
return fe;
}
static vfs_entry_t *vfs_find_entry(const char *path) {
vfs_entry_t *fe = vfs_root;
char buf[64];
int i = 0;
int j = 0;
while (1) {
buf[i++] = path[j++];
if (buf[i - 1] == '/' || buf[i - 1] == '\0') {
buf[i - 1] = '\0';
fe = vfs_find_child(fe, buf);
if (fe == NULL)
return NULL;
i = 0;
}
if (buf[i - 1] == '\0')
break;
}
return fe;
}
vfs_handle_t *vfs_open(const char *path) {
vfs_entry_t *f_entry = vfs_find_entry(path);
if (f_entry == NULL)
return NULL;
vfs_handle_t *f_handle = kmalloc(sizeof(vfs_handle_t), NULL);
f_handle->entry = f_entry;
f_handle->pos = 0;
f_handle->mode = vfs_RW;
f_handle->size = 0;
return f_handle;
}
void vfs_close(vfs_handle_t *f_handle) { kfree(f_handle); }
int vfs_read(vfs_handle_t *fh, int n, char buf[n]) {
switch (fh->entry->type) {
case vfs_drv_fls:
cpu_atomic_start();
const int fd = _open_file_os((unsigned short *)fh->entry->data, 1, 0); // open in mode RO_SHARE
const int nb_read = _readfile_os(fd, buf, n, fh->pos);
_close_file_os(fd);
cpu_atomic_end();
fh->pos += nb_read;
return nb_read;
default:
term_kprint("I/O driver not implemented");
return -1;
}
}