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

📄 fuse_lowlevel.c

📁 Linux下fuse用户文件系统的的源代码
💻 C
📖 第 1 页 / 共 3 页
字号:
/*    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*/#include "fuse_lowlevel.h"#include "fuse_kernel.h"#include "fuse_opt.h"#include "fuse_i.h"#include "fuse_misc.h"#include "fuse_common_compat.h"#include "fuse_lowlevel_compat.h"#include <stdio.h>#include <stdlib.h>#include <stddef.h>#include <string.h>#include <unistd.h>#include <limits.h>#include <errno.h>#define PARAM(inarg) (((char *)(inarg)) + sizeof(*(inarg)))#define OFFSET_MAX 0x7fffffffffffffffLLstruct fuse_ll;struct fuse_req {    struct fuse_ll *f;    uint64_t unique;    int ctr;    pthread_mutex_t lock;    struct fuse_ctx ctx;    struct fuse_chan *ch;    int interrupted;    union {        struct {            uint64_t unique;        } i;        struct {            fuse_interrupt_func_t func;            void *data;        } ni;    } u;    struct fuse_req *next;    struct fuse_req *prev;};struct fuse_ll {    int debug;    int allow_root;    struct fuse_lowlevel_ops op;    int got_init;    void *userdata;    uid_t owner;    struct fuse_conn_info conn;    struct fuse_req list;    struct fuse_req interrupts;    pthread_mutex_t lock;    int got_destroy;};static void convert_stat(const struct stat *stbuf, struct fuse_attr *attr){    attr->ino       = stbuf->st_ino;    attr->mode      = stbuf->st_mode;    attr->nlink     = stbuf->st_nlink;    attr->uid       = stbuf->st_uid;    attr->gid       = stbuf->st_gid;    attr->rdev      = stbuf->st_rdev;    attr->size      = stbuf->st_size;    attr->blocks    = stbuf->st_blocks;    attr->atime     = stbuf->st_atime;    attr->mtime     = stbuf->st_mtime;    attr->ctime     = stbuf->st_ctime;#ifdef FUSE_STAT_HAS_NANOSEC    attr->atimensec = ST_ATIM(stbuf).tv_nsec;    attr->mtimensec = ST_MTIM(stbuf).tv_nsec;    attr->ctimensec = ST_CTIM(stbuf).tv_nsec;#endif}static void convert_attr(const struct fuse_setattr_in *attr, struct stat *stbuf){    stbuf->st_mode         = attr->mode;    stbuf->st_uid          = attr->uid;    stbuf->st_gid          = attr->gid;    stbuf->st_size         = attr->size;    stbuf->st_atime        = attr->atime;    stbuf->st_mtime        = attr->mtime;#ifdef FUSE_STAT_HAS_NANOSEC    ST_ATIM(stbuf).tv_nsec = attr->atimensec;    ST_MTIM(stbuf).tv_nsec = attr->mtimensec;#endif}static  size_t iov_length(const struct iovec *iov, size_t count){    size_t seg;    size_t ret = 0;    for (seg = 0; seg < count; seg++)        ret += iov[seg].iov_len;    return ret;}static void list_init_req(struct fuse_req *req){    req->next = req;    req->prev = req;}static void list_del_req(struct fuse_req *req){    struct fuse_req *prev = req->prev;    struct fuse_req *next = req->next;    prev->next = next;    next->prev = prev;}static void list_add_req(struct fuse_req *req, struct fuse_req *next){    struct fuse_req *prev = next->prev;    req->next = next;    req->prev = prev;    prev->next = req;    next->prev = req;}static void destroy_req(fuse_req_t req){    pthread_mutex_destroy(&req->lock);    free(req);}static void free_req(fuse_req_t req){    int ctr;    struct fuse_ll *f = req->f;    pthread_mutex_lock(&req->lock);    req->u.ni.func = NULL;    req->u.ni.data = NULL;    pthread_mutex_unlock(&req->lock);    pthread_mutex_lock(&f->lock);    list_del_req(req);    ctr = --req->ctr;    pthread_mutex_unlock(&f->lock);    if (!ctr)        destroy_req(req);}static int send_reply(fuse_req_t req, int error, const void *arg,                      size_t argsize){    struct fuse_out_header out;    struct iovec iov[2];    size_t count;    int res;    if (error <= -1000 || error > 0) {        fprintf(stderr, "fuse: bad error value: %i\n",  error);        error = -ERANGE;    }    out.unique = req->unique;    out.error = error;    count = 1;    iov[0].iov_base = &out;    iov[0].iov_len = sizeof(struct fuse_out_header);    if (argsize && !error) {        count++;        iov[1].iov_base = (void *) arg;        iov[1].iov_len = argsize;    }    out.len = iov_length(iov, count);    if (req->f->debug) {        printf("   unique: %llu, error: %i (%s), outsize: %i\n",               out.unique, out.error, strerror(-out.error), out.len);        fflush(stdout);    }    res = fuse_chan_send(req->ch, iov, count);    free_req(req);    return res;}size_t fuse_dirent_size(size_t namelen){    return FUSE_DIRENT_ALIGN(FUSE_NAME_OFFSET + namelen);}char *fuse_add_dirent(char *buf, const char *name, const struct stat *stbuf,                      off_t off){    unsigned namelen = strlen(name);    unsigned entlen = FUSE_NAME_OFFSET + namelen;    unsigned entsize = fuse_dirent_size(namelen);    unsigned padlen = entsize - entlen;    struct fuse_dirent *dirent = (struct fuse_dirent *) buf;    dirent->ino = stbuf->st_ino;    dirent->off = off;    dirent->namelen = namelen;    dirent->type = (stbuf->st_mode & 0170000) >> 12;    strncpy(dirent->name, name, namelen);    if (padlen)        memset(buf + entlen, 0, padlen);    return buf + entsize;}size_t fuse_add_direntry(fuse_req_t req, char *buf, size_t bufsize,                         const char *name, const struct stat *stbuf, off_t off){    size_t entsize;    (void) req;    entsize = fuse_dirent_size(strlen(name));    if (entsize <= bufsize && buf)        fuse_add_dirent(buf, name, stbuf, off);    return entsize;}static void convert_statfs(const struct statvfs *stbuf,                           struct fuse_kstatfs *kstatfs){    kstatfs->bsize	= stbuf->f_bsize;    kstatfs->frsize	= stbuf->f_frsize;    kstatfs->blocks	= stbuf->f_blocks;    kstatfs->bfree	= stbuf->f_bfree;    kstatfs->bavail	= stbuf->f_bavail;    kstatfs->files	= stbuf->f_files;    kstatfs->ffree	= stbuf->f_ffree;    kstatfs->namelen	= stbuf->f_namemax;}static int send_reply_ok(fuse_req_t req, const void *arg, size_t argsize){    return send_reply(req, 0, arg, argsize);}int fuse_reply_err(fuse_req_t req, int err){    return send_reply(req, -err, NULL, 0);}void fuse_reply_none(fuse_req_t req){    fuse_chan_send(req->ch, NULL, 0);    free_req(req);}static unsigned long calc_timeout_sec(double t){    if (t > (double) ULONG_MAX)        return ULONG_MAX;    else if (t < 0.0)        return 0;    else        return (unsigned long) t;}static unsigned int calc_timeout_nsec(double t){    double f = t - (double) calc_timeout_sec(t);    if (f < 0.0)        return 0;    else if (f >= 0.999999999)        return 999999999;    else        return (unsigned int) (f * 1.0e9);}static void fill_entry(struct fuse_entry_out *arg,                       const struct fuse_entry_param *e){    arg->nodeid = e->ino;    arg->generation = e->generation;    arg->entry_valid = calc_timeout_sec(e->entry_timeout);    arg->entry_valid_nsec = calc_timeout_nsec(e->entry_timeout);    arg->attr_valid = calc_timeout_sec(e->attr_timeout);    arg->attr_valid_nsec = calc_timeout_nsec(e->attr_timeout);    convert_stat(&e->attr, &arg->attr);}static void fill_open(struct fuse_open_out *arg,                      const struct fuse_file_info *f){    arg->fh = f->fh;    if (f->direct_io)        arg->open_flags |= FOPEN_DIRECT_IO;    if (f->keep_cache)        arg->open_flags |= FOPEN_KEEP_CACHE;}int fuse_reply_entry(fuse_req_t req, const struct fuse_entry_param *e){    struct fuse_entry_out arg;    /* before ABI 7.4 e->ino == 0 was invalid, only ENOENT meant       negative entry */    if (!e->ino && req->f->conn.proto_minor < 4)        return fuse_reply_err(req, ENOENT);    memset(&arg, 0, sizeof(arg));    fill_entry(&arg, e);    return send_reply_ok(req, &arg, sizeof(arg));}int fuse_reply_create(fuse_req_t req, const struct fuse_entry_param *e,                      const struct fuse_file_info *f){    struct {        struct fuse_entry_out e;        struct fuse_open_out o;    } arg;    memset(&arg, 0, sizeof(arg));    fill_entry(&arg.e, e);    fill_open(&arg.o, f);    return send_reply_ok(req, &arg, sizeof(arg));}int fuse_reply_attr(fuse_req_t req, const struct stat *attr,                    double attr_timeout){    struct fuse_attr_out arg;    memset(&arg, 0, sizeof(arg));    arg.attr_valid = calc_timeout_sec(attr_timeout);    arg.attr_valid_nsec = calc_timeout_nsec(attr_timeout);    convert_stat(attr, &arg.attr);    return send_reply_ok(req, &arg, sizeof(arg));}int fuse_reply_readlink(fuse_req_t req, const char *linkname){    return send_reply_ok(req, linkname, strlen(linkname));}int fuse_reply_open(fuse_req_t req, const struct fuse_file_info *f){    struct fuse_open_out arg;    memset(&arg, 0, sizeof(arg));    fill_open(&arg, f);    return send_reply_ok(req, &arg, sizeof(arg));}int fuse_reply_write(fuse_req_t req, size_t count){    struct fuse_write_out arg;    memset(&arg, 0, sizeof(arg));    arg.size = count;    return send_reply_ok(req, &arg, sizeof(arg));}int fuse_reply_buf(fuse_req_t req, const char *buf, size_t size){    return send_reply_ok(req, buf, size);}int fuse_reply_statfs(fuse_req_t req, const struct statvfs *stbuf){    struct fuse_statfs_out arg;    size_t size = req->f->conn.proto_minor < 4 ? FUSE_COMPAT_STATFS_SIZE : sizeof(arg);    memset(&arg, 0, sizeof(arg));    convert_statfs(stbuf, &arg.st);    return send_reply_ok(req, &arg, size);}int fuse_reply_xattr(fuse_req_t req, size_t count){    struct fuse_getxattr_out arg;    memset(&arg, 0, sizeof(arg));    arg.size = count;    return send_reply_ok(req, &arg, sizeof(arg));}int fuse_reply_lock(fuse_req_t req, struct flock *lock){    struct fuse_lk_out arg;    memset(&arg, 0, sizeof(arg));    arg.lk.type = lock->l_type;    if (lock->l_type != F_UNLCK) {        arg.lk.start = lock->l_start;        if (lock->l_len == 0)            arg.lk.end = OFFSET_MAX;        else            arg.lk.end = lock->l_start + lock->l_len - 1;    }    arg.lk.pid = lock->l_pid;    return send_reply_ok(req, &arg, sizeof(arg));}int fuse_reply_bmap(fuse_req_t req, uint64_t idx){    struct fuse_bmap_out arg;    memset(&arg, 0, sizeof(arg));    arg.block = idx;    return send_reply_ok(req, &arg, sizeof(arg));}static void do_lookup(fuse_req_t req, fuse_ino_t nodeid, const void *inarg){    char *name = (char *) inarg;    if (req->f->op.lookup)        req->f->op.lookup(req, nodeid, name);    else        fuse_reply_err(req, ENOSYS);}static void do_forget(fuse_req_t req, fuse_ino_t nodeid, const void *inarg){    struct fuse_forget_in *arg = (struct fuse_forget_in *) inarg;    if (req->f->op.forget)        req->f->op.forget(req, nodeid, arg->nlookup);}static void do_getattr(fuse_req_t req, fuse_ino_t nodeid, const void *inarg){    (void) inarg;    if (req->f->op.getattr)        req->f->op.getattr(req, nodeid, NULL);    else        fuse_reply_err(req, ENOSYS);}static void do_setattr(fuse_req_t req, fuse_ino_t nodeid, const void *inarg){    struct fuse_setattr_in *arg = (struct fuse_setattr_in *) inarg;    if (req->f->op.setattr) {        struct fuse_file_info *fi = NULL;        struct fuse_file_info fi_store;        struct stat stbuf;        memset(&stbuf, 0, sizeof(stbuf));        convert_attr(arg, &stbuf);        if (arg->valid & FATTR_FH) {            arg->valid &= ~FATTR_FH;            memset(&fi_store, 0, sizeof(fi_store));            fi = &fi_store;            fi->fh = arg->fh;            fi->fh_old = fi->fh;        }        req->f->op.setattr(req, nodeid, &stbuf, arg->valid, fi);    } else        fuse_reply_err(req, ENOSYS);}static void do_access(fuse_req_t req, fuse_ino_t nodeid, const void *inarg){    struct fuse_access_in *arg = (struct fuse_access_in *) inarg;    if (req->f->op.access)        req->f->op.access(req, nodeid, arg->mask);    else

⌨️ 快捷键说明

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