123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559 |
- /* vim: tabstop=4 shiftwidth=4 noexpandtab
- * This file is part of ToaruOS and is released under the terms
- * of the NCSA / University of Illinois License - see LICENSE.md
- * Copyright (C) 2014-2018 K. Lange
- */
- #include <kernel/system.h>
- #include <kernel/logging.h>
- #include <kernel/fs.h>
- #include <kernel/version.h>
- #include <kernel/process.h>
- #include <kernel/mem.h>
- #include <kernel/module.h>
- #include <kernel/mod/tmpfs.h>
- /* 4KB */
- #define BLOCKSIZE 0x1000
- #define TMPFS_TYPE_FILE 1
- #define TMPFS_TYPE_DIR 2
- #define TMPFS_TYPE_LINK 3
- static char * buf_space = NULL;
- static spin_lock_t tmpfs_lock = { 0 };
- static spin_lock_t tmpfs_page_lock = { 0 };
- struct tmpfs_dir * tmpfs_root = NULL;
- static fs_node_t * tmpfs_from_dir(struct tmpfs_dir * d);
- static struct tmpfs_file * tmpfs_file_new(char * name) {
- spin_lock(tmpfs_lock);
- struct tmpfs_file * t = malloc(sizeof(struct tmpfs_file));
- t->name = strdup(name);
- t->type = TMPFS_TYPE_FILE;
- t->length = 0;
- t->pointers = 2;
- t->block_count = 0;
- t->mask = 0;
- t->uid = 0;
- t->gid = 0;
- t->atime = now();
- t->mtime = t->atime;
- t->ctime = t->atime;
- t->blocks = malloc(t->pointers * sizeof(char *));
- for (size_t i = 0; i < t->pointers; ++i) {
- t->blocks[i] = NULL;
- }
- spin_unlock(tmpfs_lock);
- return t;
- }
- static int symlink_tmpfs(fs_node_t * parent, char * target, char * name) {
- struct tmpfs_dir * d = (struct tmpfs_dir *)parent->device;
- debug_print(NOTICE, "Creating TMPFS file (symlink) %s in %s", name, d->name);
- spin_lock(tmpfs_lock);
- foreach(f, d->files) {
- struct tmpfs_file * t = (struct tmpfs_file *)f->value;
- if (!strcmp(name, t->name)) {
- spin_unlock(tmpfs_lock);
- debug_print(WARNING, "... already exists.");
- return -EEXIST; /* Already exists */
- }
- }
- spin_unlock(tmpfs_lock);
- debug_print(NOTICE, "... creating a new file (symlink).");
- struct tmpfs_file * t = tmpfs_file_new(name);
- t->type = TMPFS_TYPE_LINK;
- debug_print(NOTICE, "symlink target is [%s]", target);
- t->target = strdup(target);
- t->mask = 0777;
- t->uid = current_process->user;
- t->gid = current_process->user;
- spin_lock(tmpfs_lock);
- list_insert(d->files, t);
- spin_unlock(tmpfs_lock);
- return 0;
- }
- static int readlink_tmpfs(fs_node_t * node, char * buf, size_t size) {
- struct tmpfs_file * t = (struct tmpfs_file *)(node->device);
- if (t->type != TMPFS_TYPE_LINK) {
- debug_print(WARNING, "Not a symlink? Very confused!");
- return -1;
- }
- if (size < strlen(t->target) + 1) {
- debug_print(INFO, "Requested read size was only %d, need %d.", size, strlen(t->target)+1);
- memcpy(buf, t->target, size);
- buf[size] = '\0';
- return size-1;
- } else {
- debug_print(INFO, "Reading link target is [%s]", t->target);
- memcpy(buf, t->target, strlen(t->target) + 1);
- return strlen(t->target);
- }
- }
- static struct tmpfs_dir * tmpfs_dir_new(char * name, struct tmpfs_dir * parent) {
- spin_lock(tmpfs_lock);
- struct tmpfs_dir * d = malloc(sizeof(struct tmpfs_dir));
- d->name = strdup(name);
- d->type = TMPFS_TYPE_DIR;
- d->mask = 0;
- d->uid = 0;
- d->gid = 0;
- d->atime = now();
- d->mtime = d->atime;
- d->ctime = d->atime;
- d->files = list_create();
- spin_unlock(tmpfs_lock);
- return d;
- }
- static void tmpfs_file_free(struct tmpfs_file * t) {
- if (t->type == TMPFS_TYPE_LINK) {
- debug_print(ERROR, "uh, what");
- free(t->target);
- }
- for (size_t i = 0; i < t->block_count; ++i) {
- clear_frame((uintptr_t)t->blocks[i] * 0x1000);
- }
- }
- static void tmpfs_file_blocks_embiggen(struct tmpfs_file * t) {
- t->pointers *= 2;
- debug_print(INFO, "Embiggening file %s to %d blocks", t->name, t->pointers);
- t->blocks = realloc(t->blocks, sizeof(char *) * t->pointers);
- }
- static char * tmpfs_file_getset_block(struct tmpfs_file * t, size_t blockid, int create) {
- debug_print(INFO, "Reading block %d from file %s", blockid, t->name);
- spin_lock(tmpfs_page_lock);
- if (create) {
- spin_lock(tmpfs_lock);
- while (blockid >= t->pointers) {
- tmpfs_file_blocks_embiggen(t);
- }
- while (blockid >= t->block_count) {
- debug_print(INFO, "Allocating block %d for file %s", blockid, t->name);
- uintptr_t index = first_frame();
- set_frame(index * 0x1000);
- t->blocks[t->block_count] = (char*)index;
- t->block_count += 1;
- }
- spin_unlock(tmpfs_lock);
- } else {
- if (blockid >= t->block_count) {
- debug_print(ERROR, "This will probably end badly.");
- return NULL;
- }
- }
- debug_print(INFO, "Using block %d->0x%x (of %d) on file %s", blockid, t->blocks[blockid], t->block_count, t->name);
- page_t * page = get_page((uintptr_t)buf_space,0,current_directory);
- page->rw = 1;
- page->user = 0;
- page->frame = (uintptr_t)t->blocks[blockid];
- page->present = 1;
- invalidate_tables_at((uintptr_t)buf_space);
- return (char *)buf_space;
- }
- static uint32_t read_tmpfs(fs_node_t *node, uint32_t offset, uint32_t size, uint8_t *buffer) {
- struct tmpfs_file * t = (struct tmpfs_file *)(node->device);
- t->atime = now();
- uint32_t end;
- if (offset + size > t->length) {
- end = t->length;
- } else {
- end = offset + size;
- }
- debug_print(INFO, "reading from %d to %d", offset, end);
- uint32_t start_block = offset / BLOCKSIZE;
- uint32_t end_block = end / BLOCKSIZE;
- uint32_t end_size = end - end_block * BLOCKSIZE;
- uint32_t size_to_read = end - offset;
- if (start_block == end_block && offset == end) return 0;
- if (start_block == end_block) {
- void *buf = tmpfs_file_getset_block(t, start_block, 0);
- memcpy(buffer, (uint8_t *)(((uint32_t)buf) + (offset % BLOCKSIZE)), size_to_read);
- spin_unlock(tmpfs_page_lock);
- return size_to_read;
- } else {
- uint32_t block_offset;
- uint32_t blocks_read = 0;
- for (block_offset = start_block; block_offset < end_block; block_offset++, blocks_read++) {
- if (block_offset == start_block) {
- void *buf = tmpfs_file_getset_block(t, block_offset, 0);
- memcpy(buffer, (uint8_t *)(((uint32_t)buf) + (offset % BLOCKSIZE)), BLOCKSIZE - (offset % BLOCKSIZE));
- spin_unlock(tmpfs_page_lock);
- } else {
- void *buf = tmpfs_file_getset_block(t, block_offset, 0);
- memcpy(buffer + BLOCKSIZE * blocks_read - (offset % BLOCKSIZE), buf, BLOCKSIZE);
- spin_unlock(tmpfs_page_lock);
- }
- }
- if (end_size) {
- void *buf = tmpfs_file_getset_block(t, end_block, 0);
- memcpy(buffer + BLOCKSIZE * blocks_read - (offset % BLOCKSIZE), buf, end_size);
- spin_unlock(tmpfs_page_lock);
- }
- }
- return size_to_read;
- }
- static uint32_t write_tmpfs(fs_node_t *node, uint32_t offset, uint32_t size, uint8_t *buffer) {
- struct tmpfs_file * t = (struct tmpfs_file *)(node->device);
- t->atime = now();
- t->mtime = t->atime;
- uint32_t end;
- if (offset + size > t->length) {
- t->length = offset + size;
- }
- end = offset + size;
- uint32_t start_block = offset / BLOCKSIZE;
- uint32_t end_block = end / BLOCKSIZE;
- uint32_t end_size = end - end_block * BLOCKSIZE;
- uint32_t size_to_read = end - offset;
- if (start_block == end_block) {
- void *buf = tmpfs_file_getset_block(t, start_block, 1);
- memcpy((uint8_t *)(((uint32_t)buf) + (offset % BLOCKSIZE)), buffer, size_to_read);
- spin_unlock(tmpfs_page_lock);
- return size_to_read;
- } else {
- uint32_t block_offset;
- uint32_t blocks_read = 0;
- for (block_offset = start_block; block_offset < end_block; block_offset++, blocks_read++) {
- if (block_offset == start_block) {
- void *buf = tmpfs_file_getset_block(t, block_offset, 1);
- memcpy((uint8_t *)(((uint32_t)buf) + (offset % BLOCKSIZE)), buffer, BLOCKSIZE - (offset % BLOCKSIZE));
- spin_unlock(tmpfs_page_lock);
- } else {
- void *buf = tmpfs_file_getset_block(t, block_offset, 1);
- memcpy(buf, buffer + BLOCKSIZE * blocks_read - (offset % BLOCKSIZE), BLOCKSIZE);
- spin_unlock(tmpfs_page_lock);
- }
- }
- if (end_size) {
- void *buf = tmpfs_file_getset_block(t, end_block, 1);
- memcpy(buf, buffer + BLOCKSIZE * blocks_read - (offset % BLOCKSIZE), end_size);
- spin_unlock(tmpfs_page_lock);
- }
- }
- return size_to_read;
- }
- static int chmod_tmpfs(fs_node_t * node, int mode) {
- struct tmpfs_file * t = (struct tmpfs_file *)(node->device);
- /* XXX permissions */
- t->mask = mode;
- return 0;
- }
- static int chown_tmpfs(fs_node_t * node, int uid, int gid) {
- struct tmpfs_file * t = (struct tmpfs_file *)(node->device);
- debug_print(INFO, "chown(..., %d, %d)", uid, gid);
- t->uid = uid;
- t->gid = gid;
- return 0;
- }
- static void open_tmpfs(fs_node_t * node, unsigned int flags) {
- struct tmpfs_file * t = (struct tmpfs_file *)(node->device);
- debug_print(INFO, "---- Opened TMPFS file %s with flags 0x%x ----", t->name, flags);
- if (flags & O_TRUNC) {
- debug_print(INFO, "Truncating file %s", t->name);
- for (size_t i = 0; i < t->block_count; ++i) {
- clear_frame((uintptr_t)t->blocks[i] * 0x1000);
- t->blocks[i] = 0;
- }
- t->block_count = 0;
- t->length = 0;
- }
- return;
- }
- static fs_node_t * tmpfs_from_file(struct tmpfs_file * t) {
- fs_node_t * fnode = malloc(sizeof(fs_node_t));
- memset(fnode, 0x00, sizeof(fs_node_t));
- fnode->inode = 0;
- strcpy(fnode->name, t->name);
- fnode->device = t;
- fnode->mask = t->mask;
- fnode->uid = t->uid;
- fnode->gid = t->gid;
- fnode->atime = t->atime;
- fnode->ctime = t->ctime;
- fnode->mtime = t->mtime;
- fnode->flags = FS_FILE;
- fnode->read = read_tmpfs;
- fnode->write = write_tmpfs;
- fnode->open = open_tmpfs;
- fnode->close = NULL;
- fnode->readdir = NULL;
- fnode->finddir = NULL;
- fnode->chmod = chmod_tmpfs;
- fnode->chown = chown_tmpfs;
- fnode->length = t->length;
- fnode->nlink = 1;
- return fnode;
- }
- static fs_node_t * tmpfs_from_link(struct tmpfs_file * t) {
- fs_node_t * fnode = tmpfs_from_file(t);
- fnode->flags |= FS_SYMLINK;
- fnode->readlink = readlink_tmpfs;
- fnode->read = NULL;
- fnode->write = NULL;
- fnode->create = NULL;
- fnode->mkdir = NULL;
- fnode->readdir = NULL;
- fnode->finddir = NULL;
- return fnode;
- }
- static struct dirent * readdir_tmpfs(fs_node_t *node, uint32_t index) {
- struct tmpfs_dir * d = (struct tmpfs_dir *)node->device;
- uint32_t i = 0;
- debug_print(NOTICE, "tmpfs - readdir id=%d", index);
- if (index == 0) {
- struct dirent * out = malloc(sizeof(struct dirent));
- memset(out, 0x00, sizeof(struct dirent));
- out->ino = 0;
- strcpy(out->name, ".");
- return out;
- }
- if (index == 1) {
- struct dirent * out = malloc(sizeof(struct dirent));
- memset(out, 0x00, sizeof(struct dirent));
- out->ino = 0;
- strcpy(out->name, "..");
- return out;
- }
- index -= 2;
- if (index >= d->files->length) return NULL;
- foreach(f, d->files) {
- if (i == index) {
- struct tmpfs_file * t = (struct tmpfs_file *)f->value;
- struct dirent * out = malloc(sizeof(struct dirent));
- memset(out, 0x00, sizeof(struct dirent));
- out->ino = (uint32_t)t;
- strcpy(out->name, t->name);
- return out;
- } else {
- ++i;
- }
- }
- return NULL;
- }
- static fs_node_t * finddir_tmpfs(fs_node_t * node, char * name) {
- if (!name) return NULL;
- struct tmpfs_dir * d = (struct tmpfs_dir *)node->device;
- spin_lock(tmpfs_lock);
- foreach(f, d->files) {
- struct tmpfs_file * t = (struct tmpfs_file *)f->value;
- if (!strcmp(name, t->name)) {
- spin_unlock(tmpfs_lock);
- switch (t->type) {
- case TMPFS_TYPE_FILE:
- return tmpfs_from_file(t);
- case TMPFS_TYPE_LINK:
- return tmpfs_from_link(t);
- case TMPFS_TYPE_DIR:
- return tmpfs_from_dir((struct tmpfs_dir *)t);
- }
- return NULL;
- }
- }
- spin_unlock(tmpfs_lock);
- return NULL;
- }
- static int unlink_tmpfs(fs_node_t * node, char * name) {
- struct tmpfs_dir * d = (struct tmpfs_dir *)node->device;
- int i = -1, j = 0;
- spin_lock(tmpfs_lock);
- foreach(f, d->files) {
- struct tmpfs_file * t = (struct tmpfs_file *)f->value;
- if (!strcmp(name, t->name)) {
- tmpfs_file_free(t);
- free(t);
- i = j;
- break;
- }
- j++;
- }
- if (i >= 0) {
- list_remove(d->files, i);
- } else {
- spin_unlock(tmpfs_lock);
- return -ENOENT;
- }
- spin_unlock(tmpfs_lock);
- return 0;
- }
- static int create_tmpfs(fs_node_t *parent, char *name, uint16_t permission) {
- if (!name) return -EINVAL;
- struct tmpfs_dir * d = (struct tmpfs_dir *)parent->device;
- debug_print(NOTICE, "Creating TMPFS file %s in %s", name, d->name);
- spin_lock(tmpfs_lock);
- foreach(f, d->files) {
- struct tmpfs_file * t = (struct tmpfs_file *)f->value;
- if (!strcmp(name, t->name)) {
- spin_unlock(tmpfs_lock);
- debug_print(WARNING, "... already exists.");
- return -EEXIST; /* Already exists */
- }
- }
- spin_unlock(tmpfs_lock);
- debug_print(NOTICE, "... creating a new file.");
- struct tmpfs_file * t = tmpfs_file_new(name);
- t->mask = permission;
- t->uid = current_process->user;
- t->gid = current_process->user;
- spin_lock(tmpfs_lock);
- list_insert(d->files, t);
- spin_unlock(tmpfs_lock);
- return 0;
- }
- static int mkdir_tmpfs(fs_node_t * parent, char * name, uint16_t permission) {
- if (!name) return -EINVAL;
- struct tmpfs_dir * d = (struct tmpfs_dir *)parent->device;
- debug_print(NOTICE, "Creating TMPFS directory %s (in %s)", name, d->name);
- spin_lock(tmpfs_lock);
- foreach(f, d->files) {
- struct tmpfs_file * t = (struct tmpfs_file *)f->value;
- if (!strcmp(name, t->name)) {
- spin_unlock(tmpfs_lock);
- debug_print(WARNING, "... already exists.");
- return -EEXIST; /* Already exists */
- }
- }
- spin_unlock(tmpfs_lock);
- debug_print(NOTICE, "... creating a new directory.");
- struct tmpfs_dir * out = tmpfs_dir_new(name, d);
- out->mask = permission;
- out->uid = current_process->user;
- out->gid = current_process->user;
- spin_lock(tmpfs_lock);
- list_insert(d->files, out);
- spin_unlock(tmpfs_lock);
- return 0;
- }
- static fs_node_t * tmpfs_from_dir(struct tmpfs_dir * d) {
- fs_node_t * fnode = malloc(sizeof(fs_node_t));
- memset(fnode, 0x00, sizeof(fs_node_t));
- fnode->inode = 0;
- strcpy(fnode->name, "tmp");
- fnode->mask = d->mask;
- fnode->uid = d->uid;
- fnode->gid = d->gid;
- fnode->device = d;
- fnode->atime = d->atime;
- fnode->mtime = d->mtime;
- fnode->ctime = d->ctime;
- fnode->flags = FS_DIRECTORY;
- fnode->read = NULL;
- fnode->write = NULL;
- fnode->open = NULL;
- fnode->close = NULL;
- fnode->readdir = readdir_tmpfs;
- fnode->finddir = finddir_tmpfs;
- fnode->create = create_tmpfs;
- fnode->unlink = unlink_tmpfs;
- fnode->mkdir = mkdir_tmpfs;
- fnode->nlink = 1; /* should be "number of children that are directories + 1" */
- fnode->symlink = symlink_tmpfs;
- fnode->chown = chown_tmpfs;
- fnode->chmod = chmod_tmpfs;
- return fnode;
- }
- fs_node_t * tmpfs_create(char * name) {
- tmpfs_root = tmpfs_dir_new(name, NULL);
- tmpfs_root->mask = 0777;
- tmpfs_root->uid = 0;
- tmpfs_root->gid = 0;
- return tmpfs_from_dir(tmpfs_root);
- }
- fs_node_t * tmpfs_mount(char * device, char * mount_path) {
- fs_node_t * fs = tmpfs_create(device);
- return fs;
- }
- static int tmpfs_initialize(void) {
- buf_space = (void*)kvmalloc(BLOCKSIZE);
- vfs_mount("/tmp", tmpfs_create("tmp"));
- vfs_mount("/var", tmpfs_create("var"));
- vfs_register("tmpfs", tmpfs_mount);
- return 0;
- }
- static int tmpfs_finalize(void) {
- return 0;
- }
- MODULE_DEF(tmpfs, tmpfs_initialize, tmpfs_finalize);
|