From: Nikolaus Rath Date: Mon, 10 Oct 2016 02:22:57 +0000 (-0700) Subject: Renamed some examples to make their function more obvious X-Git-Tag: fuse-3.0.0rc1~74 X-Git-Url: http://git.maquefel.me/?a=commitdiff_plain;h=463189cd121ce9a9f79d24c207e7c6c31898ea06;p=qemu-gpiodev%2Flibfuse.git Renamed some examples to make their function more obvious Also, added more comments for the same purpose. --- diff --git a/configure.ac b/configure.ac index 39bddc7..7482f8a 100644 --- a/configure.ac +++ b/configure.ac @@ -69,8 +69,8 @@ AC_SEARCH_LIBS(clock_gettime, [rt]) libfuse_libs=$LIBS LIBS= AC_CHECK_LIB(ulockmgr, ulockmgr_op) -fusexmp_fh_libs=$LIBS -AC_SUBST(fusexmp_fh_libs) +passthrough_fh_libs=$LIBS +AC_SUBST(passthrough_fh_libs) LIBS= AC_ARG_WITH([libiconv-prefix], diff --git a/example/.gitignore b/example/.gitignore index a738dbc..ea56c8d 100644 --- a/example/.gitignore +++ b/example/.gitignore @@ -1,5 +1,5 @@ -/fusexmp -/fusexmp_fh +/passthrough +/passthrough_fh /hello /hello_ll /fioc @@ -7,6 +7,6 @@ /fsel /fselclient /cusexmp -/fuse_lo-plus +/passthrough_ll /timefs1 /timefs2 diff --git a/example/Makefile.am b/example/Makefile.am index 7ddd7d9..5d82f64 100644 --- a/example/Makefile.am +++ b/example/Makefile.am @@ -2,12 +2,12 @@ AM_CPPFLAGS = -I$(top_srcdir)/include -D_REENTRANT noinst_HEADERS = fioc.h -noinst_PROGRAMS = fusexmp fusexmp_fh hello hello_ll fioc fioclient \ - fsel fselclient cusexmp fuse_lo-plus timefs1 timefs2 \ +noinst_PROGRAMS = passthrough passthrough_fh hello hello_ll fioc fioclient \ + fsel fselclient cusexmp passthrough_ll timefs1 timefs2 \ timefs3 LDADD = ../lib/libfuse3.la -fusexmp_fh_LDADD = ../lib/libfuse3.la @fusexmp_fh_libs@ +passthrough_fh_LDADD = ../lib/libfuse3.la @passthrough_fh_libs@ fioclient_CPPFLAGS = fioclient_LDFLAGS = diff --git a/example/fuse_lo-plus.c b/example/fuse_lo-plus.c deleted file mode 100644 index c27f377..0000000 --- a/example/fuse_lo-plus.c +++ /dev/null @@ -1,508 +0,0 @@ -/* - FUSE: Filesystem in Userspace - Copyright (C) 2001-2007 Miklos Szeredi - - This program can be distributed under the terms of the GNU GPL. - See the file COPYING. -*/ - -/* - * gcc -Wall fuse_lo-plus.c `pkg-config fuse3 --cflags --libs` -o fuse_lo-plus - */ - -#define _GNU_SOURCE -#define FUSE_USE_VERSION 30 - -#ifdef HAVE_CONFIG_H -#include -#endif - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -/* Compat stuff. Doesn't make it work, just makes it compile. */ -#ifndef HAVE_FSTATAT -#warning fstatat(2) needed by this program -int fstatat(int dirfd, const char *pathname, struct stat *buf, int flags) -{ - errno = ENOSYS; - return -1; -} -#endif -#ifndef HAVE_OPENAT -#warning openat(2) needed by this program -int openat(int dirfd, const char *pathname, int flags, ...) -{ - errno = ENOSYS; - return -1; -} -#endif -#ifndef HAVE_READLINKAT -#warning readlinkat(2) needed by this program -ssize_t readlinkat(int dirfd, const char *pathname, char *buf, size_t bufsiz) -{ - errno = ENOSYS; - return -1; -} -#endif -#ifndef AT_EMPTY_PATH -#warning AT_EMPTY_PATH needed by this program -#define AT_EMPTY_PATH 0 -#endif -#ifndef AT_SYMLINK_NOFOLLOW -#warning AT_SYMLINK_NOFOLLOW needed by this program -#define AT_SYMLINK_NOFOLLOW 0 -#endif -#ifndef O_PATH -#warning O_PATH needed by this program -#define O_PATH 0 -#endif -#ifndef O_NOFOLLOW -#warning O_NOFOLLOW needed by this program -#define O_NOFOLLOW 0 -#endif - -struct lo_inode { - struct lo_inode *next; - struct lo_inode *prev; - int fd; - ino_t ino; - dev_t dev; - uint64_t nlookup; -}; - -struct lo_data { - int debug; - struct lo_inode root; -}; - -static struct lo_data *lo_data(fuse_req_t req) -{ - return (struct lo_data *) fuse_req_userdata(req); -} - -static struct lo_inode *lo_inode(fuse_req_t req, fuse_ino_t ino) -{ - if (ino == FUSE_ROOT_ID) - return &lo_data(req)->root; - else - return (struct lo_inode *) (uintptr_t) ino; -} - -static int lo_fd(fuse_req_t req, fuse_ino_t ino) -{ - return lo_inode(req, ino)->fd; -} - -static bool lo_debug(fuse_req_t req) -{ - return lo_data(req)->debug != 0; -} - -static void lo_getattr(fuse_req_t req, fuse_ino_t ino, - struct fuse_file_info *fi) -{ - int res; - struct stat buf; - (void) fi; - - res = fstatat(lo_fd(req, ino), "", &buf, AT_EMPTY_PATH | AT_SYMLINK_NOFOLLOW); - if (res == -1) - return (void) fuse_reply_err(req, errno); - - fuse_reply_attr(req, &buf, 1.0); -} - -static struct lo_inode *lo_find(struct lo_data *lo, struct stat *st) -{ - struct lo_inode *p; - - for (p = lo->root.next; p != &lo->root; p = p->next) { - if (p->ino == st->st_ino && p->dev == st->st_dev) - return p; - } - return NULL; -} - -static int lo_do_lookup(fuse_req_t req, fuse_ino_t parent, const char *name, - struct fuse_entry_param *e) -{ - int newfd; - int res; - int saverr; - struct lo_inode *inode; - - memset(e, 0, sizeof(*e)); - e->attr_timeout = 1.0; - e->entry_timeout = 1.0; - - newfd = openat(lo_fd(req, parent), name, O_PATH | O_NOFOLLOW); - if (newfd == -1) - goto out_err; - - res = fstatat(newfd, "", &e->attr, AT_EMPTY_PATH | AT_SYMLINK_NOFOLLOW); - if (res == -1) - goto out_err; - - inode = lo_find(lo_data(req), &e->attr); - if (inode) { - close(newfd); - newfd = -1; - } else { - struct lo_inode *prev = &lo_data(req)->root; - struct lo_inode *next = prev->next; - saverr = ENOMEM; - inode = calloc(1, sizeof(struct lo_inode)); - if (!inode) - goto out_err; - - inode->fd = newfd; - inode->ino = e->attr.st_ino; - inode->dev = e->attr.st_dev; - - next->prev = inode; - inode->next = next; - inode->prev = prev; - prev->next = inode; - } - inode->nlookup++; - e->ino = (uintptr_t) inode; - - if (lo_debug(req)) - fprintf(stderr, " %lli/%s -> %lli\n", - (unsigned long long) parent, name, (unsigned long long) e->ino); - - return 0; - -out_err: - saverr = errno; - if (newfd != -1) - close(newfd); - return saverr; -} - -static void lo_lookup(fuse_req_t req, fuse_ino_t parent, const char *name) -{ - struct fuse_entry_param e; - int err; - - err = lo_do_lookup(req, parent, name, &e); - if (err) - fuse_reply_err(req, err); - else - fuse_reply_entry(req, &e); -} - -static void lo_free(struct lo_inode *inode) -{ - struct lo_inode *prev = inode->prev; - struct lo_inode *next = inode->next; - - next->prev = prev; - prev->next = next; - close(inode->fd); - free(inode); -} - -static void lo_forget(fuse_req_t req, fuse_ino_t ino, uint64_t nlookup) -{ - struct lo_inode *inode = lo_inode(req, ino); - - if (lo_debug(req)) { - fprintf(stderr, " forget %lli %lli -%lli\n", - (unsigned long long) ino, (unsigned long long) inode->nlookup, - (unsigned long long) nlookup); - } - - assert(inode->nlookup >= nlookup); - inode->nlookup -= nlookup; - - if (!inode->nlookup) - lo_free(inode); - - fuse_reply_none(req); -} - -static void lo_readlink(fuse_req_t req, fuse_ino_t ino) -{ - char buf[PATH_MAX + 1]; - int res; - - res = readlinkat(lo_fd(req, ino), "", buf, sizeof(buf)); - if (res == -1) - return (void) fuse_reply_err(req, errno); - - if (res == sizeof(buf)) - return (void) fuse_reply_err(req, ENAMETOOLONG); - - buf[res] = '\0'; - - fuse_reply_readlink(req, buf); -} - -struct lo_dirp { - int fd; - DIR *dp; - struct dirent *entry; - off_t offset; -}; - -static struct lo_dirp *lo_dirp(struct fuse_file_info *fi) -{ - return (struct lo_dirp *) (uintptr_t) fi->fh; -} - -static void lo_opendir(fuse_req_t req, fuse_ino_t ino, struct fuse_file_info *fi) -{ - int error = ENOMEM; - struct lo_dirp *d = calloc(1, sizeof(struct lo_dirp)); - if (d == NULL) - goto out_err; - - d->fd = openat(lo_fd(req, ino), ".", O_RDONLY); - if (d->fd == -1) - goto out_errno; - - d->dp = fdopendir(d->fd); - if (d->dp == NULL) - goto out_errno; - - d->offset = 0; - d->entry = NULL; - - fi->fh = (uintptr_t) d; - fuse_reply_open(req, fi); - return; - -out_errno: - error = errno; -out_err: - if (d) { - if (d->fd != -1) - close(d->fd); - free(d); - } - fuse_reply_err(req, error); -} - -static void lo_do_readdir(fuse_req_t req, fuse_ino_t ino, size_t size, - off_t offset, struct fuse_file_info *fi, int plus) -{ - struct lo_dirp *d = lo_dirp(fi); - char *buf; - char *p; - size_t rem; - int err; - - (void) ino; - - buf = calloc(size, 1); - if (!buf) - return (void) fuse_reply_err(req, ENOMEM); - - if (offset != d->offset) { - seekdir(d->dp, offset); - d->entry = NULL; - d->offset = offset; - } - p = buf; - rem = size; - while (1) { - size_t entsize; - off_t nextoff; - - if (!d->entry) { - errno = 0; - d->entry = readdir(d->dp); - if (!d->entry) { - if (errno && rem == size) { - err = errno; - goto error; - } - break; - } - } - nextoff = telldir(d->dp); - if (plus) { - struct fuse_entry_param e; - - err = lo_do_lookup(req, ino, d->entry->d_name, &e); - if (err) - goto error; - - entsize = fuse_add_direntry_plus(req, p, rem, - d->entry->d_name, - &e, nextoff); - } else { - struct stat st = { - .st_ino = d->entry->d_ino, - .st_mode = d->entry->d_type << 12, - }; - entsize = fuse_add_direntry(req, p, rem, - d->entry->d_name, - &st, nextoff); - } - if (entsize > rem) - break; - - p += entsize; - rem -= entsize; - - d->entry = NULL; - d->offset = nextoff; - } - - fuse_reply_buf(req, buf, size - rem); - free(buf); - return; - -error: - free(buf); - fuse_reply_err(req, err); -} - -static void lo_readdir(fuse_req_t req, fuse_ino_t ino, size_t size, - off_t offset, struct fuse_file_info *fi) -{ - lo_do_readdir(req, ino, size, offset, fi, 0); -} - -static void lo_readdirplus(fuse_req_t req, fuse_ino_t ino, size_t size, - off_t offset, struct fuse_file_info *fi) -{ - lo_do_readdir(req, ino, size, offset, fi, 1); -} - -static void lo_releasedir(fuse_req_t req, fuse_ino_t ino, struct fuse_file_info *fi) -{ - struct lo_dirp *d = lo_dirp(fi); - (void) ino; - closedir(d->dp); - free(d); - fuse_reply_err(req, 0); -} - -static void lo_open(fuse_req_t req, fuse_ino_t ino, - struct fuse_file_info *fi) -{ - int fd; - char buf[64]; - - sprintf(buf, "/proc/self/fd/%i", lo_fd(req, ino)); - fd = open(buf, fi->flags & ~O_NOFOLLOW); - if (fd == -1) - return (void) fuse_reply_err(req, errno); - - fi->fh = fd; - fuse_reply_open(req, fi); -} - -static void lo_release(fuse_req_t req, fuse_ino_t ino, struct fuse_file_info *fi) -{ - (void) ino; - - close(fi->fh); - fuse_reply_err(req, 0); -} - -static void lo_read(fuse_req_t req, fuse_ino_t ino, size_t size, - off_t offset, struct fuse_file_info *fi) -{ - struct fuse_bufvec buf = FUSE_BUFVEC_INIT(size); - - (void) ino; - - buf.buf[0].flags = FUSE_BUF_IS_FD | FUSE_BUF_FD_SEEK; - buf.buf[0].fd = fi->fh; - buf.buf[0].pos = offset; - - fuse_reply_data(req, &buf, FUSE_BUF_SPLICE_MOVE); -} - -static struct fuse_lowlevel_ops lo_oper = { - .lookup = lo_lookup, - .forget = lo_forget, - .getattr = lo_getattr, - .readlink = lo_readlink, - .opendir = lo_opendir, - .readdir = lo_readdir, - .readdirplus = lo_readdirplus, - .releasedir = lo_releasedir, - .open = lo_open, - .release = lo_release, - .read = lo_read, -}; - -int main(int argc, char *argv[]) -{ - struct fuse_args args = FUSE_ARGS_INIT(argc, argv); - struct fuse_session *se; - struct fuse_cmdline_opts opts; - struct lo_data lo = { .debug = 0 }; - int ret = -1; - - if (fuse_parse_cmdline(&args, &opts) != 0) - return 1; - if (opts.show_help) { - printf("usage: %s [options] \n\n", argv[0]); - fuse_cmdline_help(); - fuse_lowlevel_help(); - fuse_mount_help(); - ret = 0; - goto err_out1; - } else if (opts.show_version) { - printf("FUSE library version %s\n", fuse_pkgversion()); - fuse_lowlevel_version(); - fuse_mount_version(); - ret = 0; - goto err_out1; - } - - lo.debug = opts.debug; - lo.root.next = lo.root.prev = &lo.root; - lo.root.fd = open("/", O_PATH); - lo.root.nlookup = 2; - if (lo.root.fd == -1) - err(1, "open(\"/\", O_PATH)"); - - se = fuse_session_new(&args, &lo_oper, sizeof(lo_oper), &lo); - if (se == NULL) - goto err_out1; - - if (fuse_set_signal_handlers(se) != 0) - goto err_out2; - - if (fuse_session_mount(se, opts.mountpoint) != 0) - goto err_out3; - - fuse_daemonize(opts.foreground); - - /* Block until ctrl+c or fusermount -u */ - if (opts.singlethread) - ret = fuse_session_loop(se); - else - ret = fuse_session_loop_mt(se); - - fuse_session_unmount(se); -err_out3: - fuse_remove_signal_handlers(se); -err_out2: - fuse_session_destroy(se); -err_out1: - free(opts.mountpoint); - fuse_opt_free_args(&args); - - while (lo.root.next != &lo.root) - lo_free(lo.root.next); - - return ret ? 1 : 0; -} diff --git a/example/fusexmp.c b/example/fusexmp.c deleted file mode 100644 index eae3562..0000000 --- a/example/fusexmp.c +++ /dev/null @@ -1,429 +0,0 @@ -/* - FUSE: Filesystem in Userspace - Copyright (C) 2001-2007 Miklos Szeredi - Copyright (C) 2011 Sebastian Pipping - - This program can be distributed under the terms of the GNU GPL. - See the file COPYING. -*/ - -/** @file - * @tableofcontents - * - * fusexmp.c - FUSE: Filesystem in Userspace - * - * \section section_compile compiling this example - * - * gcc -Wall fusexmp.c `pkg-config fuse3 --cflags --libs` -o fusexmp - * - * \section section_source the complete source - * \include fusexmp.c - */ - - -#define FUSE_USE_VERSION 30 - -#ifdef HAVE_CONFIG_H -#include -#endif - -#ifdef linux -/* For pread()/pwrite()/utimensat() */ -#define _XOPEN_SOURCE 700 -#endif - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#ifdef HAVE_SETXATTR -#include -#endif - -static int xmp_getattr(const char *path, struct stat *stbuf) -{ - int res; - - res = lstat(path, stbuf); - if (res == -1) - return -errno; - - return 0; -} - -static int xmp_access(const char *path, int mask) -{ - int res; - - res = access(path, mask); - if (res == -1) - return -errno; - - return 0; -} - -static int xmp_readlink(const char *path, char *buf, size_t size) -{ - int res; - - res = readlink(path, buf, size - 1); - if (res == -1) - return -errno; - - buf[res] = '\0'; - return 0; -} - - -static int xmp_readdir(const char *path, void *buf, fuse_fill_dir_t filler, - off_t offset, struct fuse_file_info *fi, - enum fuse_readdir_flags flags) -{ - DIR *dp; - struct dirent *de; - - (void) offset; - (void) fi; - (void) flags; - - dp = opendir(path); - if (dp == NULL) - return -errno; - - while ((de = readdir(dp)) != NULL) { - struct stat st; - memset(&st, 0, sizeof(st)); - st.st_ino = de->d_ino; - st.st_mode = de->d_type << 12; - if (filler(buf, de->d_name, &st, 0, 0)) - break; - } - - closedir(dp); - return 0; -} - -static int xmp_mknod(const char *path, mode_t mode, dev_t rdev) -{ - int res; - - /* On Linux this could just be 'mknod(path, mode, rdev)' but this - is more portable */ - if (S_ISREG(mode)) { - res = open(path, O_CREAT | O_EXCL | O_WRONLY, mode); - if (res >= 0) - res = close(res); - } else if (S_ISFIFO(mode)) - res = mkfifo(path, mode); - else - res = mknod(path, mode, rdev); - if (res == -1) - return -errno; - - return 0; -} - -static int xmp_mkdir(const char *path, mode_t mode) -{ - int res; - - res = mkdir(path, mode); - if (res == -1) - return -errno; - - return 0; -} - -static int xmp_unlink(const char *path) -{ - int res; - - res = unlink(path); - if (res == -1) - return -errno; - - return 0; -} - -static int xmp_rmdir(const char *path) -{ - int res; - - res = rmdir(path); - if (res == -1) - return -errno; - - return 0; -} - -static int xmp_symlink(const char *from, const char *to) -{ - int res; - - res = symlink(from, to); - if (res == -1) - return -errno; - - return 0; -} - -static int xmp_rename(const char *from, const char *to, unsigned int flags) -{ - int res; - - if (flags) - return -EINVAL; - - res = rename(from, to); - if (res == -1) - return -errno; - - return 0; -} - -static int xmp_link(const char *from, const char *to) -{ - int res; - - res = link(from, to); - if (res == -1) - return -errno; - - return 0; -} - -static int xmp_chmod(const char *path, mode_t mode) -{ - int res; - - res = chmod(path, mode); - if (res == -1) - return -errno; - - return 0; -} - -static int xmp_chown(const char *path, uid_t uid, gid_t gid) -{ - int res; - - res = lchown(path, uid, gid); - if (res == -1) - return -errno; - - return 0; -} - -static int xmp_truncate(const char *path, off_t size) -{ - int res; - - res = truncate(path, size); - if (res == -1) - return -errno; - - return 0; -} - -#ifdef HAVE_UTIMENSAT -static int xmp_utimens(const char *path, const struct timespec ts[2]) -{ - int res; - - /* don't use utime/utimes since they follow symlinks */ - res = utimensat(0, path, ts, AT_SYMLINK_NOFOLLOW); - if (res == -1) - return -errno; - - return 0; -} -#endif - -static int xmp_open(const char *path, struct fuse_file_info *fi) -{ - int res; - - res = open(path, fi->flags); - if (res == -1) - return -errno; - - close(res); - return 0; -} - -static int xmp_read(const char *path, char *buf, size_t size, off_t offset, - struct fuse_file_info *fi) -{ - int fd; - int res; - - (void) fi; - fd = open(path, O_RDONLY); - if (fd == -1) - return -errno; - - res = pread(fd, buf, size, offset); - if (res == -1) - res = -errno; - - close(fd); - return res; -} - -static int xmp_write(const char *path, const char *buf, size_t size, - off_t offset, struct fuse_file_info *fi) -{ - int fd; - int res; - - (void) fi; - fd = open(path, O_WRONLY); - if (fd == -1) - return -errno; - - res = pwrite(fd, buf, size, offset); - if (res == -1) - res = -errno; - - close(fd); - return res; -} - -static int xmp_statfs(const char *path, struct statvfs *stbuf) -{ - int res; - - res = statvfs(path, stbuf); - if (res == -1) - return -errno; - - return 0; -} - -static int xmp_release(const char *path, struct fuse_file_info *fi) -{ - /* Just a stub. This method is optional and can safely be left - unimplemented */ - - (void) path; - (void) fi; - return 0; -} - -static int xmp_fsync(const char *path, int isdatasync, - struct fuse_file_info *fi) -{ - /* Just a stub. This method is optional and can safely be left - unimplemented */ - - (void) path; - (void) isdatasync; - (void) fi; - return 0; -} - -#ifdef HAVE_POSIX_FALLOCATE -static int xmp_fallocate(const char *path, int mode, - off_t offset, off_t length, struct fuse_file_info *fi) -{ - int fd; - int res; - - (void) fi; - - if (mode) - return -EOPNOTSUPP; - - fd = open(path, O_WRONLY); - if (fd == -1) - return -errno; - - res = -posix_fallocate(fd, offset, length); - - close(fd); - return res; -} -#endif - -#ifdef HAVE_SETXATTR -/* xattr operations are optional and can safely be left unimplemented */ -static int xmp_setxattr(const char *path, const char *name, const char *value, - size_t size, int flags) -{ - int res = lsetxattr(path, name, value, size, flags); - if (res == -1) - return -errno; - return 0; -} - -static int xmp_getxattr(const char *path, const char *name, char *value, - size_t size) -{ - int res = lgetxattr(path, name, value, size); - if (res == -1) - return -errno; - return res; -} - -static int xmp_listxattr(const char *path, char *list, size_t size) -{ - int res = llistxattr(path, list, size); - if (res == -1) - return -errno; - return res; -} - -static int xmp_removexattr(const char *path, const char *name) -{ - int res = lremovexattr(path, name); - if (res == -1) - return -errno; - return 0; -} -#endif /* HAVE_SETXATTR */ - -static struct fuse_operations xmp_oper = { - .getattr = xmp_getattr, - .access = xmp_access, - .readlink = xmp_readlink, - .readdir = xmp_readdir, - .mknod = xmp_mknod, - .mkdir = xmp_mkdir, - .symlink = xmp_symlink, - .unlink = xmp_unlink, - .rmdir = xmp_rmdir, - .rename = xmp_rename, - .link = xmp_link, - .chmod = xmp_chmod, - .chown = xmp_chown, - .truncate = xmp_truncate, -#ifdef HAVE_UTIMENSAT - .utimens = xmp_utimens, -#endif - .open = xmp_open, - .read = xmp_read, - .write = xmp_write, - .statfs = xmp_statfs, - .release = xmp_release, - .fsync = xmp_fsync, -#ifdef HAVE_POSIX_FALLOCATE - .fallocate = xmp_fallocate, -#endif -#ifdef HAVE_SETXATTR - .setxattr = xmp_setxattr, - .getxattr = xmp_getxattr, - .listxattr = xmp_listxattr, - .removexattr = xmp_removexattr, -#endif -}; - -int main(int argc, char *argv[]) -{ - umask(0); - return fuse_main(argc, argv, &xmp_oper, NULL); -} diff --git a/example/fusexmp_fh.c b/example/fusexmp_fh.c deleted file mode 100644 index 84fce3f..0000000 --- a/example/fusexmp_fh.c +++ /dev/null @@ -1,598 +0,0 @@ -/* - FUSE: Filesystem in Userspace - Copyright (C) 2001-2007 Miklos Szeredi - Copyright (C) 2011 Sebastian Pipping - - This program can be distributed under the terms of the GNU GPL. - See the file COPYING. -*/ - -/** @file - * @tableofcontents - * - * fusexmp_fh.c - FUSE: Filesystem in Userspace - * - * \section section_compile compiling this example - * - * gcc -Wall fusexmp_fh.c `pkg-config fuse3 --cflags --libs` -lulockmgr -o fusexmp_fh - * - * \section section_source the complete source - * \include fusexmp_fh.c - */ - -#define FUSE_USE_VERSION 30 - -#ifdef HAVE_CONFIG_H -#include -#endif - -#define _GNU_SOURCE - -#include - -#ifdef HAVE_LIBULOCKMGR -#include -#endif - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#ifdef HAVE_SETXATTR -#include -#endif -#include /* flock(2) */ - -static int xmp_getattr(const char *path, struct stat *stbuf) -{ - int res; - - res = lstat(path, stbuf); - if (res == -1) - return -errno; - - return 0; -} - -static int xmp_fgetattr(const char *path, struct stat *stbuf, - struct fuse_file_info *fi) -{ - int res; - - (void) path; - - res = fstat(fi->fh, stbuf); - if (res == -1) - return -errno; - - return 0; -} - -static int xmp_access(const char *path, int mask) -{ - int res; - - res = access(path, mask); - if (res == -1) - return -errno; - - return 0; -} - -static int xmp_readlink(const char *path, char *buf, size_t size) -{ - int res; - - res = readlink(path, buf, size - 1); - if (res == -1) - return -errno; - - buf[res] = '\0'; - return 0; -} - -struct xmp_dirp { - DIR *dp; - struct dirent *entry; - off_t offset; -}; - -static int xmp_opendir(const char *path, struct fuse_file_info *fi) -{ - int res; - struct xmp_dirp *d = malloc(sizeof(struct xmp_dirp)); - if (d == NULL) - return -ENOMEM; - - d->dp = opendir(path); - if (d->dp == NULL) { - res = -errno; - free(d); - return res; - } - d->offset = 0; - d->entry = NULL; - - fi->fh = (unsigned long) d; - return 0; -} - -static inline struct xmp_dirp *get_dirp(struct fuse_file_info *fi) -{ - return (struct xmp_dirp *) (uintptr_t) fi->fh; -} - -static int xmp_readdir(const char *path, void *buf, fuse_fill_dir_t filler, - off_t offset, struct fuse_file_info *fi, - enum fuse_readdir_flags flags) -{ - struct xmp_dirp *d = get_dirp(fi); - - (void) path; - if (offset != d->offset) { - seekdir(d->dp, offset); - d->entry = NULL; - d->offset = offset; - } - while (1) { - struct stat st; - off_t nextoff; - enum fuse_fill_dir_flags fill_flags = 0; - - if (!d->entry) { - d->entry = readdir(d->dp); - if (!d->entry) - break; - } -#ifdef HAVE_FSTATAT - if (flags & FUSE_READDIR_PLUS) { - int res; - - res = fstatat(dirfd(d->dp), d->entry->d_name, &st, - AT_SYMLINK_NOFOLLOW); - if (res != -1) - fill_flags |= FUSE_FILL_DIR_PLUS; - } -#endif - if (!(fill_flags & FUSE_FILL_DIR_PLUS)) { - memset(&st, 0, sizeof(st)); - st.st_ino = d->entry->d_ino; - st.st_mode = d->entry->d_type << 12; - } - nextoff = telldir(d->dp); - if (filler(buf, d->entry->d_name, &st, nextoff, fill_flags)) - break; - - d->entry = NULL; - d->offset = nextoff; - } - - return 0; -} - -static int xmp_releasedir(const char *path, struct fuse_file_info *fi) -{ - struct xmp_dirp *d = get_dirp(fi); - (void) path; - closedir(d->dp); - free(d); - return 0; -} - -static int xmp_mknod(const char *path, mode_t mode, dev_t rdev) -{ - int res; - - if (S_ISFIFO(mode)) - res = mkfifo(path, mode); - else - res = mknod(path, mode, rdev); - if (res == -1) - return -errno; - - return 0; -} - -static int xmp_mkdir(const char *path, mode_t mode) -{ - int res; - - res = mkdir(path, mode); - if (res == -1) - return -errno; - - return 0; -} - -static int xmp_unlink(const char *path) -{ - int res; - - res = unlink(path); - if (res == -1) - return -errno; - - return 0; -} - -static int xmp_rmdir(const char *path) -{ - int res; - - res = rmdir(path); - if (res == -1) - return -errno; - - return 0; -} - -static int xmp_symlink(const char *from, const char *to) -{ - int res; - - res = symlink(from, to); - if (res == -1) - return -errno; - - return 0; -} - -static int xmp_rename(const char *from, const char *to, unsigned int flags) -{ - int res; - - /* When we have renameat2() in libc, then we can implement flags */ - if (flags) - return -EINVAL; - - res = rename(from, to); - if (res == -1) - return -errno; - - return 0; -} - -static int xmp_link(const char *from, const char *to) -{ - int res; - - res = link(from, to); - if (res == -1) - return -errno; - - return 0; -} - -static int xmp_chmod(const char *path, mode_t mode) -{ - int res; - - res = chmod(path, mode); - if (res == -1) - return -errno; - - return 0; -} - -static int xmp_chown(const char *path, uid_t uid, gid_t gid) -{ - int res; - - res = lchown(path, uid, gid); - if (res == -1) - return -errno; - - return 0; -} - -static int xmp_truncate(const char *path, off_t size) -{ - int res; - - res = truncate(path, size); - if (res == -1) - return -errno; - - return 0; -} - -static int xmp_ftruncate(const char *path, off_t size, - struct fuse_file_info *fi) -{ - int res; - - (void) path; - - res = ftruncate(fi->fh, size); - if (res == -1) - return -errno; - - return 0; -} - -#ifdef HAVE_UTIMENSAT -static int xmp_utimens(const char *path, const struct timespec ts[2]) -{ - int res; - - /* don't use utime/utimes since they follow symlinks */ - res = utimensat(0, path, ts, AT_SYMLINK_NOFOLLOW); - if (res == -1) - return -errno; - - return 0; -} -#endif - -static int xmp_create(const char *path, mode_t mode, struct fuse_file_info *fi) -{ - int fd; - - fd = open(path, fi->flags, mode); - if (fd == -1) - return -errno; - - fi->fh = fd; - return 0; -} - -static int xmp_open(const char *path, struct fuse_file_info *fi) -{ - int fd; - - fd = open(path, fi->flags); - if (fd == -1) - return -errno; - - fi->fh = fd; - return 0; -} - -static int xmp_read(const char *path, char *buf, size_t size, off_t offset, - struct fuse_file_info *fi) -{ - int res; - - (void) path; - res = pread(fi->fh, buf, size, offset); - if (res == -1) - res = -errno; - - return res; -} - -static int xmp_read_buf(const char *path, struct fuse_bufvec **bufp, - size_t size, off_t offset, struct fuse_file_info *fi) -{ - struct fuse_bufvec *src; - - (void) path; - - src = malloc(sizeof(struct fuse_bufvec)); - if (src == NULL) - return -ENOMEM; - - *src = FUSE_BUFVEC_INIT(size); - - src->buf[0].flags = FUSE_BUF_IS_FD | FUSE_BUF_FD_SEEK; - src->buf[0].fd = fi->fh; - src->buf[0].pos = offset; - - *bufp = src; - - return 0; -} - -static int xmp_write(const char *path, const char *buf, size_t size, - off_t offset, struct fuse_file_info *fi) -{ - int res; - - (void) path; - res = pwrite(fi->fh, buf, size, offset); - if (res == -1) - res = -errno; - - return res; -} - -static int xmp_write_buf(const char *path, struct fuse_bufvec *buf, - off_t offset, struct fuse_file_info *fi) -{ - struct fuse_bufvec dst = FUSE_BUFVEC_INIT(fuse_buf_size(buf)); - - (void) path; - - dst.buf[0].flags = FUSE_BUF_IS_FD | FUSE_BUF_FD_SEEK; - dst.buf[0].fd = fi->fh; - dst.buf[0].pos = offset; - - return fuse_buf_copy(&dst, buf, FUSE_BUF_SPLICE_NONBLOCK); -} - -static int xmp_statfs(const char *path, struct statvfs *stbuf) -{ - int res; - - res = statvfs(path, stbuf); - if (res == -1) - return -errno; - - return 0; -} - -static int xmp_flush(const char *path, struct fuse_file_info *fi) -{ - int res; - - (void) path; - /* This is called from every close on an open file, so call the - close on the underlying filesystem. But since flush may be - called multiple times for an open file, this must not really - close the file. This is important if used on a network - filesystem like NFS which flush the data/metadata on close() */ - res = close(dup(fi->fh)); - if (res == -1) - return -errno; - - return 0; -} - -static int xmp_release(const char *path, struct fuse_file_info *fi) -{ - (void) path; - close(fi->fh); - - return 0; -} - -static int xmp_fsync(const char *path, int isdatasync, - struct fuse_file_info *fi) -{ - int res; - (void) path; - -#ifndef HAVE_FDATASYNC - (void) isdatasync; -#else - if (isdatasync) - res = fdatasync(fi->fh); - else -#endif - res = fsync(fi->fh); - if (res == -1) - return -errno; - - return 0; -} - -#ifdef HAVE_POSIX_FALLOCATE -static int xmp_fallocate(const char *path, int mode, - off_t offset, off_t length, struct fuse_file_info *fi) -{ - (void) path; - - if (mode) - return -EOPNOTSUPP; - - return -posix_fallocate(fi->fh, offset, length); -} -#endif - -#ifdef HAVE_SETXATTR -/* xattr operations are optional and can safely be left unimplemented */ -static int xmp_setxattr(const char *path, const char *name, const char *value, - size_t size, int flags) -{ - int res = lsetxattr(path, name, value, size, flags); - if (res == -1) - return -errno; - return 0; -} - -static int xmp_getxattr(const char *path, const char *name, char *value, - size_t size) -{ - int res = lgetxattr(path, name, value, size); - if (res == -1) - return -errno; - return res; -} - -static int xmp_listxattr(const char *path, char *list, size_t size) -{ - int res = llistxattr(path, list, size); - if (res == -1) - return -errno; - return res; -} - -static int xmp_removexattr(const char *path, const char *name) -{ - int res = lremovexattr(path, name); - if (res == -1) - return -errno; - return 0; -} -#endif /* HAVE_SETXATTR */ - -#ifdef HAVE_LIBULOCKMGR -static int xmp_lock(const char *path, struct fuse_file_info *fi, int cmd, - struct flock *lock) -{ - (void) path; - - return ulockmgr_op(fi->fh, cmd, lock, &fi->lock_owner, - sizeof(fi->lock_owner)); -} -#endif - -static int xmp_flock(const char *path, struct fuse_file_info *fi, int op) -{ - int res; - (void) path; - - res = flock(fi->fh, op); - if (res == -1) - return -errno; - - return 0; -} - -static struct fuse_operations xmp_oper = { - .getattr = xmp_getattr, - .fgetattr = xmp_fgetattr, - .access = xmp_access, - .readlink = xmp_readlink, - .opendir = xmp_opendir, - .readdir = xmp_readdir, - .releasedir = xmp_releasedir, - .mknod = xmp_mknod, - .mkdir = xmp_mkdir, - .symlink = xmp_symlink, - .unlink = xmp_unlink, - .rmdir = xmp_rmdir, - .rename = xmp_rename, - .link = xmp_link, - .chmod = xmp_chmod, - .chown = xmp_chown, - .truncate = xmp_truncate, - .ftruncate = xmp_ftruncate, -#ifdef HAVE_UTIMENSAT - .utimens = xmp_utimens, -#endif - .create = xmp_create, - .open = xmp_open, - .read = xmp_read, - .read_buf = xmp_read_buf, - .write = xmp_write, - .write_buf = xmp_write_buf, - .statfs = xmp_statfs, - .flush = xmp_flush, - .release = xmp_release, - .fsync = xmp_fsync, -#ifdef HAVE_POSIX_FALLOCATE - .fallocate = xmp_fallocate, -#endif -#ifdef HAVE_SETXATTR - .setxattr = xmp_setxattr, - .getxattr = xmp_getxattr, - .listxattr = xmp_listxattr, - .removexattr = xmp_removexattr, -#endif -#ifdef HAVE_LIBULOCKMGR - .lock = xmp_lock, -#endif - .flock = xmp_flock, -}; - -int main(int argc, char *argv[]) -{ - umask(0); - return fuse_main(argc, argv, &xmp_oper, NULL); -} diff --git a/example/passthrough.c b/example/passthrough.c new file mode 100644 index 0000000..cf72cb2 --- /dev/null +++ b/example/passthrough.c @@ -0,0 +1,432 @@ +/* + FUSE: Filesystem in Userspace + Copyright (C) 2001-2007 Miklos Szeredi + Copyright (C) 2011 Sebastian Pipping + + This program can be distributed under the terms of the GNU GPL. + See the file COPYING. +*/ + +/** @file + * @tableofcontents + * + * This file system mirrors the existing file system hierarchy of the + * system, starting at the root file system. This is implemented by + * just "passing through" all requests to the corresponding user-space + * libc functions. It's performance is terrible. + * + * \section section_compile compiling this example + * + * gcc -Wall passthrough.c `pkg-config fuse3 --cflags --libs` -o passthrough + * + * \section section_source the complete source + * \include passthrough.c + */ + + +#define FUSE_USE_VERSION 30 + +#ifdef HAVE_CONFIG_H +#include +#endif + +#ifdef linux +/* For pread()/pwrite()/utimensat() */ +#define _XOPEN_SOURCE 700 +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#ifdef HAVE_SETXATTR +#include +#endif + +static int xmp_getattr(const char *path, struct stat *stbuf) +{ + int res; + + res = lstat(path, stbuf); + if (res == -1) + return -errno; + + return 0; +} + +static int xmp_access(const char *path, int mask) +{ + int res; + + res = access(path, mask); + if (res == -1) + return -errno; + + return 0; +} + +static int xmp_readlink(const char *path, char *buf, size_t size) +{ + int res; + + res = readlink(path, buf, size - 1); + if (res == -1) + return -errno; + + buf[res] = '\0'; + return 0; +} + + +static int xmp_readdir(const char *path, void *buf, fuse_fill_dir_t filler, + off_t offset, struct fuse_file_info *fi, + enum fuse_readdir_flags flags) +{ + DIR *dp; + struct dirent *de; + + (void) offset; + (void) fi; + (void) flags; + + dp = opendir(path); + if (dp == NULL) + return -errno; + + while ((de = readdir(dp)) != NULL) { + struct stat st; + memset(&st, 0, sizeof(st)); + st.st_ino = de->d_ino; + st.st_mode = de->d_type << 12; + if (filler(buf, de->d_name, &st, 0, 0)) + break; + } + + closedir(dp); + return 0; +} + +static int xmp_mknod(const char *path, mode_t mode, dev_t rdev) +{ + int res; + + /* On Linux this could just be 'mknod(path, mode, rdev)' but this + is more portable */ + if (S_ISREG(mode)) { + res = open(path, O_CREAT | O_EXCL | O_WRONLY, mode); + if (res >= 0) + res = close(res); + } else if (S_ISFIFO(mode)) + res = mkfifo(path, mode); + else + res = mknod(path, mode, rdev); + if (res == -1) + return -errno; + + return 0; +} + +static int xmp_mkdir(const char *path, mode_t mode) +{ + int res; + + res = mkdir(path, mode); + if (res == -1) + return -errno; + + return 0; +} + +static int xmp_unlink(const char *path) +{ + int res; + + res = unlink(path); + if (res == -1) + return -errno; + + return 0; +} + +static int xmp_rmdir(const char *path) +{ + int res; + + res = rmdir(path); + if (res == -1) + return -errno; + + return 0; +} + +static int xmp_symlink(const char *from, const char *to) +{ + int res; + + res = symlink(from, to); + if (res == -1) + return -errno; + + return 0; +} + +static int xmp_rename(const char *from, const char *to, unsigned int flags) +{ + int res; + + if (flags) + return -EINVAL; + + res = rename(from, to); + if (res == -1) + return -errno; + + return 0; +} + +static int xmp_link(const char *from, const char *to) +{ + int res; + + res = link(from, to); + if (res == -1) + return -errno; + + return 0; +} + +static int xmp_chmod(const char *path, mode_t mode) +{ + int res; + + res = chmod(path, mode); + if (res == -1) + return -errno; + + return 0; +} + +static int xmp_chown(const char *path, uid_t uid, gid_t gid) +{ + int res; + + res = lchown(path, uid, gid); + if (res == -1) + return -errno; + + return 0; +} + +static int xmp_truncate(const char *path, off_t size) +{ + int res; + + res = truncate(path, size); + if (res == -1) + return -errno; + + return 0; +} + +#ifdef HAVE_UTIMENSAT +static int xmp_utimens(const char *path, const struct timespec ts[2]) +{ + int res; + + /* don't use utime/utimes since they follow symlinks */ + res = utimensat(0, path, ts, AT_SYMLINK_NOFOLLOW); + if (res == -1) + return -errno; + + return 0; +} +#endif + +static int xmp_open(const char *path, struct fuse_file_info *fi) +{ + int res; + + res = open(path, fi->flags); + if (res == -1) + return -errno; + + close(res); + return 0; +} + +static int xmp_read(const char *path, char *buf, size_t size, off_t offset, + struct fuse_file_info *fi) +{ + int fd; + int res; + + (void) fi; + fd = open(path, O_RDONLY); + if (fd == -1) + return -errno; + + res = pread(fd, buf, size, offset); + if (res == -1) + res = -errno; + + close(fd); + return res; +} + +static int xmp_write(const char *path, const char *buf, size_t size, + off_t offset, struct fuse_file_info *fi) +{ + int fd; + int res; + + (void) fi; + fd = open(path, O_WRONLY); + if (fd == -1) + return -errno; + + res = pwrite(fd, buf, size, offset); + if (res == -1) + res = -errno; + + close(fd); + return res; +} + +static int xmp_statfs(const char *path, struct statvfs *stbuf) +{ + int res; + + res = statvfs(path, stbuf); + if (res == -1) + return -errno; + + return 0; +} + +static int xmp_release(const char *path, struct fuse_file_info *fi) +{ + /* Just a stub. This method is optional and can safely be left + unimplemented */ + + (void) path; + (void) fi; + return 0; +} + +static int xmp_fsync(const char *path, int isdatasync, + struct fuse_file_info *fi) +{ + /* Just a stub. This method is optional and can safely be left + unimplemented */ + + (void) path; + (void) isdatasync; + (void) fi; + return 0; +} + +#ifdef HAVE_POSIX_FALLOCATE +static int xmp_fallocate(const char *path, int mode, + off_t offset, off_t length, struct fuse_file_info *fi) +{ + int fd; + int res; + + (void) fi; + + if (mode) + return -EOPNOTSUPP; + + fd = open(path, O_WRONLY); + if (fd == -1) + return -errno; + + res = -posix_fallocate(fd, offset, length); + + close(fd); + return res; +} +#endif + +#ifdef HAVE_SETXATTR +/* xattr operations are optional and can safely be left unimplemented */ +static int xmp_setxattr(const char *path, const char *name, const char *value, + size_t size, int flags) +{ + int res = lsetxattr(path, name, value, size, flags); + if (res == -1) + return -errno; + return 0; +} + +static int xmp_getxattr(const char *path, const char *name, char *value, + size_t size) +{ + int res = lgetxattr(path, name, value, size); + if (res == -1) + return -errno; + return res; +} + +static int xmp_listxattr(const char *path, char *list, size_t size) +{ + int res = llistxattr(path, list, size); + if (res == -1) + return -errno; + return res; +} + +static int xmp_removexattr(const char *path, const char *name) +{ + int res = lremovexattr(path, name); + if (res == -1) + return -errno; + return 0; +} +#endif /* HAVE_SETXATTR */ + +static struct fuse_operations xmp_oper = { + .getattr = xmp_getattr, + .access = xmp_access, + .readlink = xmp_readlink, + .readdir = xmp_readdir, + .mknod = xmp_mknod, + .mkdir = xmp_mkdir, + .symlink = xmp_symlink, + .unlink = xmp_unlink, + .rmdir = xmp_rmdir, + .rename = xmp_rename, + .link = xmp_link, + .chmod = xmp_chmod, + .chown = xmp_chown, + .truncate = xmp_truncate, +#ifdef HAVE_UTIMENSAT + .utimens = xmp_utimens, +#endif + .open = xmp_open, + .read = xmp_read, + .write = xmp_write, + .statfs = xmp_statfs, + .release = xmp_release, + .fsync = xmp_fsync, +#ifdef HAVE_POSIX_FALLOCATE + .fallocate = xmp_fallocate, +#endif +#ifdef HAVE_SETXATTR + .setxattr = xmp_setxattr, + .getxattr = xmp_getxattr, + .listxattr = xmp_listxattr, + .removexattr = xmp_removexattr, +#endif +}; + +int main(int argc, char *argv[]) +{ + umask(0); + return fuse_main(argc, argv, &xmp_oper, NULL); +} diff --git a/example/passthrough_fh.c b/example/passthrough_fh.c new file mode 100644 index 0000000..a179f65 --- /dev/null +++ b/example/passthrough_fh.c @@ -0,0 +1,602 @@ +/* + FUSE: Filesystem in Userspace + Copyright (C) 2001-2007 Miklos Szeredi + Copyright (C) 2011 Sebastian Pipping + + This program can be distributed under the terms of the GNU GPL. + See the file COPYING. +*/ + +/** @file + * @tableofcontents + * + * This file system mirrors the existing file system hierarchy of the + * system, starting at the root file system. This is implemented by + * just "passing through" all requests to the corresponding user-space + * libc functions. This implementation is a little more sophisticated + * than the one in passthrough.c, so performance is not quite as bad. + * + * \section section_compile compiling this example + * + * gcc -Wall passthrough_fh.c `pkg-config fuse3 --cflags --libs` -lulockmgr -o passthrough_fh + * + * \section section_source the complete source + * \include passthrough_fh.c + */ + +#define FUSE_USE_VERSION 30 + +#ifdef HAVE_CONFIG_H +#include +#endif + +#define _GNU_SOURCE + +#include + +#ifdef HAVE_LIBULOCKMGR +#include +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#ifdef HAVE_SETXATTR +#include +#endif +#include /* flock(2) */ + +static int xmp_getattr(const char *path, struct stat *stbuf) +{ + int res; + + res = lstat(path, stbuf); + if (res == -1) + return -errno; + + return 0; +} + +static int xmp_fgetattr(const char *path, struct stat *stbuf, + struct fuse_file_info *fi) +{ + int res; + + (void) path; + + res = fstat(fi->fh, stbuf); + if (res == -1) + return -errno; + + return 0; +} + +static int xmp_access(const char *path, int mask) +{ + int res; + + res = access(path, mask); + if (res == -1) + return -errno; + + return 0; +} + +static int xmp_readlink(const char *path, char *buf, size_t size) +{ + int res; + + res = readlink(path, buf, size - 1); + if (res == -1) + return -errno; + + buf[res] = '\0'; + return 0; +} + +struct xmp_dirp { + DIR *dp; + struct dirent *entry; + off_t offset; +}; + +static int xmp_opendir(const char *path, struct fuse_file_info *fi) +{ + int res; + struct xmp_dirp *d = malloc(sizeof(struct xmp_dirp)); + if (d == NULL) + return -ENOMEM; + + d->dp = opendir(path); + if (d->dp == NULL) { + res = -errno; + free(d); + return res; + } + d->offset = 0; + d->entry = NULL; + + fi->fh = (unsigned long) d; + return 0; +} + +static inline struct xmp_dirp *get_dirp(struct fuse_file_info *fi) +{ + return (struct xmp_dirp *) (uintptr_t) fi->fh; +} + +static int xmp_readdir(const char *path, void *buf, fuse_fill_dir_t filler, + off_t offset, struct fuse_file_info *fi, + enum fuse_readdir_flags flags) +{ + struct xmp_dirp *d = get_dirp(fi); + + (void) path; + if (offset != d->offset) { + seekdir(d->dp, offset); + d->entry = NULL; + d->offset = offset; + } + while (1) { + struct stat st; + off_t nextoff; + enum fuse_fill_dir_flags fill_flags = 0; + + if (!d->entry) { + d->entry = readdir(d->dp); + if (!d->entry) + break; + } +#ifdef HAVE_FSTATAT + if (flags & FUSE_READDIR_PLUS) { + int res; + + res = fstatat(dirfd(d->dp), d->entry->d_name, &st, + AT_SYMLINK_NOFOLLOW); + if (res != -1) + fill_flags |= FUSE_FILL_DIR_PLUS; + } +#endif + if (!(fill_flags & FUSE_FILL_DIR_PLUS)) { + memset(&st, 0, sizeof(st)); + st.st_ino = d->entry->d_ino; + st.st_mode = d->entry->d_type << 12; + } + nextoff = telldir(d->dp); + if (filler(buf, d->entry->d_name, &st, nextoff, fill_flags)) + break; + + d->entry = NULL; + d->offset = nextoff; + } + + return 0; +} + +static int xmp_releasedir(const char *path, struct fuse_file_info *fi) +{ + struct xmp_dirp *d = get_dirp(fi); + (void) path; + closedir(d->dp); + free(d); + return 0; +} + +static int xmp_mknod(const char *path, mode_t mode, dev_t rdev) +{ + int res; + + if (S_ISFIFO(mode)) + res = mkfifo(path, mode); + else + res = mknod(path, mode, rdev); + if (res == -1) + return -errno; + + return 0; +} + +static int xmp_mkdir(const char *path, mode_t mode) +{ + int res; + + res = mkdir(path, mode); + if (res == -1) + return -errno; + + return 0; +} + +static int xmp_unlink(const char *path) +{ + int res; + + res = unlink(path); + if (res == -1) + return -errno; + + return 0; +} + +static int xmp_rmdir(const char *path) +{ + int res; + + res = rmdir(path); + if (res == -1) + return -errno; + + return 0; +} + +static int xmp_symlink(const char *from, const char *to) +{ + int res; + + res = symlink(from, to); + if (res == -1) + return -errno; + + return 0; +} + +static int xmp_rename(const char *from, const char *to, unsigned int flags) +{ + int res; + + /* When we have renameat2() in libc, then we can implement flags */ + if (flags) + return -EINVAL; + + res = rename(from, to); + if (res == -1) + return -errno; + + return 0; +} + +static int xmp_link(const char *from, const char *to) +{ + int res; + + res = link(from, to); + if (res == -1) + return -errno; + + return 0; +} + +static int xmp_chmod(const char *path, mode_t mode) +{ + int res; + + res = chmod(path, mode); + if (res == -1) + return -errno; + + return 0; +} + +static int xmp_chown(const char *path, uid_t uid, gid_t gid) +{ + int res; + + res = lchown(path, uid, gid); + if (res == -1) + return -errno; + + return 0; +} + +static int xmp_truncate(const char *path, off_t size) +{ + int res; + + res = truncate(path, size); + if (res == -1) + return -errno; + + return 0; +} + +static int xmp_ftruncate(const char *path, off_t size, + struct fuse_file_info *fi) +{ + int res; + + (void) path; + + res = ftruncate(fi->fh, size); + if (res == -1) + return -errno; + + return 0; +} + +#ifdef HAVE_UTIMENSAT +static int xmp_utimens(const char *path, const struct timespec ts[2]) +{ + int res; + + /* don't use utime/utimes since they follow symlinks */ + res = utimensat(0, path, ts, AT_SYMLINK_NOFOLLOW); + if (res == -1) + return -errno; + + return 0; +} +#endif + +static int xmp_create(const char *path, mode_t mode, struct fuse_file_info *fi) +{ + int fd; + + fd = open(path, fi->flags, mode); + if (fd == -1) + return -errno; + + fi->fh = fd; + return 0; +} + +static int xmp_open(const char *path, struct fuse_file_info *fi) +{ + int fd; + + fd = open(path, fi->flags); + if (fd == -1) + return -errno; + + fi->fh = fd; + return 0; +} + +static int xmp_read(const char *path, char *buf, size_t size, off_t offset, + struct fuse_file_info *fi) +{ + int res; + + (void) path; + res = pread(fi->fh, buf, size, offset); + if (res == -1) + res = -errno; + + return res; +} + +static int xmp_read_buf(const char *path, struct fuse_bufvec **bufp, + size_t size, off_t offset, struct fuse_file_info *fi) +{ + struct fuse_bufvec *src; + + (void) path; + + src = malloc(sizeof(struct fuse_bufvec)); + if (src == NULL) + return -ENOMEM; + + *src = FUSE_BUFVEC_INIT(size); + + src->buf[0].flags = FUSE_BUF_IS_FD | FUSE_BUF_FD_SEEK; + src->buf[0].fd = fi->fh; + src->buf[0].pos = offset; + + *bufp = src; + + return 0; +} + +static int xmp_write(const char *path, const char *buf, size_t size, + off_t offset, struct fuse_file_info *fi) +{ + int res; + + (void) path; + res = pwrite(fi->fh, buf, size, offset); + if (res == -1) + res = -errno; + + return res; +} + +static int xmp_write_buf(const char *path, struct fuse_bufvec *buf, + off_t offset, struct fuse_file_info *fi) +{ + struct fuse_bufvec dst = FUSE_BUFVEC_INIT(fuse_buf_size(buf)); + + (void) path; + + dst.buf[0].flags = FUSE_BUF_IS_FD | FUSE_BUF_FD_SEEK; + dst.buf[0].fd = fi->fh; + dst.buf[0].pos = offset; + + return fuse_buf_copy(&dst, buf, FUSE_BUF_SPLICE_NONBLOCK); +} + +static int xmp_statfs(const char *path, struct statvfs *stbuf) +{ + int res; + + res = statvfs(path, stbuf); + if (res == -1) + return -errno; + + return 0; +} + +static int xmp_flush(const char *path, struct fuse_file_info *fi) +{ + int res; + + (void) path; + /* This is called from every close on an open file, so call the + close on the underlying filesystem. But since flush may be + called multiple times for an open file, this must not really + close the file. This is important if used on a network + filesystem like NFS which flush the data/metadata on close() */ + res = close(dup(fi->fh)); + if (res == -1) + return -errno; + + return 0; +} + +static int xmp_release(const char *path, struct fuse_file_info *fi) +{ + (void) path; + close(fi->fh); + + return 0; +} + +static int xmp_fsync(const char *path, int isdatasync, + struct fuse_file_info *fi) +{ + int res; + (void) path; + +#ifndef HAVE_FDATASYNC + (void) isdatasync; +#else + if (isdatasync) + res = fdatasync(fi->fh); + else +#endif + res = fsync(fi->fh); + if (res == -1) + return -errno; + + return 0; +} + +#ifdef HAVE_POSIX_FALLOCATE +static int xmp_fallocate(const char *path, int mode, + off_t offset, off_t length, struct fuse_file_info *fi) +{ + (void) path; + + if (mode) + return -EOPNOTSUPP; + + return -posix_fallocate(fi->fh, offset, length); +} +#endif + +#ifdef HAVE_SETXATTR +/* xattr operations are optional and can safely be left unimplemented */ +static int xmp_setxattr(const char *path, const char *name, const char *value, + size_t size, int flags) +{ + int res = lsetxattr(path, name, value, size, flags); + if (res == -1) + return -errno; + return 0; +} + +static int xmp_getxattr(const char *path, const char *name, char *value, + size_t size) +{ + int res = lgetxattr(path, name, value, size); + if (res == -1) + return -errno; + return res; +} + +static int xmp_listxattr(const char *path, char *list, size_t size) +{ + int res = llistxattr(path, list, size); + if (res == -1) + return -errno; + return res; +} + +static int xmp_removexattr(const char *path, const char *name) +{ + int res = lremovexattr(path, name); + if (res == -1) + return -errno; + return 0; +} +#endif /* HAVE_SETXATTR */ + +#ifdef HAVE_LIBULOCKMGR +static int xmp_lock(const char *path, struct fuse_file_info *fi, int cmd, + struct flock *lock) +{ + (void) path; + + return ulockmgr_op(fi->fh, cmd, lock, &fi->lock_owner, + sizeof(fi->lock_owner)); +} +#endif + +static int xmp_flock(const char *path, struct fuse_file_info *fi, int op) +{ + int res; + (void) path; + + res = flock(fi->fh, op); + if (res == -1) + return -errno; + + return 0; +} + +static struct fuse_operations xmp_oper = { + .getattr = xmp_getattr, + .fgetattr = xmp_fgetattr, + .access = xmp_access, + .readlink = xmp_readlink, + .opendir = xmp_opendir, + .readdir = xmp_readdir, + .releasedir = xmp_releasedir, + .mknod = xmp_mknod, + .mkdir = xmp_mkdir, + .symlink = xmp_symlink, + .unlink = xmp_unlink, + .rmdir = xmp_rmdir, + .rename = xmp_rename, + .link = xmp_link, + .chmod = xmp_chmod, + .chown = xmp_chown, + .truncate = xmp_truncate, + .ftruncate = xmp_ftruncate, +#ifdef HAVE_UTIMENSAT + .utimens = xmp_utimens, +#endif + .create = xmp_create, + .open = xmp_open, + .read = xmp_read, + .read_buf = xmp_read_buf, + .write = xmp_write, + .write_buf = xmp_write_buf, + .statfs = xmp_statfs, + .flush = xmp_flush, + .release = xmp_release, + .fsync = xmp_fsync, +#ifdef HAVE_POSIX_FALLOCATE + .fallocate = xmp_fallocate, +#endif +#ifdef HAVE_SETXATTR + .setxattr = xmp_setxattr, + .getxattr = xmp_getxattr, + .listxattr = xmp_listxattr, + .removexattr = xmp_removexattr, +#endif +#ifdef HAVE_LIBULOCKMGR + .lock = xmp_lock, +#endif + .flock = xmp_flock, +}; + +int main(int argc, char *argv[]) +{ + umask(0); + return fuse_main(argc, argv, &xmp_oper, NULL); +} diff --git a/example/passthrough_ll.c b/example/passthrough_ll.c new file mode 100644 index 0000000..66f92cf --- /dev/null +++ b/example/passthrough_ll.c @@ -0,0 +1,522 @@ +/* + FUSE: Filesystem in Userspace + Copyright (C) 2001-2007 Miklos Szeredi + + This program can be distributed under the terms of the GNU GPL. + See the file COPYING. +*/ + +/** @file + * @tableofcontents + * + * This file system mirrors the existing file system hierarchy of the + * system, starting at the root file system. This is implemented by + * just "passing through" all requests to the corresponding user-space + * libc functions. In contrast to passthrough.c and passthrough_fh.c, + * this implementation ises the low-level API. Its performance should + * be the least bad among the three. + * + * \section section_compile compiling this example + * + * gcc -Wall passthrough_ll.c `pkg-config fuse3 --cflags --libs` -o passthrough_ll + * + * \section section_source the complete source + * \include passthrough_ll.c + */ + +#define _GNU_SOURCE +#define FUSE_USE_VERSION 30 + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* Compat stuff. Doesn't make it work, just makes it compile. */ +#ifndef HAVE_FSTATAT +#warning fstatat(2) needed by this program +int fstatat(int dirfd, const char *pathname, struct stat *buf, int flags) +{ + errno = ENOSYS; + return -1; +} +#endif +#ifndef HAVE_OPENAT +#warning openat(2) needed by this program +int openat(int dirfd, const char *pathname, int flags, ...) +{ + errno = ENOSYS; + return -1; +} +#endif +#ifndef HAVE_READLINKAT +#warning readlinkat(2) needed by this program +ssize_t readlinkat(int dirfd, const char *pathname, char *buf, size_t bufsiz) +{ + errno = ENOSYS; + return -1; +} +#endif +#ifndef AT_EMPTY_PATH +#warning AT_EMPTY_PATH needed by this program +#define AT_EMPTY_PATH 0 +#endif +#ifndef AT_SYMLINK_NOFOLLOW +#warning AT_SYMLINK_NOFOLLOW needed by this program +#define AT_SYMLINK_NOFOLLOW 0 +#endif +#ifndef O_PATH +#warning O_PATH needed by this program +#define O_PATH 0 +#endif +#ifndef O_NOFOLLOW +#warning O_NOFOLLOW needed by this program +#define O_NOFOLLOW 0 +#endif + +struct lo_inode { + struct lo_inode *next; + struct lo_inode *prev; + int fd; + ino_t ino; + dev_t dev; + uint64_t nlookup; +}; + +struct lo_data { + int debug; + struct lo_inode root; +}; + +static struct lo_data *lo_data(fuse_req_t req) +{ + return (struct lo_data *) fuse_req_userdata(req); +} + +static struct lo_inode *lo_inode(fuse_req_t req, fuse_ino_t ino) +{ + if (ino == FUSE_ROOT_ID) + return &lo_data(req)->root; + else + return (struct lo_inode *) (uintptr_t) ino; +} + +static int lo_fd(fuse_req_t req, fuse_ino_t ino) +{ + return lo_inode(req, ino)->fd; +} + +static bool lo_debug(fuse_req_t req) +{ + return lo_data(req)->debug != 0; +} + +static void lo_getattr(fuse_req_t req, fuse_ino_t ino, + struct fuse_file_info *fi) +{ + int res; + struct stat buf; + (void) fi; + + res = fstatat(lo_fd(req, ino), "", &buf, AT_EMPTY_PATH | AT_SYMLINK_NOFOLLOW); + if (res == -1) + return (void) fuse_reply_err(req, errno); + + fuse_reply_attr(req, &buf, 1.0); +} + +static struct lo_inode *lo_find(struct lo_data *lo, struct stat *st) +{ + struct lo_inode *p; + + for (p = lo->root.next; p != &lo->root; p = p->next) { + if (p->ino == st->st_ino && p->dev == st->st_dev) + return p; + } + return NULL; +} + +static int lo_do_lookup(fuse_req_t req, fuse_ino_t parent, const char *name, + struct fuse_entry_param *e) +{ + int newfd; + int res; + int saverr; + struct lo_inode *inode; + + memset(e, 0, sizeof(*e)); + e->attr_timeout = 1.0; + e->entry_timeout = 1.0; + + newfd = openat(lo_fd(req, parent), name, O_PATH | O_NOFOLLOW); + if (newfd == -1) + goto out_err; + + res = fstatat(newfd, "", &e->attr, AT_EMPTY_PATH | AT_SYMLINK_NOFOLLOW); + if (res == -1) + goto out_err; + + inode = lo_find(lo_data(req), &e->attr); + if (inode) { + close(newfd); + newfd = -1; + } else { + struct lo_inode *prev = &lo_data(req)->root; + struct lo_inode *next = prev->next; + saverr = ENOMEM; + inode = calloc(1, sizeof(struct lo_inode)); + if (!inode) + goto out_err; + + inode->fd = newfd; + inode->ino = e->attr.st_ino; + inode->dev = e->attr.st_dev; + + next->prev = inode; + inode->next = next; + inode->prev = prev; + prev->next = inode; + } + inode->nlookup++; + e->ino = (uintptr_t) inode; + + if (lo_debug(req)) + fprintf(stderr, " %lli/%s -> %lli\n", + (unsigned long long) parent, name, (unsigned long long) e->ino); + + return 0; + +out_err: + saverr = errno; + if (newfd != -1) + close(newfd); + return saverr; +} + +static void lo_lookup(fuse_req_t req, fuse_ino_t parent, const char *name) +{ + struct fuse_entry_param e; + int err; + + err = lo_do_lookup(req, parent, name, &e); + if (err) + fuse_reply_err(req, err); + else + fuse_reply_entry(req, &e); +} + +static void lo_free(struct lo_inode *inode) +{ + struct lo_inode *prev = inode->prev; + struct lo_inode *next = inode->next; + + next->prev = prev; + prev->next = next; + close(inode->fd); + free(inode); +} + +static void lo_forget(fuse_req_t req, fuse_ino_t ino, uint64_t nlookup) +{ + struct lo_inode *inode = lo_inode(req, ino); + + if (lo_debug(req)) { + fprintf(stderr, " forget %lli %lli -%lli\n", + (unsigned long long) ino, (unsigned long long) inode->nlookup, + (unsigned long long) nlookup); + } + + assert(inode->nlookup >= nlookup); + inode->nlookup -= nlookup; + + if (!inode->nlookup) + lo_free(inode); + + fuse_reply_none(req); +} + +static void lo_readlink(fuse_req_t req, fuse_ino_t ino) +{ + char buf[PATH_MAX + 1]; + int res; + + res = readlinkat(lo_fd(req, ino), "", buf, sizeof(buf)); + if (res == -1) + return (void) fuse_reply_err(req, errno); + + if (res == sizeof(buf)) + return (void) fuse_reply_err(req, ENAMETOOLONG); + + buf[res] = '\0'; + + fuse_reply_readlink(req, buf); +} + +struct lo_dirp { + int fd; + DIR *dp; + struct dirent *entry; + off_t offset; +}; + +static struct lo_dirp *lo_dirp(struct fuse_file_info *fi) +{ + return (struct lo_dirp *) (uintptr_t) fi->fh; +} + +static void lo_opendir(fuse_req_t req, fuse_ino_t ino, struct fuse_file_info *fi) +{ + int error = ENOMEM; + struct lo_dirp *d = calloc(1, sizeof(struct lo_dirp)); + if (d == NULL) + goto out_err; + + d->fd = openat(lo_fd(req, ino), ".", O_RDONLY); + if (d->fd == -1) + goto out_errno; + + d->dp = fdopendir(d->fd); + if (d->dp == NULL) + goto out_errno; + + d->offset = 0; + d->entry = NULL; + + fi->fh = (uintptr_t) d; + fuse_reply_open(req, fi); + return; + +out_errno: + error = errno; +out_err: + if (d) { + if (d->fd != -1) + close(d->fd); + free(d); + } + fuse_reply_err(req, error); +} + +static void lo_do_readdir(fuse_req_t req, fuse_ino_t ino, size_t size, + off_t offset, struct fuse_file_info *fi, int plus) +{ + struct lo_dirp *d = lo_dirp(fi); + char *buf; + char *p; + size_t rem; + int err; + + (void) ino; + + buf = calloc(size, 1); + if (!buf) + return (void) fuse_reply_err(req, ENOMEM); + + if (offset != d->offset) { + seekdir(d->dp, offset); + d->entry = NULL; + d->offset = offset; + } + p = buf; + rem = size; + while (1) { + size_t entsize; + off_t nextoff; + + if (!d->entry) { + errno = 0; + d->entry = readdir(d->dp); + if (!d->entry) { + if (errno && rem == size) { + err = errno; + goto error; + } + break; + } + } + nextoff = telldir(d->dp); + if (plus) { + struct fuse_entry_param e; + + err = lo_do_lookup(req, ino, d->entry->d_name, &e); + if (err) + goto error; + + entsize = fuse_add_direntry_plus(req, p, rem, + d->entry->d_name, + &e, nextoff); + } else { + struct stat st = { + .st_ino = d->entry->d_ino, + .st_mode = d->entry->d_type << 12, + }; + entsize = fuse_add_direntry(req, p, rem, + d->entry->d_name, + &st, nextoff); + } + if (entsize > rem) + break; + + p += entsize; + rem -= entsize; + + d->entry = NULL; + d->offset = nextoff; + } + + fuse_reply_buf(req, buf, size - rem); + free(buf); + return; + +error: + free(buf); + fuse_reply_err(req, err); +} + +static void lo_readdir(fuse_req_t req, fuse_ino_t ino, size_t size, + off_t offset, struct fuse_file_info *fi) +{ + lo_do_readdir(req, ino, size, offset, fi, 0); +} + +static void lo_readdirplus(fuse_req_t req, fuse_ino_t ino, size_t size, + off_t offset, struct fuse_file_info *fi) +{ + lo_do_readdir(req, ino, size, offset, fi, 1); +} + +static void lo_releasedir(fuse_req_t req, fuse_ino_t ino, struct fuse_file_info *fi) +{ + struct lo_dirp *d = lo_dirp(fi); + (void) ino; + closedir(d->dp); + free(d); + fuse_reply_err(req, 0); +} + +static void lo_open(fuse_req_t req, fuse_ino_t ino, + struct fuse_file_info *fi) +{ + int fd; + char buf[64]; + + sprintf(buf, "/proc/self/fd/%i", lo_fd(req, ino)); + fd = open(buf, fi->flags & ~O_NOFOLLOW); + if (fd == -1) + return (void) fuse_reply_err(req, errno); + + fi->fh = fd; + fuse_reply_open(req, fi); +} + +static void lo_release(fuse_req_t req, fuse_ino_t ino, struct fuse_file_info *fi) +{ + (void) ino; + + close(fi->fh); + fuse_reply_err(req, 0); +} + +static void lo_read(fuse_req_t req, fuse_ino_t ino, size_t size, + off_t offset, struct fuse_file_info *fi) +{ + struct fuse_bufvec buf = FUSE_BUFVEC_INIT(size); + + (void) ino; + + buf.buf[0].flags = FUSE_BUF_IS_FD | FUSE_BUF_FD_SEEK; + buf.buf[0].fd = fi->fh; + buf.buf[0].pos = offset; + + fuse_reply_data(req, &buf, FUSE_BUF_SPLICE_MOVE); +} + +static struct fuse_lowlevel_ops lo_oper = { + .lookup = lo_lookup, + .forget = lo_forget, + .getattr = lo_getattr, + .readlink = lo_readlink, + .opendir = lo_opendir, + .readdir = lo_readdir, + .readdirplus = lo_readdirplus, + .releasedir = lo_releasedir, + .open = lo_open, + .release = lo_release, + .read = lo_read, +}; + +int main(int argc, char *argv[]) +{ + struct fuse_args args = FUSE_ARGS_INIT(argc, argv); + struct fuse_session *se; + struct fuse_cmdline_opts opts; + struct lo_data lo = { .debug = 0 }; + int ret = -1; + + if (fuse_parse_cmdline(&args, &opts) != 0) + return 1; + if (opts.show_help) { + printf("usage: %s [options] \n\n", argv[0]); + fuse_cmdline_help(); + fuse_lowlevel_help(); + fuse_mount_help(); + ret = 0; + goto err_out1; + } else if (opts.show_version) { + printf("FUSE library version %s\n", fuse_pkgversion()); + fuse_lowlevel_version(); + fuse_mount_version(); + ret = 0; + goto err_out1; + } + + lo.debug = opts.debug; + lo.root.next = lo.root.prev = &lo.root; + lo.root.fd = open("/", O_PATH); + lo.root.nlookup = 2; + if (lo.root.fd == -1) + err(1, "open(\"/\", O_PATH)"); + + se = fuse_session_new(&args, &lo_oper, sizeof(lo_oper), &lo); + if (se == NULL) + goto err_out1; + + if (fuse_set_signal_handlers(se) != 0) + goto err_out2; + + if (fuse_session_mount(se, opts.mountpoint) != 0) + goto err_out3; + + fuse_daemonize(opts.foreground); + + /* Block until ctrl+c or fusermount -u */ + if (opts.singlethread) + ret = fuse_session_loop(se); + else + ret = fuse_session_loop_mt(se); + + fuse_session_unmount(se); +err_out3: + fuse_remove_signal_handlers(se); +err_out2: + fuse_session_destroy(se); +err_out1: + free(opts.mountpoint); + fuse_opt_free_args(&args); + + while (lo.root.next != &lo.root) + lo_free(lo.root.next); + + return ret ? 1 : 0; +} diff --git a/test/test_examples.py b/test/test_examples.py index ef4932c..6deaff1 100755 --- a/test/test_examples.py +++ b/test/test_examples.py @@ -60,53 +60,26 @@ def test_hello(tmpdir, name, options): else: umount(mount_process, mnt_dir) +@pytest.mark.parametrize("name", ('passthrough', 'passthrough_fh', + 'passthrough_ll')) @pytest.mark.parametrize("options", LL_OPTIONS) -def test_fuse_lo_plus(tmpdir, options): +def test_passthrough(tmpdir, name, options): mnt_dir = str(tmpdir.mkdir('mnt')) src_dir = str(tmpdir.mkdir('src')) cmdline = base_cmdline + \ - [ pjoin(basename, 'example', 'fuse_lo-plus'), - '-f', '-s', mnt_dir ] + options + [ pjoin(basename, 'example', name), + '-f', mnt_dir ] + options + if not name.endswith('_ll'): + cmdline += [ '-o', 'use_ino,readdir_ino,kernel_cache' ] mount_process = subprocess.Popen(cmdline) try: wait_for_mount(mount_process, mnt_dir) work_dir = pjoin(mnt_dir, src_dir) - tst_write(work_dir) - tst_mkdir(work_dir) - tst_symlink(work_dir) - tst_mknod(work_dir) - if os.getuid() == 0: - tst_chown(work_dir) - # Underlying fs may not have full nanosecond resolution - tst_utimens(work_dir, ns_tol=1000) - tst_link(work_dir) - tst_readdir(work_dir) - tst_statvfs(work_dir) - tst_truncate_path(work_dir) - tst_truncate_fd(work_dir) - tst_unlink(work_dir) - tst_passthrough(src_dir, work_dir) - except: - cleanup(mnt_dir) - raise - else: - umount(mount_process, mnt_dir) -@pytest.mark.parametrize("name", ('fusexmp', 'fusexmp_fh')) -@pytest.mark.parametrize("options", LL_OPTIONS) -def test_fusexmp_fh(tmpdir, name, options): - mnt_dir = str(tmpdir.mkdir('mnt')) - src_dir = str(tmpdir.mkdir('src')) + subprocess.check_call([ os.path.join(basename, 'test', 'test'), + work_dir, ':' + src_dir ]) - cmdline = base_cmdline + \ - [ pjoin(basename, 'example', name), - '-f', '-o', 'use_ino,readdir_ino,kernel_cache', - mnt_dir ] + options - mount_process = subprocess.Popen(cmdline) - try: - wait_for_mount(mount_process, mnt_dir) - work_dir = pjoin(mnt_dir, src_dir) tst_write(work_dir) tst_mkdir(work_dir) tst_symlink(work_dir) diff --git a/test/test_fuse.py b/test/test_fuse.py deleted file mode 100755 index 3c60d80..0000000 --- a/test/test_fuse.py +++ /dev/null @@ -1,33 +0,0 @@ -#!/usr/bin/env python3 -import pytest -import sys - -if __name__ == '__main__': - sys.exit(pytest.main([__file__] + sys.argv[1:])) - -import subprocess -import os -from util import wait_for_mount, umount, cleanup, base_cmdline - -basename = os.path.join(os.path.dirname(__file__), '..') - -def test_fuse(tmpdir): - mnt_dir = str(tmpdir.mkdir('mnt')) - src_dir = str(tmpdir.mkdir('src')) - - cmdline = base_cmdline + \ - [ os.path.join(basename, 'example', 'fusexmp_fh'), - '-f', '-o' , 'use_ino,readdir_ino,kernel_cache', - mnt_dir ] - mount_process = subprocess.Popen(cmdline) - try: - wait_for_mount(mount_process, mnt_dir) - cmdline = [ os.path.join(basename, 'test', 'test'), - os.path.join(mnt_dir, src_dir), - ':' + src_dir ] - subprocess.check_call(cmdline) - except: - cleanup(mnt_dir) - raise - else: - umount(mount_process, mnt_dir)