📄 fuse.c
字号:
if (fuse_reply_open(req, fi) == -ENOENT) { /* The open syscall was interrupted, so it must be cancelled */ if(f->op.release && path != NULL) fuse_do_release(f, path, fi); } else { struct node *node = get_node(f, ino); node->open_count ++; } pthread_mutex_unlock(&f->lock); } else reply_err(req, err); if (path) free(path); pthread_rwlock_unlock(&f->tree_lock);}static void fuse_read(fuse_req_t req, fuse_ino_t ino, size_t size, off_t off, struct fuse_file_info *fi){ struct fuse *f = req_fuse_prepare(req); char *path; char *buf; int res; buf = (char *) malloc(size); if (buf == NULL) { reply_err(req, -ENOMEM); return; } res = -ENOENT; pthread_rwlock_rdlock(&f->tree_lock); path = get_path(f, ino); if (path != NULL) { if (f->conf.debug) { printf("READ[%llu] %u bytes from %llu\n", (unsigned long long) fi->fh, size, off); fflush(stdout); } res = -ENOSYS; if (f->op.read) res = f->op.read(path, buf, size, off, fi); free(path); } pthread_rwlock_unlock(&f->tree_lock); if (res >= 0) { if (f->conf.debug) { printf(" READ[%llu] %u bytes\n", (unsigned long long) fi->fh, res); fflush(stdout); } if ((size_t) res > size) fprintf(stderr, "fuse: read too many bytes"); fuse_reply_buf(req, buf, res); } else reply_err(req, res); free(buf);}static void fuse_write(fuse_req_t req, fuse_ino_t ino, const char *buf, size_t size, off_t off, struct fuse_file_info *fi){ struct fuse *f = req_fuse_prepare(req); char *path; int res; res = -ENOENT; pthread_rwlock_rdlock(&f->tree_lock); path = get_path(f, ino); if (path != NULL) { if (f->conf.debug) { printf("WRITE%s[%llu] %u bytes to %llu\n", fi->writepage ? "PAGE" : "", (unsigned long long) fi->fh, size, off); fflush(stdout); } res = -ENOSYS; if (f->op.write) res = f->op.write(path, buf, size, off, fi); free(path); } pthread_rwlock_unlock(&f->tree_lock); if (res >= 0) { if (f->conf.debug) { printf(" WRITE%s[%llu] %u bytes\n", fi->writepage ? "PAGE" : "", (unsigned long long) fi->fh, res); fflush(stdout); } if ((size_t) res > size) fprintf(stderr, "fuse: wrote too many bytes"); fuse_reply_write(req, res); } else reply_err(req, res);}static void fuse_flush(fuse_req_t req, fuse_ino_t ino, struct fuse_file_info *fi){ struct fuse *f = req_fuse_prepare(req); char *path; int err; err = -ENOENT; pthread_rwlock_rdlock(&f->tree_lock); path = get_path(f, ino); if (path != NULL) { if (f->conf.debug) { printf("FLUSH[%llu]\n", (unsigned long long) fi->fh); fflush(stdout); } err = -ENOSYS; if (f->op.flush) err = f->op.flush(path, fi); free(path); } pthread_rwlock_unlock(&f->tree_lock); reply_err(req, err);}static void fuse_release(fuse_req_t req, fuse_ino_t ino, struct fuse_file_info *fi){ struct fuse *f = req_fuse_prepare(req); char *path; struct node *node; int unlink_hidden; pthread_mutex_lock(&f->lock); node = get_node(f, ino); assert(node->open_count > 0); --node->open_count; unlink_hidden = (node->is_hidden && !node->open_count); pthread_mutex_unlock(&f->lock); pthread_rwlock_rdlock(&f->tree_lock); path = get_path(f, ino); if (f->conf.debug) { printf("RELEASE[%llu] flags: 0x%x\n", (unsigned long long) fi->fh, fi->flags); fflush(stdout); } if (f->op.release) fuse_do_release(f, path, fi); if(unlink_hidden && path) f->op.unlink(path); if (path) free(path); pthread_rwlock_unlock(&f->tree_lock); reply_err(req, 0);}static void fuse_fsync(fuse_req_t req, fuse_ino_t ino, int datasync, struct fuse_file_info *fi){ struct fuse *f = req_fuse_prepare(req); char *path; int err; err = -ENOENT; pthread_rwlock_rdlock(&f->tree_lock); path = get_path(f, ino); if (path != NULL) { if (f->conf.debug) { printf("FSYNC[%llu]\n", (unsigned long long) fi->fh); fflush(stdout); } err = -ENOSYS; if (f->op.fsync) err = f->op.fsync(path, datasync, fi); free(path); } pthread_rwlock_unlock(&f->tree_lock); reply_err(req, err);}static struct fuse_dirhandle *get_dirhandle(const struct fuse_file_info *llfi, struct fuse_file_info *fi){ struct fuse_dirhandle *dh = (struct fuse_dirhandle *) (uintptr_t) llfi->fh; memset(fi, 0, sizeof(struct fuse_file_info)); fi->fh = dh->fh; fi->fh_old = dh->fh; return dh;}static void fuse_opendir(fuse_req_t req, fuse_ino_t ino, struct fuse_file_info *llfi){ struct fuse *f = req_fuse_prepare(req); struct fuse_dirhandle *dh; dh = (struct fuse_dirhandle *) malloc(sizeof(struct fuse_dirhandle)); if (dh == NULL) { reply_err(req, -ENOMEM); return; } memset(dh, 0, sizeof(struct fuse_dirhandle)); dh->fuse = f; dh->contents = NULL; dh->len = 0; dh->filled = 0; dh->nodeid = ino; mutex_init(&dh->lock); llfi->fh = (uintptr_t) dh; if (f->op.opendir) { struct fuse_file_info fi; char *path; int err; memset(&fi, 0, sizeof(fi)); fi.flags = llfi->flags; err = -ENOENT; pthread_rwlock_rdlock(&f->tree_lock); path = get_path(f, ino); if (path != NULL) { err = fuse_do_opendir(f, path, &fi); dh->fh = fi.fh; } if (!err) { pthread_mutex_lock(&f->lock); if (fuse_reply_open(req, llfi) == -ENOENT) { /* The opendir syscall was interrupted, so it must be cancelled */ if(f->op.releasedir) f->op.releasedir(path, &fi); pthread_mutex_destroy(&dh->lock); free(dh); } pthread_mutex_unlock(&f->lock); } else { reply_err(req, err); free(dh); } free(path); pthread_rwlock_unlock(&f->tree_lock); } else fuse_reply_open(req, llfi);}static int fill_dir_common(struct fuse_dirhandle *dh, const char *name, const struct stat *statp, off_t off){ struct stat stbuf; unsigned namelen = strlen(name); unsigned entsize; unsigned newlen; if (statp) stbuf = *statp; else { memset(&stbuf, 0, sizeof(stbuf)); stbuf.st_ino = FUSE_UNKNOWN_INO; } if (!dh->fuse->conf.use_ino) { stbuf.st_ino = FUSE_UNKNOWN_INO; if (dh->fuse->conf.readdir_ino) { struct node *node; pthread_mutex_lock(&dh->fuse->lock); node = lookup_node(dh->fuse, dh->nodeid, name); if (node) stbuf.st_ino = (ino_t) node->nodeid; pthread_mutex_unlock(&dh->fuse->lock); } } entsize = fuse_dirent_size(namelen); newlen = dh->len + entsize; if (off) { dh->filled = 0; if (newlen > dh->needlen) return 1; } if (newlen > dh->size) { char *newptr; if (!dh->size) dh->size = 1024; while (newlen > dh->size) dh->size *= 2; newptr = (char *) realloc(dh->contents, dh->size); if (!newptr) { dh->error = -ENOMEM; return 1; } dh->contents = newptr; } fuse_add_dirent(dh->contents + dh->len, name, &stbuf, off ? off : newlen); dh->len = newlen; return 0;}static int fill_dir(void *buf, const char *name, const struct stat *stbuf, off_t off){ return fill_dir_common((struct fuse_dirhandle *) buf, name, stbuf, off);}static int fill_dir_old(struct fuse_dirhandle *dh, const char *name, int type, ino_t ino){ struct stat stbuf; memset(&stbuf, 0, sizeof(stbuf)); stbuf.st_mode = type << 12; stbuf.st_ino = ino; fill_dir_common(dh, name, &stbuf, 0); return dh->error;}static int readdir_fill(struct fuse *f, fuse_ino_t ino, size_t size, off_t off, struct fuse_dirhandle *dh, struct fuse_file_info *fi){ int err = -ENOENT; char *path; pthread_rwlock_rdlock(&f->tree_lock); path = get_path(f, ino); if (path != NULL) { dh->len = 0; dh->error = 0; dh->needlen = size; dh->filled = 1; err = -ENOSYS; if (f->op.readdir) err = f->op.readdir(path, dh, fill_dir, off, fi); else if (f->op.getdir) err = f->op.getdir(path, dh, fill_dir_old); if (!err) err = dh->error; if (err) dh->filled = 0; free(path); } pthread_rwlock_unlock(&f->tree_lock); return err;}static void fuse_readdir(fuse_req_t req, fuse_ino_t ino, size_t size, off_t off, struct fuse_file_info *llfi){ struct fuse *f = req_fuse_prepare(req); struct fuse_file_info fi; struct fuse_dirhandle *dh = get_dirhandle(llfi, &fi); pthread_mutex_lock(&dh->lock); /* According to SUS, directory contents need to be refreshed on rewinddir() */ if (!off) dh->filled = 0; if (!dh->filled) { int err = readdir_fill(f, ino, size, off, dh, &fi); if (err) { reply_err(req, err); goto out; } } if (dh->filled) { if (off < dh->len) { if (off + size > dh->len) size = dh->len - off; } else size = 0; } else { size = dh->len; off = 0; } fuse_reply_buf(req, dh->contents + off, size); out: pthread_mutex_unlock(&dh->lock);}static void fuse_releasedir(fuse_req_t req, fuse_ino_t ino, struct fuse_file_info *llfi){ struct fuse *f = req_fuse_prepare(req); struct fuse_file_info fi; struct fuse_dirhandle *dh = get_dirhandle(llfi, &fi); if (f->op.releasedir) { char *path; pthread_rwlock_rdlock(&f->tree_lock); path = get_path(f, ino); f->op.releasedir(path ? path : "-", &fi); free(path); pthread_rwlock_unlock(&f->tree_lock); } pthread_mutex_lock(&dh->lock); pthread_mutex_unlock(&dh->lock); pthread_mutex_destroy(&dh->lock); free(dh->contents); free(dh); reply_err(req, 0);}static void fuse_fsyncdir(fuse_req_t req, fuse_ino_t ino, int datasync, struct fuse_file_info *llfi){ struct fuse *f = req_fuse_prepare(req); struct fuse_file_info fi; char *path; int err; get_dirhandle(llfi, &fi); err = -ENOENT; pthread_rwlock_rdlock(&f->tree_lock); path = get_path(f, ino); if (path != NULL) { err = -ENOSYS; if (f->op.fsyncdir) err = f->op.fsyncdir(path, datasync, &fi); free(path); } pthread_rwlock_unlock(&f->tree_lock); reply_err(req, err);}static int default_statfs(struct statvfs *buf){ buf->f_namemax = 255; buf->f_bsize = 512; return 0;}static void fuse_statfs(fuse_req_t req){ struct fuse *f = req_fuse_prepare(req); struct statvfs buf; int err; memset(&buf, 0, sizeof(buf)); if (f->op.statfs) { err = fuse_do_statfs(f, "/", &buf); } else err = default_statfs(&buf); if (!err) fuse_reply_statfs(req, &buf); else reply_err(req, err);}static void fuse_setxattr(fuse_req_t req, fuse_ino_t ino, const char *name, const char *value, size_t size, int flags){ struct fuse *f = req_fuse_prepare(req); char *path; int err; err = -ENOENT; pthread_rwlock_rdlock(&f->tree_lock); path = get_path(f, ino); if (path != NULL) { err = -ENOSYS; if (f->op.setxattr) err = f->op.setxattr(path, name, value, size, flags); free(path); } pthread_rwlock_unlock(&f->tree_lock); reply_err(req, err);}static int common_getxattr(struct fuse *f, fuse_ino_t ino, const char *name, char *value, size_t size){ int err; char *path; err = -ENOENT; pthread_rwlock_rdlock(&f->tree_lock); path = get_path(f, ino); if (path != NULL) { err = -ENOSYS; if (f->op.getxattr) err = f->op.getxattr(path, name, value, size); free(path); } pthread_rwlock_unlock(&f->tree_lock); return err;}static void fuse_getxattr(fuse_req_t req, fuse_ino_t ino, const char *name, size_t size){ struct fuse *f = req_fuse_prepare(req); int res; if (size) { char *value = (char *) malloc(size); if (value == NULL) { reply_err(req, -ENOMEM); return; } res = common_getxattr(f, ino, name, value, size); if (res > 0) fuse_reply_buf(req, value, res); else reply_err(req, res); free(value); } else { res = common_getxattr(f, ino, name, NULL, 0); if (res >= 0) fuse_reply_xattr(req, res); else reply_err(req, res); }}static int common_listxattr(struct fuse *f, fuse_ino_t ino, char *list, size_t size){ char *path; int err; err = -ENOENT; pthread_rwlock_rdlock(&f->tree_lock); path = get_path(f, ino); if (path != NULL) { err = -ENOSYS; if (f->op.listxattr) err = f->op.listxattr(path, list, size); free(path); } pthread_rwlock_unlock(&f->tree_lock); return err;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -