📄 rootfs.c
字号:
/* This file contains a simple memory based file system that is used as the top-level name space by the vnode layer. It is a complete file system in and of itself but it only supports creating directories and symlinks. It is also entirely memory based so it is re-created each time the vnode layer is initialized. It is only used to mount other file systems (i.e. to create a directory that can be used as a mount point for another file system). THIS CODE COPYRIGHT DOMINIC GIAMPAOLO. NO WARRANTY IS EXPRESSED OR IMPLIED. YOU MAY USE THIS CODE AND FREELY DISTRIBUTE IT FOR NON-COMMERCIAL USE AS LONG AS THIS NOTICE REMAINS ATTACHED. FOR COMMERCIAL USE, CONTACT DOMINIC GIAMPAOLO (dbg@be.com). Dominic Giampaolo dbg@be.com*/#include <stdlib.h>#include <string.h>#include <fcntl.h>#include <time.h>#include "compat.h"#include "skiplist.h"#include "lock.h"#include "fsproto.h"typedef struct vnode vnode;typedef struct nspace nspace;typedef struct dirpos dirpos;struct nspace { nspace_id nsid; long vnnum; vnode * root; vnode_id nxvnid; lock lock; SkipList skiplist;};struct vnode { char * name; char removed; nspace *ns; vnode_id vnid; vnode *parent; time_t crtime; time_t mtime; uid_t uid; gid_t gid; mode_t mode; vnode * next; vnode * prev; vnode * head; /* for directories */ char * symlink; /* for symbolic links */};struct dirpos { lock lock; int pos; char name[FILE_NAME_LENGTH];};static int rootfs_read_vnode(void *ns, vnode_id vnid, char r, void **node);static int rootfs_write_vnode(void *ns, void *node, char r);static int rootfs_remove_vnode(void *ns, void *node, char r);static int rootfs_walk(void *ns, void *base, const char *file, char **newpath, vnode_id *vnid);static int rootfs_access(void *ns, void *node, int mode);static int rootfs_symlink(void *ns, void *dir, const char *name, const char *path);static int rootfs_mkdir(void *ns, void *dir, const char *name, int perms);static int rootfs_rename(void *ns, void *olddir, const char *oldname, void *newdir, const char *newname);static int rootfs_unlink(void *ns, void *dir, const char *name);static int rootfs_rmdir(void *ns, void *dir, const char *name);static int rootfs_readlink(void *ns, void *node, char *buf, size_t *bufsize);static int rootfs_opendir(void *ns, void *node, void **cookie);static int rootfs_closedir(void *ns, void *node, void *cookie);static int rootfs_free_dircookie(void *ns, void *node, void *cookie);static int rootfs_rewinddir(void *ns, void *node, void *cookie);static int rootfs_readdir(void *ns, void *node, void *cookie, long *num, struct my_dirent *buf, size_t bufsize);static int rootfs_rstat(void *ns, void *node, struct my_stat *st);static int rootfs_wstat(void *ns, void *node, struct my_stat *st, long mask);static int rootfs_mount(nspace_id nsid, const char *device, ulong flags, void *parms, size_t len, void **data, vnode_id *vnid);static int rootfs_unmount(void *ns);static int compare_vnode(vnode *vna, vnode *vnb);static int do_create(nspace *ns, vnode *dir, const char *name, mode_t mode, vnode **vnp);static int do_unlink(nspace *ns, vnode *dir, const char *name, bool isdir);vnode_ops rootfs = { &rootfs_read_vnode, &rootfs_write_vnode, &rootfs_remove_vnode, &rootfs_walk, &rootfs_access, NULL, &rootfs_mkdir, &rootfs_symlink, NULL, &rootfs_rename, &rootfs_unlink, &rootfs_rmdir, &rootfs_readlink, &rootfs_opendir, &rootfs_closedir, &rootfs_free_dircookie, &rootfs_rewinddir, &rootfs_readdir, NULL, NULL, NULL, NULL, NULL, NULL, &rootfs_rstat, &rootfs_wstat, NULL, &rootfs_mount, &rootfs_unmount, NULL}; #define LCK_MULTIPLE 1#define LCK_EXCLUSIVE 1000#define OMODE_MASK (O_RDONLY | O_WRONLY | O_RDWR)/* ----------------------------------------------------------------- */static introotfs_walk(void *_ns, void *_base, const char *file, char **newpath, vnode_id *vnid){ nspace *ns; vnode *base; int err; vnode *vn; char *np; ns = (nspace *) _ns; base = (vnode *) _base; LOCK(ns->lock); /* make sure base is a directory and that it has not been removed. */ if (!MY_S_ISDIR(base->mode)) { err = ENOTDIR; goto exit; } if (base->removed) { err = ENOENT; goto exit; } /* lookup the special directory '.' */ if (!strcmp(file, ".")) { err = get_vnode(ns->nsid, base->vnid, (void *)&vn); if (!err) *vnid = base->vnid; goto exit; } /* lookup the special directory '..' */ if (!strcmp(file, "..")) { err = get_vnode(ns->nsid, base->parent->vnid, (void *)&vn); if (!err) *vnid = vn->vnid; goto exit; } /* lookup the name in the directory */ vn = base->head; while (vn) { if (!strcmp(vn->name, file)) break; vn = vn->next; } /* the name has not been found. advance the path pointer, update the vnid and report an error. */ if (!vn) { err = ENOENT; goto exit; } /* we have found the item. */ /* it is a symbolic link that the kernel wants us to eat. */ if (MY_S_ISLNK(vn->mode) && newpath) { err = new_path(vn->symlink, &np); if (err) goto exit; *newpath = np; } else { /* it is a directory or it is a symbolic link that the kernel does not want to 'eat'. */ err = get_vnode(ns->nsid, vn->vnid, (void *)&vn); if (!err) *vnid = vn->vnid; } exit: UNLOCK(ns->lock); return err;}static introotfs_mkdir(void *_ns, void *_dir, const char *name, int perms){ nspace *ns; vnode *dir; int err; vnode *vn; ns = (nspace *) _ns; dir = (vnode *) _dir; LOCK(ns->lock); err = do_create(ns, dir, name, (perms & ~MY_S_IFMT) | MY_S_IFDIR, &vn); UNLOCK(ns->lock); return err;}static introotfs_symlink(void *_ns, void *_dir, const char *name, const char *path){ nspace *ns; vnode *dir; int err; char *buf; vnode *vn; ns = (nspace *) _ns; dir = (vnode *) _dir; buf = (char *) malloc(strlen(path)+1); if (!buf) { err = ENOMEM; goto error1; } strcpy(buf, path); LOCK(ns->lock); err = do_create(ns, dir, name, MY_S_IFLNK, &vn); if (err) goto error2; vn->symlink = buf; UNLOCK(ns->lock); return 0;error2: UNLOCK(ns->lock);error1: return err;} static introotfs_rename(void *_ns, void *_olddir, const char *oldname, void *_newdir, const char *newname){ nspace *ns; vnode *olddir, *newdir; int err; vnode *vn, *nvn, *pvn, *avn; char *p; ns = (nspace *) _ns; olddir = (vnode *) _olddir; newdir = (vnode *) _newdir; LOCK(ns->lock); if (!MY_S_ISDIR(olddir->mode) || !MY_S_ISDIR(newdir->mode)) { err = ENOTDIR; goto error1; } /* find (olddir, oldname) */ if (!strcmp(oldname, ".") || !strcmp(oldname, "..")) { err = EPERM; goto error1; } vn = olddir->head; while (vn) { if (!strcmp(vn->name, oldname)) break; vn = vn->next; } if (!vn) { err = ENOENT; goto error1; } /* look for (newdir, newname) */ if (!strcmp(newname, ".") || !strcmp(newname, "..")) { err = EPERM; goto error1; } nvn = newdir->head; while (nvn) { if (!strcmp(nvn->name, newname)) break; nvn = nvn->next; } /* don't do anything if old and new are the same */ if (vn == nvn) goto exit; /* make sure new is not a subdirectory of old */ avn = newdir; while (avn != ns->root) { avn = avn->parent; if (avn == olddir) { err = EINVAL; goto error1; } } if (strlen(newname) > strlen(vn->name)) { p = (char *) realloc(vn->name, strlen(newname)+1); if (!p) { err = ENOMEM; goto error1; } } else p = vn->name; /* if (newdir, newname) exists, remove it from the name space */ if (nvn) { /* make sure it is not the root and it is not empty */ if (nvn == nvn->ns->root) { err = EBUSY; goto error1; } if (MY_S_ISDIR(nvn->mode) && nvn->head) { err = ENOTEMPTY; goto error1; } err = get_vnode(ns->nsid, nvn->vnid, (void *)&nvn); if (err) goto error1; err = remove_vnode(ns->nsid, nvn->vnid); if (err) goto error1; if (nvn->prev) nvn->prev->next = nvn->next; else nvn->parent->head = nvn->next; if (nvn->next) nvn->next->prev = nvn->prev; nvn->prev = nvn->next = NULL; put_vnode(ns->nsid, nvn->vnid); } if (vn->prev) vn->prev->next = vn->next; else vn->parent->head = vn->next; if (vn->next) vn->next->prev = vn->prev; pvn = NULL; nvn = newdir->head; while (nvn && (strcmp(newname, nvn->name) > 0)) { pvn = nvn; nvn = nvn->next; } vn->next = nvn; if (nvn) nvn->prev = vn; vn->prev = pvn; if (pvn) pvn->next = vn; else newdir->head = vn; vn->parent = newdir; newdir->mtime = olddir->mtime = time(NULL); strcpy(p, newname); vn->name = p;exit: UNLOCK(ns->lock); return 0;error1: UNLOCK(ns->lock); return err;}static introotfs_unlink(void *_ns, void *_dir, const char *name){ nspace *ns; vnode *dir; ns = (nspace *) _ns; dir = (vnode *) _dir; return do_unlink(ns, dir, name, FALSE);}static introotfs_rmdir(void *_ns, void *_dir, const char *name){ nspace *ns; vnode *dir; ns = (nspace *) _ns; dir = (vnode *) _dir; return do_unlink(ns, dir, name, TRUE);}static introotfs_read_vnode(void *_ns, vnode_id vnid, char r, void **node){ nspace *ns; vnode *vn; vnode fakevn; ns = (nspace *) _ns; if (!r) LOCK(ns->lock); fakevn.vnid = vnid; fakevn.ns = ns; vn = SearchSL(ns->skiplist, &fakevn); if (vn) *node = vn; if (!r) UNLOCK(ns->lock); return (vn ? 0 : ENOENT);}static introotfs_write_vnode(void *_ns, void *_node, char r){ return 0;}static introotfs_remove_vnode(void *_ns, void *_node, char r){ nspace *ns; vnode *node; ns = (nspace *) _ns; node = (vnode *) _node; if (!r) LOCK(ns->lock); DeleteSL(ns->skiplist, node); if (!r) UNLOCK(ns->lock); atomic_add(&ns->vnnum, -1); if (node->symlink) free(node->symlink); free(node->name); free(node); return 0;}static introotfs_readlink(void *_ns, void *_node, char *buf, size_t *bufsize){ nspace *ns; vnode *node; int err; size_t l; ns = (nspace *) _ns; node = (vnode *) _node; if (!MY_S_ISLNK(node->mode)) { err = EINVAL; goto error1;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -