KimisOS/src/kernel/system/ramfs.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;
}