2011-12-11 03:42:41 +04:00
|
|
|
/* vim: shiftwidth=4 tabstop=4 noexpandtab
|
2011-12-11 03:34:10 +04:00
|
|
|
*
|
|
|
|
* Virtual File System
|
|
|
|
*
|
2011-12-09 01:37:11 +04:00
|
|
|
*/
|
2011-01-22 10:09:47 +03:00
|
|
|
#include <system.h>
|
|
|
|
#include <fs.h>
|
2011-11-29 23:28:36 +04:00
|
|
|
#include <list.h>
|
2011-12-09 01:37:11 +04:00
|
|
|
#include <process.h>
|
2011-01-22 10:09:47 +03:00
|
|
|
|
|
|
|
fs_node_t *fs_root = 0;
|
|
|
|
|
|
|
|
uint32_t read_fs(fs_node_t *node, uint32_t offset, uint32_t size, uint8_t *buffer) {
|
2012-01-26 05:25:59 +04:00
|
|
|
if (node->read) {
|
2011-12-11 05:15:12 +04:00
|
|
|
uint32_t ret = node->read(node, offset, size, buffer);
|
|
|
|
return ret;
|
2011-01-22 10:09:47 +03:00
|
|
|
} else {
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
uint32_t write_fs(fs_node_t *node, uint32_t offset, uint32_t size, uint8_t *buffer) {
|
2012-01-26 05:25:59 +04:00
|
|
|
if (node->write) {
|
2011-12-11 05:15:12 +04:00
|
|
|
uint32_t ret = node->write(node, offset, size, buffer);
|
|
|
|
return ret;
|
2011-01-22 10:09:47 +03:00
|
|
|
} else {
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void open_fs(fs_node_t *node, uint8_t read, uint8_t write) {
|
2012-01-26 05:25:59 +04:00
|
|
|
if (node->open) {
|
2011-01-22 10:09:47 +03:00
|
|
|
node->open(node, read, write);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void close_fs(fs_node_t *node) {
|
2011-04-11 23:17:15 +04:00
|
|
|
if (node == fs_root) {
|
|
|
|
HALT_AND_CATCH_FIRE("Attemped to close the filesystem root. kablooey", NULL);
|
|
|
|
}
|
2012-01-26 05:25:59 +04:00
|
|
|
if (node->close) {
|
2011-01-22 10:09:47 +03:00
|
|
|
node->close(node);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-01-26 05:25:59 +04:00
|
|
|
struct dirent *readdir_fs(fs_node_t *node, uint32_t index) {
|
|
|
|
if ((node->flags & FS_DIRECTORY) && node->readdir) {
|
|
|
|
struct dirent *ret = node->readdir(node, index);
|
2011-12-11 05:15:12 +04:00
|
|
|
return ret;
|
2011-01-22 10:09:47 +03:00
|
|
|
} else {
|
|
|
|
return (struct dirent *)NULL;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
fs_node_t *finddir_fs(fs_node_t *node, char *name) {
|
2012-01-26 05:25:59 +04:00
|
|
|
if ((node->flags & FS_DIRECTORY) && node->finddir) {
|
|
|
|
fs_node_t *ret = node->finddir(node, name);
|
2011-12-11 05:15:12 +04:00
|
|
|
return ret;
|
2011-01-22 10:09:47 +03:00
|
|
|
} else {
|
|
|
|
return (fs_node_t *)NULL;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-01-26 05:25:59 +04:00
|
|
|
void create_file_fs(char *name, uint16_t permission) {
|
|
|
|
int32_t i = strlen(name);
|
|
|
|
char *dir_name = malloc(i + 1);
|
|
|
|
memcpy(dir_name, name, i);
|
|
|
|
dir_name[i] = '\0';
|
|
|
|
if (dir_name[i - 1] == '/')
|
|
|
|
dir_name[i - 1] = '\0';
|
|
|
|
if (strlen(dir_name) == 0) {
|
|
|
|
kprintf("mkdir: /: Is a directory\n");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
for (i = strlen(dir_name) - 1; i >= 0; i--) {
|
|
|
|
if (dir_name[i] == '/') {
|
|
|
|
dir_name[i] = '\0';
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// get the parent dir node.
|
|
|
|
fs_node_t *node;
|
|
|
|
if (i >= 0) {
|
|
|
|
node = kopen(dir_name, 0);
|
|
|
|
} else {
|
|
|
|
node = kopen(".", 0);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (node == NULL) {
|
|
|
|
kprintf("mkdir: Directory does not exist\n");
|
|
|
|
free(dir_name);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
i++;
|
|
|
|
if ((node->flags & FS_DIRECTORY) && node->mkdir) {
|
|
|
|
node->create(node, dir_name + i, permission);
|
|
|
|
}
|
|
|
|
|
|
|
|
free(node);
|
|
|
|
free(dir_name);
|
|
|
|
}
|
|
|
|
|
|
|
|
void mkdir_fs(char *name, uint16_t permission) {
|
|
|
|
int32_t i = strlen(name);
|
|
|
|
char *dir_name = malloc(i + 1);
|
|
|
|
memcpy(dir_name, name, i);
|
|
|
|
dir_name[i] = '\0';
|
|
|
|
if (dir_name[i - 1] == '/')
|
|
|
|
dir_name[i - 1] = '\0';
|
|
|
|
if (strlen(dir_name) == 0) {
|
|
|
|
kprintf("mkdir: /: Is a directory\n");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
for (i = strlen(dir_name) - 1; i >= 0; i--) {
|
|
|
|
if (dir_name[i] == '/') {
|
|
|
|
dir_name[i] = '\0';
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// get the parent dir node.
|
|
|
|
fs_node_t *node;
|
|
|
|
if (i >= 0) {
|
|
|
|
node = kopen(dir_name, 0);
|
|
|
|
} else {
|
|
|
|
node = kopen(".", 0);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (node == NULL) {
|
|
|
|
kprintf("mkdir: Directory does not exist\n");
|
|
|
|
free(dir_name);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
i++;
|
|
|
|
if ((node->flags & FS_DIRECTORY) && node->mkdir) {
|
|
|
|
node->mkdir(node, dir_name + i, permission);
|
|
|
|
}
|
|
|
|
|
|
|
|
free(node);
|
|
|
|
free(dir_name);
|
|
|
|
}
|
|
|
|
|
|
|
|
fs_node_t *clone_fs(fs_node_t *source) {
|
2011-12-09 01:25:48 +04:00
|
|
|
if (!source) {
|
|
|
|
return NULL;
|
|
|
|
}
|
2012-01-26 05:25:59 +04:00
|
|
|
fs_node_t *n = malloc(sizeof(fs_node_t));
|
2011-12-09 01:25:48 +04:00
|
|
|
memcpy(n, source, sizeof(fs_node_t));
|
|
|
|
return n;
|
|
|
|
}
|
|
|
|
|
2012-01-26 05:25:59 +04:00
|
|
|
/**
|
2011-11-29 23:28:36 +04:00
|
|
|
* Canonicalize a path.
|
2012-01-26 05:25:59 +04:00
|
|
|
* Caller should free the memory.
|
2011-11-29 23:28:36 +04:00
|
|
|
*/
|
2012-01-26 05:25:59 +04:00
|
|
|
char *canonicalize_path(char *cwd, char *input) {
|
|
|
|
list_t *out = list_create();
|
2011-11-29 23:28:36 +04:00
|
|
|
|
|
|
|
if (strlen(input) && input[0] != '/') {
|
2012-01-26 05:25:59 +04:00
|
|
|
char *path = malloc((strlen(cwd) + 1) * sizeof(char));
|
2011-11-29 23:28:36 +04:00
|
|
|
memcpy(path, cwd, strlen(cwd) + 1);
|
|
|
|
|
2012-01-26 05:25:59 +04:00
|
|
|
char *pch;
|
|
|
|
char *save;
|
2011-11-29 23:28:36 +04:00
|
|
|
pch = strtok_r(path,"/",&save);
|
|
|
|
|
|
|
|
while (pch != NULL) {
|
2012-01-26 05:25:59 +04:00
|
|
|
char *s = malloc(sizeof(char) * (strlen(pch) + 1));
|
2011-11-29 23:28:36 +04:00
|
|
|
memcpy(s, pch, strlen(pch) + 1);
|
|
|
|
list_insert(out, s);
|
|
|
|
pch = strtok_r(NULL,"/",&save);
|
|
|
|
}
|
|
|
|
free(path);
|
|
|
|
}
|
|
|
|
|
2012-01-26 05:25:59 +04:00
|
|
|
char *path = malloc((strlen(input) + 1) * sizeof(char));
|
2011-11-29 23:28:36 +04:00
|
|
|
memcpy(path, input, strlen(input) + 1);
|
2012-01-26 05:25:59 +04:00
|
|
|
char *pch;
|
|
|
|
char *save;
|
2011-11-29 23:28:36 +04:00
|
|
|
pch = strtok_r(path,"/",&save);
|
|
|
|
while (pch != NULL) {
|
|
|
|
if (!strcmp(pch,"..")) {
|
|
|
|
node_t * n = list_pop(out);
|
2011-11-30 06:19:30 +04:00
|
|
|
if (n) {
|
|
|
|
free(n->value);
|
|
|
|
free(n);
|
|
|
|
}
|
2011-11-29 23:28:36 +04:00
|
|
|
} else if (!strcmp(pch,".")) {
|
|
|
|
/* pass */
|
|
|
|
} else {
|
|
|
|
char * s = malloc(sizeof(char) * (strlen(pch) + 1));
|
|
|
|
memcpy(s, pch, strlen(pch) + 1);
|
|
|
|
list_insert(out, s);
|
|
|
|
}
|
|
|
|
pch = strtok_r(NULL, "/", &save);
|
|
|
|
}
|
|
|
|
free(path);
|
|
|
|
|
|
|
|
size_t size = 0;
|
|
|
|
|
|
|
|
foreach(item, out) {
|
|
|
|
size += strlen(item->value) + 1;
|
|
|
|
}
|
|
|
|
|
2012-01-26 05:25:59 +04:00
|
|
|
char *output = malloc(sizeof(char) * (size + 1));
|
|
|
|
char *output_offset = output;
|
2011-11-30 06:19:30 +04:00
|
|
|
if (size == 0) {
|
|
|
|
output = realloc(output, sizeof(char) * 2);
|
|
|
|
output[0] = '/';
|
|
|
|
output[1] = '\0';
|
|
|
|
} else {
|
|
|
|
foreach(item, out) {
|
|
|
|
output_offset[0] = '/';
|
|
|
|
output_offset++;
|
|
|
|
memcpy(output_offset, item->value, strlen(item->value) + 1);
|
|
|
|
output_offset += strlen(item->value);
|
|
|
|
}
|
2011-11-29 23:28:36 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
list_destroy(out);
|
|
|
|
list_free(out);
|
|
|
|
free(out);
|
|
|
|
|
|
|
|
return output;
|
|
|
|
}
|
|
|
|
|
2011-01-29 23:12:00 +03:00
|
|
|
/*
|
2012-01-26 05:25:59 +04:00
|
|
|
* Retreive the node for the requested path.
|
|
|
|
* Caller should free the memory.
|
2011-04-12 23:37:10 +04:00
|
|
|
* HACK FIXME XXX TODO
|
|
|
|
* THIS IS A TERRIBLE HACK OF A FUNCTION AND IT SHOULD
|
|
|
|
* BE FIX OR ELSE EVERYTHING ELSE WILL BE HORRIBLY BROKEN!
|
2011-01-29 23:12:00 +03:00
|
|
|
*/
|
2012-01-26 05:25:59 +04:00
|
|
|
fs_node_t *kopen(char *filename, uint32_t flags) {
|
|
|
|
|
2011-04-12 23:37:10 +04:00
|
|
|
/* Some sanity checks */
|
2011-11-30 06:19:30 +04:00
|
|
|
if (!fs_root || !filename) {
|
2011-04-12 23:37:10 +04:00
|
|
|
return NULL;
|
2011-01-29 23:12:00 +03:00
|
|
|
}
|
2012-01-26 05:25:59 +04:00
|
|
|
char *cwd = (char *)(current_process->wd_name);
|
|
|
|
char *npath = canonicalize_path(cwd, filename);
|
2011-11-18 01:55:59 +04:00
|
|
|
size_t path_len = strlen(npath);
|
2012-01-26 05:25:59 +04:00
|
|
|
|
2011-02-07 23:30:17 +03:00
|
|
|
if (path_len == 1) {
|
2012-01-26 05:25:59 +04:00
|
|
|
fs_node_t *root_clone = malloc(sizeof(fs_node_t));
|
2011-04-12 23:37:10 +04:00
|
|
|
memcpy(root_clone, fs_root, sizeof(fs_node_t));
|
2012-01-26 05:25:59 +04:00
|
|
|
free(npath);
|
2011-04-12 23:37:10 +04:00
|
|
|
return root_clone;
|
2011-02-07 23:30:17 +03:00
|
|
|
}
|
2012-01-26 05:25:59 +04:00
|
|
|
char *path = (char *)malloc(sizeof(char) * (path_len + 1));
|
2011-11-30 06:19:30 +04:00
|
|
|
memcpy(path, npath, path_len + 1);
|
|
|
|
free(npath);
|
2012-01-26 05:25:59 +04:00
|
|
|
char *path_offset = path;
|
2011-01-29 23:12:00 +03:00
|
|
|
uint32_t path_depth = 0;
|
|
|
|
while (path_offset < path + path_len) {
|
|
|
|
if (*path_offset == '/') {
|
|
|
|
*path_offset = '\0';
|
|
|
|
path_depth++;
|
|
|
|
}
|
|
|
|
path_offset++;
|
|
|
|
}
|
|
|
|
path[path_len] = '\0';
|
|
|
|
path_offset = path + 1;
|
|
|
|
uint32_t depth;
|
2012-01-26 05:25:59 +04:00
|
|
|
fs_node_t *node_ptr = malloc(sizeof(fs_node_t));
|
2011-04-12 23:37:10 +04:00
|
|
|
memcpy(node_ptr, fs_root, sizeof(fs_node_t));
|
2012-01-26 05:25:59 +04:00
|
|
|
fs_node_t *node_next = NULL;
|
2011-01-29 23:12:00 +03:00
|
|
|
for (depth = 0; depth < path_depth; ++depth) {
|
2011-04-12 23:37:10 +04:00
|
|
|
node_next = finddir_fs(node_ptr, path_offset);
|
|
|
|
free(node_ptr);
|
|
|
|
node_ptr = node_next;
|
2011-01-29 23:12:00 +03:00
|
|
|
if (!node_ptr) {
|
|
|
|
free((void *)path);
|
|
|
|
return NULL;
|
|
|
|
} else if (depth == path_depth - 1) {
|
2011-01-29 23:52:44 +03:00
|
|
|
open_fs(node_ptr, 1, 0);
|
2011-04-09 02:53:52 +04:00
|
|
|
free((void *)path);
|
2011-01-29 23:12:00 +03:00
|
|
|
return node_ptr;
|
|
|
|
}
|
2011-01-29 23:52:44 +03:00
|
|
|
path_offset += strlen(path_offset) + 1;
|
2011-01-29 23:12:00 +03:00
|
|
|
}
|
|
|
|
free((void *)path);
|
|
|
|
return NULL;
|
2011-01-29 09:43:39 +03:00
|
|
|
}
|
|
|
|
|