mirror of
https://github.com/Mathewnd/Astral.git
synced 2026-10-27 20:58:22 +00:00
243 lines
5.0 KiB
C
243 lines
5.0 KiB
C
#include <kernel/tmpfs.h>
|
|
#include <kernel/vfs.h>
|
|
#include <kernel/alloc.h>
|
|
#include <arch/mmu.h>
|
|
#include <kernel/pmm.h>
|
|
#include <string.h>
|
|
#include <dirent.h>
|
|
|
|
fs_t kerneltmpfs;
|
|
|
|
static int tmpfs_mount(dirnode_t* mountpoint, vnode_t* device, int mountflags, void* fsinfo){
|
|
|
|
fs_t* desc = alloc(sizeof(fs_t));
|
|
|
|
if(!desc)
|
|
return ENOMEM;
|
|
|
|
dirnode_t* root = vfs_newdirnode(mountpoint->vnode.name, desc, NULL, mountpoint->vnode.parent);
|
|
|
|
if(!root){
|
|
free(desc);
|
|
return ENOMEM;
|
|
}
|
|
|
|
desc->calls = tmpfs_getfuncs();
|
|
mountpoint->mount = root;
|
|
root->vnode.st.st_mode = MAKETYPE(TYPE_DIR) | 0777;
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int tmpfs_write(int* error, vnode_t* node, void* buff, size_t count, size_t offset){
|
|
|
|
// TODO use virtual memory
|
|
|
|
size_t targetpage = (count + offset) / PAGE_SIZE;
|
|
|
|
if(node->st.st_blocks <= targetpage){
|
|
void* new = pmm_hhdmalloc(targetpage+1);
|
|
if(!new){
|
|
*error = ENOMEM;
|
|
return -1;
|
|
};
|
|
memcpy(new, node->fsdata, node->st.st_size);
|
|
pmm_free(node->fsdata, node->st.st_size / PAGE_SIZE + 1);
|
|
node->fsdata = new;
|
|
node->st.st_blocks = targetpage+1;
|
|
node->st.st_size = count + offset;
|
|
}
|
|
|
|
memcpy(node->fsdata + offset, buff, count);
|
|
|
|
if(offset + count > node->st.st_size)
|
|
node->st.st_size = offset + count;
|
|
|
|
*error = 0;
|
|
return count;
|
|
}
|
|
|
|
static int tmpfs_read(int *error, vnode_t* node, void* buff, size_t count, size_t offset){
|
|
|
|
size_t sizemax = node->st.st_size - offset;
|
|
|
|
if(count > sizemax)
|
|
count = sizemax;
|
|
|
|
memcpy(buff, node->fsdata + offset, count);
|
|
*error = 0;
|
|
|
|
return count;
|
|
|
|
}
|
|
|
|
static int tmpfs_unmount(fs_t* fs) UNIMPLEMENTED
|
|
static int tmpfs_open(dirnode_t* parent, char* name){ return ENOENT;} // tmpfs open should never be called if a file exists
|
|
static int tmpfs_close(vnode_t* node){return 0;} // nothing to do really
|
|
|
|
static int tmpfs_mkdir(dirnode_t* parent, char* name, mode_t mode){
|
|
|
|
dirnode_t* node = vfs_newdirnode(name, parent->vnode.fs, NULL, parent);
|
|
|
|
if(!node)
|
|
return ENOMEM;
|
|
|
|
if(!hashtable_insert(&parent->children, name, node)){
|
|
vfs_destroynode(node);
|
|
return ENOMEM;
|
|
}
|
|
|
|
stat* st = &node->vnode.st;
|
|
|
|
st->st_mode = MAKETYPE(TYPE_DIR) | mode;
|
|
st->st_blksize = PAGE_SIZE;
|
|
st->st_ino = parent->vnode.fs->data++;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
static int tmpfs_create(dirnode_t* parent, char* name, mode_t mode){
|
|
|
|
// TODO use virtual memory
|
|
void* firstpage = pmm_hhdmalloc(1);
|
|
|
|
if(!firstpage)
|
|
return ENOMEM;
|
|
|
|
vnode_t* node = vfs_newnode(name, parent->vnode.fs, NULL);
|
|
|
|
if(!node){
|
|
pmm_free(firstpage, 1);
|
|
return ENOMEM;
|
|
}
|
|
|
|
if(!hashtable_insert(&parent->children, name, node)){
|
|
pmm_free(firstpage, 1);
|
|
vfs_destroynode(node);
|
|
return ENOMEM;
|
|
}
|
|
|
|
node->parent = parent;
|
|
node->fsdata = firstpage;
|
|
stat* st = &node->st;
|
|
st->st_blksize = PAGE_SIZE;
|
|
st->st_blocks = 1;
|
|
st->st_mode = MAKETYPE(TYPE_REGULAR) | mode;
|
|
st->st_nlink = 1;
|
|
st->st_ino = parent->vnode.fs->data++;
|
|
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int tmpfs_getdirent(dirnode_t* node, dent_t* buff, size_t count, uintmax_t offset, size_t* readcount){
|
|
|
|
*readcount = 0;
|
|
|
|
for(uintmax_t i = 0; i < count; ++i){
|
|
dent_t* d = &buff[i];
|
|
vnode_t* child = hashtable_fromoffset(&node->children, offset, d->d_name);
|
|
if(!child){
|
|
*readcount = i;
|
|
return 0;
|
|
}
|
|
|
|
d->d_ino = child->st.st_ino;
|
|
d->d_off = offset;
|
|
d->d_reclen = sizeof(dent_t);
|
|
d->d_type = GETTYPE(child->st.st_mode);
|
|
++offset;
|
|
}
|
|
|
|
*readcount = count;
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int tmpfs_chmod(vnode_t* node, mode_t mode){
|
|
node->st.st_mode &= ~07777;
|
|
node->st.st_mode |= mode & 07777;
|
|
return 0;
|
|
}
|
|
|
|
static int tmpfs_mksocket(dirnode_t* parent, char* name, mode_t mode){
|
|
|
|
vnode_t* node = vfs_newnode(name, parent->vnode.fs, NULL);
|
|
|
|
if(!node)
|
|
return ENOMEM;
|
|
|
|
if(!hashtable_insert(&parent->children, name, node)){
|
|
vfs_destroynode(node);
|
|
return ENOMEM;
|
|
}
|
|
|
|
stat* st = &node->st;
|
|
|
|
st->st_mode = MAKETYPE(TYPE_SOCKET) | mode;
|
|
st->st_blksize = PAGE_SIZE;
|
|
st->st_ino = parent->vnode.fs->data++;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
static int tmpfs_symlink(dirnode_t* parent, char* name, char* target, mode_t mode){
|
|
int error = tmpfs_create(parent, name, mode);
|
|
|
|
if(error)
|
|
return error;
|
|
|
|
vnode_t* node = hashtable_get(&parent->children, name);
|
|
|
|
node->st.st_mode = MAKETYPE(TYPE_LINK) | mode;
|
|
|
|
tmpfs_write(&error, node, target, strlen(target)+1, 0);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
static int tmpfs_readlink(vnode_t *node, char** buff, size_t* linksize){
|
|
|
|
if(node->st.st_size >= 512)
|
|
return ENAMETOOLONG;
|
|
|
|
*buff = alloc(node->st.st_size+1);
|
|
|
|
if(!*buff)
|
|
return ENOMEM;
|
|
|
|
int error;
|
|
|
|
*linksize = tmpfs_read(&error, node, *buff, 512, 0);
|
|
|
|
if(error)
|
|
free(*buff);
|
|
|
|
return error;
|
|
|
|
}
|
|
|
|
static int tmpfs_link(dirnode_t* parent, vnode_t* link, char* name){
|
|
|
|
if(!hashtable_insert(&parent->children, name, link))
|
|
return ENOMEM;
|
|
|
|
++link->st.st_nlink;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
static fscalls_t funcs = {
|
|
tmpfs_mount, tmpfs_unmount, tmpfs_open, tmpfs_close, tmpfs_mkdir, tmpfs_create, tmpfs_write, tmpfs_read, tmpfs_getdirent, tmpfs_chmod, tmpfs_mksocket, tmpfs_symlink, tmpfs_readlink, tmpfs_link
|
|
};
|
|
|
|
|
|
fscalls_t* tmpfs_getfuncs(){
|
|
kerneltmpfs.calls = &funcs;
|
|
return &funcs;
|
|
}
|