📄 fuse.c
字号:
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, req, 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); fuse_do_releasedir(f, req, 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) { struct fuse_intr_data d; fuse_prepare_interrupt(f, req, &d); err = f->op.fsyncdir(path, datasync, &fi); fuse_finish_interrupt(f, req, &d); } 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, fuse_ino_t ino){ struct fuse *f = req_fuse_prepare(req); struct statvfs buf; int err; memset(&buf, 0, sizeof(buf)); if (f->op.statfs) { if (ino && (!f->compat || f->compat >= 26)) { char *path; pthread_rwlock_rdlock(&f->tree_lock); err = -ENOENT; path = get_path(f, ino); if (path) { err = fuse_do_statfs(f, req, path, &buf); free(path); } pthread_rwlock_unlock(&f->tree_lock); } else err = fuse_compat_statfs(f, req, &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) { struct fuse_intr_data d; fuse_prepare_interrupt(f, req, &d); err = f->op.setxattr(path, name, value, size, flags); fuse_finish_interrupt(f, req, &d); } free(path); } pthread_rwlock_unlock(&f->tree_lock); reply_err(req, err);}static int common_getxattr(struct fuse *f, fuse_req_t req, 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) { struct fuse_intr_data d; fuse_prepare_interrupt(f, req, &d); err = f->op.getxattr(path, name, value, size); fuse_finish_interrupt(f, req, &d); } 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, req, 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, req, 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_req_t req, 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) { struct fuse_intr_data d; fuse_prepare_interrupt(f, req, &d); err = f->op.listxattr(path, list, size); fuse_finish_interrupt(f, req, &d); } free(path); } pthread_rwlock_unlock(&f->tree_lock); return err;}static void fuse_listxattr(fuse_req_t req, fuse_ino_t ino, size_t size){ struct fuse *f = req_fuse_prepare(req); int res; if (size) { char *list = (char *) malloc(size); if (list == NULL) { reply_err(req, -ENOMEM); return; } res = common_listxattr(f, req, ino, list, size); if (res > 0) fuse_reply_buf(req, list, res); else reply_err(req, res); free(list); } else { res = common_listxattr(f, req, ino, NULL, 0); if (res >= 0) fuse_reply_xattr(req, res); else reply_err(req, res); }}static void fuse_removexattr(fuse_req_t req, fuse_ino_t ino, const char *name){ 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.removexattr) { struct fuse_intr_data d; fuse_prepare_interrupt(f, req, &d); err = f->op.removexattr(path, name); fuse_finish_interrupt(f, req, &d); } free(path); } pthread_rwlock_unlock(&f->tree_lock); reply_err(req, err);}static struct lock *locks_conflict(struct node *node, const struct lock *lock){ struct lock *l; for (l = node->locks; l; l = l->next) if (l->owner != lock->owner && lock->start <= l->end && l->start <= lock->end && (l->type == F_WRLCK || lock->type == F_WRLCK)) break; return l;}static void delete_lock(struct lock **lockp){ struct lock *l = *lockp; *lockp = l->next; free(l);}static void insert_lock(struct lock **pos, struct lock *lock){ lock->next = *pos; *pos = lock;}static int locks_insert(struct node *node, struct lock *lock){ struct lock **lp; struct lock *newl1 = NULL; struct lock *newl2 = NULL; if (lock->type != F_UNLCK || lock->start != 0 || lock->end != OFFSET_MAX) { newl1 = malloc(sizeof(struct lock)); newl2 = malloc(sizeof(struct lock)); if (!newl1 || !newl2) { free(newl1); free(newl2); return -ENOLCK; } } for (lp = &node->locks; *lp;) { struct lock *l = *lp; if (l->owner != lock->owner) goto skip; if (lock->type == l->type) { if (l->end < lock->start - 1) goto skip; if (lock->end < l->start - 1) break; if (l->start <= lock->start && lock->end <= l->end) goto out; if (l->start < lock->start) lock->start = l->start; if (lock->end < l->end) lock->end = l->end; goto delete; } else { if (l->end < lock->start) goto skip; if (lock->end < l->start) break; if (lock->start <= l->start && l->end <= lock->end) goto delete; if (l->end <= lock->end) { l->end = lock->start - 1; goto skip; } if (lock->start <= l->start) { l->start = lock->end + 1; break; } *newl2 = *l; newl2->start = lock->end + 1; l->end = lock->start - 1; insert_lock(&l->next, newl2); newl2 = NULL; } skip: lp = &l->next; continue; delete: delete_lock(lp); } if (lock->type != F_UNLCK) { *newl1 = *lock; insert_lock(lp, newl1); newl1 = NULL; }out: free(newl1); free(newl2); return 0;}static void flock_to_lock(struct flock *flock, struct lock *lock){ memset(lock, 0, sizeof(struct lock)); lock->type = flock->l_type; lock->start = flock->l_start; lock->end = flock->l_len ? flock->l_start + flock->l_len - 1 : OFFSET_MAX; lock->pid = flock->l_pid;}static void lock_to_flock(struct lock *lock, struct flock *flock){ flock->l_type = lock->type; flock->l_start = lock->start; flock->l_len = (lock->end == OFFSET_MAX) ? 0 : lock->end - lock->start + 1; flock->l_pid = lock->pid;}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 = fuse_do_flush(f, req, path, fi); } if (f->op.lock) { struct flock lock; struct lock l; memset(&lock, 0, sizeof(lock)); lock.l_type = F_UNLCK; lock.l_whence = SEEK_SET; fuse_do_lock(f, req, path, fi, F_SETLK, &lock); flock_to_lock(&lock, &l); l.owner = fi->lock_owner; pthread_mutex_lock(&f->lock); locks_insert(get_node(f, ino), &l); pthread_mutex_unlock(&f->lock); /* if op.lock() is defined FLUSH is needed regardless of op.flush() */ if (err == -ENOSYS) err = 0; } free(path); pthread_rwlock_unlock(&f->tree_lock); reply_err(req, err);}static int fuse_lock_common(fuse_req_t req, fuse_ino_t ino, struct fuse_file_info *fi, struct flock *lock, int cmd){ 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 = fuse_do_lock(f, req, path, fi, cmd, lock); free(path); } pthread_rwlock_unlock(&f->tree_lock); return err;}static void fuse_getlk(fuse_req_t req, fuse_ino_t ino, struct fuse_file_info *fi, struct flock *lock){ int err; struct lock l; struct lock *conflict; struct fuse *f = req_fuse(req); flock_to_lock(lock, &l); l.owner = fi->lock_owner; pthread_mutex_lock(&f->lock); conflict = locks_conflict(get_node(f, ino), &l); if (conflict) lock_to_flock(conflict, lock); pthread_mutex_unlock(&f->lock); if (!conflict) err = fuse_lock_common(req, ino, fi, lock, F_GETLK); else err = 0; if (!err) fuse_reply_lock(req, lock); else reply_err(req, err);}static void fuse_setlk(fuse_req_t req, fuse_ino_t ino, struct fuse_file_info *fi, struct flock *lock, int sleep){ int err = fuse_lock_common(req, ino, fi, lock, sleep ? F_SETLKW : F_SETLK); if (!err) { struct fuse *f = req_fuse(req); struct lock l; flock_to_lock(lock, &l); l.owner = fi->lock_owner; pthread_mutex_
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -