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

📄 fuse.c

📁 linux下的用户文件系统fuse-2.5.2
💻 C
📖 第 1 页 / 共 4 页
字号:
/*    FUSE: Filesystem in Userspace    Copyright (C) 2001-2006  Miklos Szeredi <miklos@szeredi.hu>    This program can be distributed under the terms of the GNU LGPL.    See the file COPYING.LIB*//* For pthread_rwlock_t */#define _GNU_SOURCE#include "fuse_i.h"#include "fuse_lowlevel.h"#include "fuse_opt.h"#include <stdio.h>#include <string.h>#include <stdlib.h>#include <stddef.h>#include <unistd.h>#include <fcntl.h>#include <limits.h>#include <errno.h>#include <assert.h>#include <pthread.h>#include <sys/param.h>#include <sys/uio.h>#define FUSE_MAX_PATH 4096#define FUSE_UNKNOWN_INO 0xffffffffstruct fuse_config {    unsigned int uid;    unsigned int gid;    unsigned int  umask;    double entry_timeout;    double negative_timeout;    double attr_timeout;    int debug;    int hard_remove;    int use_ino;    int readdir_ino;    int set_mode;    int set_uid;    int set_gid;    int direct_io;    int kernel_cache;};struct fuse {    struct fuse_session *se;    struct fuse_operations op;    int compat;    struct node **name_table;    size_t name_table_size;    struct node **id_table;    size_t id_table_size;    fuse_ino_t ctr;    unsigned int generation;    unsigned int hidectr;    pthread_mutex_t lock;    pthread_rwlock_t tree_lock;    void *user_data;    struct fuse_config conf;};struct node {    struct node *name_next;    struct node *id_next;    fuse_ino_t nodeid;    unsigned int generation;    int refctr;    fuse_ino_t parent;    char *name;    uint64_t nlookup;    int open_count;    int is_hidden;};struct fuse_dirhandle {    pthread_mutex_t lock;    struct fuse *fuse;    char *contents;    int allocated;    unsigned len;    unsigned size;    unsigned needlen;    int filled;    uint64_t fh;    int error;    fuse_ino_t nodeid;};static struct fuse_context *(*fuse_getcontext)(void) = NULL;static int fuse_do_open(struct fuse *, char *, struct fuse_file_info *);static void fuse_do_release(struct fuse *, char *, struct fuse_file_info *);static int fuse_do_opendir(struct fuse *, char *, struct fuse_file_info *);static int fuse_do_statfs(struct fuse *, char *, struct statvfs *);#ifndef USE_UCLIBC#define mutex_init(mut) pthread_mutex_init(mut, NULL)#elsestatic void mutex_init(pthread_mutex_t *mut){    pthread_mutexattr_t attr;    pthread_mutexattr_init(&attr);    pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_ADAPTIVE_NP);    pthread_mutex_init(mut, &attr);    pthread_mutexattr_destroy(&attr);}#endifstatic struct node *get_node_nocheck(struct fuse *f, fuse_ino_t nodeid){    size_t hash = nodeid % f->id_table_size;    struct node *node;    for (node = f->id_table[hash]; node != NULL; node = node->id_next)        if (node->nodeid == nodeid)            return node;    return NULL;}static struct node *get_node(struct fuse *f, fuse_ino_t nodeid){    struct node *node = get_node_nocheck(f, nodeid);    if (!node) {        fprintf(stderr, "fuse internal error: node %llu not found\n",                (unsigned long long) nodeid);        abort();    }    return node;}static void free_node(struct node *node){    free(node->name);    free(node);}static void unhash_id(struct fuse *f, struct node *node){    size_t hash = node->nodeid % f->id_table_size;    struct node **nodep = &f->id_table[hash];    for (; *nodep != NULL; nodep = &(*nodep)->id_next)        if (*nodep == node) {            *nodep = node->id_next;            return;        }}static void hash_id(struct fuse *f, struct node *node){    size_t hash = node->nodeid % f->id_table_size;    node->id_next = f->id_table[hash];    f->id_table[hash] = node;}static unsigned int name_hash(struct fuse *f, fuse_ino_t parent, const char *name){    unsigned int hash = *name;    if (hash)        for (name += 1; *name != '\0'; name++)            hash = (hash << 5) - hash + *name;    return (hash + parent) % f->name_table_size;}static void unref_node(struct fuse *f, struct node *node);static void unhash_name(struct fuse *f, struct node *node){    if (node->name) {        size_t hash = name_hash(f, node->parent, node->name);        struct node **nodep = &f->name_table[hash];        for (; *nodep != NULL; nodep = &(*nodep)->name_next)            if (*nodep == node) {                *nodep = node->name_next;                node->name_next = NULL;                unref_node(f, get_node(f, node->parent));                free(node->name);                node->name = NULL;                node->parent = 0;                return;            }        fprintf(stderr, "fuse internal error: unable to unhash node: %llu\n",                (unsigned long long) node->nodeid);        abort();    }}static int hash_name(struct fuse *f, struct node *node, fuse_ino_t parent,                     const char *name){    size_t hash = name_hash(f, parent, name);    node->name = strdup(name);    if (node->name == NULL)        return -1;    get_node(f, parent)->refctr ++;    node->parent = parent;    node->name_next = f->name_table[hash];    f->name_table[hash] = node;    return 0;}static void delete_node(struct fuse *f, struct node *node){    if (f->conf.debug) {        printf("delete: %llu\n", (unsigned long long) node->nodeid);        fflush(stdout);    }    assert(!node->name);    unhash_id(f, node);    free_node(node);}static void unref_node(struct fuse *f, struct node *node){    assert(node->refctr > 0);    node->refctr --;    if (!node->refctr)        delete_node(f, node);}static fuse_ino_t next_id(struct fuse *f){    do {        f->ctr++;        if (!f->ctr)            f->generation ++;    } while (f->ctr == 0 || get_node_nocheck(f, f->ctr) != NULL);    return f->ctr;}static struct node *lookup_node(struct fuse *f, fuse_ino_t parent,                                const char *name){    size_t hash = name_hash(f, parent, name);    struct node *node;    for (node = f->name_table[hash]; node != NULL; node = node->name_next)        if (node->parent == parent && strcmp(node->name, name) == 0)            return node;    return NULL;}static struct node *find_node(struct fuse *f, fuse_ino_t parent,                              const char *name){    struct node *node;    pthread_mutex_lock(&f->lock);    node = lookup_node(f, parent, name);    if (node == NULL) {        node = (struct node *) calloc(1, sizeof(struct node));        if (node == NULL)            goto out_err;        node->refctr = 1;        node->nodeid = next_id(f);        node->open_count = 0;        node->is_hidden = 0;        node->generation = f->generation;        if (hash_name(f, node, parent, name) == -1) {            free(node);            node = NULL;            goto out_err;        }        hash_id(f, node);    }    node->nlookup ++; out_err:    pthread_mutex_unlock(&f->lock);    return node;}static char *add_name(char *buf, char *s, const char *name){    size_t len = strlen(name);    s -= len;    if (s <= buf) {        fprintf(stderr, "fuse: path too long: ...%s\n", s + len);        return NULL;    }    strncpy(s, name, len);    s--;    *s = '/';    return s;}static char *get_path_name(struct fuse *f, fuse_ino_t nodeid, const char *name){    char buf[FUSE_MAX_PATH];    char *s = buf + FUSE_MAX_PATH - 1;    struct node *node;    *s = '\0';    if (name != NULL) {        s = add_name(buf, s, name);        if (s == NULL)            return NULL;    }    pthread_mutex_lock(&f->lock);    for (node = get_node(f, nodeid); node && node->nodeid != FUSE_ROOT_ID;         node = get_node(f, node->parent)) {        if (node->name == NULL) {            s = NULL;            break;        }        s = add_name(buf, s, node->name);        if (s == NULL)            break;    }    pthread_mutex_unlock(&f->lock);    if (node == NULL || s == NULL)        return NULL;    else if (*s == '\0')        return strdup("/");    else        return strdup(s);}static char *get_path(struct fuse *f, fuse_ino_t nodeid){    return get_path_name(f, nodeid, NULL);}static void forget_node(struct fuse *f, fuse_ino_t nodeid, uint64_t nlookup){    struct node *node;    if (nodeid == FUSE_ROOT_ID)        return;    pthread_mutex_lock(&f->lock);    node = get_node(f, nodeid);    assert(node->nlookup >= nlookup);    node->nlookup -= nlookup;    if (!node->nlookup) {        unhash_name(f, node);        unref_node(f, node);    }    pthread_mutex_unlock(&f->lock);}static void remove_node(struct fuse *f, fuse_ino_t dir, const char *name){    struct node *node;    pthread_mutex_lock(&f->lock);    node = lookup_node(f, dir, name);    if (node != NULL)        unhash_name(f, node);    pthread_mutex_unlock(&f->lock);}static int rename_node(struct fuse *f, fuse_ino_t olddir, const char *oldname,                        fuse_ino_t newdir, const char *newname, int hide){    struct node *node;    struct node *newnode;    int err = 0;    pthread_mutex_lock(&f->lock);    node  = lookup_node(f, olddir, oldname);    newnode  = lookup_node(f, newdir, newname);    if (node == NULL)        goto out;    if (newnode != NULL) {        if (hide) {            fprintf(stderr, "fuse: hidden file got created during hiding\n");            err = -EBUSY;            goto out;        }        unhash_name(f, newnode);    }    unhash_name(f, node);    if (hash_name(f, node, newdir, newname) == -1) {        err = -ENOMEM;        goto out;    }    if (hide)        node->is_hidden = 1; out:    pthread_mutex_unlock(&f->lock);    return err;}static void set_stat(struct fuse *f, fuse_ino_t nodeid, struct stat *stbuf){    if (!f->conf.use_ino)        stbuf->st_ino = nodeid;    if (f->conf.set_mode)        stbuf->st_mode = (stbuf->st_mode & S_IFMT) | (0777 & ~f->conf.umask);    if (f->conf.set_uid)        stbuf->st_uid = f->conf.uid;    if (f->conf.set_gid)        stbuf->st_gid = f->conf.gid;}static int is_open(struct fuse *f, fuse_ino_t dir, const char *name){    struct node *node;    int isopen = 0;    pthread_mutex_lock(&f->lock);    node = lookup_node(f, dir, name);    if (node && node->open_count > 0)        isopen = 1;    pthread_mutex_unlock(&f->lock);    return isopen;}static char *hidden_name(struct fuse *f, fuse_ino_t dir, const char *oldname,                        char *newname, size_t bufsize){    struct stat buf;    struct node *node;    struct node *newnode;    char *newpath;    int res;    int failctr = 10;    if (!f->op.getattr)        return NULL;    do {        pthread_mutex_lock(&f->lock);        node = lookup_node(f, dir, oldname);        if (node == NULL) {            pthread_mutex_unlock(&f->lock);            return NULL;        }        do {            f->hidectr ++;            snprintf(newname, bufsize, ".fuse_hidden%08x%08x",                     (unsigned int) node->nodeid, f->hidectr);            newnode = lookup_node(f, dir, newname);        } while(newnode);        pthread_mutex_unlock(&f->lock);        newpath = get_path_name(f, dir, newname);        if (!newpath)            break;        res = f->op.getattr(newpath, &buf);        if (res != 0)            break;        free(newpath);        newpath = NULL;    } while(--failctr);    return newpath;}static int hide_node(struct fuse *f, const char *oldpath, fuse_ino_t dir,                     const char *oldname){    char newname[64];    char *newpath;    int err = -EBUSY;    if (f->op.rename && f->op.unlink) {        newpath = hidden_name(f, dir, oldname, newname, sizeof(newname));        if (newpath) {            int res = f->op.rename(oldpath, newpath);            if (res == 0)                err = rename_node(f, dir, oldname, dir, newname, 1);            free(newpath);        }    }    return err;}static int lookup_path(struct fuse *f, fuse_ino_t nodeid, const char *name,                       const char *path, struct fuse_entry_param *e,                       struct fuse_file_info *fi){    int res;    memset(e, 0, sizeof(struct fuse_entry_param));    if (fi && f->op.fgetattr)        res = f->op.fgetattr(path, &e->attr, fi);    else        res = f->op.getattr(path, &e->attr);    if (res == 0) {        struct node *node;        node = find_node(f, nodeid, name);        if (node == NULL)            res = -ENOMEM;        else {            e->ino = node->nodeid;            e->generation = node->generation;            e->entry_timeout = f->conf.entry_timeout;            e->attr_timeout = f->conf.attr_timeout;            set_stat(f, e->ino, &e->attr);            if (f->conf.debug) {                printf("   NODEID: %lu\n", (unsigned long) e->ino);                fflush(stdout);            }        }    }    return res;}static struct fuse *req_fuse(fuse_req_t req){    return (struct fuse *) fuse_req_userdata(req);}static struct fuse *req_fuse_prepare(fuse_req_t req){    struct fuse_context *c = fuse_get_context();    const struct fuse_ctx *ctx = fuse_req_ctx(req);    c->fuse = req_fuse(req);    c->uid = ctx->uid;    c->gid = ctx->gid;    c->pid = ctx->pid;    c->private_data = c->fuse->user_data;    return c->fuse;}static inline void reply_err(fuse_req_t req, int err){    /* fuse_reply_err() uses non-negated errno values */    fuse_reply_err(req, -err);}static void reply_entry(fuse_req_t req, const struct fuse_entry_param *e,

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -