⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 rootfs.c

📁 be文件系统实现的源码
💻 C
📖 第 1 页 / 共 2 页
字号:
/*  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 + -