#include "vfs.h" #include "../shared/kstdlib.h" #include "../shared/memory.h" #include "../shared/string.h" #define MODULE_NAME "KVFS" vfile_t root_dir = {"/", VFILE_DIRECTORY}; struct mount_handler{ int (*callback)(vfile_t *device, MOUNT_OPERATION op, ...); uint32_t key; }mount_handlers[32]; void vfs_add_mount_handler(int (*mount_handler)(vfile_t *device, MOUNT_OPERATION op, ...), uint32_t key){ if(mount_handler == 0){ return; } for(uint32_t i = 0; i < 32; i++){ if(mount_handlers[i].callback == 0){ mount_handlers[i].callback = mount_handler; mount_handlers[i].key = key; } } } void vfs_del_mount_handler(uint32_t key){ for(uint32_t i = 0; i < 32; i++){ if(mount_handlers[i].key == key){ mount_handlers[i].callback = 0; mount_handlers[i].key = 0; } } } void vfs_init(){ mlog(MODULE_NAME, "Initializing VFS\n", MLOG_PRINT); root_dir.access.data.ptr = kmalloc(1); root_dir.access.data.size_pgs = 1; } void add_file(vfile_t *vfile, vfile_t *current_dir){ vfile_t **dir_data = current_dir->access.data.ptr; int i = 0; while(dir_data[i] && (i * sizeof(vfile_t *))/4096 < current_dir->access.data.size_pgs){ i++; } dir_data[i] = vfile; dir_data[i + 1] = 0; } /* Long comment cause this one's a complicated one. Create a file of the specified path in name if the path leads to a mounted filesystem then use the mounted filesystem's specified create() function to create the file. else, create a pointer in the virtual path that points to a file entry for the new file. If this new file is a Directory or Pointer, specify a pointer to be used as a buffer to store data for this file, as well as the size of the buffer, in pages. If this new file is a Mounted filesystem, this pointer must be an array of functions as defined below: int fwrite(vfile_t *file, void *data, uint32_t offset, uint32_t count); //must write count bytes from data to file offset by offset bytes. int fread(vfile_t *file, void *data, uint32_t offset, uint32_t count); //must read count bytes from data to file offset by offset bytes. int fopen(char *filename, vfile_t *file); //must return a vfile_t struct written to the address specified in file, to represent a file named name (from the mount's filename) (eg. /mount/root/test is passed as /root/test) fcreate(char *filename, FS_FILE_FLAGS flags); FS_FILE_FLAGS is in the same format as FAT's file attribute byte of dirents. filenames are truncated, as with the previous example. fdelete(vfile_t *file); //the file specified in the file pointer must be deleted. else, if the file is a virtual representation of a device, of of a file (any miscellaneous file object that does not fit the other types) then specify a pointer to be used as the read function, as defined below: void read(struct virtual_file *file, void *data, uint32_t offset, uint32_t count); specify a pointer to be used as the write function, with the same function prototype as the function above void write(struct virtual_file *file, void *data, uint32_t offset, uint32_t count); */ vfile_t *fcreate(char *name, VFILE_TYPE type, ...){ name += name[0]== '/'; char *last = strtok(name, '/'); char *tmp = last; uint32_t filename_offset = 0; vfile_t *current_dir = &root_dir; vfile_t *tmpfile; va_list args; va_start(args, type); while(tmp != 0){ // dir = tmp; tmpfile = search_dir(tmp, *current_dir); // printf("%s\n", name + filename_offset); if(!tmpfile){ //create file in folder; vfile_t *vfile = kmalloc(1); vfile->type = type; vfile->parent = current_dir; uint32_t tmpnsize = strlen(tmp); if(tmp[tmpnsize - 1] == '/'){ tmp[tmpnsize - 1] = 0; } strcpy(tmp, vfile->name); switch(type){ case VFILE_POINTER: case VFILE_DIRECTORY: case VFILE_MOUNT: case VFILE_SYMLINK: void *ptr = va_arg(args, void*); vfile->access.data.ptr = ptr; vfile->access.data.size_pgs = va_arg(args, uint32_t); // *(uint32_t *)(ptr + (vfile->access.data.size_pgs * 4096)) = 0; // what was the above line even for add_file(vfile, current_dir); break; case VFILE_FILE: case VFILE_DEVICE: void *write = va_arg(args, void *); void *read = va_arg(args, void *); vfile->access.funcs.write = write; vfile->access.funcs.read = read; // strcpy add_file(vfile, current_dir); break; } return vfile; //allow drivers to make last minute changes before it's sent to the user } if(tmpfile->type == VFILE_SYMLINK){ tmpfile = (vfile_t *)tmpfile->access.data.ptr; } switch(tmpfile->type){ case VFILE_DIRECTORY: current_dir = tmpfile; break; case VFILE_MOUNT: ((mount_t*)(tmpfile->access.data.ptr))->create(name + filename_offset, type == VFILE_DIRECTORY ? FS_FILE_IS_DIR : 0); return (void *)-1; default: // mlog(MODULE_NAME, "Error: Cannot create file with same name as another file! %d\n", MLOG_ERR, tmpfile->type); return 0; break; } filename_offset += strlen(tmp) + 1; tmp = strtok(0, '/'); } return 0; } //who needs a way to delete things? //TODO: Write a function to delete files void fdelete(); // navya was here https://github.com/novabansal int fwrite(vfile_t *file_entry, void *byte_array, uint32_t offset, uint32_t count){ //sorry navya, I deleted the comment and it's not coming back :( switch(file_entry->type){ case VFILE_DIRECTORY: case VFILE_POINTER: memcpy(byte_array, file_entry->access.data.ptr + offset, count); return 0; //always successful. If it's not, there's been a page fault. Yk, quantum sort style. break; case VFILE_MOUNT: mount_t *funcs = file_entry->access.data.ptr; return funcs->write(file_entry, byte_array, offset, count); case VFILE_PDIR: case VFILE_FILE: case VFILE_DEVICE: return file_entry->access.funcs.write(file_entry, byte_array, offset, count); break; case VFILE_SYMLINK: return fwrite(file_entry->access.data.ptr, byte_array, offset, count); } return INT32_MIN;//how did we get here? } int fread(vfile_t *file_entry, void *byte_array, uint32_t offset, uint32_t count){ switch(file_entry->type){ case VFILE_DIRECTORY: case VFILE_POINTER: memcpy(file_entry->access.data.ptr + offset, byte_array, count); return 0; //always successful. If it's not, there's been a page fault. Yk, quantum sort style. break; case VFILE_MOUNT: mount_t *funcs = file_entry->access.data.ptr; return funcs->read(file_entry, byte_array, offset, count); case VFILE_PDIR: case VFILE_FILE: case VFILE_DEVICE: return file_entry->access.funcs.read(file_entry, byte_array, offset, count); break; case VFILE_SYMLINK: return fread(file_entry->access.data.ptr, byte_array, offset, count); } return INT32_MIN; //Okay, alright, funny joke guys but we really shouldn't be able to get here } vfile_t *search_dir(char *name, vfile_t dir){ vfile_t **dir_data = (vfile_t **)dir.access.data.ptr; uint32_t i = 0; while(dir_data[i]){ if(!strcmp(dir_data[i]->name, name)){ return dir_data[i]; } i++; } return 0; } vfile_t *fopen(char *name){ if(name[0] == '/'){ if(strlen(name) == 1){ return &root_dir; } name++; } if(name[strlen(name) - 1] == '/'){ name[strlen(name) - 1] = 0; } // printf("%s\n", name); char *dir = strtok(name, '/'); // printf("%s", name); char *tmp = dir; uint32_t filename_offset = 0; vfile_t *current_dir = &root_dir; vfile_t *tmpfile; while(tmp != 0){ dir = tmp; tmpfile = search_dir(tmp, *current_dir); if(!tmpfile){ // printf("not found\n"); return 0; } if(tmpfile->type == VFILE_SYMLINK){ tmpfile = (vfile_t *)tmpfile->access.data.ptr; } switch(tmpfile->type){ case VFILE_DIRECTORY: // printf("found directory in %s: %s\n", current_dir->name, tmpfile->name); current_dir = tmpfile; break; case VFILE_MOUNT: vfile_t *file = kmalloc(1); ((mount_t*)(tmpfile->access.data.ptr))->open(name + filename_offset, file); return file; default: return tmpfile; } filename_offset += strlen(tmp) + 1; tmp = strtok(0, '/'); } return tmpfile; }