#include #include #include #include #include #include #include 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; }