212 lines
6.4 KiB
C
212 lines
6.4 KiB
C
#include "vfs.h"
|
|
#include "ramfs.h"
|
|
#include "../shared/kstdlib.h"
|
|
#include "../shared/memory.h"
|
|
#include "../shared/string.h"
|
|
#define MODULE_NAME "RAMFS"
|
|
|
|
fileops_t ramfs_ops =
|
|
{
|
|
ramfs_create,
|
|
ramfs_delete,
|
|
ramfs_write,
|
|
ramfs_read,
|
|
// ramfs_open,
|
|
ramfs_close,
|
|
ramfs_rfopen,
|
|
};
|
|
|
|
vfile_t root_dir = {"/", FS_FILE_IS_DIR | FS_FILE_SYSTEM, &ramfs_ops};
|
|
|
|
void ramfs_init(){
|
|
mlog(MODULE_NAME, "Initializing VFS\n", MLOG_PRINT);
|
|
root_dir.private = 0;
|
|
root_dir.size = 0;
|
|
}
|
|
|
|
vfile_t *search_dir(char *subname, vfile_t *directory){
|
|
if(!directory) return 0;
|
|
vfile_t **children = (vfile_t **)directory->private;
|
|
if(!children){
|
|
return 0;
|
|
}
|
|
for(int i = 0; i < directory->size / sizeof(vfile_t *); i++){
|
|
if(children[i] && !strcmp(children[i]->name, subname)){
|
|
return children[i];
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
//resolves the path relative to start
|
|
vfile_t *resolve_path(char *pathname, vfile_t *start, uint32_t get_last_child){
|
|
const uint32_t MAX_TOKENS = PAGE_SIZE_BYTES/4;
|
|
|
|
if(!start){
|
|
return 0;
|
|
}
|
|
char *path = kmalloc(1);
|
|
strcpy(pathname, path);
|
|
|
|
char **path_tokens = kmalloc(1);
|
|
uint32_t pathname_entries = 0;
|
|
char *pathtok = path;
|
|
char *i = path;
|
|
while (*i != '\0') {
|
|
if (*i == '/') {
|
|
*i = '\0';
|
|
if (pathname_entries < MAX_TOKENS) {
|
|
path_tokens[pathname_entries++] = pathtok;
|
|
}
|
|
pathtok = i + 1;
|
|
}
|
|
i++;
|
|
}
|
|
if (pathname_entries < MAX_TOKENS) {
|
|
path_tokens[pathname_entries++] = pathtok;
|
|
}
|
|
|
|
// vfile_t **buffer = (vfile_t **)start->private;
|
|
vfile_t *entry = start;
|
|
char *current_path = pathname;
|
|
for(int i = 0; i < pathname_entries - !get_last_child; i++){
|
|
entry = search_dir(path_tokens[i], entry);
|
|
current_path += strlen(path_tokens[i]) + 1;
|
|
if(!entry){
|
|
break;
|
|
}
|
|
if(entry->flags & FS_FILE_MOUNT){
|
|
if(!get_last_child){
|
|
entry = 0;
|
|
break;
|
|
}
|
|
entry = entry->fileops->rfopen(current_path, entry);
|
|
break;
|
|
}
|
|
}
|
|
kfree(path);
|
|
kfree(path_tokens);
|
|
return entry;
|
|
}
|
|
|
|
char *get_filename(char *path){
|
|
char *filename = path + strlen(path) - 1;//get last character in pathname
|
|
while(*filename != path[0] && (*filename != '/' || filename == path)) filename--;
|
|
filename += filename != path;//if the new filename is at the beginning of the path, don't adjust for '/' character
|
|
return filename;
|
|
}
|
|
|
|
int ramfs_resize(vfile_t *file, uint32_t new_size_bytes){
|
|
if(new_size_bytes == file->size) return new_size_bytes;
|
|
uint32_t new_size_pages = (new_size_bytes + PAGE_SIZE_BYTES - 1)/PAGE_SIZE_BYTES;
|
|
uint32_t old_size_pages = (file->size + PAGE_SIZE_BYTES - 1)/PAGE_SIZE_BYTES;
|
|
do{
|
|
if(old_size_pages == new_size_pages){
|
|
break;
|
|
}
|
|
void *new_ptr = kmalloc(new_size_pages);
|
|
if(!new_ptr){
|
|
mlog(MODULE_NAME, "Failed to allocate memory for virtual file!\n", MLOG_PRINT);
|
|
return 0;
|
|
}
|
|
if(file->private){
|
|
memcpy((uint32_t *)file->private, (uint32_t*)new_ptr, file->size);
|
|
kfree(file->private);
|
|
}
|
|
file->private = new_ptr;
|
|
}while(0);
|
|
file->size = new_size_bytes;
|
|
return new_size_bytes;
|
|
}
|
|
|
|
vfile_t *ramfs_create(vfile_t *root, char *path, FS_FILE_FLAGS flags){
|
|
if(!path){
|
|
return 0;
|
|
}
|
|
if(path[0] == '/') path++;
|
|
// vfile_t *parent = resolve_path(path, root, false);
|
|
vfile_t *parent = root;
|
|
if(!parent || !parent->flags & FS_FILE_IS_DIR){
|
|
mlog(MODULE_NAME, "Could not locate parent directory for %s\n", MLOG_PRINT, path);
|
|
path--;
|
|
return 0;
|
|
}
|
|
char *new_name = path;
|
|
vfile_t **dirents = (vfile_t **)parent->private;
|
|
uint32_t insert_index = 0;
|
|
for(uint32_t i = 0; i < parent->size/sizeof(vfile_t *); i++){
|
|
if(dirents[i]){
|
|
continue;
|
|
}
|
|
//Empty dirent, can insert
|
|
vfile_t *new_file = kmalloc(1);
|
|
*new_file = (vfile_t){0};
|
|
// new_file->name = new_name;
|
|
strcpy(new_name, new_file->name);
|
|
new_file->flags = flags;
|
|
dirents[i] = new_file;
|
|
new_file->fileops = &ramfs_ops;
|
|
path--;
|
|
return new_file;
|
|
}
|
|
//no empty dirents, must resize
|
|
if( !ramfs_resize(parent, parent->size + 4)) return 0;
|
|
dirents = parent->private;
|
|
vfile_t *new_file = kmalloc(1);
|
|
if(!new_file) return 0;
|
|
*new_file = (vfile_t){0};
|
|
strcpy(new_name, new_file->name);
|
|
new_file->flags = flags;
|
|
dirents[parent->size/(sizeof(vfile_t*)) - 1] = new_file;
|
|
new_file->fileops = &ramfs_ops;
|
|
path--;
|
|
return new_file;
|
|
}
|
|
|
|
int ramfs_translate_dir(vfile_t *file, void *buffer, uint32_t offset, uint32_t count){
|
|
uint32_t dirents_requested = count / sizeof(vfile_t);
|
|
uint32_t dirents_availible = file->size / sizeof(vfile_t *);
|
|
uint32_t to_copy = unsigned_min(dirents_availible, dirents_requested);
|
|
vfile_t **dirents = (vfile_t **)file->private;
|
|
for(uint32_t i = 0; i < to_copy; i++){
|
|
memcpy(dirents[i], buffer + i * sizeof(vfile_t), sizeof(vfile_t));
|
|
}
|
|
return to_copy * sizeof(vfile_t);
|
|
}
|
|
|
|
int ramfs_delete(vfile_t *file){
|
|
return 0;
|
|
}
|
|
int ramfs_write(vfile_t *file, char *buffer, uint32_t offset, uint32_t count){
|
|
//file->private can be null here, as ramfs_resize will handle assigning if it is not already assigned
|
|
if(!file || !buffer || (file->flags & (FS_FILE_READ_ONLY | FS_FILE_IS_DIR | FS_FILE_MOUNT))) return 0;
|
|
if(!ramfs_resize(file, count + offset)) return 0;
|
|
memcpy(buffer, file->private + offset, count);
|
|
return count;
|
|
}
|
|
int ramfs_read(vfile_t *file, char *buffer, uint32_t offset, uint32_t count){
|
|
if(!file || !buffer || !file->private || file->flags & (FS_FILE_MOUNT)) return 0;
|
|
if(file->flags & FS_FILE_IS_DIR){
|
|
return ramfs_translate_dir(file, buffer, offset, count);
|
|
}
|
|
memcpy(file->private + offset, buffer, count);
|
|
return count;
|
|
}
|
|
// vfile_t *ramfs_open(char *path){
|
|
// return 0;
|
|
// }
|
|
void ramfs_close(vfile_t *file){
|
|
file->refcount--;
|
|
if(file->refcount < 0) file->refcount = 0;
|
|
return;
|
|
}
|
|
vfile_t *ramfs_rfopen(char *name, vfile_t *parent){
|
|
vfile_t *returnable = resolve_path(name, parent, true);
|
|
// for(;;);
|
|
return returnable;
|
|
}
|
|
|
|
vfile_t *get_root_dir(){
|
|
return &root_dir;
|
|
} |