38 #define FUSE_USE_VERSION 31 40 #include <fuse_lowlevel.h> 58 #if defined(__GNUC__) && (__GNUC__ > 4 || __GNUC__ == 4 && __GNUC_MINOR__ >= 6) && !defined __cplusplus 59 _Static_assert(
sizeof(
fuse_ino_t) >=
sizeof(uintptr_t),
60 "fuse_ino_t too small to hold uintptr_t values!");
62 struct _uintptr_to_must_hold_fuse_ino_t_dummy_struct \
63 {
unsigned _uintptr_to_must_hold_fuse_ino_t:
64 ((
sizeof(
fuse_ino_t) >=
sizeof(uintptr_t)) ? 1 : -1); };
68 struct lo_inode *next;
69 struct lo_inode *prev;
82 static const struct fuse_opt lo_opts[] = {
84 offsetof(
struct lo_data, writeback), 1 },
86 offsetof(
struct lo_data, writeback), 0 },
98 return &lo_data(req)->root;
100 return (
struct lo_inode *) (uintptr_t) ino;
105 return lo_inode(req, ino)->fd;
110 return lo_data(req)->debug != 0;
113 static void lo_init(
void *userdata,
116 struct lo_data *lo = (
struct lo_data*) userdata;
124 fprintf(stderr,
"lo_init: activating writeback\n");
136 res = fstatat(lo_fd(req, ino),
"", &buf, AT_EMPTY_PATH | AT_SYMLINK_NOFOLLOW);
143 static struct lo_inode *lo_find(
struct lo_data *lo,
struct stat *st)
147 for (p = lo->root.next; p != &lo->root; p = p->next) {
148 if (p->ino == st->st_ino && p->dev == st->st_dev)
160 struct lo_inode *inode;
162 memset(e, 0,
sizeof(*e));
166 newfd = openat(lo_fd(req, parent), name, O_PATH | O_NOFOLLOW);
170 res = fstatat(newfd,
"", &e->
attr, AT_EMPTY_PATH | AT_SYMLINK_NOFOLLOW);
174 inode = lo_find(lo_data(req), &e->
attr);
179 struct lo_inode *prev = &lo_data(req)->root;
180 struct lo_inode *next = prev->next;
182 inode = calloc(1,
sizeof(
struct lo_inode));
187 inode->ino = e->
attr.st_ino;
188 inode->dev = e->
attr.st_dev;
196 e->
ino = (uintptr_t) inode;
199 fprintf(stderr,
" %lli/%s -> %lli\n",
200 (
unsigned long long) parent, name, (
unsigned long long) e->
ino);
217 fprintf(stderr,
"lo_lookup(parent=%" PRIu64
", name=%s)\n",
220 err = lo_do_lookup(req, parent, name, &e);
227 static void lo_free(
struct lo_inode *inode)
229 struct lo_inode *prev = inode->prev;
230 struct lo_inode *next = inode->next;
240 struct lo_inode *inode = lo_inode(req, ino);
243 fprintf(stderr,
" forget %lli %lli -%lli\n",
244 (
unsigned long long) ino, (
unsigned long long) inode->nlookup,
245 (
unsigned long long) nlookup);
248 assert(inode->nlookup >= nlookup);
249 inode->nlookup -= nlookup;
259 char buf[PATH_MAX + 1];
262 res = readlinkat(lo_fd(req, ino),
"", buf,
sizeof(buf));
266 if (res ==
sizeof(buf))
277 struct dirent *entry;
283 return (
struct lo_dirp *) (uintptr_t) fi->
fh;
289 struct lo_dirp *d = calloc(1,
sizeof(
struct lo_dirp));
293 d->fd = openat(lo_fd(req, ino),
".", O_RDONLY);
297 d->dp = fdopendir(d->fd);
304 fi->
fh = (uintptr_t) d;
322 struct lo_dirp *d = lo_dirp(fi);
330 buf = calloc(1, size);
334 if (offset != d->offset) {
335 seekdir(d->dp, offset);
347 d->entry = readdir(d->dp);
349 if (errno && rem == size) {
356 nextoff = telldir(d->dp);
360 err = lo_do_lookup(req, ino, d->entry->d_name, &e);
369 .st_ino = d->entry->d_ino,
370 .st_mode = d->entry->d_type << 12,
398 lo_do_readdir(req, ino, size, offset, fi, 0);
404 lo_do_readdir(req, ino, size, offset, fi, 1);
409 struct lo_dirp *d = lo_dirp(fi);
424 fprintf(stderr,
"lo_create(parent=%" PRIu64
", name=%s)\n",
427 fd = openat(lo_fd(req, parent), name,
428 (fi->
flags | O_CREAT) & ~O_NOFOLLOW, mode);
434 err = lo_do_lookup(req, parent, name, &e);
448 fprintf(stderr,
"lo_open(ino=%" PRIu64
", flags=%d)\n",
453 if (lo_data(req)->writeback &&
454 (fi->
flags & O_ACCMODE) == O_WRONLY) {
455 fi->
flags &= ~O_ACCMODE;
465 if (lo_data(req)->writeback && (fi->
flags & O_APPEND))
466 fi->
flags &= ~O_APPEND;
468 sprintf(buf,
"/proc/self/fd/%i", lo_fd(req, ino));
469 fd = open(buf, fi->
flags & ~O_NOFOLLOW);
491 fprintf(stderr,
"lo_read(ino=%" PRIu64
", size=%zd, " 492 "off=%lu)\n", ino, size, (
unsigned long) offset);
514 fprintf(stderr,
"lo_write(ino=%" PRIu64
", size=%zd, off=%lu)\n",
515 ino, out_buf.
buf[0].
size, (
unsigned long) off);
528 .getattr = lo_getattr,
529 .readlink = lo_readlink,
530 .opendir = lo_opendir,
531 .readdir = lo_readdir,
532 .readdirplus = lo_readdirplus,
533 .releasedir = lo_releasedir,
536 .release = lo_release,
538 .write_buf = lo_write_buf
541 int main(
int argc,
char *argv[])
544 struct fuse_session *se;
545 struct fuse_cmdline_opts opts;
546 struct lo_data lo = { .debug = 0,
550 lo.root.next = lo.root.prev = &lo.root;
555 if (opts.show_help) {
556 printf(
"usage: %s [options] <mountpoint>\n\n", argv[0]);
561 }
else if (opts.show_version) {
571 lo.debug = opts.debug;
572 lo.root.fd = open(
"/", O_PATH);
574 if (lo.root.fd == -1)
575 err(1,
"open(\"/\", O_PATH)");
590 if (opts.singlethread)
593 ret = fuse_session_loop_mt(se, opts.clone_fd);
601 free(opts.mountpoint);
604 while (lo.root.next != &lo.root)
605 lo_free(lo.root.next);
int fuse_parse_cmdline(struct fuse_args *args, struct fuse_cmdline_opts *opts)
int fuse_reply_write(fuse_req_t req, size_t count)
struct fuse_req * fuse_req_t
const char * fuse_pkgversion(void)
#define FUSE_CAP_WRITEBACK_CACHE
void fuse_session_unmount(struct fuse_session *se)
size_t fuse_add_direntry_plus(fuse_req_t req, char *buf, size_t bufsize, const char *name, const struct fuse_entry_param *e, off_t off)
int fuse_reply_data(fuse_req_t req, struct fuse_bufvec *bufv, enum fuse_buf_copy_flags flags)
int fuse_session_loop(struct fuse_session *se)
int fuse_reply_entry(fuse_req_t req, const struct fuse_entry_param *e)
int fuse_session_mount(struct fuse_session *se, const char *mountpoint)
int fuse_daemonize(int foreground)
size_t fuse_buf_size(const struct fuse_bufvec *bufv)
void fuse_lowlevel_help(void)
ssize_t fuse_buf_copy(struct fuse_bufvec *dst, struct fuse_bufvec *src, enum fuse_buf_copy_flags flags)
#define FUSE_ARGS_INIT(argc, argv)
int fuse_reply_err(fuse_req_t req, int err)
void fuse_cmdline_help(void)
void * fuse_req_userdata(fuse_req_t req)
enum fuse_buf_flags flags
void fuse_reply_none(fuse_req_t req)
int fuse_set_signal_handlers(struct fuse_session *se)
void fuse_session_destroy(struct fuse_session *se)
int fuse_reply_open(fuse_req_t req, const struct fuse_file_info *fi)
int fuse_reply_readlink(fuse_req_t req, const char *link)
int fuse_reply_attr(fuse_req_t req, const struct stat *attr, double attr_timeout)
void fuse_opt_free_args(struct fuse_args *args)
int fuse_reply_create(fuse_req_t req, const struct fuse_entry_param *e, const struct fuse_file_info *fi)
struct fuse_session * fuse_session_new(struct fuse_args *args, const struct fuse_lowlevel_ops *op, size_t op_size, void *userdata)
void fuse_lowlevel_version(void)
#define FUSE_CAP_EXPORT_SUPPORT
void(* init)(void *userdata, struct fuse_conn_info *conn)
void fuse_remove_signal_handlers(struct fuse_session *se)
int fuse_opt_parse(struct fuse_args *args, void *data, const struct fuse_opt opts[], fuse_opt_proc_t proc)
int fuse_reply_buf(fuse_req_t req, const char *buf, size_t size)
size_t fuse_add_direntry(fuse_req_t req, char *buf, size_t bufsize, const char *name, const struct stat *stbuf, off_t off)