#include "vfs.h" #include #include #include #include #include #include #include #include #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; } }