From cdb8b79bad5fea81b74931a9027f1d5ca344af8e Mon Sep 17 00:00:00 2001 From: Miklos Szeredi Date: Wed, 12 Dec 2007 14:25:40 +0000 Subject: change indenting --- example/fusexmp.c | 412 ++-- example/fusexmp_fh.c | 468 ++-- example/hello.c | 106 +- example/hello_ll.c | 231 +- example/null.c | 90 +- include/fuse.h | 875 +++---- include/fuse_common.h | 160 +- include/fuse_common_compat.h | 19 +- include/fuse_compat.h | 300 +-- include/fuse_lowlevel.h | 1561 ++++++------- include/fuse_lowlevel_compat.h | 223 +- include/fuse_opt.h | 56 +- include/ulockmgr.h | 10 +- lib/fuse.c | 4987 ++++++++++++++++++++-------------------- lib/fuse_i.h | 22 +- lib/fuse_kern_chan.c | 118 +- lib/fuse_loop.c | 48 +- lib/fuse_loop_mt.c | 347 +-- lib/fuse_lowlevel.c | 1791 ++++++++------- lib/fuse_misc.h | 18 +- lib/fuse_mt.c | 136 +- lib/fuse_opt.c | 528 ++--- lib/fuse_session.c | 185 +- lib/fuse_signals.c | 78 +- lib/helper.c | 568 ++--- lib/modules/iconv.c | 1021 ++++---- lib/modules/subdir.c | 913 ++++---- lib/mount.c | 966 ++++---- lib/mount_bsd.c | 560 ++--- lib/mount_util.c | 397 ++-- lib/mount_util.h | 12 +- lib/ulockmgr.c | 702 +++--- test/stracedecode.c | 348 +-- test/test.c | 2318 +++++++++---------- util/fusermount.c | 1533 ++++++------ util/mount.fuse.c | 353 +-- util/ulockmgr_server.c | 671 +++--- 37 files changed, 11656 insertions(+), 11475 deletions(-) diff --git a/example/fusexmp.c b/example/fusexmp.c index 8df474c..083bbea 100644 --- a/example/fusexmp.c +++ b/example/fusexmp.c @@ -1,11 +1,11 @@ /* - FUSE: Filesystem in Userspace - Copyright (C) 2001-2007 Miklos Szeredi + 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. + This program can be distributed under the terms of the GNU GPL. + See the file COPYING. - gcc -Wall `pkg-config fuse --cflags --libs` fusexmp.c -o fusexmp + gcc -Wall `pkg-config fuse --cflags --libs` fusexmp.c -o fusexmp */ #define FUSE_USE_VERSION 26 @@ -33,353 +33,353 @@ static int xmp_getattr(const char *path, struct stat *stbuf) { - int res; + int res; - res = lstat(path, stbuf); - if (res == -1) - return -errno; + res = lstat(path, stbuf); + if (res == -1) + return -errno; - return 0; + return 0; } static int xmp_access(const char *path, int mask) { - int res; + int res; - res = access(path, mask); - if (res == -1) - return -errno; + res = access(path, mask); + if (res == -1) + return -errno; - return 0; + return 0; } static int xmp_readlink(const char *path, char *buf, size_t size) { - int res; + int res; - res = readlink(path, buf, size - 1); - if (res == -1) - return -errno; + res = readlink(path, buf, size - 1); + if (res == -1) + return -errno; - buf[res] = '\0'; - return 0; + 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) + off_t offset, struct fuse_file_info *fi) { - DIR *dp; - struct dirent *de; - - (void) offset; - (void) fi; - - 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)) - break; - } - - closedir(dp); - return 0; + DIR *dp; + struct dirent *de; + + (void) offset; + (void) fi; + + 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)) + 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; + 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; + int res; - res = mkdir(path, mode); - if (res == -1) - return -errno; + res = mkdir(path, mode); + if (res == -1) + return -errno; - return 0; + return 0; } static int xmp_unlink(const char *path) { - int res; + int res; - res = unlink(path); - if (res == -1) - return -errno; + res = unlink(path); + if (res == -1) + return -errno; - return 0; + return 0; } static int xmp_rmdir(const char *path) { - int res; + int res; - res = rmdir(path); - if (res == -1) - return -errno; + res = rmdir(path); + if (res == -1) + return -errno; - return 0; + return 0; } static int xmp_symlink(const char *from, const char *to) { - int res; + int res; - res = symlink(from, to); - if (res == -1) - return -errno; + res = symlink(from, to); + if (res == -1) + return -errno; - return 0; + return 0; } static int xmp_rename(const char *from, const char *to) { - int res; + int res; - res = rename(from, to); - if (res == -1) - return -errno; + res = rename(from, to); + if (res == -1) + return -errno; - return 0; + return 0; } static int xmp_link(const char *from, const char *to) { - int res; + int res; - res = link(from, to); - if (res == -1) - return -errno; + res = link(from, to); + if (res == -1) + return -errno; - return 0; + return 0; } static int xmp_chmod(const char *path, mode_t mode) { - int res; + int res; - res = chmod(path, mode); - if (res == -1) - return -errno; + res = chmod(path, mode); + if (res == -1) + return -errno; - return 0; + return 0; } static int xmp_chown(const char *path, uid_t uid, gid_t gid) { - int res; + int res; - res = lchown(path, uid, gid); - if (res == -1) - return -errno; + res = lchown(path, uid, gid); + if (res == -1) + return -errno; - return 0; + return 0; } static int xmp_truncate(const char *path, off_t size) { - int res; + int res; - res = truncate(path, size); - if (res == -1) - return -errno; + res = truncate(path, size); + if (res == -1) + return -errno; - return 0; + return 0; } static int xmp_utimens(const char *path, const struct timespec ts[2]) { - int res; - struct timeval tv[2]; + int res; + struct timeval tv[2]; - tv[0].tv_sec = ts[0].tv_sec; - tv[0].tv_usec = ts[0].tv_nsec / 1000; - tv[1].tv_sec = ts[1].tv_sec; - tv[1].tv_usec = ts[1].tv_nsec / 1000; + tv[0].tv_sec = ts[0].tv_sec; + tv[0].tv_usec = ts[0].tv_nsec / 1000; + tv[1].tv_sec = ts[1].tv_sec; + tv[1].tv_usec = ts[1].tv_nsec / 1000; - res = utimes(path, tv); - if (res == -1) - return -errno; + res = utimes(path, tv); + if (res == -1) + return -errno; - return 0; + return 0; } static int xmp_open(const char *path, struct fuse_file_info *fi) { - int res; + int res; - res = open(path, fi->flags); - if (res == -1) - return -errno; + res = open(path, fi->flags); + if (res == -1) + return -errno; - close(res); - return 0; + close(res); + return 0; } static int xmp_read(const char *path, char *buf, size_t size, off_t offset, - struct fuse_file_info *fi) + struct fuse_file_info *fi) { - int fd; - int res; + int fd; + int res; - (void) fi; - fd = open(path, O_RDONLY); - if (fd == -1) - return -errno; + (void) fi; + fd = open(path, O_RDONLY); + if (fd == -1) + return -errno; - res = pread(fd, buf, size, offset); - if (res == -1) - res = -errno; + res = pread(fd, buf, size, offset); + if (res == -1) + res = -errno; - close(fd); - return res; + 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) + off_t offset, struct fuse_file_info *fi) { - int fd; - int res; + int fd; + int res; - (void) fi; - fd = open(path, O_WRONLY); - if (fd == -1) - return -errno; + (void) fi; + fd = open(path, O_WRONLY); + if (fd == -1) + return -errno; - res = pwrite(fd, buf, size, offset); - if (res == -1) - res = -errno; + res = pwrite(fd, buf, size, offset); + if (res == -1) + res = -errno; - close(fd); - return res; + close(fd); + return res; } static int xmp_statfs(const char *path, struct statvfs *stbuf) { - int res; + int res; - res = statvfs(path, stbuf); - if (res == -1) - return -errno; + res = statvfs(path, stbuf); + if (res == -1) + return -errno; - return 0; + 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 */ + /* Just a stub. This method is optional and can safely be left + unimplemented */ - (void) path; - (void) fi; - return 0; + (void) path; + (void) fi; + return 0; } static int xmp_fsync(const char *path, int isdatasync, - struct fuse_file_info *fi) + struct fuse_file_info *fi) { - /* Just a stub. This method is optional and can safely be left - unimplemented */ + /* Just a stub. This method is optional and can safely be left + unimplemented */ - (void) path; - (void) isdatasync; - (void) fi; - return 0; + (void) path; + (void) isdatasync; + (void) fi; + return 0; } #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) + size_t size, int flags) { - int res = lsetxattr(path, name, value, size, flags); - if (res == -1) - return -errno; - return 0; + 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) + size_t size) { - int res = lgetxattr(path, name, value, size); - if (res == -1) - return -errno; - return res; + 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; + 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; + 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, - .utimens = xmp_utimens, - .open = xmp_open, - .read = xmp_read, - .write = xmp_write, - .statfs = xmp_statfs, - .release = xmp_release, - .fsync = xmp_fsync, + .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, + .utimens = xmp_utimens, + .open = xmp_open, + .read = xmp_read, + .write = xmp_write, + .statfs = xmp_statfs, + .release = xmp_release, + .fsync = xmp_fsync, #ifdef HAVE_SETXATTR - .setxattr = xmp_setxattr, - .getxattr = xmp_getxattr, - .listxattr = xmp_listxattr, - .removexattr= xmp_removexattr, + .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); + umask(0); + return fuse_main(argc, argv, &xmp_oper, NULL); } diff --git a/example/fusexmp_fh.c b/example/fusexmp_fh.c index 6565cf9..616c263 100644 --- a/example/fusexmp_fh.c +++ b/example/fusexmp_fh.c @@ -1,11 +1,11 @@ /* - FUSE: Filesystem in Userspace - Copyright (C) 2001-2007 Miklos Szeredi + 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. + This program can be distributed under the terms of the GNU GPL. + See the file COPYING. - gcc -Wall `pkg-config fuse --cflags --libs` -lulockmgr fusexmp_fh.c -o fusexmp_fh + gcc -Wall `pkg-config fuse --cflags --libs` -lulockmgr fusexmp_fh.c -o fusexmp_fh */ #define FUSE_USE_VERSION 26 @@ -31,430 +31,430 @@ static int xmp_getattr(const char *path, struct stat *stbuf) { - int res; + int res; - res = lstat(path, stbuf); - if (res == -1) - return -errno; + res = lstat(path, stbuf); + if (res == -1) + return -errno; - return 0; + return 0; } static int xmp_fgetattr(const char *path, struct stat *stbuf, - struct fuse_file_info *fi) + struct fuse_file_info *fi) { - int res; + int res; - (void) path; + (void) path; - res = fstat(fi->fh, stbuf); - if (res == -1) - return -errno; + res = fstat(fi->fh, stbuf); + if (res == -1) + return -errno; - return 0; + return 0; } static int xmp_access(const char *path, int mask) { - int res; + int res; - res = access(path, mask); - if (res == -1) - return -errno; + res = access(path, mask); + if (res == -1) + return -errno; - return 0; + return 0; } static int xmp_readlink(const char *path, char *buf, size_t size) { - int res; + int res; - res = readlink(path, buf, size - 1); - if (res == -1) - return -errno; + res = readlink(path, buf, size - 1); + if (res == -1) + return -errno; - buf[res] = '\0'; - return 0; + buf[res] = '\0'; + return 0; } static int xmp_opendir(const char *path, struct fuse_file_info *fi) { - DIR *dp = opendir(path); - if (dp == NULL) - return -errno; + DIR *dp = opendir(path); + if (dp == NULL) + return -errno; - fi->fh = (unsigned long) dp; - return 0; + fi->fh = (unsigned long) dp; + return 0; } static inline DIR *get_dirp(struct fuse_file_info *fi) { - return (DIR *) (uintptr_t) fi->fh; + return (DIR *) (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) + off_t offset, struct fuse_file_info *fi) { - DIR *dp = get_dirp(fi); - struct dirent *de; + DIR *dp = get_dirp(fi); + struct dirent *de; - (void) path; - seekdir(dp, offset); - 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, telldir(dp))) - break; - } + (void) path; + seekdir(dp, offset); + 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, telldir(dp))) + break; + } - return 0; + return 0; } static int xmp_releasedir(const char *path, struct fuse_file_info *fi) { - DIR *dp = get_dirp(fi); - (void) path; - closedir(dp); - return 0; + DIR *dp = get_dirp(fi); + (void) path; + closedir(dp); + return 0; } static int xmp_mknod(const char *path, mode_t mode, dev_t rdev) { - int res; + int res; - if (S_ISFIFO(mode)) - res = mkfifo(path, mode); - else - res = mknod(path, mode, rdev); - if (res == -1) - return -errno; + if (S_ISFIFO(mode)) + res = mkfifo(path, mode); + else + res = mknod(path, mode, rdev); + if (res == -1) + return -errno; - return 0; + return 0; } static int xmp_mkdir(const char *path, mode_t mode) { - int res; + int res; - res = mkdir(path, mode); - if (res == -1) - return -errno; + res = mkdir(path, mode); + if (res == -1) + return -errno; - return 0; + return 0; } static int xmp_unlink(const char *path) { - int res; + int res; - res = unlink(path); - if (res == -1) - return -errno; + res = unlink(path); + if (res == -1) + return -errno; - return 0; + return 0; } static int xmp_rmdir(const char *path) { - int res; + int res; - res = rmdir(path); - if (res == -1) - return -errno; + res = rmdir(path); + if (res == -1) + return -errno; - return 0; + return 0; } static int xmp_symlink(const char *from, const char *to) { - int res; + int res; - res = symlink(from, to); - if (res == -1) - return -errno; + res = symlink(from, to); + if (res == -1) + return -errno; - return 0; + return 0; } static int xmp_rename(const char *from, const char *to) { - int res; + int res; - res = rename(from, to); - if (res == -1) - return -errno; + res = rename(from, to); + if (res == -1) + return -errno; - return 0; + return 0; } static int xmp_link(const char *from, const char *to) { - int res; + int res; - res = link(from, to); - if (res == -1) - return -errno; + res = link(from, to); + if (res == -1) + return -errno; - return 0; + return 0; } static int xmp_chmod(const char *path, mode_t mode) { - int res; + int res; - res = chmod(path, mode); - if (res == -1) - return -errno; + res = chmod(path, mode); + if (res == -1) + return -errno; - return 0; + return 0; } static int xmp_chown(const char *path, uid_t uid, gid_t gid) { - int res; + int res; - res = lchown(path, uid, gid); - if (res == -1) - return -errno; + res = lchown(path, uid, gid); + if (res == -1) + return -errno; - return 0; + return 0; } static int xmp_truncate(const char *path, off_t size) { - int res; + int res; - res = truncate(path, size); - if (res == -1) - return -errno; + res = truncate(path, size); + if (res == -1) + return -errno; - return 0; + return 0; } static int xmp_ftruncate(const char *path, off_t size, - struct fuse_file_info *fi) + struct fuse_file_info *fi) { - int res; + int res; - (void) path; + (void) path; - res = ftruncate(fi->fh, size); - if (res == -1) - return -errno; + res = ftruncate(fi->fh, size); + if (res == -1) + return -errno; - return 0; + return 0; } static int xmp_utimens(const char *path, const struct timespec ts[2]) { - int res; - struct timeval tv[2]; + int res; + struct timeval tv[2]; - tv[0].tv_sec = ts[0].tv_sec; - tv[0].tv_usec = ts[0].tv_nsec / 1000; - tv[1].tv_sec = ts[1].tv_sec; - tv[1].tv_usec = ts[1].tv_nsec / 1000; + tv[0].tv_sec = ts[0].tv_sec; + tv[0].tv_usec = ts[0].tv_nsec / 1000; + tv[1].tv_sec = ts[1].tv_sec; + tv[1].tv_usec = ts[1].tv_nsec / 1000; - res = utimes(path, tv); - if (res == -1) - return -errno; + res = utimes(path, tv); + if (res == -1) + return -errno; - return 0; + return 0; } static int xmp_create(const char *path, mode_t mode, struct fuse_file_info *fi) { - int fd; + int fd; - fd = open(path, fi->flags, mode); - if (fd == -1) - return -errno; + fd = open(path, fi->flags, mode); + if (fd == -1) + return -errno; - fi->fh = fd; - return 0; + fi->fh = fd; + return 0; } static int xmp_open(const char *path, struct fuse_file_info *fi) { - int fd; + int fd; - fd = open(path, fi->flags); - if (fd == -1) - return -errno; + fd = open(path, fi->flags); + if (fd == -1) + return -errno; - fi->fh = fd; - return 0; + 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) + struct fuse_file_info *fi) { - int res; + int res; - (void) path; - res = pread(fi->fh, buf, size, offset); - if (res == -1) - res = -errno; + (void) path; + res = pread(fi->fh, buf, size, offset); + if (res == -1) + res = -errno; - return res; + return res; } static int xmp_write(const char *path, const char *buf, size_t size, - off_t offset, struct fuse_file_info *fi) + off_t offset, struct fuse_file_info *fi) { - int res; + int res; - (void) path; - res = pwrite(fi->fh, buf, size, offset); - if (res == -1) - res = -errno; + (void) path; + res = pwrite(fi->fh, buf, size, offset); + if (res == -1) + res = -errno; - return res; + return res; } static int xmp_statfs(const char *path, struct statvfs *stbuf) { - int res; + int res; - res = statvfs(path, stbuf); - if (res == -1) - return -errno; + res = statvfs(path, stbuf); + if (res == -1) + return -errno; - return 0; + return 0; } static int xmp_flush(const char *path, struct fuse_file_info *fi) { - int res; + 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; + (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; + return 0; } static int xmp_release(const char *path, struct fuse_file_info *fi) { - (void) path; - close(fi->fh); + (void) path; + close(fi->fh); - return 0; + return 0; } static int xmp_fsync(const char *path, int isdatasync, - struct fuse_file_info *fi) + struct fuse_file_info *fi) { - int res; - (void) path; + int res; + (void) path; #ifndef HAVE_FDATASYNC - (void) isdatasync; + (void) isdatasync; #else - if (isdatasync) - res = fdatasync(fi->fh); - else + if (isdatasync) + res = fdatasync(fi->fh); + else #endif - res = fsync(fi->fh); - if (res == -1) - return -errno; + res = fsync(fi->fh); + if (res == -1) + return -errno; - return 0; + return 0; } #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) + size_t size, int flags) { - int res = lsetxattr(path, name, value, size, flags); - if (res == -1) - return -errno; - return 0; + 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) + size_t size) { - int res = lgetxattr(path, name, value, size); - if (res == -1) - return -errno; - return res; + 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; + 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; + int res = lremovexattr(path, name); + if (res == -1) + return -errno; + return 0; } #endif /* HAVE_SETXATTR */ static int xmp_lock(const char *path, struct fuse_file_info *fi, int cmd, - struct flock *lock) + struct flock *lock) { - (void) path; + (void) path; - return ulockmgr_op(fi->fh, cmd, lock, &fi->lock_owner, - sizeof(fi->lock_owner)); + return ulockmgr_op(fi->fh, cmd, lock, &fi->lock_owner, + sizeof(fi->lock_owner)); } 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, - .utimens = xmp_utimens, - .create = xmp_create, - .open = xmp_open, - .read = xmp_read, - .write = xmp_write, - .statfs = xmp_statfs, - .flush = xmp_flush, - .release = xmp_release, - .fsync = xmp_fsync, + .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, + .utimens = xmp_utimens, + .create = xmp_create, + .open = xmp_open, + .read = xmp_read, + .write = xmp_write, + .statfs = xmp_statfs, + .flush = xmp_flush, + .release = xmp_release, + .fsync = xmp_fsync, #ifdef HAVE_SETXATTR - .setxattr = xmp_setxattr, - .getxattr = xmp_getxattr, - .listxattr = xmp_listxattr, - .removexattr= xmp_removexattr, + .setxattr = xmp_setxattr, + .getxattr = xmp_getxattr, + .listxattr = xmp_listxattr, + .removexattr = xmp_removexattr, #endif - .lock = xmp_lock, + .lock = xmp_lock, }; int main(int argc, char *argv[]) { - umask(0); - return fuse_main(argc, argv, &xmp_oper, NULL); + umask(0); + return fuse_main(argc, argv, &xmp_oper, NULL); } diff --git a/example/hello.c b/example/hello.c index 463e286..bcde80a 100644 --- a/example/hello.c +++ b/example/hello.c @@ -1,11 +1,11 @@ /* - FUSE: Filesystem in Userspace - Copyright (C) 2001-2007 Miklos Szeredi + 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. + This program can be distributed under the terms of the GNU GPL. + See the file COPYING. - gcc -Wall `pkg-config fuse --cflags --libs` hello.c -o hello + gcc -Wall `pkg-config fuse --cflags --libs` hello.c -o hello */ #define FUSE_USE_VERSION 26 @@ -21,76 +21,76 @@ static const char *hello_path = "/hello"; static int hello_getattr(const char *path, struct stat *stbuf) { - int res = 0; - - memset(stbuf, 0, sizeof(struct stat)); - if (strcmp(path, "/") == 0) { - stbuf->st_mode = S_IFDIR | 0755; - stbuf->st_nlink = 2; - } else if (strcmp(path, hello_path) == 0) { - stbuf->st_mode = S_IFREG | 0444; - stbuf->st_nlink = 1; - stbuf->st_size = strlen(hello_str); - } else - res = -ENOENT; - - return res; + int res = 0; + + memset(stbuf, 0, sizeof(struct stat)); + if (strcmp(path, "/") == 0) { + stbuf->st_mode = S_IFDIR | 0755; + stbuf->st_nlink = 2; + } else if (strcmp(path, hello_path) == 0) { + stbuf->st_mode = S_IFREG | 0444; + stbuf->st_nlink = 1; + stbuf->st_size = strlen(hello_str); + } else + res = -ENOENT; + + return res; } static int hello_readdir(const char *path, void *buf, fuse_fill_dir_t filler, - off_t offset, struct fuse_file_info *fi) + off_t offset, struct fuse_file_info *fi) { - (void) offset; - (void) fi; + (void) offset; + (void) fi; - if (strcmp(path, "/") != 0) - return -ENOENT; + if (strcmp(path, "/") != 0) + return -ENOENT; - filler(buf, ".", NULL, 0); - filler(buf, "..", NULL, 0); - filler(buf, hello_path + 1, NULL, 0); + filler(buf, ".", NULL, 0); + filler(buf, "..", NULL, 0); + filler(buf, hello_path + 1, NULL, 0); - return 0; + return 0; } static int hello_open(const char *path, struct fuse_file_info *fi) { - if (strcmp(path, hello_path) != 0) - return -ENOENT; + if (strcmp(path, hello_path) != 0) + return -ENOENT; - if ((fi->flags & 3) != O_RDONLY) - return -EACCES; + if ((fi->flags & 3) != O_RDONLY) + return -EACCES; - return 0; + return 0; } static int hello_read(const char *path, char *buf, size_t size, off_t offset, - struct fuse_file_info *fi) + struct fuse_file_info *fi) { - size_t len; - (void) fi; - if(strcmp(path, hello_path) != 0) - return -ENOENT; - - len = strlen(hello_str); - if (offset < len) { - if (offset + size > len) - size = len - offset; - memcpy(buf, hello_str + offset, size); - } else - size = 0; - - return size; + size_t len; + (void) fi; + if(strcmp(path, hello_path) != 0) + return -ENOENT; + + len = strlen(hello_str); + if (offset < len) { + if (offset + size > len) + size = len - offset; + memcpy(buf, hello_str + offset, size); + } else + size = 0; + + return size; } static struct fuse_operations hello_oper = { - .getattr = hello_getattr, - .readdir = hello_readdir, - .open = hello_open, - .read = hello_read, + .getattr = hello_getattr, + .readdir = hello_readdir, + .open = hello_open, + .read = hello_read, }; int main(int argc, char *argv[]) { - return fuse_main(argc, argv, &hello_oper, NULL); + return fuse_main(argc, argv, &hello_oper, NULL); } diff --git a/example/hello_ll.c b/example/hello_ll.c index 6ab6172..1d3a1a8 100644 --- a/example/hello_ll.c +++ b/example/hello_ll.c @@ -1,11 +1,11 @@ /* - FUSE: Filesystem in Userspace - Copyright (C) 2001-2007 Miklos Szeredi + 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. + This program can be distributed under the terms of the GNU GPL. + See the file COPYING. - gcc -Wall `pkg-config fuse --cflags --libs` hello_ll.c -o hello_ll + gcc -Wall `pkg-config fuse --cflags --libs` hello_ll.c -o hello_ll */ #define FUSE_USE_VERSION 26 @@ -24,157 +24,158 @@ static const char *hello_name = "hello"; static int hello_stat(fuse_ino_t ino, struct stat *stbuf) { - stbuf->st_ino = ino; - switch (ino) { - case 1: - stbuf->st_mode = S_IFDIR | 0755; - stbuf->st_nlink = 2; - break; - - case 2: - stbuf->st_mode = S_IFREG | 0444; - stbuf->st_nlink = 1; - stbuf->st_size = strlen(hello_str); - break; - - default: - return -1; - } - return 0; + stbuf->st_ino = ino; + switch (ino) { + case 1: + stbuf->st_mode = S_IFDIR | 0755; + stbuf->st_nlink = 2; + break; + + case 2: + stbuf->st_mode = S_IFREG | 0444; + stbuf->st_nlink = 1; + stbuf->st_size = strlen(hello_str); + break; + + default: + return -1; + } + return 0; } static void hello_ll_getattr(fuse_req_t req, fuse_ino_t ino, - struct fuse_file_info *fi) + struct fuse_file_info *fi) { - struct stat stbuf; + struct stat stbuf; - (void) fi; + (void) fi; - memset(&stbuf, 0, sizeof(stbuf)); - if (hello_stat(ino, &stbuf) == -1) - fuse_reply_err(req, ENOENT); - else - fuse_reply_attr(req, &stbuf, 1.0); + memset(&stbuf, 0, sizeof(stbuf)); + if (hello_stat(ino, &stbuf) == -1) + fuse_reply_err(req, ENOENT); + else + fuse_reply_attr(req, &stbuf, 1.0); } static void hello_ll_lookup(fuse_req_t req, fuse_ino_t parent, const char *name) { - struct fuse_entry_param e; - - if (parent != 1 || strcmp(name, hello_name) != 0) - fuse_reply_err(req, ENOENT); - else { - memset(&e, 0, sizeof(e)); - e.ino = 2; - e.attr_timeout = 1.0; - e.entry_timeout = 1.0; - hello_stat(e.ino, &e.attr); - - fuse_reply_entry(req, &e); - } + struct fuse_entry_param e; + + if (parent != 1 || strcmp(name, hello_name) != 0) + fuse_reply_err(req, ENOENT); + else { + memset(&e, 0, sizeof(e)); + e.ino = 2; + e.attr_timeout = 1.0; + e.entry_timeout = 1.0; + hello_stat(e.ino, &e.attr); + + fuse_reply_entry(req, &e); + } } struct dirbuf { - char *p; - size_t size; + char *p; + size_t size; }; static void dirbuf_add(fuse_req_t req, struct dirbuf *b, const char *name, - fuse_ino_t ino) + fuse_ino_t ino) { - struct stat stbuf; - size_t oldsize = b->size; - b->size += fuse_add_direntry(req, NULL, 0, name, NULL, 0); - b->p = (char *) realloc(b->p, b->size); - memset(&stbuf, 0, sizeof(stbuf)); - stbuf.st_ino = ino; - fuse_add_direntry(req, b->p + oldsize, b->size - oldsize, name, &stbuf, - b->size); + struct stat stbuf; + size_t oldsize = b->size; + b->size += fuse_add_direntry(req, NULL, 0, name, NULL, 0); + b->p = (char *) realloc(b->p, b->size); + memset(&stbuf, 0, sizeof(stbuf)); + stbuf.st_ino = ino; + fuse_add_direntry(req, b->p + oldsize, b->size - oldsize, name, &stbuf, + b->size); } #define min(x, y) ((x) < (y) ? (x) : (y)) static int reply_buf_limited(fuse_req_t req, const char *buf, size_t bufsize, - off_t off, size_t maxsize) + off_t off, size_t maxsize) { - if (off < bufsize) - return fuse_reply_buf(req, buf + off, min(bufsize - off, maxsize)); - else - return fuse_reply_buf(req, NULL, 0); + if (off < bufsize) + return fuse_reply_buf(req, buf + off, + min(bufsize - off, maxsize)); + else + return fuse_reply_buf(req, NULL, 0); } static void hello_ll_readdir(fuse_req_t req, fuse_ino_t ino, size_t size, - off_t off, struct fuse_file_info *fi) + off_t off, struct fuse_file_info *fi) { - (void) fi; - - if (ino != 1) - fuse_reply_err(req, ENOTDIR); - else { - struct dirbuf b; - - memset(&b, 0, sizeof(b)); - dirbuf_add(req, &b, ".", 1); - dirbuf_add(req, &b, "..", 1); - dirbuf_add(req, &b, hello_name, 2); - reply_buf_limited(req, b.p, b.size, off, size); - free(b.p); - } + (void) fi; + + if (ino != 1) + fuse_reply_err(req, ENOTDIR); + else { + struct dirbuf b; + + memset(&b, 0, sizeof(b)); + dirbuf_add(req, &b, ".", 1); + dirbuf_add(req, &b, "..", 1); + dirbuf_add(req, &b, hello_name, 2); + reply_buf_limited(req, b.p, b.size, off, size); + free(b.p); + } } static void hello_ll_open(fuse_req_t req, fuse_ino_t ino, - struct fuse_file_info *fi) + struct fuse_file_info *fi) { - if (ino != 2) - fuse_reply_err(req, EISDIR); - else if ((fi->flags & 3) != O_RDONLY) - fuse_reply_err(req, EACCES); - else - fuse_reply_open(req, fi); + if (ino != 2) + fuse_reply_err(req, EISDIR); + else if ((fi->flags & 3) != O_RDONLY) + fuse_reply_err(req, EACCES); + else + fuse_reply_open(req, fi); } static void hello_ll_read(fuse_req_t req, fuse_ino_t ino, size_t size, - off_t off, struct fuse_file_info *fi) + off_t off, struct fuse_file_info *fi) { - (void) fi; + (void) fi; - assert(ino == 2); - reply_buf_limited(req, hello_str, strlen(hello_str), off, size); + assert(ino == 2); + reply_buf_limited(req, hello_str, strlen(hello_str), off, size); } static struct fuse_lowlevel_ops hello_ll_oper = { - .lookup = hello_ll_lookup, - .getattr = hello_ll_getattr, - .readdir = hello_ll_readdir, - .open = hello_ll_open, - .read = hello_ll_read, + .lookup = hello_ll_lookup, + .getattr = hello_ll_getattr, + .readdir = hello_ll_readdir, + .open = hello_ll_open, + .read = hello_ll_read, }; int main(int argc, char *argv[]) { - struct fuse_args args = FUSE_ARGS_INIT(argc, argv); - struct fuse_chan *ch; - char *mountpoint; - int err = -1; - - if (fuse_parse_cmdline(&args, &mountpoint, NULL, NULL) != -1 && - (ch = fuse_mount(mountpoint, &args)) != NULL) { - struct fuse_session *se; - - se = fuse_lowlevel_new(&args, &hello_ll_oper, sizeof(hello_ll_oper), - NULL); - if (se != NULL) { - if (fuse_set_signal_handlers(se) != -1) { - fuse_session_add_chan(se, ch); - err = fuse_session_loop(se); - fuse_remove_signal_handlers(se); - fuse_session_remove_chan(ch); - } - fuse_session_destroy(se); - } - fuse_unmount(mountpoint, ch); - } - fuse_opt_free_args(&args); - - return err ? 1 : 0; + struct fuse_args args = FUSE_ARGS_INIT(argc, argv); + struct fuse_chan *ch; + char *mountpoint; + int err = -1; + + if (fuse_parse_cmdline(&args, &mountpoint, NULL, NULL) != -1 && + (ch = fuse_mount(mountpoint, &args)) != NULL) { + struct fuse_session *se; + + se = fuse_lowlevel_new(&args, &hello_ll_oper, + sizeof(hello_ll_oper), NULL); + if (se != NULL) { + if (fuse_set_signal_handlers(se) != -1) { + fuse_session_add_chan(se, ch); + err = fuse_session_loop(se); + fuse_remove_signal_handlers(se); + fuse_session_remove_chan(ch); + } + fuse_session_destroy(se); + } + fuse_unmount(mountpoint, ch); + } + fuse_opt_free_args(&args); + + return err ? 1 : 0; } diff --git a/example/null.c b/example/null.c index 0793de6..a98226e 100644 --- a/example/null.c +++ b/example/null.c @@ -1,11 +1,11 @@ /* - FUSE: Filesystem in Userspace - Copyright (C) 2001-2007 Miklos Szeredi + 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. + This program can be distributed under the terms of the GNU GPL. + See the file COPYING. - gcc -Wall `pkg-config fuse --cflags --libs` null.c -o null + gcc -Wall `pkg-config fuse --cflags --libs` null.c -o null */ #define FUSE_USE_VERSION 26 @@ -18,75 +18,75 @@ static int null_getattr(const char *path, struct stat *stbuf) { - if(strcmp(path, "/") != 0) - return -ENOENT; - - stbuf->st_mode = S_IFREG | 0644; - stbuf->st_nlink = 1; - stbuf->st_uid = getuid(); - stbuf->st_gid = getgid(); - stbuf->st_size = (1ULL << 32); /* 4G */ - stbuf->st_blocks = 0; - stbuf->st_atime = stbuf->st_mtime = stbuf->st_ctime = time(NULL); - - return 0; + if(strcmp(path, "/") != 0) + return -ENOENT; + + stbuf->st_mode = S_IFREG | 0644; + stbuf->st_nlink = 1; + stbuf->st_uid = getuid(); + stbuf->st_gid = getgid(); + stbuf->st_size = (1ULL << 32); /* 4G */ + stbuf->st_blocks = 0; + stbuf->st_atime = stbuf->st_mtime = stbuf->st_ctime = time(NULL); + + return 0; } static int null_truncate(const char *path, off_t size) { - (void) size; + (void) size; - if(strcmp(path, "/") != 0) - return -ENOENT; + if(strcmp(path, "/") != 0) + return -ENOENT; - return 0; + return 0; } static int null_open(const char *path, struct fuse_file_info *fi) { - (void) fi; + (void) fi; - if(strcmp(path, "/") != 0) - return -ENOENT; + if(strcmp(path, "/") != 0) + return -ENOENT; - return 0; + return 0; } static int null_read(const char *path, char *buf, size_t size, - off_t offset, struct fuse_file_info *fi) + off_t offset, struct fuse_file_info *fi) { - (void) buf; - (void) offset; - (void) fi; + (void) buf; + (void) offset; + (void) fi; - if(strcmp(path, "/") != 0) - return -ENOENT; + if(strcmp(path, "/") != 0) + return -ENOENT; - return size; + return size; } static int null_write(const char *path, const char *buf, size_t size, - off_t offset, struct fuse_file_info *fi) + off_t offset, struct fuse_file_info *fi) { - (void) buf; - (void) offset; - (void) fi; + (void) buf; + (void) offset; + (void) fi; - if(strcmp(path, "/") != 0) - return -ENOENT; + if(strcmp(path, "/") != 0) + return -ENOENT; - return size; + return size; } static struct fuse_operations null_oper = { - .getattr = null_getattr, - .truncate = null_truncate, - .open = null_open, - .read = null_read, - .write = null_write, + .getattr = null_getattr, + .truncate = null_truncate, + .open = null_open, + .read = null_read, + .write = null_write, }; int main(int argc, char *argv[]) { - return fuse_main(argc, argv, &null_oper, NULL); + return fuse_main(argc, argv, &null_oper, NULL); } diff --git a/include/fuse.h b/include/fuse.h index 683ab1a..b7708c7 100644 --- a/include/fuse.h +++ b/include/fuse.h @@ -1,9 +1,9 @@ /* - FUSE: Filesystem in Userspace - Copyright (C) 2001-2007 Miklos Szeredi + FUSE: Filesystem in Userspace + Copyright (C) 2001-2007 Miklos Szeredi - This program can be distributed under the terms of the GNU LGPLv2. - See the file COPYING.LIB. + This program can be distributed under the terms of the GNU LGPLv2. + See the file COPYING.LIB. */ #ifndef _FUSE_H_ @@ -37,7 +37,7 @@ extern "C" { #endif /* ----------------------------------------------------------- * - * Basic FUSE API * + * Basic FUSE API * * ----------------------------------------------------------- */ /** Handle for a FUSE filesystem */ @@ -55,12 +55,12 @@ struct fuse_cmd; * @return 1 if buffer is full, zero otherwise */ typedef int (*fuse_fill_dir_t) (void *buf, const char *name, - const struct stat *stbuf, off_t off); + const struct stat *stbuf, off_t off); /* Used by deprecated getdir() method */ typedef struct fuse_dirhandle *fuse_dirh_t; typedef int (*fuse_dirfil_t) (fuse_dirh_t h, const char *name, int type, - ino_t ino); + ino_t ino); /** * The file system operations: @@ -77,351 +77,352 @@ typedef int (*fuse_dirfil_t) (fuse_dirh_t h, const char *name, int type, * featured filesystem can still be implemented. */ struct fuse_operations { - /** Get file attributes. - * - * Similar to stat(). The 'st_dev' and 'st_blksize' fields are - * ignored. The 'st_ino' field is ignored except if the 'use_ino' - * mount option is given. - */ - int (*getattr) (const char *, struct stat *); - - /** Read the target of a symbolic link - * - * The buffer should be filled with a null terminated string. The - * buffer size argument includes the space for the terminating - * null character. If the linkname is too long to fit in the - * buffer, it should be truncated. The return value should be 0 - * for success. - */ - int (*readlink) (const char *, char *, size_t); - - /* Deprecated, use readdir() instead */ - int (*getdir) (const char *, fuse_dirh_t, fuse_dirfil_t); - - /** Create a file node - * - * This is called for creation of all non-directory, non-symlink - * nodes. If the filesystem defines a create() method, then for - * regular files that will be called instead. - */ - int (*mknod) (const char *, mode_t, dev_t); - - /** Create a directory */ - int (*mkdir) (const char *, mode_t); - - /** Remove a file */ - int (*unlink) (const char *); - - /** Remove a directory */ - int (*rmdir) (const char *); - - /** Create a symbolic link */ - int (*symlink) (const char *, const char *); - - /** Rename a file */ - int (*rename) (const char *, const char *); - - /** Create a hard link to a file */ - int (*link) (const char *, const char *); - - /** Change the permission bits of a file */ - int (*chmod) (const char *, mode_t); - - /** Change the owner and group of a file */ - int (*chown) (const char *, uid_t, gid_t); - - /** Change the size of a file */ - int (*truncate) (const char *, off_t); - - /** Change the access and/or modification times of a file - * - * Deprecated, use utimens() instead. - */ - int (*utime) (const char *, struct utimbuf *); - - /** File open operation - * - * No creation, or truncation flags (O_CREAT, O_EXCL, O_TRUNC) - * will be passed to open(). Open should check if the operation - * is permitted for the given flags. Optionally open may also - * return an arbitrary filehandle in the fuse_file_info structure, - * which will be passed to all file operations. - * - * Changed in version 2.2 - */ - int (*open) (const char *, struct fuse_file_info *); - - /** Read data from an open file - * - * Read should return exactly the number of bytes requested except - * on EOF or error, otherwise the rest of the data will be - * substituted with zeroes. An exception to this is when the - * 'direct_io' mount option is specified, in which case the return - * value of the read system call will reflect the return value of - * this operation. - * - * Changed in version 2.2 - */ - int (*read) (const char *, char *, size_t, off_t, struct fuse_file_info *); - - /** Write data to an open file - * - * Write should return exactly the number of bytes requested - * except on error. An exception to this is when the 'direct_io' - * mount option is specified (see read operation). - * - * Changed in version 2.2 - */ - int (*write) (const char *, const char *, size_t, off_t, - struct fuse_file_info *); - - /** Get file system statistics - * - * The 'f_frsize', 'f_favail', 'f_fsid' and 'f_flag' fields are ignored - * - * Replaced 'struct statfs' parameter with 'struct statvfs' in - * version 2.5 - */ - int (*statfs) (const char *, struct statvfs *); - - /** Possibly flush cached data - * - * BIG NOTE: This is not equivalent to fsync(). It's not a - * request to sync dirty data. - * - * Flush is called on each close() of a file descriptor. So if a - * filesystem wants to return write errors in close() and the file - * has cached dirty data, this is a good place to write back data - * and return any errors. Since many applications ignore close() - * errors this is not always useful. - * - * NOTE: The flush() method may be called more than once for each - * open(). This happens if more than one file descriptor refers - * to an opened file due to dup(), dup2() or fork() calls. It is - * not possible to determine if a flush is final, so each flush - * should be treated equally. Multiple write-flush sequences are - * relatively rare, so this shouldn't be a problem. - * - * Filesystems shouldn't assume that flush will always be called - * after some writes, or that if will be called at all. - * - * Changed in version 2.2 - */ - int (*flush) (const char *, struct fuse_file_info *); - - /** Release an open file - * - * Release is called when there are no more references to an open - * file: all file descriptors are closed and all memory mappings - * are unmapped. - * - * For every open() call there will be exactly one release() call - * with the same flags and file descriptor. It is possible to - * have a file opened more than once, in which case only the last - * release will mean, that no more reads/writes will happen on the - * file. The return value of release is ignored. - * - * Changed in version 2.2 - */ - int (*release) (const char *, struct fuse_file_info *); - - /** Synchronize file contents - * - * If the datasync parameter is non-zero, then only the user data - * should be flushed, not the meta data. - * - * Changed in version 2.2 - */ - int (*fsync) (const char *, int, struct fuse_file_info *); - - /** Set extended attributes */ - int (*setxattr) (const char *, const char *, const char *, size_t, int); - - /** Get extended attributes */ - int (*getxattr) (const char *, const char *, char *, size_t); - - /** List extended attributes */ - int (*listxattr) (const char *, char *, size_t); - - /** Remove extended attributes */ - int (*removexattr) (const char *, const char *); - - /** Open directory - * - * This method should check if the open operation is permitted for - * this directory - * - * Introduced in version 2.3 - */ - int (*opendir) (const char *, struct fuse_file_info *); - - /** Read directory - * - * This supersedes the old getdir() interface. New applications - * should use this. - * - * The filesystem may choose between two modes of operation: - * - * 1) The readdir implementation ignores the offset parameter, and - * passes zero to the filler function's offset. The filler - * function will not return '1' (unless an error happens), so the - * whole directory is read in a single readdir operation. This - * works just like the old getdir() method. - * - * 2) The readdir implementation keeps track of the offsets of the - * directory entries. It uses the offset parameter and always - * passes non-zero offset to the filler function. When the buffer - * is full (or an error happens) the filler function will return - * '1'. - * - * Introduced in version 2.3 - */ - int (*readdir) (const char *, void *, fuse_fill_dir_t, off_t, - struct fuse_file_info *); - - /** Release directory - * - * Introduced in version 2.3 - */ - int (*releasedir) (const char *, struct fuse_file_info *); - - /** Synchronize directory contents - * - * If the datasync parameter is non-zero, then only the user data - * should be flushed, not the meta data - * - * Introduced in version 2.3 - */ - int (*fsyncdir) (const char *, int, struct fuse_file_info *); - - /** - * Initialize filesystem - * - * The return value will passed in the private_data field of - * fuse_context to all file operations and as a parameter to the - * destroy() method. - * - * Introduced in version 2.3 - * Changed in version 2.6 - */ - void *(*init) (struct fuse_conn_info *conn); - - /** - * Clean up filesystem - * - * Called on filesystem exit. - * - * Introduced in version 2.3 - */ - void (*destroy) (void *); - - /** - * Check file access permissions - * - * This will be called for the access() system call. If the - * 'default_permissions' mount option is given, this method is not - * called. - * - * This method is not called under Linux kernel versions 2.4.x - * - * Introduced in version 2.5 - */ - int (*access) (const char *, int); - - /** - * Create and open a file - * - * If the file does not exist, first create it with the specified - * mode, and then open it. - * - * If this method is not implemented or under Linux kernel - * versions earlier than 2.6.15, the mknod() and open() methods - * will be called instead. - * - * Introduced in version 2.5 - */ - int (*create) (const char *, mode_t, struct fuse_file_info *); - - /** - * Change the size of an open file - * - * This method is called instead of the truncate() method if the - * truncation was invoked from an ftruncate() system call. - * - * If this method is not implemented or under Linux kernel - * versions earlier than 2.6.15, the truncate() method will be - * called instead. - * - * Introduced in version 2.5 - */ - int (*ftruncate) (const char *, off_t, struct fuse_file_info *); - - /** - * Get attributes from an open file - * - * This method is called instead of the getattr() method if the - * file information is available. - * - * Currently this is only called after the create() method if that - * is implemented (see above). Later it may be called for - * invocations of fstat() too. - * - * Introduced in version 2.5 - */ - int (*fgetattr) (const char *, struct stat *, struct fuse_file_info *); - - /** - * Perform POSIX file locking operation - * - * The cmd argument will be either F_GETLK, F_SETLK or F_SETLKW. - * - * For the meaning of fields in 'struct flock' see the man page - * for fcntl(2). The l_whence field will always be set to - * SEEK_SET. - * - * For checking lock ownership, the 'fuse_file_info->owner' - * argument must be used. - * - * For F_GETLK operation, the library will first check currently - * held locks, and if a conflicting lock is found it will return - * information without calling this method. This ensures, that - * for local locks the l_pid field is correctly filled in. The - * results may not be accurate in case of race conditions and in - * the presence of hard links, but it's unlikly that an - * application would rely on accurate GETLK results in these - * cases. If a conflicting lock is not found, this method will be - * called, and the filesystem may fill out l_pid by a meaningful - * value, or it may leave this field zero. - * - * For F_SETLK and F_SETLKW the l_pid field will be set to the pid - * of the process performing the locking operation. - * - * Note: if this method is not implemented, the kernel will still - * allow file locking to work locally. Hence it is only - * interesting for network filesystems and similar. - * - * Introduced in version 2.6 - */ - int (*lock) (const char *, struct fuse_file_info *, int cmd, - struct flock *); - - /** - * Change the access and modification times of a file with - * nanosecond resolution - * - * Introduced in version 2.6 - */ - int (*utimens) (const char *, const struct timespec tv[2]); - - /** - * Map block index within file to block index within device - * - * Note: This makes sense only for block device backed filesystems - * mounted with the 'blkdev' option - * - * Introduced in version 2.6 - */ - int (*bmap) (const char *, size_t blocksize, uint64_t *idx); + /** Get file attributes. + * + * Similar to stat(). The 'st_dev' and 'st_blksize' fields are + * ignored. The 'st_ino' field is ignored except if the 'use_ino' + * mount option is given. + */ + int (*getattr) (const char *, struct stat *); + + /** Read the target of a symbolic link + * + * The buffer should be filled with a null terminated string. The + * buffer size argument includes the space for the terminating + * null character. If the linkname is too long to fit in the + * buffer, it should be truncated. The return value should be 0 + * for success. + */ + int (*readlink) (const char *, char *, size_t); + + /* Deprecated, use readdir() instead */ + int (*getdir) (const char *, fuse_dirh_t, fuse_dirfil_t); + + /** Create a file node + * + * This is called for creation of all non-directory, non-symlink + * nodes. If the filesystem defines a create() method, then for + * regular files that will be called instead. + */ + int (*mknod) (const char *, mode_t, dev_t); + + /** Create a directory */ + int (*mkdir) (const char *, mode_t); + + /** Remove a file */ + int (*unlink) (const char *); + + /** Remove a directory */ + int (*rmdir) (const char *); + + /** Create a symbolic link */ + int (*symlink) (const char *, const char *); + + /** Rename a file */ + int (*rename) (const char *, const char *); + + /** Create a hard link to a file */ + int (*link) (const char *, const char *); + + /** Change the permission bits of a file */ + int (*chmod) (const char *, mode_t); + + /** Change the owner and group of a file */ + int (*chown) (const char *, uid_t, gid_t); + + /** Change the size of a file */ + int (*truncate) (const char *, off_t); + + /** Change the access and/or modification times of a file + * + * Deprecated, use utimens() instead. + */ + int (*utime) (const char *, struct utimbuf *); + + /** File open operation + * + * No creation, or truncation flags (O_CREAT, O_EXCL, O_TRUNC) + * will be passed to open(). Open should check if the operation + * is permitted for the given flags. Optionally open may also + * return an arbitrary filehandle in the fuse_file_info structure, + * which will be passed to all file operations. + * + * Changed in version 2.2 + */ + int (*open) (const char *, struct fuse_file_info *); + + /** Read data from an open file + * + * Read should return exactly the number of bytes requested except + * on EOF or error, otherwise the rest of the data will be + * substituted with zeroes. An exception to this is when the + * 'direct_io' mount option is specified, in which case the return + * value of the read system call will reflect the return value of + * this operation. + * + * Changed in version 2.2 + */ + int (*read) (const char *, char *, size_t, off_t, + struct fuse_file_info *); + + /** Write data to an open file + * + * Write should return exactly the number of bytes requested + * except on error. An exception to this is when the 'direct_io' + * mount option is specified (see read operation). + * + * Changed in version 2.2 + */ + int (*write) (const char *, const char *, size_t, off_t, + struct fuse_file_info *); + + /** Get file system statistics + * + * The 'f_frsize', 'f_favail', 'f_fsid' and 'f_flag' fields are ignored + * + * Replaced 'struct statfs' parameter with 'struct statvfs' in + * version 2.5 + */ + int (*statfs) (const char *, struct statvfs *); + + /** Possibly flush cached data + * + * BIG NOTE: This is not equivalent to fsync(). It's not a + * request to sync dirty data. + * + * Flush is called on each close() of a file descriptor. So if a + * filesystem wants to return write errors in close() and the file + * has cached dirty data, this is a good place to write back data + * and return any errors. Since many applications ignore close() + * errors this is not always useful. + * + * NOTE: The flush() method may be called more than once for each + * open(). This happens if more than one file descriptor refers + * to an opened file due to dup(), dup2() or fork() calls. It is + * not possible to determine if a flush is final, so each flush + * should be treated equally. Multiple write-flush sequences are + * relatively rare, so this shouldn't be a problem. + * + * Filesystems shouldn't assume that flush will always be called + * after some writes, or that if will be called at all. + * + * Changed in version 2.2 + */ + int (*flush) (const char *, struct fuse_file_info *); + + /** Release an open file + * + * Release is called when there are no more references to an open + * file: all file descriptors are closed and all memory mappings + * are unmapped. + * + * For every open() call there will be exactly one release() call + * with the same flags and file descriptor. It is possible to + * have a file opened more than once, in which case only the last + * release will mean, that no more reads/writes will happen on the + * file. The return value of release is ignored. + * + * Changed in version 2.2 + */ + int (*release) (const char *, struct fuse_file_info *); + + /** Synchronize file contents + * + * If the datasync parameter is non-zero, then only the user data + * should be flushed, not the meta data. + * + * Changed in version 2.2 + */ + int (*fsync) (const char *, int, struct fuse_file_info *); + + /** Set extended attributes */ + int (*setxattr) (const char *, const char *, const char *, size_t, int); + + /** Get extended attributes */ + int (*getxattr) (const char *, const char *, char *, size_t); + + /** List extended attributes */ + int (*listxattr) (const char *, char *, size_t); + + /** Remove extended attributes */ + int (*removexattr) (const char *, const char *); + + /** Open directory + * + * This method should check if the open operation is permitted for + * this directory + * + * Introduced in version 2.3 + */ + int (*opendir) (const char *, struct fuse_file_info *); + + /** Read directory + * + * This supersedes the old getdir() interface. New applications + * should use this. + * + * The filesystem may choose between two modes of operation: + * + * 1) The readdir implementation ignores the offset parameter, and + * passes zero to the filler function's offset. The filler + * function will not return '1' (unless an error happens), so the + * whole directory is read in a single readdir operation. This + * works just like the old getdir() method. + * + * 2) The readdir implementation keeps track of the offsets of the + * directory entries. It uses the offset parameter and always + * passes non-zero offset to the filler function. When the buffer + * is full (or an error happens) the filler function will return + * '1'. + * + * Introduced in version 2.3 + */ + int (*readdir) (const char *, void *, fuse_fill_dir_t, off_t, + struct fuse_file_info *); + + /** Release directory + * + * Introduced in version 2.3 + */ + int (*releasedir) (const char *, struct fuse_file_info *); + + /** Synchronize directory contents + * + * If the datasync parameter is non-zero, then only the user data + * should be flushed, not the meta data + * + * Introduced in version 2.3 + */ + int (*fsyncdir) (const char *, int, struct fuse_file_info *); + + /** + * Initialize filesystem + * + * The return value will passed in the private_data field of + * fuse_context to all file operations and as a parameter to the + * destroy() method. + * + * Introduced in version 2.3 + * Changed in version 2.6 + */ + void *(*init) (struct fuse_conn_info *conn); + + /** + * Clean up filesystem + * + * Called on filesystem exit. + * + * Introduced in version 2.3 + */ + void (*destroy) (void *); + + /** + * Check file access permissions + * + * This will be called for the access() system call. If the + * 'default_permissions' mount option is given, this method is not + * called. + * + * This method is not called under Linux kernel versions 2.4.x + * + * Introduced in version 2.5 + */ + int (*access) (const char *, int); + + /** + * Create and open a file + * + * If the file does not exist, first create it with the specified + * mode, and then open it. + * + * If this method is not implemented or under Linux kernel + * versions earlier than 2.6.15, the mknod() and open() methods + * will be called instead. + * + * Introduced in version 2.5 + */ + int (*create) (const char *, mode_t, struct fuse_file_info *); + + /** + * Change the size of an open file + * + * This method is called instead of the truncate() method if the + * truncation was invoked from an ftruncate() system call. + * + * If this method is not implemented or under Linux kernel + * versions earlier than 2.6.15, the truncate() method will be + * called instead. + * + * Introduced in version 2.5 + */ + int (*ftruncate) (const char *, off_t, struct fuse_file_info *); + + /** + * Get attributes from an open file + * + * This method is called instead of the getattr() method if the + * file information is available. + * + * Currently this is only called after the create() method if that + * is implemented (see above). Later it may be called for + * invocations of fstat() too. + * + * Introduced in version 2.5 + */ + int (*fgetattr) (const char *, struct stat *, struct fuse_file_info *); + + /** + * Perform POSIX file locking operation + * + * The cmd argument will be either F_GETLK, F_SETLK or F_SETLKW. + * + * For the meaning of fields in 'struct flock' see the man page + * for fcntl(2). The l_whence field will always be set to + * SEEK_SET. + * + * For checking lock ownership, the 'fuse_file_info->owner' + * argument must be used. + * + * For F_GETLK operation, the library will first check currently + * held locks, and if a conflicting lock is found it will return + * information without calling this method. This ensures, that + * for local locks the l_pid field is correctly filled in. The + * results may not be accurate in case of race conditions and in + * the presence of hard links, but it's unlikly that an + * application would rely on accurate GETLK results in these + * cases. If a conflicting lock is not found, this method will be + * called, and the filesystem may fill out l_pid by a meaningful + * value, or it may leave this field zero. + * + * For F_SETLK and F_SETLKW the l_pid field will be set to the pid + * of the process performing the locking operation. + * + * Note: if this method is not implemented, the kernel will still + * allow file locking to work locally. Hence it is only + * interesting for network filesystems and similar. + * + * Introduced in version 2.6 + */ + int (*lock) (const char *, struct fuse_file_info *, int cmd, + struct flock *); + + /** + * Change the access and modification times of a file with + * nanosecond resolution + * + * Introduced in version 2.6 + */ + int (*utimens) (const char *, const struct timespec tv[2]); + + /** + * Map block index within file to block index within device + * + * Note: This makes sense only for block device backed filesystems + * mounted with the 'blkdev' option + * + * Introduced in version 2.6 + */ + int (*bmap) (const char *, size_t blocksize, uint64_t *idx); }; /** Extra context that may be needed by some filesystems @@ -430,20 +431,20 @@ struct fuse_operations { * operation. */ struct fuse_context { - /** Pointer to the fuse object */ - struct fuse *fuse; + /** Pointer to the fuse object */ + struct fuse *fuse; - /** User ID of the calling process */ - uid_t uid; + /** User ID of the calling process */ + uid_t uid; - /** Group ID of the calling process */ - gid_t gid; + /** Group ID of the calling process */ + gid_t gid; - /** Thread ID of the calling process */ - pid_t pid; + /** Thread ID of the calling process */ + pid_t pid; - /** Private filesystem data */ - void *private_data; + /** Private filesystem data */ + void *private_data; }; /** @@ -470,14 +471,14 @@ struct fuse_context { * @return 0 on success, nonzero on failure */ /* -int fuse_main(int argc, char *argv[], const struct fuse_operations *op, - void *user_data); + int fuse_main(int argc, char *argv[], const struct fuse_operations *op, + void *user_data); */ -#define fuse_main(argc, argv, op, user_data) \ - fuse_main_real(argc, argv, op, sizeof(*(op)), user_data) +#define fuse_main(argc, argv, op, user_data) \ + fuse_main_real(argc, argv, op, sizeof(*(op)), user_data) /* ----------------------------------------------------------- * - * More detailed API * + * More detailed API * * ----------------------------------------------------------- */ /** @@ -491,15 +492,15 @@ int fuse_main(int argc, char *argv[], const struct fuse_operations *op, * @return the created FUSE handle */ struct fuse *fuse_new(struct fuse_chan *ch, struct fuse_args *args, - const struct fuse_operations *op, size_t op_size, - void *user_data); + const struct fuse_operations *op, size_t op_size, + void *user_data); /** * Destroy the FUSE handle. * * The communication channel attached to the handle is also destroyed. * - * NOTE: This function does not unmount the filesystem. If this is + * NOTE: This function does not unmount the filesystem. If this is * needed, call fuse_unmount() before calling this function. * * @param f the FUSE handle @@ -573,7 +574,7 @@ int fuse_is_lib_option(const char *opt); * Do not call this directly, use fuse_main() */ int fuse_main_real(int argc, char *argv[], const struct fuse_operations *op, - size_t op_size, void *user_data); + size_t op_size, void *user_data); /* * Stacking API @@ -597,63 +598,63 @@ struct fuse_fs; int fuse_fs_getattr(struct fuse_fs *fs, const char *path, struct stat *buf); int fuse_fs_fgetattr(struct fuse_fs *fs, const char *path, struct stat *buf, - struct fuse_file_info *fi); + struct fuse_file_info *fi); int fuse_fs_rename(struct fuse_fs *fs, const char *oldpath, - const char *newpath); + const char *newpath); int fuse_fs_unlink(struct fuse_fs *fs, const char *path); int fuse_fs_rmdir(struct fuse_fs *fs, const char *path); int fuse_fs_symlink(struct fuse_fs *fs, const char *linkname, - const char *path); + const char *path); int fuse_fs_link(struct fuse_fs *fs, const char *oldpath, const char *newpath); -int fuse_fs_release(struct fuse_fs *fs, const char *path, - struct fuse_file_info *fi); +int fuse_fs_release(struct fuse_fs *fs, const char *path, + struct fuse_file_info *fi); int fuse_fs_open(struct fuse_fs *fs, const char *path, - struct fuse_file_info *fi); + struct fuse_file_info *fi); int fuse_fs_read(struct fuse_fs *fs, const char *path, char *buf, size_t size, - off_t off, struct fuse_file_info *fi); + off_t off, struct fuse_file_info *fi); int fuse_fs_write(struct fuse_fs *fs, const char *path, const char *buf, - size_t size, off_t off, struct fuse_file_info *fi); + size_t size, off_t off, struct fuse_file_info *fi); int fuse_fs_fsync(struct fuse_fs *fs, const char *path, int datasync, - struct fuse_file_info *fi); + struct fuse_file_info *fi); int fuse_fs_flush(struct fuse_fs *fs, const char *path, - struct fuse_file_info *fi); + struct fuse_file_info *fi); int fuse_fs_statfs(struct fuse_fs *fs, const char *path, struct statvfs *buf); int fuse_fs_opendir(struct fuse_fs *fs, const char *path, - struct fuse_file_info *fi); + struct fuse_file_info *fi); int fuse_fs_readdir(struct fuse_fs *fs, const char *path, void *buf, - fuse_fill_dir_t filler, off_t off, - struct fuse_file_info *fi); + fuse_fill_dir_t filler, off_t off, + struct fuse_file_info *fi); int fuse_fs_fsyncdir(struct fuse_fs *fs, const char *path, int datasync, - struct fuse_file_info *fi); + struct fuse_file_info *fi); int fuse_fs_releasedir(struct fuse_fs *fs, const char *path, - struct fuse_file_info *fi); + struct fuse_file_info *fi); int fuse_fs_create(struct fuse_fs *fs, const char *path, mode_t mode, - struct fuse_file_info *fi); + struct fuse_file_info *fi); int fuse_fs_lock(struct fuse_fs *fs, const char *path, - struct fuse_file_info *fi, int cmd, struct flock *lock); + struct fuse_file_info *fi, int cmd, struct flock *lock); int fuse_fs_chmod(struct fuse_fs *fs, const char *path, mode_t mode); int fuse_fs_chown(struct fuse_fs *fs, const char *path, uid_t uid, gid_t gid); int fuse_fs_truncate(struct fuse_fs *fs, const char *path, off_t size); int fuse_fs_ftruncate(struct fuse_fs *fs, const char *path, off_t size, - struct fuse_file_info *fi); + struct fuse_file_info *fi); int fuse_fs_utimens(struct fuse_fs *fs, const char *path, - const struct timespec tv[2]); + const struct timespec tv[2]); int fuse_fs_access(struct fuse_fs *fs, const char *path, int mask); int fuse_fs_readlink(struct fuse_fs *fs, const char *path, char *buf, - size_t len); + size_t len); int fuse_fs_mknod(struct fuse_fs *fs, const char *path, mode_t mode, - dev_t rdev); + dev_t rdev); int fuse_fs_mkdir(struct fuse_fs *fs, const char *path, mode_t mode); int fuse_fs_setxattr(struct fuse_fs *fs, const char *path, const char *name, - const char *value, size_t size, int flags); + const char *value, size_t size, int flags); int fuse_fs_getxattr(struct fuse_fs *fs, const char *path, const char *name, - char *value, size_t size); + char *value, size_t size); int fuse_fs_listxattr(struct fuse_fs *fs, const char *path, char *list, - size_t size); + size_t size); int fuse_fs_removexattr(struct fuse_fs *fs, const char *path, - const char *name); + const char *name); int fuse_fs_bmap(struct fuse_fs *fs, const char *path, size_t blocksize, - uint64_t *idx); + uint64_t *idx); void fuse_fs_init(struct fuse_fs *fs, struct fuse_conn_info *conn); void fuse_fs_destroy(struct fuse_fs *fs); @@ -669,7 +670,7 @@ void fuse_fs_destroy(struct fuse_fs *fs); * @return a new filesystem object */ struct fuse_fs *fuse_fs_new(const struct fuse_operations *op, size_t op_size, - void *user_data); + void *user_data); /** * Filesystem module @@ -682,30 +683,31 @@ struct fuse_fs *fuse_fs_new(const struct fuse_operations *op, size_t op_size, * function. */ struct fuse_module { - /** - * Name of filesystem - */ - const char *name; - - /** - * Factory for creating filesystem objects - * - * The function may use and remove options from 'args' that belong - * to this module. - * - * For now the 'fs' vector always contains exactly one filesystem. - * This is the filesystem which will be below the newly created - * filesystem in the stack. - * - * @param args the command line arguments - * @param fs NULL terminated filesystem object vector - * @return the new filesystem object - */ - struct fuse_fs *(*factory)(struct fuse_args *args, struct fuse_fs *fs[]); - - struct fuse_module *next; - struct fusemod_so *so; - int ctr; + /** + * Name of filesystem + */ + const char *name; + + /** + * Factory for creating filesystem objects + * + * The function may use and remove options from 'args' that belong + * to this module. + * + * For now the 'fs' vector always contains exactly one filesystem. + * This is the filesystem which will be below the newly created + * filesystem in the stack. + * + * @param args the command line arguments + * @param fs NULL terminated filesystem object vector + * @return the new filesystem object + */ + struct fuse_fs *(*factory)(struct fuse_args *args, + struct fuse_fs *fs[]); + + struct fuse_module *next; + struct fusemod_so *so; + int ctr; }; /** @@ -722,12 +724,13 @@ void fuse_register_module(struct fuse_module *mod); * For the parameters, see description of the fields in 'struct * fuse_module' */ -#define FUSE_REGISTER_MODULE(name_, factory_) \ -static __attribute__((constructor)) void name_ ## _register(void) \ -{ \ - static struct fuse_module mod = { #name_, factory_, NULL, NULL, 0 }; \ - fuse_register_module(&mod); \ -} +#define FUSE_REGISTER_MODULE(name_, factory_) \ + static __attribute__((constructor)) void name_ ## _register(void) \ + { \ + static struct fuse_module mod = \ + { #name_, factory_, NULL, NULL, 0 }; \ + fuse_register_module(&mod); \ + } /* ----------------------------------------------------------- * @@ -742,9 +745,9 @@ typedef void (*fuse_processor_t)(struct fuse *, struct fuse_cmd *, void *); /** This is the part of fuse_main() before the event loop */ struct fuse *fuse_setup(int argc, char *argv[], - const struct fuse_operations *op, size_t op_size, - char **mountpoint, int *multithreaded, - void *user_data); + const struct fuse_operations *op, size_t op_size, + char **mountpoint, int *multithreaded, + void *user_data); /** This is the part of fuse_main() after the event loop */ void fuse_teardown(struct fuse *fuse, char *mountpoint); @@ -770,22 +773,22 @@ void fuse_set_getcontext_func(struct fuse_context *(*func)(void)); struct fuse_session *fuse_get_session(struct fuse *f); /* ----------------------------------------------------------- * - * Compatibility stuff * + * Compatibility stuff * * ----------------------------------------------------------- */ #if FUSE_USE_VERSION < 26 # include "fuse_compat.h" # undef fuse_main # if FUSE_USE_VERSION == 25 -# define fuse_main(argc, argv, op) \ - fuse_main_real_compat25(argc, argv, op, sizeof(*(op))) +# define fuse_main(argc, argv, op) \ + fuse_main_real_compat25(argc, argv, op, sizeof(*(op))) # define fuse_new fuse_new_compat25 # define fuse_setup fuse_setup_compat25 # define fuse_teardown fuse_teardown_compat22 # define fuse_operations fuse_operations_compat25 # elif FUSE_USE_VERSION == 22 -# define fuse_main(argc, argv, op) \ - fuse_main_real_compat22(argc, argv, op, sizeof(*(op))) +# define fuse_main(argc, argv, op) \ + fuse_main_real_compat22(argc, argv, op, sizeof(*(op))) # define fuse_new fuse_new_compat22 # define fuse_setup fuse_setup_compat22 # define fuse_teardown fuse_teardown_compat22 diff --git a/include/fuse_common.h b/include/fuse_common.h index 1a97512..9747e45 100644 --- a/include/fuse_common.h +++ b/include/fuse_common.h @@ -1,9 +1,9 @@ /* - FUSE: Filesystem in Userspace - Copyright (C) 2001-2007 Miklos Szeredi + FUSE: Filesystem in Userspace + Copyright (C) 2001-2007 Miklos Szeredi - This program can be distributed under the terms of the GNU LGPLv2. - See the file COPYING.LIB. + This program can be distributed under the terms of the GNU LGPLv2. + See the file COPYING.LIB. */ /** @file */ @@ -42,38 +42,38 @@ extern "C" { * Changed in version 2.5 */ struct fuse_file_info { - /** Open flags. Available in open() and release() */ - int flags; + /** Open flags. Available in open() and release() */ + int flags; - /** Old file handle, don't use */ - unsigned long fh_old; + /** Old file handle, don't use */ + unsigned long fh_old; - /** In case of a write operation indicates if this was caused by a - writepage */ - int writepage; + /** In case of a write operation indicates if this was caused by a + writepage */ + int writepage; - /** Can be filled in by open, to use direct I/O on this file. - Introduced in version 2.4 */ - unsigned int direct_io : 1; + /** Can be filled in by open, to use direct I/O on this file. + Introduced in version 2.4 */ + unsigned int direct_io : 1; - /** Can be filled in by open, to indicate, that cached file data - need not be invalidated. Introduced in version 2.4 */ - unsigned int keep_cache : 1; + /** Can be filled in by open, to indicate, that cached file data + need not be invalidated. Introduced in version 2.4 */ + unsigned int keep_cache : 1; - /** Indicates a flush operation. Set in flush operation, also - maybe set in highlevel lock operation and lowlevel release - operation. Introduced in version 2.6 */ - unsigned int flush : 1; + /** Indicates a flush operation. Set in flush operation, also + maybe set in highlevel lock operation and lowlevel release + operation. Introduced in version 2.6 */ + unsigned int flush : 1; - /** Padding. Do not use*/ - unsigned int padding : 29; + /** Padding. Do not use*/ + unsigned int padding : 29; - /** File handle. May be filled in by filesystem in open(). - Available in all other file operations */ - uint64_t fh; + /** File handle. May be filled in by filesystem in open(). + Available in all other file operations */ + uint64_t fh; - /** Lock owner id. Available in locking operations and flush */ - uint64_t lock_owner; + /** Lock owner id. Available in locking operations and flush */ + uint64_t lock_owner; }; /** @@ -84,35 +84,35 @@ struct fuse_file_info { * value must usually be smaller than the indicated value. */ struct fuse_conn_info { - /** - * Major version of the protocol (read-only) - */ - unsigned proto_major; - - /** - * Minor version of the protocol (read-only) - */ - unsigned proto_minor; - - /** - * Is asynchronous read supported (read-write) - */ - unsigned async_read; - - /** - * Maximum size of the write buffer - */ - unsigned max_write; - - /** - * Maximum readahead - */ - unsigned max_readahead; - - /** - * For future use. - */ - unsigned reserved[27]; + /** + * Major version of the protocol (read-only) + */ + unsigned proto_major; + + /** + * Minor version of the protocol (read-only) + */ + unsigned proto_minor; + + /** + * Is asynchronous read supported (read-write) + */ + unsigned async_read; + + /** + * Maximum size of the write buffer + */ + unsigned max_write; + + /** + * Maximum readahead + */ + unsigned max_readahead; + + /** + * For future use. + */ + unsigned reserved[27]; }; struct fuse_session; @@ -143,13 +143,13 @@ void fuse_unmount(const char *mountpoint, struct fuse_chan *ch); * * The following options are parsed: * - * '-f' foreground + * '-f' foreground * '-d' '-odebug' foreground, but keep the debug option - * '-s' single threaded + * '-s' single threaded * '-h' '--help' help - * '-ho' help without header + * '-ho' help without header * '-ofsname=..' file system name, if not present, then set to the program - * name + * name * * All parameters may be NULL * @@ -160,7 +160,7 @@ void fuse_unmount(const char *mountpoint, struct fuse_chan *ch); * @return 0 on success, -1 on failure */ int fuse_parse_cmdline(struct fuse_args *args, char **mountpoint, - int *multithreaded, int *foreground); + int *multithreaded, int *foreground); /** * Go into the background @@ -178,13 +178,13 @@ int fuse_daemonize(int foreground); int fuse_version(void); /* ----------------------------------------------------------- * - * Signal handling * + * Signal handling * * ----------------------------------------------------------- */ /** * Exit session on HUP, TERM and INT signals and ignore PIPE signal * - * Stores session in a global variable. May only be called once per + * Stores session in a global variable. May only be called once per * process until fuse_remove_signal_handlers() is called. * * @param se the session to exit @@ -203,36 +203,36 @@ int fuse_set_signal_handlers(struct fuse_session *se); void fuse_remove_signal_handlers(struct fuse_session *se); /* ----------------------------------------------------------- * - * Compatibility stuff * + * Compatibility stuff * * ----------------------------------------------------------- */ #if FUSE_USE_VERSION < 26 # ifdef __FreeBSD__ -# if FUSE_USE_VERSION < 25 -# error On FreeBSD API version 25 or greater must be used -# endif +# if FUSE_USE_VERSION < 25 +# error On FreeBSD API version 25 or greater must be used +# endif # endif # include "fuse_common_compat.h" # undef FUSE_MINOR_VERSION # undef fuse_main # define fuse_unmount fuse_unmount_compat22 # if FUSE_USE_VERSION == 25 -# define FUSE_MINOR_VERSION 5 -# define fuse_mount fuse_mount_compat25 +# define FUSE_MINOR_VERSION 5 +# define fuse_mount fuse_mount_compat25 # elif FUSE_USE_VERSION == 24 || FUSE_USE_VERSION == 22 -# define FUSE_MINOR_VERSION 4 -# define fuse_mount fuse_mount_compat22 +# define FUSE_MINOR_VERSION 4 +# define fuse_mount fuse_mount_compat22 # elif FUSE_USE_VERSION == 21 -# define FUSE_MINOR_VERSION 1 -# define fuse_mount fuse_mount_compat22 +# define FUSE_MINOR_VERSION 1 +# define fuse_mount fuse_mount_compat22 # elif FUSE_USE_VERSION == 11 -# warning Compatibility with API version 11 is deprecated -# undef FUSE_MAJOR_VERSION -# define FUSE_MAJOR_VERSION 1 -# define FUSE_MINOR_VERSION 1 -# define fuse_mount fuse_mount_compat1 +# warning Compatibility with API version 11 is deprecated +# undef FUSE_MAJOR_VERSION +# define FUSE_MAJOR_VERSION 1 +# define FUSE_MINOR_VERSION 1 +# define fuse_mount fuse_mount_compat1 # else -# error Compatibility with API version other than 21, 22, 24, 25 and 11 not supported +# error Compatibility with API version other than 21, 22, 24, 25 and 11 not supported # endif #endif diff --git a/include/fuse_common_compat.h b/include/fuse_common_compat.h index 0383ed7..34440ff 100644 --- a/include/fuse_common_compat.h +++ b/include/fuse_common_compat.h @@ -1,20 +1,20 @@ /* - FUSE: Filesystem in Userspace - Copyright (C) 2001-2007 Miklos Szeredi + FUSE: Filesystem in Userspace + Copyright (C) 2001-2007 Miklos Szeredi - This program can be distributed under the terms of the GNU LGPLv2. - See the file COPYING.LIB. + This program can be distributed under the terms of the GNU LGPLv2. + See the file COPYING.LIB. */ /* these definitions provide source compatibility to prior versions. Do not include this file directly! */ struct fuse_file_info_compat { - int flags; - unsigned long fh; - int writepage; - unsigned int direct_io : 1; - unsigned int keep_cache : 1; + int flags; + unsigned long fh; + int writepage; + unsigned int direct_io : 1; + unsigned int keep_cache : 1; }; int fuse_mount_compat25(const char *mountpoint, struct fuse_args *args); @@ -24,4 +24,3 @@ int fuse_mount_compat22(const char *mountpoint, const char *opts); int fuse_mount_compat1(const char *mountpoint, const char *args[]); void fuse_unmount_compat22(const char *mountpoint); - diff --git a/include/fuse_compat.h b/include/fuse_compat.h index 59df3d3..225276f 100644 --- a/include/fuse_compat.h +++ b/include/fuse_compat.h @@ -1,66 +1,67 @@ /* - FUSE: Filesystem in Userspace - Copyright (C) 2001-2007 Miklos Szeredi + FUSE: Filesystem in Userspace + Copyright (C) 2001-2007 Miklos Szeredi - This program can be distributed under the terms of the GNU LGPLv2. - See the file COPYING.LIB. + This program can be distributed under the terms of the GNU LGPLv2. + See the file COPYING.LIB. */ /* these definitions provide source compatibility to prior versions. Do not include this file directly! */ struct fuse_operations_compat25 { - int (*getattr) (const char *, struct stat *); - int (*readlink) (const char *, char *, size_t); - int (*getdir) (const char *, fuse_dirh_t, fuse_dirfil_t); - int (*mknod) (const char *, mode_t, dev_t); - int (*mkdir) (const char *, mode_t); - int (*unlink) (const char *); - int (*rmdir) (const char *); - int (*symlink) (const char *, const char *); - int (*rename) (const char *, const char *); - int (*link) (const char *, const char *); - int (*chmod) (const char *, mode_t); - int (*chown) (const char *, uid_t, gid_t); - int (*truncate) (const char *, off_t); - int (*utime) (const char *, struct utimbuf *); - int (*open) (const char *, struct fuse_file_info *); - int (*read) (const char *, char *, size_t, off_t, struct fuse_file_info *); - int (*write) (const char *, const char *, size_t, off_t, - struct fuse_file_info *); - int (*statfs) (const char *, struct statvfs *); - int (*flush) (const char *, struct fuse_file_info *); - int (*release) (const char *, struct fuse_file_info *); - int (*fsync) (const char *, int, struct fuse_file_info *); - int (*setxattr) (const char *, const char *, const char *, size_t, int); - int (*getxattr) (const char *, const char *, char *, size_t); - int (*listxattr) (const char *, char *, size_t); - int (*removexattr) (const char *, const char *); - int (*opendir) (const char *, struct fuse_file_info *); - int (*readdir) (const char *, void *, fuse_fill_dir_t, off_t, - struct fuse_file_info *); - int (*releasedir) (const char *, struct fuse_file_info *); - int (*fsyncdir) (const char *, int, struct fuse_file_info *); - void *(*init) (void); - void (*destroy) (void *); - int (*access) (const char *, int); - int (*create) (const char *, mode_t, struct fuse_file_info *); - int (*ftruncate) (const char *, off_t, struct fuse_file_info *); - int (*fgetattr) (const char *, struct stat *, struct fuse_file_info *); + int (*getattr) (const char *, struct stat *); + int (*readlink) (const char *, char *, size_t); + int (*getdir) (const char *, fuse_dirh_t, fuse_dirfil_t); + int (*mknod) (const char *, mode_t, dev_t); + int (*mkdir) (const char *, mode_t); + int (*unlink) (const char *); + int (*rmdir) (const char *); + int (*symlink) (const char *, const char *); + int (*rename) (const char *, const char *); + int (*link) (const char *, const char *); + int (*chmod) (const char *, mode_t); + int (*chown) (const char *, uid_t, gid_t); + int (*truncate) (const char *, off_t); + int (*utime) (const char *, struct utimbuf *); + int (*open) (const char *, struct fuse_file_info *); + int (*read) (const char *, char *, size_t, off_t, + struct fuse_file_info *); + int (*write) (const char *, const char *, size_t, off_t, + struct fuse_file_info *); + int (*statfs) (const char *, struct statvfs *); + int (*flush) (const char *, struct fuse_file_info *); + int (*release) (const char *, struct fuse_file_info *); + int (*fsync) (const char *, int, struct fuse_file_info *); + int (*setxattr) (const char *, const char *, const char *, size_t, int); + int (*getxattr) (const char *, const char *, char *, size_t); + int (*listxattr) (const char *, char *, size_t); + int (*removexattr) (const char *, const char *); + int (*opendir) (const char *, struct fuse_file_info *); + int (*readdir) (const char *, void *, fuse_fill_dir_t, off_t, + struct fuse_file_info *); + int (*releasedir) (const char *, struct fuse_file_info *); + int (*fsyncdir) (const char *, int, struct fuse_file_info *); + void *(*init) (void); + void (*destroy) (void *); + int (*access) (const char *, int); + int (*create) (const char *, mode_t, struct fuse_file_info *); + int (*ftruncate) (const char *, off_t, struct fuse_file_info *); + int (*fgetattr) (const char *, struct stat *, struct fuse_file_info *); }; struct fuse *fuse_new_compat25(int fd, struct fuse_args *args, - const struct fuse_operations_compat25 *op, - size_t op_size); + const struct fuse_operations_compat25 *op, + size_t op_size); int fuse_main_real_compat25(int argc, char *argv[], - const struct fuse_operations_compat25 *op, - size_t op_size); + const struct fuse_operations_compat25 *op, + size_t op_size); struct fuse *fuse_setup_compat25(int argc, char *argv[], - const struct fuse_operations_compat25 *op, - size_t op_size, char **mountpoint, - int *multithreaded, int *fd); + const struct fuse_operations_compat25 *op, + size_t op_size, char **mountpoint, + int *multithreaded, int *fd); void fuse_teardown_compat22(struct fuse *fuse, int fd, char *mountpoint); @@ -68,126 +69,133 @@ void fuse_teardown_compat22(struct fuse *fuse, int fd, char *mountpoint); #include struct fuse_operations_compat22 { - int (*getattr) (const char *, struct stat *); - int (*readlink) (const char *, char *, size_t); - int (*getdir) (const char *, fuse_dirh_t, fuse_dirfil_t); - int (*mknod) (const char *, mode_t, dev_t); - int (*mkdir) (const char *, mode_t); - int (*unlink) (const char *); - int (*rmdir) (const char *); - int (*symlink) (const char *, const char *); - int (*rename) (const char *, const char *); - int (*link) (const char *, const char *); - int (*chmod) (const char *, mode_t); - int (*chown) (const char *, uid_t, gid_t); - int (*truncate) (const char *, off_t); - int (*utime) (const char *, struct utimbuf *); - int (*open) (const char *, struct fuse_file_info_compat *); - int (*read) (const char *, char *, size_t, off_t, - struct fuse_file_info_compat *); - int (*write) (const char *, const char *, size_t, off_t, - struct fuse_file_info_compat *); - int (*statfs) (const char *, struct statfs *); - int (*flush) (const char *, struct fuse_file_info_compat *); - int (*release) (const char *, struct fuse_file_info_compat *); - int (*fsync) (const char *, int, struct fuse_file_info_compat *); - int (*setxattr) (const char *, const char *, const char *, size_t, int); - int (*getxattr) (const char *, const char *, char *, size_t); - int (*listxattr) (const char *, char *, size_t); - int (*removexattr) (const char *, const char *); - int (*opendir) (const char *, struct fuse_file_info_compat *); - int (*readdir) (const char *, void *, fuse_fill_dir_t, off_t, - struct fuse_file_info_compat *); - int (*releasedir) (const char *, struct fuse_file_info_compat *); - int (*fsyncdir) (const char *, int, struct fuse_file_info_compat *); - void *(*init) (void); - void (*destroy) (void *); + int (*getattr) (const char *, struct stat *); + int (*readlink) (const char *, char *, size_t); + int (*getdir) (const char *, fuse_dirh_t, fuse_dirfil_t); + int (*mknod) (const char *, mode_t, dev_t); + int (*mkdir) (const char *, mode_t); + int (*unlink) (const char *); + int (*rmdir) (const char *); + int (*symlink) (const char *, const char *); + int (*rename) (const char *, const char *); + int (*link) (const char *, const char *); + int (*chmod) (const char *, mode_t); + int (*chown) (const char *, uid_t, gid_t); + int (*truncate) (const char *, off_t); + int (*utime) (const char *, struct utimbuf *); + int (*open) (const char *, struct fuse_file_info_compat *); + int (*read) (const char *, char *, size_t, off_t, + struct fuse_file_info_compat *); + int (*write) (const char *, const char *, size_t, off_t, + struct fuse_file_info_compat *); + int (*statfs) (const char *, struct statfs *); + int (*flush) (const char *, struct fuse_file_info_compat *); + int (*release) (const char *, struct fuse_file_info_compat *); + int (*fsync) (const char *, int, struct fuse_file_info_compat *); + int (*setxattr) (const char *, const char *, const char *, size_t, int); + int (*getxattr) (const char *, const char *, char *, size_t); + int (*listxattr) (const char *, char *, size_t); + int (*removexattr) (const char *, const char *); + int (*opendir) (const char *, struct fuse_file_info_compat *); + int (*readdir) (const char *, void *, fuse_fill_dir_t, off_t, + struct fuse_file_info_compat *); + int (*releasedir) (const char *, struct fuse_file_info_compat *); + int (*fsyncdir) (const char *, int, struct fuse_file_info_compat *); + void *(*init) (void); + void (*destroy) (void *); }; struct fuse *fuse_new_compat22(int fd, const char *opts, - const struct fuse_operations_compat22 *op, - size_t op_size); + const struct fuse_operations_compat22 *op, + size_t op_size); struct fuse *fuse_setup_compat22(int argc, char *argv[], - const struct fuse_operations_compat22 *op, - size_t op_size, char **mountpoint, - int *multithreaded, int *fd); + const struct fuse_operations_compat22 *op, + size_t op_size, char **mountpoint, + int *multithreaded, int *fd); int fuse_main_real_compat22(int argc, char *argv[], - const struct fuse_operations_compat22 *op, - size_t op_size); + const struct fuse_operations_compat22 *op, + size_t op_size); typedef int (*fuse_dirfil_t_compat) (fuse_dirh_t h, const char *name, int type); struct fuse_operations_compat2 { - int (*getattr) (const char *, struct stat *); - int (*readlink) (const char *, char *, size_t); - int (*getdir) (const char *, fuse_dirh_t, fuse_dirfil_t_compat); - int (*mknod) (const char *, mode_t, dev_t); - int (*mkdir) (const char *, mode_t); - int (*unlink) (const char *); - int (*rmdir) (const char *); - int (*symlink) (const char *, const char *); - int (*rename) (const char *, const char *); - int (*link) (const char *, const char *); - int (*chmod) (const char *, mode_t); - int (*chown) (const char *, uid_t, gid_t); - int (*truncate) (const char *, off_t); - int (*utime) (const char *, struct utimbuf *); - int (*open) (const char *, int); - int (*read) (const char *, char *, size_t, off_t); - int (*write) (const char *, const char *, size_t, off_t); - int (*statfs) (const char *, struct statfs *); - int (*flush) (const char *); - int (*release) (const char *, int); - int (*fsync) (const char *, int); - int (*setxattr) (const char *, const char *, const char *, size_t, int); - int (*getxattr) (const char *, const char *, char *, size_t); - int (*listxattr) (const char *, char *, size_t); - int (*removexattr) (const char *, const char *); + int (*getattr) (const char *, struct stat *); + int (*readlink) (const char *, char *, size_t); + int (*getdir) (const char *, fuse_dirh_t, fuse_dirfil_t_compat); + int (*mknod) (const char *, mode_t, dev_t); + int (*mkdir) (const char *, mode_t); + int (*unlink) (const char *); + int (*rmdir) (const char *); + int (*symlink) (const char *, const char *); + int (*rename) (const char *, const char *); + int (*link) (const char *, const char *); + int (*chmod) (const char *, mode_t); + int (*chown) (const char *, uid_t, gid_t); + int (*truncate) (const char *, off_t); + int (*utime) (const char *, struct utimbuf *); + int (*open) (const char *, int); + int (*read) (const char *, char *, size_t, off_t); + int (*write) (const char *, const char *, size_t, off_t); + int (*statfs) (const char *, struct statfs *); + int (*flush) (const char *); + int (*release) (const char *, int); + int (*fsync) (const char *, int); + int (*setxattr) (const char *, const char *, const char *, + size_t, int); + int (*getxattr) (const char *, const char *, char *, size_t); + int (*listxattr) (const char *, char *, size_t); + int (*removexattr) (const char *, const char *); }; -int fuse_main_compat2(int argc, char *argv[], const struct fuse_operations_compat2 *op); +int fuse_main_compat2(int argc, char *argv[], + const struct fuse_operations_compat2 *op); -struct fuse *fuse_new_compat2(int fd, const char *opts, const struct fuse_operations_compat2 *op); +struct fuse *fuse_new_compat2(int fd, const char *opts, + const struct fuse_operations_compat2 *op); -struct fuse *fuse_setup_compat2(int argc, char *argv[], const struct fuse_operations_compat2 *op, char **mountpoint, int *multithreaded, int *fd); +struct fuse *fuse_setup_compat2(int argc, char *argv[], + const struct fuse_operations_compat2 *op, + char **mountpoint, int *multithreaded, int *fd); struct fuse_statfs_compat1 { - long block_size; - long blocks; - long blocks_free; - long files; - long files_free; - long namelen; + long block_size; + long blocks; + long blocks_free; + long files; + long files_free; + long namelen; }; struct fuse_operations_compat1 { - int (*getattr) (const char *, struct stat *); - int (*readlink) (const char *, char *, size_t); - int (*getdir) (const char *, fuse_dirh_t, fuse_dirfil_t_compat); - int (*mknod) (const char *, mode_t, dev_t); - int (*mkdir) (const char *, mode_t); - int (*unlink) (const char *); - int (*rmdir) (const char *); - int (*symlink) (const char *, const char *); - int (*rename) (const char *, const char *); - int (*link) (const char *, const char *); - int (*chmod) (const char *, mode_t); - int (*chown) (const char *, uid_t, gid_t); - int (*truncate) (const char *, off_t); - int (*utime) (const char *, struct utimbuf *); - int (*open) (const char *, int); - int (*read) (const char *, char *, size_t, off_t); - int (*write) (const char *, const char *, size_t, off_t); - int (*statfs) (struct fuse_statfs_compat1 *); - int (*release) (const char *, int); - int (*fsync) (const char *, int); + int (*getattr) (const char *, struct stat *); + int (*readlink) (const char *, char *, size_t); + int (*getdir) (const char *, fuse_dirh_t, fuse_dirfil_t_compat); + int (*mknod) (const char *, mode_t, dev_t); + int (*mkdir) (const char *, mode_t); + int (*unlink) (const char *); + int (*rmdir) (const char *); + int (*symlink) (const char *, const char *); + int (*rename) (const char *, const char *); + int (*link) (const char *, const char *); + int (*chmod) (const char *, mode_t); + int (*chown) (const char *, uid_t, gid_t); + int (*truncate) (const char *, off_t); + int (*utime) (const char *, struct utimbuf *); + int (*open) (const char *, int); + int (*read) (const char *, char *, size_t, off_t); + int (*write) (const char *, const char *, size_t, off_t); + int (*statfs) (struct fuse_statfs_compat1 *); + int (*release) (const char *, int); + int (*fsync) (const char *, int); }; -#define FUSE_DEBUG_COMPAT1 (1 << 1) +#define FUSE_DEBUG_COMPAT1 (1 << 1) -struct fuse *fuse_new_compat1(int fd, int flags, const struct fuse_operations_compat1 *op); +struct fuse *fuse_new_compat1(int fd, int flags, + const struct fuse_operations_compat1 *op); -void fuse_main_compat1(int argc, char *argv[], const struct fuse_operations_compat1 *op); +void fuse_main_compat1(int argc, char *argv[], + const struct fuse_operations_compat1 *op); #endif /* __FreeBSD__ */ diff --git a/include/fuse_lowlevel.h b/include/fuse_lowlevel.h index 96c7340..9330548 100644 --- a/include/fuse_lowlevel.h +++ b/include/fuse_lowlevel.h @@ -1,9 +1,9 @@ /* - FUSE: Filesystem in Userspace - Copyright (C) 2001-2007 Miklos Szeredi + FUSE: Filesystem in Userspace + Copyright (C) 2001-2007 Miklos Szeredi - This program can be distributed under the terms of the GNU LGPLv2. - See the file COPYING.LIB. + This program can be distributed under the terms of the GNU LGPLv2. + See the file COPYING.LIB. */ #ifndef _FUSE_LOWLEVEL_H_ @@ -37,7 +37,7 @@ extern "C" { #endif /* ----------------------------------------------------------- * - * Miscellaneous definitions * + * Miscellaneous definitions * * ----------------------------------------------------------- */ /** The node ID of the root inode */ @@ -66,43 +66,49 @@ struct fuse_chan; /** Directory entry parameters supplied to fuse_reply_entry() */ struct fuse_entry_param { - /** Unique inode number - * - * In lookup, zero means negative entry (from version 2.5) - * Returning ENOENT also means negative entry, but by setting zero - * ino the kernel may cache negative entries for entry_timeout - * seconds. - */ - fuse_ino_t ino; - - /** Generation number for this entry. The ino/generation pair - should be unique for the filesystem's lifetime. It must be - non-zero, otherwise FUSE will treat it as an error. */ - unsigned long generation; - - /** Inode attributes. Even if attr_timeout == 0, attr must be - correct. For example, for open(), FUSE uses attr.st_size from - lookup() to determine how many bytes to request. If this - value is not correct, incorrect data will be returned. */ - struct stat attr; - - /** Validity timeout (in seconds) for the attributes */ - double attr_timeout; - - /** Validity timeout (in seconds) for the name */ - double entry_timeout; + /** Unique inode number + * + * In lookup, zero means negative entry (from version 2.5) + * Returning ENOENT also means negative entry, but by setting zero + * ino the kernel may cache negative entries for entry_timeout + * seconds. + */ + fuse_ino_t ino; + + /** Generation number for this entry. + * + * The ino/generation pair should be unique for the filesystem's + * lifetime. It must be non-zero, otherwise FUSE will treat it as an + * error. + */ + unsigned long generation; + + /** Inode attributes. + * + * Even if attr_timeout == 0, attr must be correct. For example, + * for open(), FUSE uses attr.st_size from lookup() to determine + * how many bytes to request. If this value is not correct, + * incorrect data will be returned. + */ + struct stat attr; + + /** Validity timeout (in seconds) for the attributes */ + double attr_timeout; + + /** Validity timeout (in seconds) for the name */ + double entry_timeout; }; /** Additional context associated with requests */ struct fuse_ctx { - /** User ID of the calling process */ - uid_t uid; + /** User ID of the calling process */ + uid_t uid; - /** Group ID of the calling process */ - gid_t gid; + /** Group ID of the calling process */ + gid_t gid; - /** Thread ID of the calling process */ - pid_t pid; + /** Thread ID of the calling process */ + pid_t pid; }; /* 'to_set' flags in setattr */ @@ -114,7 +120,7 @@ struct fuse_ctx { #define FUSE_SET_ATTR_MTIME (1 << 5) /* ----------------------------------------------------------- * - * Request methods and replies * + * Request methods and replies * * ----------------------------------------------------------- */ /** @@ -139,662 +145,668 @@ struct fuse_ctx { * this file will not be called. */ struct fuse_lowlevel_ops { - /** - * Initialize filesystem - * - * Called before any other filesystem method - * - * There's no reply to this function - * - * @param userdata the user data passed to fuse_lowlevel_new() - */ - void (*init) (void *userdata, struct fuse_conn_info *conn); - - /** - * Clean up filesystem - * - * Called on filesystem exit - * - * There's no reply to this function - * - * @param userdata the user data passed to fuse_lowlevel_new() - */ - void (*destroy) (void *userdata); - - /** - * Look up a directory entry by name and get its attributes. - * - * Valid replies: - * fuse_reply_entry - * fuse_reply_err - * - * @param req request handle - * @param parent inode number of the parent directory - * @param name the name to look up - */ - void (*lookup) (fuse_req_t req, fuse_ino_t parent, const char *name); - - /** - * Forget about an inode - * - * The nlookup parameter indicates the number of lookups - * previously performed on this inode. - * - * If the filesystem implements inode lifetimes, it is recommended - * that inodes acquire a single reference on each lookup, and lose - * nlookup references on each forget. - * - * The filesystem may ignore forget calls, if the inodes don't - * need to have a limited lifetime. - * - * On unmount it is not guaranteed, that all referenced inodes - * will receive a forget message. - * - * Valid replies: - * fuse_reply_none - * - * @param req request handle - * @param ino the inode number - * @param nlookup the number of lookups to forget - */ - void (*forget) (fuse_req_t req, fuse_ino_t ino, unsigned long nlookup); - - /** - * Get file attributes - * - * Valid replies: - * fuse_reply_attr - * fuse_reply_err - * - * @param req request handle - * @param ino the inode number - * @param fi for future use, currently always NULL - */ - void (*getattr) (fuse_req_t req, fuse_ino_t ino, struct fuse_file_info *fi); - - /** - * Set file attributes - * - * In the 'attr' argument only members indicated by the 'to_set' - * bitmask contain valid values. Other members contain undefined - * values. - * - * If the setattr was invoked from the ftruncate() system call - * under Linux kernel versions 2.6.15 or later, the fi->fh will - * contain the value set by the open method or will be undefined - * if the open method didn't set any value. Otherwise (not - * ftruncate call, or kernel version earlier than 2.6.15) the fi - * parameter will be NULL. - * - * Valid replies: - * fuse_reply_attr - * fuse_reply_err - * - * @param req request handle - * @param ino the inode number - * @param attr the attributes - * @param to_set bit mask of attributes which should be set - * @param fi file information, or NULL - * - * Changed in version 2.5: - * file information filled in for ftruncate - */ - void (*setattr) (fuse_req_t req, fuse_ino_t ino, struct stat *attr, - int to_set, struct fuse_file_info *fi); - - /** - * Read symbolic link - * - * Valid replies: - * fuse_reply_readlink - * fuse_reply_err - * - * @param req request handle - * @param ino the inode number - */ - void (*readlink) (fuse_req_t req, fuse_ino_t ino); - - /** - * Create file node - * - * Create a regular file, character device, block device, fifo or - * socket node. - * - * Valid replies: - * fuse_reply_entry - * fuse_reply_err - * - * @param req request handle - * @param parent inode number of the parent directory - * @param name to create - * @param mode file type and mode with which to create the new file - * @param rdev the device number (only valid if created file is a device) - */ - void (*mknod) (fuse_req_t req, fuse_ino_t parent, const char *name, - mode_t mode, dev_t rdev); - - /** - * Create a directory - * - * Valid replies: - * fuse_reply_entry - * fuse_reply_err - * - * @param req request handle - * @param parent inode number of the parent directory - * @param name to create - * @param mode with which to create the new file - */ - void (*mkdir) (fuse_req_t req, fuse_ino_t parent, const char *name, - mode_t mode); - - /** - * Remove a file - * - * Valid replies: - * fuse_reply_err - * - * @param req request handle - * @param parent inode number of the parent directory - * @param name to remove - */ - void (*unlink) (fuse_req_t req, fuse_ino_t parent, const char *name); - - /** - * Remove a directory - * - * Valid replies: - * fuse_reply_err - * - * @param req request handle - * @param parent inode number of the parent directory - * @param name to remove - */ - void (*rmdir) (fuse_req_t req, fuse_ino_t parent, const char *name); - - /** - * Create a symbolic link - * - * Valid replies: - * fuse_reply_entry - * fuse_reply_err - * - * @param req request handle - * @param link the contents of the symbolic link - * @param parent inode number of the parent directory - * @param name to create - */ - void (*symlink) (fuse_req_t req, const char *link, fuse_ino_t parent, - const char *name); - - /** Rename a file - * - * Valid replies: - * fuse_reply_err - * - * @param req request handle - * @param parent inode number of the old parent directory - * @param name old name - * @param newparent inode number of the new parent directory - * @param newname new name - */ - void (*rename) (fuse_req_t req, fuse_ino_t parent, const char *name, - fuse_ino_t newparent, const char *newname); - - /** - * Create a hard link - * - * Valid replies: - * fuse_reply_entry - * fuse_reply_err - * - * @param req request handle - * @param ino the old inode number - * @param newparent inode number of the new parent directory - * @param newname new name to create - */ - void (*link) (fuse_req_t req, fuse_ino_t ino, fuse_ino_t newparent, - const char *newname); - - /** - * Open a file - * - * Open flags (with the exception of O_CREAT, O_EXCL, O_NOCTTY and - * O_TRUNC) are available in fi->flags. - * - * Filesystem may store an arbitrary file handle (pointer, index, - * etc) in fi->fh, and use this in other all other file operations - * (read, write, flush, release, fsync). - * - * Filesystem may also implement stateless file I/O and not store - * anything in fi->fh. - * - * There are also some flags (direct_io, keep_cache) which the - * filesystem may set in fi, to change the way the file is opened. - * See fuse_file_info structure in for more details. - * - * Valid replies: - * fuse_reply_open - * fuse_reply_err - * - * @param req request handle - * @param ino the inode number - * @param fi file information - */ - void (*open) (fuse_req_t req, fuse_ino_t ino, struct fuse_file_info *fi); - - /** - * Read data - * - * Read should send exactly the number of bytes requested except - * on EOF or error, otherwise the rest of the data will be - * substituted with zeroes. An exception to this is when the file - * has been opened in 'direct_io' mode, in which case the return - * value of the read system call will reflect the return value of - * this operation. - * - * fi->fh will contain the value set by the open method, or will - * be undefined if the open method didn't set any value. - * - * Valid replies: - * fuse_reply_buf - * fuse_reply_err - * - * @param req request handle - * @param ino the inode number - * @param size number of bytes to read - * @param off offset to read from - * @param fi file information - */ - void (*read) (fuse_req_t req, fuse_ino_t ino, size_t size, off_t off, - struct fuse_file_info *fi); - - /** - * Write data - * - * Write should return exactly the number of bytes requested - * except on error. An exception to this is when the file has - * been opened in 'direct_io' mode, in which case the return value - * of the write system call will reflect the return value of this - * operation. - * - * fi->fh will contain the value set by the open method, or will - * be undefined if the open method didn't set any value. - * - * Valid replies: - * fuse_reply_write - * fuse_reply_err - * - * @param req request handle - * @param ino the inode number - * @param buf data to write - * @param size number of bytes to write - * @param off offset to write to - * @param fi file information - */ - void (*write) (fuse_req_t req, fuse_ino_t ino, const char *buf, - size_t size, off_t off, struct fuse_file_info *fi); - - /** - * Flush method - * - * This is called on each close() of the opened file. - * - * Since file descriptors can be duplicated (dup, dup2, fork), for - * one open call there may be many flush calls. - * - * Filesystems shouldn't assume that flush will always be called - * after some writes, or that if will be called at all. - * - * fi->fh will contain the value set by the open method, or will - * be undefined if the open method didn't set any value. - * - * NOTE: the name of the method is misleading, since (unlike - * fsync) the filesystem is not forced to flush pending writes. - * One reason to flush data, is if the filesystem wants to return - * write errors. - * - * If the filesystem supports file locking operations (setlk, - * getlk) it should remove all locks belonging to 'fi->owner'. - * - * Valid replies: - * fuse_reply_err - * - * @param req request handle - * @param ino the inode number - * @param fi file information - */ - void (*flush) (fuse_req_t req, fuse_ino_t ino, struct fuse_file_info *fi); - - /** - * Release an open file - * - * Release is called when there are no more references to an open - * file: all file descriptors are closed and all memory mappings - * are unmapped. - * - * For every open call there will be exactly one release call. - * - * The filesystem may reply with an error, but error values are - * not returned to close() or munmap() which triggered the - * release. - * - * fi->fh will contain the value set by the open method, or will - * be undefined if the open method didn't set any value. - * fi->flags will contain the same flags as for open. - * - * Valid replies: - * fuse_reply_err - * - * @param req request handle - * @param ino the inode number - * @param fi file information - */ - void (*release) (fuse_req_t req, fuse_ino_t ino, struct fuse_file_info *fi); - - /** - * Synchronize file contents - * - * If the datasync parameter is non-zero, then only the user data - * should be flushed, not the meta data. - * - * Valid replies: - * fuse_reply_err - * - * @param req request handle - * @param ino the inode number - * @param datasync flag indicating if only data should be flushed - * @param fi file information - */ - void (*fsync) (fuse_req_t req, fuse_ino_t ino, int datasync, - struct fuse_file_info *fi); - - /** - * Open a directory - * - * Filesystem may store an arbitrary file handle (pointer, index, - * etc) in fi->fh, and use this in other all other directory - * stream operations (readdir, releasedir, fsyncdir). - * - * Filesystem may also implement stateless directory I/O and not - * store anything in fi->fh, though that makes it impossible to - * implement standard conforming directory stream operations in - * case the contents of the directory can change between opendir - * and releasedir. - * - * Valid replies: - * fuse_reply_open - * fuse_reply_err - * - * @param req request handle - * @param ino the inode number - * @param fi file information - */ - void (*opendir) (fuse_req_t req, fuse_ino_t ino, struct fuse_file_info *fi); - - /** - * Read directory - * - * Send a buffer filled using fuse_add_direntry(), with size not - * exceeding the requested size. Send an empty buffer on end of - * stream. - * - * fi->fh will contain the value set by the opendir method, or - * will be undefined if the opendir method didn't set any value. - * - * Valid replies: - * fuse_reply_buf - * fuse_reply_err - * - * @param req request handle - * @param ino the inode number - * @param size maximum number of bytes to send - * @param off offset to continue reading the directory stream - * @param fi file information - */ - void (*readdir) (fuse_req_t req, fuse_ino_t ino, size_t size, off_t off, - struct fuse_file_info *fi); - - /** - * Release an open directory - * - * For every opendir call there will be exactly one releasedir - * call. - * - * fi->fh will contain the value set by the opendir method, or - * will be undefined if the opendir method didn't set any value. - * - * Valid replies: - * fuse_reply_err - * - * @param req request handle - * @param ino the inode number - * @param fi file information - */ - void (*releasedir) (fuse_req_t req, fuse_ino_t ino, - struct fuse_file_info *fi); - - /** - * Synchronize directory contents - * - * If the datasync parameter is non-zero, then only the directory - * contents should be flushed, not the meta data. - * - * fi->fh will contain the value set by the opendir method, or - * will be undefined if the opendir method didn't set any value. - * - * Valid replies: - * fuse_reply_err - * - * @param req request handle - * @param ino the inode number - * @param datasync flag indicating if only data should be flushed - * @param fi file information - */ - void (*fsyncdir) (fuse_req_t req, fuse_ino_t ino, int datasync, - struct fuse_file_info *fi); - - /** - * Get file system statistics - * - * Valid replies: - * fuse_reply_statfs - * fuse_reply_err - * - * @param req request handle - * @param ino the inode number, zero means "undefined" - */ - void (*statfs) (fuse_req_t req, fuse_ino_t ino); - - /** - * Set an extended attribute - * - * Valid replies: - * fuse_reply_err - */ - void (*setxattr) (fuse_req_t req, fuse_ino_t ino, const char *name, - const char *value, size_t size, int flags); - - /** - * Get an extended attribute - * - * If size is zero, the size of the value should be sent with - * fuse_reply_xattr. - * - * If the size is non-zero, and the value fits in the buffer, the - * value should be sent with fuse_reply_buf. - * - * If the size is too small for the value, the ERANGE error should - * be sent. - * - * Valid replies: - * fuse_reply_buf - * fuse_reply_xattr - * fuse_reply_err - * - * @param req request handle - * @param ino the inode number - * @param name of the extended attribute - * @param size maximum size of the value to send - */ - void (*getxattr) (fuse_req_t req, fuse_ino_t ino, const char *name, - size_t size); - - /** - * List extended attribute names - * - * If size is zero, the total size of the attribute list should be - * sent with fuse_reply_xattr. - * - * If the size is non-zero, and the null character separated - * attribute list fits in the buffer, the list should be sent with - * fuse_reply_buf. - * - * If the size is too small for the list, the ERANGE error should - * be sent. - * - * Valid replies: - * fuse_reply_buf - * fuse_reply_xattr - * fuse_reply_err - * - * @param req request handle - * @param ino the inode number - * @param size maximum size of the list to send - */ - void (*listxattr) (fuse_req_t req, fuse_ino_t ino, size_t size); - - /** - * Remove an extended attribute - * - * Valid replies: - * fuse_reply_err - * - * @param req request handle - * @param ino the inode number - * @param name of the extended attribute - */ - void (*removexattr) (fuse_req_t req, fuse_ino_t ino, const char *name); - - /** - * Check file access permissions - * - * This will be called for the access() system call. If the - * 'default_permissions' mount option is given, this method is not - * called. - * - * This method is not called under Linux kernel versions 2.4.x - * - * Introduced in version 2.5 - * - * Valid replies: - * fuse_reply_err - * - * @param req request handle - * @param ino the inode number - * @param mask requested access mode - */ - void (*access) (fuse_req_t req, fuse_ino_t ino, int mask); - - /** - * Create and open a file - * - * If the file does not exist, first create it with the specified - * mode, and then open it. - * - * Open flags (with the exception of O_NOCTTY) are available in - * fi->flags. - * - * Filesystem may store an arbitrary file handle (pointer, index, - * etc) in fi->fh, and use this in other all other file operations - * (read, write, flush, release, fsync). - * - * There are also some flags (direct_io, keep_cache) which the - * filesystem may set in fi, to change the way the file is opened. - * See fuse_file_info structure in for more details. - * - * If this method is not implemented or under Linux kernel - * versions earlier than 2.6.15, the mknod() and open() methods - * will be called instead. - * - * Introduced in version 2.5 - * - * Valid replies: - * fuse_reply_create - * fuse_reply_err - * - * @param req request handle - * @param parent inode number of the parent directory - * @param name to create - * @param mode file type and mode with which to create the new file - * @param fi file information - */ - void (*create) (fuse_req_t req, fuse_ino_t parent, const char *name, - mode_t mode, struct fuse_file_info *fi); - - /** - * Test for a POSIX file lock - * - * Introduced in version 2.6 - * - * Valid replies: - * fuse_reply_lock - * fuse_reply_err - * - * @param req request handle - * @param ino the inode number - * @param fi file information - * @param lock the region/type to test - */ - void (*getlk) (fuse_req_t req, fuse_ino_t ino, struct fuse_file_info *fi, - struct flock *lock); - - /** - * Acquire, modify or release a POSIX file lock - * - * For POSIX threads (NPTL) there's a 1-1 relation between pid and - * owner, but otherwise this is not always the case. For checking - * lock ownership, 'fi->owner' must be used. The l_pid field in - * 'struct flock' should only be used to fill in this field in - * getlk(). - * - * Note: if the locking methods are not implemented, the kernel - * will still allow file locking to work locally. Hence these are - * only interesting for network filesystems and similar. - * - * Introduced in version 2.6 - * - * Valid replies: - * fuse_reply_err - * - * @param req request handle - * @param ino the inode number - * @param fi file information - * @param lock the region/type to test - * @param sleep locking operation may sleep - */ - void (*setlk) (fuse_req_t req, fuse_ino_t ino, struct fuse_file_info *fi, - struct flock *lock, int sleep); - - /** - * Map block index within file to block index within device - * - * Note: This makes sense only for block device backed filesystems - * mounted with the 'blkdev' option - * - * Introduced in version 2.6 - * - * Valid replies: - * fuse_reply_bmap - * fuse_reply_err - * - * @param req request handle - * @param ino the inode number - * @param blocksize unit of block index - * @param idx block index within file - */ - void (*bmap) (fuse_req_t req, fuse_ino_t ino, size_t blocksize, - uint64_t idx); + /** + * Initialize filesystem + * + * Called before any other filesystem method + * + * There's no reply to this function + * + * @param userdata the user data passed to fuse_lowlevel_new() + */ + void (*init) (void *userdata, struct fuse_conn_info *conn); + + /** + * Clean up filesystem + * + * Called on filesystem exit + * + * There's no reply to this function + * + * @param userdata the user data passed to fuse_lowlevel_new() + */ + void (*destroy) (void *userdata); + + /** + * Look up a directory entry by name and get its attributes. + * + * Valid replies: + * fuse_reply_entry + * fuse_reply_err + * + * @param req request handle + * @param parent inode number of the parent directory + * @param name the name to look up + */ + void (*lookup) (fuse_req_t req, fuse_ino_t parent, const char *name); + + /** + * Forget about an inode + * + * The nlookup parameter indicates the number of lookups + * previously performed on this inode. + * + * If the filesystem implements inode lifetimes, it is recommended + * that inodes acquire a single reference on each lookup, and lose + * nlookup references on each forget. + * + * The filesystem may ignore forget calls, if the inodes don't + * need to have a limited lifetime. + * + * On unmount it is not guaranteed, that all referenced inodes + * will receive a forget message. + * + * Valid replies: + * fuse_reply_none + * + * @param req request handle + * @param ino the inode number + * @param nlookup the number of lookups to forget + */ + void (*forget) (fuse_req_t req, fuse_ino_t ino, unsigned long nlookup); + + /** + * Get file attributes + * + * Valid replies: + * fuse_reply_attr + * fuse_reply_err + * + * @param req request handle + * @param ino the inode number + * @param fi for future use, currently always NULL + */ + void (*getattr) (fuse_req_t req, fuse_ino_t ino, + struct fuse_file_info *fi); + + /** + * Set file attributes + * + * In the 'attr' argument only members indicated by the 'to_set' + * bitmask contain valid values. Other members contain undefined + * values. + * + * If the setattr was invoked from the ftruncate() system call + * under Linux kernel versions 2.6.15 or later, the fi->fh will + * contain the value set by the open method or will be undefined + * if the open method didn't set any value. Otherwise (not + * ftruncate call, or kernel version earlier than 2.6.15) the fi + * parameter will be NULL. + * + * Valid replies: + * fuse_reply_attr + * fuse_reply_err + * + * @param req request handle + * @param ino the inode number + * @param attr the attributes + * @param to_set bit mask of attributes which should be set + * @param fi file information, or NULL + * + * Changed in version 2.5: + * file information filled in for ftruncate + */ + void (*setattr) (fuse_req_t req, fuse_ino_t ino, struct stat *attr, + int to_set, struct fuse_file_info *fi); + + /** + * Read symbolic link + * + * Valid replies: + * fuse_reply_readlink + * fuse_reply_err + * + * @param req request handle + * @param ino the inode number + */ + void (*readlink) (fuse_req_t req, fuse_ino_t ino); + + /** + * Create file node + * + * Create a regular file, character device, block device, fifo or + * socket node. + * + * Valid replies: + * fuse_reply_entry + * fuse_reply_err + * + * @param req request handle + * @param parent inode number of the parent directory + * @param name to create + * @param mode file type and mode with which to create the new file + * @param rdev the device number (only valid if created file is a device) + */ + void (*mknod) (fuse_req_t req, fuse_ino_t parent, const char *name, + mode_t mode, dev_t rdev); + + /** + * Create a directory + * + * Valid replies: + * fuse_reply_entry + * fuse_reply_err + * + * @param req request handle + * @param parent inode number of the parent directory + * @param name to create + * @param mode with which to create the new file + */ + void (*mkdir) (fuse_req_t req, fuse_ino_t parent, const char *name, + mode_t mode); + + /** + * Remove a file + * + * Valid replies: + * fuse_reply_err + * + * @param req request handle + * @param parent inode number of the parent directory + * @param name to remove + */ + void (*unlink) (fuse_req_t req, fuse_ino_t parent, const char *name); + + /** + * Remove a directory + * + * Valid replies: + * fuse_reply_err + * + * @param req request handle + * @param parent inode number of the parent directory + * @param name to remove + */ + void (*rmdir) (fuse_req_t req, fuse_ino_t parent, const char *name); + + /** + * Create a symbolic link + * + * Valid replies: + * fuse_reply_entry + * fuse_reply_err + * + * @param req request handle + * @param link the contents of the symbolic link + * @param parent inode number of the parent directory + * @param name to create + */ + void (*symlink) (fuse_req_t req, const char *link, fuse_ino_t parent, + const char *name); + + /** Rename a file + * + * Valid replies: + * fuse_reply_err + * + * @param req request handle + * @param parent inode number of the old parent directory + * @param name old name + * @param newparent inode number of the new parent directory + * @param newname new name + */ + void (*rename) (fuse_req_t req, fuse_ino_t parent, const char *name, + fuse_ino_t newparent, const char *newname); + + /** + * Create a hard link + * + * Valid replies: + * fuse_reply_entry + * fuse_reply_err + * + * @param req request handle + * @param ino the old inode number + * @param newparent inode number of the new parent directory + * @param newname new name to create + */ + void (*link) (fuse_req_t req, fuse_ino_t ino, fuse_ino_t newparent, + const char *newname); + + /** + * Open a file + * + * Open flags (with the exception of O_CREAT, O_EXCL, O_NOCTTY and + * O_TRUNC) are available in fi->flags. + * + * Filesystem may store an arbitrary file handle (pointer, index, + * etc) in fi->fh, and use this in other all other file operations + * (read, write, flush, release, fsync). + * + * Filesystem may also implement stateless file I/O and not store + * anything in fi->fh. + * + * There are also some flags (direct_io, keep_cache) which the + * filesystem may set in fi, to change the way the file is opened. + * See fuse_file_info structure in for more details. + * + * Valid replies: + * fuse_reply_open + * fuse_reply_err + * + * @param req request handle + * @param ino the inode number + * @param fi file information + */ + void (*open) (fuse_req_t req, fuse_ino_t ino, + struct fuse_file_info *fi); + + /** + * Read data + * + * Read should send exactly the number of bytes requested except + * on EOF or error, otherwise the rest of the data will be + * substituted with zeroes. An exception to this is when the file + * has been opened in 'direct_io' mode, in which case the return + * value of the read system call will reflect the return value of + * this operation. + * + * fi->fh will contain the value set by the open method, or will + * be undefined if the open method didn't set any value. + * + * Valid replies: + * fuse_reply_buf + * fuse_reply_err + * + * @param req request handle + * @param ino the inode number + * @param size number of bytes to read + * @param off offset to read from + * @param fi file information + */ + void (*read) (fuse_req_t req, fuse_ino_t ino, size_t size, off_t off, + struct fuse_file_info *fi); + + /** + * Write data + * + * Write should return exactly the number of bytes requested + * except on error. An exception to this is when the file has + * been opened in 'direct_io' mode, in which case the return value + * of the write system call will reflect the return value of this + * operation. + * + * fi->fh will contain the value set by the open method, or will + * be undefined if the open method didn't set any value. + * + * Valid replies: + * fuse_reply_write + * fuse_reply_err + * + * @param req request handle + * @param ino the inode number + * @param buf data to write + * @param size number of bytes to write + * @param off offset to write to + * @param fi file information + */ + void (*write) (fuse_req_t req, fuse_ino_t ino, const char *buf, + size_t size, off_t off, struct fuse_file_info *fi); + + /** + * Flush method + * + * This is called on each close() of the opened file. + * + * Since file descriptors can be duplicated (dup, dup2, fork), for + * one open call there may be many flush calls. + * + * Filesystems shouldn't assume that flush will always be called + * after some writes, or that if will be called at all. + * + * fi->fh will contain the value set by the open method, or will + * be undefined if the open method didn't set any value. + * + * NOTE: the name of the method is misleading, since (unlike + * fsync) the filesystem is not forced to flush pending writes. + * One reason to flush data, is if the filesystem wants to return + * write errors. + * + * If the filesystem supports file locking operations (setlk, + * getlk) it should remove all locks belonging to 'fi->owner'. + * + * Valid replies: + * fuse_reply_err + * + * @param req request handle + * @param ino the inode number + * @param fi file information + */ + void (*flush) (fuse_req_t req, fuse_ino_t ino, + struct fuse_file_info *fi); + + /** + * Release an open file + * + * Release is called when there are no more references to an open + * file: all file descriptors are closed and all memory mappings + * are unmapped. + * + * For every open call there will be exactly one release call. + * + * The filesystem may reply with an error, but error values are + * not returned to close() or munmap() which triggered the + * release. + * + * fi->fh will contain the value set by the open method, or will + * be undefined if the open method didn't set any value. + * fi->flags will contain the same flags as for open. + * + * Valid replies: + * fuse_reply_err + * + * @param req request handle + * @param ino the inode number + * @param fi file information + */ + void (*release) (fuse_req_t req, fuse_ino_t ino, + struct fuse_file_info *fi); + + /** + * Synchronize file contents + * + * If the datasync parameter is non-zero, then only the user data + * should be flushed, not the meta data. + * + * Valid replies: + * fuse_reply_err + * + * @param req request handle + * @param ino the inode number + * @param datasync flag indicating if only data should be flushed + * @param fi file information + */ + void (*fsync) (fuse_req_t req, fuse_ino_t ino, int datasync, + struct fuse_file_info *fi); + + /** + * Open a directory + * + * Filesystem may store an arbitrary file handle (pointer, index, + * etc) in fi->fh, and use this in other all other directory + * stream operations (readdir, releasedir, fsyncdir). + * + * Filesystem may also implement stateless directory I/O and not + * store anything in fi->fh, though that makes it impossible to + * implement standard conforming directory stream operations in + * case the contents of the directory can change between opendir + * and releasedir. + * + * Valid replies: + * fuse_reply_open + * fuse_reply_err + * + * @param req request handle + * @param ino the inode number + * @param fi file information + */ + void (*opendir) (fuse_req_t req, fuse_ino_t ino, + struct fuse_file_info *fi); + + /** + * Read directory + * + * Send a buffer filled using fuse_add_direntry(), with size not + * exceeding the requested size. Send an empty buffer on end of + * stream. + * + * fi->fh will contain the value set by the opendir method, or + * will be undefined if the opendir method didn't set any value. + * + * Valid replies: + * fuse_reply_buf + * fuse_reply_err + * + * @param req request handle + * @param ino the inode number + * @param size maximum number of bytes to send + * @param off offset to continue reading the directory stream + * @param fi file information + */ + void (*readdir) (fuse_req_t req, fuse_ino_t ino, size_t size, off_t off, + struct fuse_file_info *fi); + + /** + * Release an open directory + * + * For every opendir call there will be exactly one releasedir + * call. + * + * fi->fh will contain the value set by the opendir method, or + * will be undefined if the opendir method didn't set any value. + * + * Valid replies: + * fuse_reply_err + * + * @param req request handle + * @param ino the inode number + * @param fi file information + */ + void (*releasedir) (fuse_req_t req, fuse_ino_t ino, + struct fuse_file_info *fi); + + /** + * Synchronize directory contents + * + * If the datasync parameter is non-zero, then only the directory + * contents should be flushed, not the meta data. + * + * fi->fh will contain the value set by the opendir method, or + * will be undefined if the opendir method didn't set any value. + * + * Valid replies: + * fuse_reply_err + * + * @param req request handle + * @param ino the inode number + * @param datasync flag indicating if only data should be flushed + * @param fi file information + */ + void (*fsyncdir) (fuse_req_t req, fuse_ino_t ino, int datasync, + struct fuse_file_info *fi); + + /** + * Get file system statistics + * + * Valid replies: + * fuse_reply_statfs + * fuse_reply_err + * + * @param req request handle + * @param ino the inode number, zero means "undefined" + */ + void (*statfs) (fuse_req_t req, fuse_ino_t ino); + + /** + * Set an extended attribute + * + * Valid replies: + * fuse_reply_err + */ + void (*setxattr) (fuse_req_t req, fuse_ino_t ino, const char *name, + const char *value, size_t size, int flags); + + /** + * Get an extended attribute + * + * If size is zero, the size of the value should be sent with + * fuse_reply_xattr. + * + * If the size is non-zero, and the value fits in the buffer, the + * value should be sent with fuse_reply_buf. + * + * If the size is too small for the value, the ERANGE error should + * be sent. + * + * Valid replies: + * fuse_reply_buf + * fuse_reply_xattr + * fuse_reply_err + * + * @param req request handle + * @param ino the inode number + * @param name of the extended attribute + * @param size maximum size of the value to send + */ + void (*getxattr) (fuse_req_t req, fuse_ino_t ino, const char *name, + size_t size); + + /** + * List extended attribute names + * + * If size is zero, the total size of the attribute list should be + * sent with fuse_reply_xattr. + * + * If the size is non-zero, and the null character separated + * attribute list fits in the buffer, the list should be sent with + * fuse_reply_buf. + * + * If the size is too small for the list, the ERANGE error should + * be sent. + * + * Valid replies: + * fuse_reply_buf + * fuse_reply_xattr + * fuse_reply_err + * + * @param req request handle + * @param ino the inode number + * @param size maximum size of the list to send + */ + void (*listxattr) (fuse_req_t req, fuse_ino_t ino, size_t size); + + /** + * Remove an extended attribute + * + * Valid replies: + * fuse_reply_err + * + * @param req request handle + * @param ino the inode number + * @param name of the extended attribute + */ + void (*removexattr) (fuse_req_t req, fuse_ino_t ino, const char *name); + + /** + * Check file access permissions + * + * This will be called for the access() system call. If the + * 'default_permissions' mount option is given, this method is not + * called. + * + * This method is not called under Linux kernel versions 2.4.x + * + * Introduced in version 2.5 + * + * Valid replies: + * fuse_reply_err + * + * @param req request handle + * @param ino the inode number + * @param mask requested access mode + */ + void (*access) (fuse_req_t req, fuse_ino_t ino, int mask); + + /** + * Create and open a file + * + * If the file does not exist, first create it with the specified + * mode, and then open it. + * + * Open flags (with the exception of O_NOCTTY) are available in + * fi->flags. + * + * Filesystem may store an arbitrary file handle (pointer, index, + * etc) in fi->fh, and use this in other all other file operations + * (read, write, flush, release, fsync). + * + * There are also some flags (direct_io, keep_cache) which the + * filesystem may set in fi, to change the way the file is opened. + * See fuse_file_info structure in for more details. + * + * If this method is not implemented or under Linux kernel + * versions earlier than 2.6.15, the mknod() and open() methods + * will be called instead. + * + * Introduced in version 2.5 + * + * Valid replies: + * fuse_reply_create + * fuse_reply_err + * + * @param req request handle + * @param parent inode number of the parent directory + * @param name to create + * @param mode file type and mode with which to create the new file + * @param fi file information + */ + void (*create) (fuse_req_t req, fuse_ino_t parent, const char *name, + mode_t mode, struct fuse_file_info *fi); + + /** + * Test for a POSIX file lock + * + * Introduced in version 2.6 + * + * Valid replies: + * fuse_reply_lock + * fuse_reply_err + * + * @param req request handle + * @param ino the inode number + * @param fi file information + * @param lock the region/type to test + */ + void (*getlk) (fuse_req_t req, fuse_ino_t ino, + struct fuse_file_info *fi, struct flock *lock); + + /** + * Acquire, modify or release a POSIX file lock + * + * For POSIX threads (NPTL) there's a 1-1 relation between pid and + * owner, but otherwise this is not always the case. For checking + * lock ownership, 'fi->owner' must be used. The l_pid field in + * 'struct flock' should only be used to fill in this field in + * getlk(). + * + * Note: if the locking methods are not implemented, the kernel + * will still allow file locking to work locally. Hence these are + * only interesting for network filesystems and similar. + * + * Introduced in version 2.6 + * + * Valid replies: + * fuse_reply_err + * + * @param req request handle + * @param ino the inode number + * @param fi file information + * @param lock the region/type to test + * @param sleep locking operation may sleep + */ + void (*setlk) (fuse_req_t req, fuse_ino_t ino, + struct fuse_file_info *fi, + struct flock *lock, int sleep); + + /** + * Map block index within file to block index within device + * + * Note: This makes sense only for block device backed filesystems + * mounted with the 'blkdev' option + * + * Introduced in version 2.6 + * + * Valid replies: + * fuse_reply_bmap + * fuse_reply_err + * + * @param req request handle + * @param ino the inode number + * @param blocksize unit of block index + * @param idx block index within file + */ + void (*bmap) (fuse_req_t req, fuse_ino_t ino, size_t blocksize, + uint64_t idx); }; /** @@ -849,7 +861,7 @@ int fuse_reply_entry(fuse_req_t req, const struct fuse_entry_param *e); * @return zero for success, -errno for failure to send reply */ int fuse_reply_create(fuse_req_t req, const struct fuse_entry_param *e, - const struct fuse_file_info *fi); + const struct fuse_file_info *fi); /** * Reply with attributes @@ -859,11 +871,11 @@ int fuse_reply_create(fuse_req_t req, const struct fuse_entry_param *e, * * @param req request handle * @param the attributes - * @param attr_timeout validity timeout (in seconds) for the attributes + * @param attr_timeout validity timeout (in seconds) for the attributes * @return zero for success, -errno for failure to send reply */ int fuse_reply_attr(fuse_req_t req, const struct stat *attr, - double attr_timeout); + double attr_timeout); /** * Reply with the contents of a symbolic link @@ -973,13 +985,13 @@ int fuse_reply_lock(fuse_req_t req, struct flock *lock); * bmap * * @param req request handle - * @param idx block index within device + * @param idx block index within device * @return zero for success, -errno for failure to send reply */ int fuse_reply_bmap(fuse_req_t req, uint64_t idx); /* ----------------------------------------------------------- * - * Filling a buffer in readdir * + * Filling a buffer in readdir * * ----------------------------------------------------------- */ /** @@ -1007,11 +1019,11 @@ int fuse_reply_bmap(fuse_req_t req, uint64_t idx); * @return the space needed for the entry */ size_t fuse_add_direntry(fuse_req_t req, char *buf, size_t bufsize, - const char *name, const struct stat *stbuf, - off_t off); + const char *name, const struct stat *stbuf, + off_t off); /* ----------------------------------------------------------- * - * Utility functions * + * Utility functions * * ----------------------------------------------------------- */ /** @@ -1053,7 +1065,7 @@ typedef void (*fuse_interrupt_func_t)(fuse_req_t req, void *data); * @parm data user data passed to the callback function */ void fuse_req_interrupt_func(fuse_req_t req, fuse_interrupt_func_t func, - void *data); + void *data); /** * Check if a request has already been interrupted @@ -1064,7 +1076,7 @@ void fuse_req_interrupt_func(fuse_req_t req, fuse_interrupt_func_t func, int fuse_req_interrupted(fuse_req_t req); /* ----------------------------------------------------------- * - * Filesystem setup * + * Filesystem setup * * ----------------------------------------------------------- */ /* Deprecated, don't use */ @@ -1080,11 +1092,11 @@ int fuse_lowlevel_is_lib_option(const char *opt); * @return the created session object, or NULL on failure */ struct fuse_session *fuse_lowlevel_new(struct fuse_args *args, - const struct fuse_lowlevel_ops *op, - size_t op_size, void *userdata); + const struct fuse_lowlevel_ops *op, + size_t op_size, void *userdata); /* ----------------------------------------------------------- * - * Session interface * + * Session interface * * ----------------------------------------------------------- */ /** @@ -1093,39 +1105,39 @@ struct fuse_session *fuse_lowlevel_new(struct fuse_args *args, * This is used in session creation */ struct fuse_session_ops { - /** - * Hook to process a request (mandatory) - * - * @param data user data passed to fuse_session_new() - * @param buf buffer containing the raw request - * @param len request length - * @param ch channel on which the request was received - */ - void (*process) (void *data, const char *buf, size_t len, - struct fuse_chan *ch); - - /** - * Hook for session exit and reset (optional) - * - * @param data user data passed to fuse_session_new() - * @param val exited status (1 - exited, 0 - not exited) - */ - void (*exit) (void *data, int val); - - /** - * Hook for querying the current exited status (optional) - * - * @param data user data passed to fuse_session_new() - * @return 1 if exited, 0 if not exited - */ - int (*exited) (void *data); - - /** - * Hook for cleaning up the channel on destroy (optional) - * - * @param data user data passed to fuse_session_new() - */ - void (*destroy) (void *data); + /** + * Hook to process a request (mandatory) + * + * @param data user data passed to fuse_session_new() + * @param buf buffer containing the raw request + * @param len request length + * @param ch channel on which the request was received + */ + void (*process) (void *data, const char *buf, size_t len, + struct fuse_chan *ch); + + /** + * Hook for session exit and reset (optional) + * + * @param data user data passed to fuse_session_new() + * @param val exited status (1 - exited, 0 - not exited) + */ + void (*exit) (void *data, int val); + + /** + * Hook for querying the current exited status (optional) + * + * @param data user data passed to fuse_session_new() + * @return 1 if exited, 0 if not exited + */ + int (*exited) (void *data); + + /** + * Hook for cleaning up the channel on destroy (optional) + * + * @param data user data passed to fuse_session_new() + */ + void (*destroy) (void *data); }; /** @@ -1171,7 +1183,7 @@ void fuse_session_remove_chan(struct fuse_chan *ch); * @return the next channel, or NULL if no more channels exist */ struct fuse_chan *fuse_session_next_chan(struct fuse_session *se, - struct fuse_chan *ch); + struct fuse_chan *ch); /** * Process a raw request @@ -1182,7 +1194,7 @@ struct fuse_chan *fuse_session_next_chan(struct fuse_session *se, * @param ch channel on which the request was received */ void fuse_session_process(struct fuse_session *se, const char *buf, size_t len, - struct fuse_chan *ch); + struct fuse_chan *ch); /** * Destroy a session @@ -1230,7 +1242,7 @@ int fuse_session_loop(struct fuse_session *se); int fuse_session_loop_mt(struct fuse_session *se); /* ----------------------------------------------------------- * - * Channel interface * + * Channel interface * * ----------------------------------------------------------- */ /** @@ -1239,35 +1251,36 @@ int fuse_session_loop_mt(struct fuse_session *se); * This is used in channel creation */ struct fuse_chan_ops { - /** - * Hook for receiving a raw request - * - * @param ch pointer to the channel - * @param buf the buffer to store the request in - * @param size the size of the buffer - * @return the actual size of the raw request, or -1 on error - */ - int (*receive)(struct fuse_chan **chp, char *buf, size_t size); - - /** - * Hook for sending a raw reply - * - * A return value of -ENOENT means, that the request was - * interrupted, and the reply was discarded - * - * @param ch the channel - * @param iov vector of blocks - * @param count the number of blocks in vector - * @return zero on success, -errno on failure - */ - int (*send)(struct fuse_chan *ch, const struct iovec iov[], size_t count); - - /** - * Destroy the channel - * - * @param ch the channel - */ - void (*destroy)(struct fuse_chan *ch); + /** + * Hook for receiving a raw request + * + * @param ch pointer to the channel + * @param buf the buffer to store the request in + * @param size the size of the buffer + * @return the actual size of the raw request, or -1 on error + */ + int (*receive)(struct fuse_chan **chp, char *buf, size_t size); + + /** + * Hook for sending a raw reply + * + * A return value of -ENOENT means, that the request was + * interrupted, and the reply was discarded + * + * @param ch the channel + * @param iov vector of blocks + * @param count the number of blocks in vector + * @return zero on success, -errno on failure + */ + int (*send)(struct fuse_chan *ch, const struct iovec iov[], + size_t count); + + /** + * Destroy the channel + * + * @param ch the channel + */ + void (*destroy)(struct fuse_chan *ch); }; /** @@ -1280,7 +1293,7 @@ struct fuse_chan_ops { * @return the new channel object, or NULL on failure */ struct fuse_chan *fuse_chan_new(struct fuse_chan_ops *op, int fd, - size_t bufsize, void *data); + size_t bufsize, void *data); /** * Query the file descriptor of the channel @@ -1338,7 +1351,7 @@ int fuse_chan_recv(struct fuse_chan **ch, char *buf, size_t size); * @return zero on success, -errno on failure */ int fuse_chan_send(struct fuse_chan *ch, const struct iovec iov[], - size_t count); + size_t count); /** * Destroy a channel @@ -1348,7 +1361,7 @@ int fuse_chan_send(struct fuse_chan *ch, const struct iovec iov[], void fuse_chan_destroy(struct fuse_chan *ch); /* ----------------------------------------------------------- * - * Compatibility stuff * + * Compatibility stuff * * ----------------------------------------------------------- */ #if FUSE_USE_VERSION < 26 diff --git a/include/fuse_lowlevel_compat.h b/include/fuse_lowlevel_compat.h index d9313b8..aba45e6 100644 --- a/include/fuse_lowlevel_compat.h +++ b/include/fuse_lowlevel_compat.h @@ -1,144 +1,155 @@ /* - FUSE: Filesystem in Userspace - Copyright (C) 2001-2007 Miklos Szeredi + FUSE: Filesystem in Userspace + Copyright (C) 2001-2007 Miklos Szeredi - This program can be distributed under the terms of the GNU LGPLv2. - See the file COPYING.LIB. + This program can be distributed under the terms of the GNU LGPLv2. + See the file COPYING.LIB. */ /* these definitions provide source compatibility to prior versions. Do not include this file directly! */ struct fuse_lowlevel_ops_compat25 { - void (*init) (void *userdata); - void (*destroy) (void *userdata); - void (*lookup) (fuse_req_t req, fuse_ino_t parent, const char *name); - void (*forget) (fuse_req_t req, fuse_ino_t ino, unsigned long nlookup); - void (*getattr) (fuse_req_t req, fuse_ino_t ino, struct fuse_file_info *fi); - void (*setattr) (fuse_req_t req, fuse_ino_t ino, struct stat *attr, - int to_set, struct fuse_file_info *fi); - void (*readlink) (fuse_req_t req, fuse_ino_t ino); - void (*mknod) (fuse_req_t req, fuse_ino_t parent, const char *name, - mode_t mode, dev_t rdev); - void (*mkdir) (fuse_req_t req, fuse_ino_t parent, const char *name, - mode_t mode); - void (*unlink) (fuse_req_t req, fuse_ino_t parent, const char *name); - void (*rmdir) (fuse_req_t req, fuse_ino_t parent, const char *name); - void (*symlink) (fuse_req_t req, const char *link, fuse_ino_t parent, - const char *name); - void (*rename) (fuse_req_t req, fuse_ino_t parent, const char *name, - fuse_ino_t newparent, const char *newname); - void (*link) (fuse_req_t req, fuse_ino_t ino, fuse_ino_t newparent, - const char *newname); - void (*open) (fuse_req_t req, fuse_ino_t ino, struct fuse_file_info *fi); - void (*read) (fuse_req_t req, fuse_ino_t ino, size_t size, off_t off, - struct fuse_file_info *fi); - void (*write) (fuse_req_t req, fuse_ino_t ino, const char *buf, - size_t size, off_t off, struct fuse_file_info *fi); - void (*flush) (fuse_req_t req, fuse_ino_t ino, struct fuse_file_info *fi); - void (*release) (fuse_req_t req, fuse_ino_t ino, struct fuse_file_info *fi); - void (*fsync) (fuse_req_t req, fuse_ino_t ino, int datasync, - struct fuse_file_info *fi); - void (*opendir) (fuse_req_t req, fuse_ino_t ino, struct fuse_file_info *fi); - void (*readdir) (fuse_req_t req, fuse_ino_t ino, size_t size, off_t off, - struct fuse_file_info *fi); - void (*releasedir) (fuse_req_t req, fuse_ino_t ino, - struct fuse_file_info *fi); - void (*fsyncdir) (fuse_req_t req, fuse_ino_t ino, int datasync, - struct fuse_file_info *fi); - void (*statfs) (fuse_req_t req); - void (*setxattr) (fuse_req_t req, fuse_ino_t ino, const char *name, - const char *value, size_t size, int flags); - void (*getxattr) (fuse_req_t req, fuse_ino_t ino, const char *name, - size_t size); - void (*listxattr) (fuse_req_t req, fuse_ino_t ino, size_t size); - void (*removexattr) (fuse_req_t req, fuse_ino_t ino, const char *name); - void (*access) (fuse_req_t req, fuse_ino_t ino, int mask); - void (*create) (fuse_req_t req, fuse_ino_t parent, const char *name, - mode_t mode, struct fuse_file_info *fi); + void (*init) (void *userdata); + void (*destroy) (void *userdata); + void (*lookup) (fuse_req_t req, fuse_ino_t parent, const char *name); + void (*forget) (fuse_req_t req, fuse_ino_t ino, unsigned long nlookup); + void (*getattr) (fuse_req_t req, fuse_ino_t ino, + struct fuse_file_info *fi); + void (*setattr) (fuse_req_t req, fuse_ino_t ino, struct stat *attr, + int to_set, struct fuse_file_info *fi); + void (*readlink) (fuse_req_t req, fuse_ino_t ino); + void (*mknod) (fuse_req_t req, fuse_ino_t parent, const char *name, + mode_t mode, dev_t rdev); + void (*mkdir) (fuse_req_t req, fuse_ino_t parent, const char *name, + mode_t mode); + void (*unlink) (fuse_req_t req, fuse_ino_t parent, const char *name); + void (*rmdir) (fuse_req_t req, fuse_ino_t parent, const char *name); + void (*symlink) (fuse_req_t req, const char *link, fuse_ino_t parent, + const char *name); + void (*rename) (fuse_req_t req, fuse_ino_t parent, const char *name, + fuse_ino_t newparent, const char *newname); + void (*link) (fuse_req_t req, fuse_ino_t ino, fuse_ino_t newparent, + const char *newname); + void (*open) (fuse_req_t req, fuse_ino_t ino, + struct fuse_file_info *fi); + void (*read) (fuse_req_t req, fuse_ino_t ino, size_t size, off_t off, + struct fuse_file_info *fi); + void (*write) (fuse_req_t req, fuse_ino_t ino, const char *buf, + size_t size, off_t off, struct fuse_file_info *fi); + void (*flush) (fuse_req_t req, fuse_ino_t ino, + struct fuse_file_info *fi); + void (*release) (fuse_req_t req, fuse_ino_t ino, + struct fuse_file_info *fi); + void (*fsync) (fuse_req_t req, fuse_ino_t ino, int datasync, + struct fuse_file_info *fi); + void (*opendir) (fuse_req_t req, fuse_ino_t ino, + struct fuse_file_info *fi); + void (*readdir) (fuse_req_t req, fuse_ino_t ino, size_t size, off_t off, + struct fuse_file_info *fi); + void (*releasedir) (fuse_req_t req, fuse_ino_t ino, + struct fuse_file_info *fi); + void (*fsyncdir) (fuse_req_t req, fuse_ino_t ino, int datasync, + struct fuse_file_info *fi); + void (*statfs) (fuse_req_t req); + void (*setxattr) (fuse_req_t req, fuse_ino_t ino, const char *name, + const char *value, size_t size, int flags); + void (*getxattr) (fuse_req_t req, fuse_ino_t ino, const char *name, + size_t size); + void (*listxattr) (fuse_req_t req, fuse_ino_t ino, size_t size); + void (*removexattr) (fuse_req_t req, fuse_ino_t ino, const char *name); + void (*access) (fuse_req_t req, fuse_ino_t ino, int mask); + void (*create) (fuse_req_t req, fuse_ino_t parent, const char *name, + mode_t mode, struct fuse_file_info *fi); }; struct fuse_session *fuse_lowlevel_new_compat25(struct fuse_args *args, - const struct fuse_lowlevel_ops_compat25 *op, - size_t op_size, void *userdata); + const struct fuse_lowlevel_ops_compat25 *op, + size_t op_size, void *userdata); size_t fuse_dirent_size(size_t namelen); char *fuse_add_dirent(char *buf, const char *name, const struct stat *stbuf, - off_t off); + off_t off); #ifndef __FreeBSD__ #include struct fuse_lowlevel_ops_compat { - void (*init) (void *userdata); - void (*destroy) (void *userdata); - void (*lookup) (fuse_req_t req, fuse_ino_t parent, const char *name); - void (*forget) (fuse_req_t req, fuse_ino_t ino, unsigned long nlookup); - void (*getattr) (fuse_req_t req, fuse_ino_t ino, struct fuse_file_info_compat *fi); - void (*setattr) (fuse_req_t req, fuse_ino_t ino, struct stat *attr, - int to_set, struct fuse_file_info_compat *fi); - void (*readlink) (fuse_req_t req, fuse_ino_t ino); - void (*mknod) (fuse_req_t req, fuse_ino_t parent, const char *name, - mode_t mode, dev_t rdev); - void (*mkdir) (fuse_req_t req, fuse_ino_t parent, const char *name, - mode_t mode); - void (*unlink) (fuse_req_t req, fuse_ino_t parent, const char *name); - void (*rmdir) (fuse_req_t req, fuse_ino_t parent, const char *name); - void (*symlink) (fuse_req_t req, const char *link, fuse_ino_t parent, - const char *name); - void (*rename) (fuse_req_t req, fuse_ino_t parent, const char *name, - fuse_ino_t newparent, const char *newname); - void (*link) (fuse_req_t req, fuse_ino_t ino, fuse_ino_t newparent, - const char *newname); - void (*open) (fuse_req_t req, fuse_ino_t ino, struct fuse_file_info_compat *fi); - void (*read) (fuse_req_t req, fuse_ino_t ino, size_t size, off_t off, - struct fuse_file_info_compat *fi); - void (*write) (fuse_req_t req, fuse_ino_t ino, const char *buf, - size_t size, off_t off, struct fuse_file_info_compat *fi); - void (*flush) (fuse_req_t req, fuse_ino_t ino, struct fuse_file_info_compat *fi); - void (*release) (fuse_req_t req, fuse_ino_t ino, struct fuse_file_info_compat *fi); - void (*fsync) (fuse_req_t req, fuse_ino_t ino, int datasync, - struct fuse_file_info_compat *fi); - void (*opendir) (fuse_req_t req, fuse_ino_t ino, struct fuse_file_info_compat *fi); - void (*readdir) (fuse_req_t req, fuse_ino_t ino, size_t size, off_t off, - struct fuse_file_info_compat *fi); - void (*releasedir) (fuse_req_t req, fuse_ino_t ino, - struct fuse_file_info_compat *fi); - void (*fsyncdir) (fuse_req_t req, fuse_ino_t ino, int datasync, - struct fuse_file_info_compat *fi); - void (*statfs) (fuse_req_t req); - void (*setxattr) (fuse_req_t req, fuse_ino_t ino, const char *name, - const char *value, size_t size, int flags); - void (*getxattr) (fuse_req_t req, fuse_ino_t ino, const char *name, - size_t size); - void (*listxattr) (fuse_req_t req, fuse_ino_t ino, size_t size); - void (*removexattr) (fuse_req_t req, fuse_ino_t ino, const char *name); - void (*access) (fuse_req_t req, fuse_ino_t ino, int mask); - void (*create) (fuse_req_t req, fuse_ino_t parent, const char *name, - mode_t mode, struct fuse_file_info_compat *fi); + void (*init) (void *userdata); + void (*destroy) (void *userdata); + void (*lookup) (fuse_req_t req, fuse_ino_t parent, const char *name); + void (*forget) (fuse_req_t req, fuse_ino_t ino, unsigned long nlookup); + void (*getattr) (fuse_req_t req, fuse_ino_t ino, + struct fuse_file_info_compat *fi); + void (*setattr) (fuse_req_t req, fuse_ino_t ino, struct stat *attr, + int to_set, struct fuse_file_info_compat *fi); + void (*readlink) (fuse_req_t req, fuse_ino_t ino); + void (*mknod) (fuse_req_t req, fuse_ino_t parent, const char *name, + mode_t mode, dev_t rdev); + void (*mkdir) (fuse_req_t req, fuse_ino_t parent, const char *name, + mode_t mode); + void (*unlink) (fuse_req_t req, fuse_ino_t parent, const char *name); + void (*rmdir) (fuse_req_t req, fuse_ino_t parent, const char *name); + void (*symlink) (fuse_req_t req, const char *link, fuse_ino_t parent, + const char *name); + void (*rename) (fuse_req_t req, fuse_ino_t parent, const char *name, + fuse_ino_t newparent, const char *newname); + void (*link) (fuse_req_t req, fuse_ino_t ino, fuse_ino_t newparent, + const char *newname); + void (*open) (fuse_req_t req, fuse_ino_t ino, + struct fuse_file_info_compat *fi); + void (*read) (fuse_req_t req, fuse_ino_t ino, size_t size, off_t off, + struct fuse_file_info_compat *fi); + void (*write) (fuse_req_t req, fuse_ino_t ino, const char *buf, + size_t size, off_t off, struct fuse_file_info_compat *fi); + void (*flush) (fuse_req_t req, fuse_ino_t ino, + struct fuse_file_info_compat *fi); + void (*release) (fuse_req_t req, fuse_ino_t ino, + struct fuse_file_info_compat *fi); + void (*fsync) (fuse_req_t req, fuse_ino_t ino, int datasync, + struct fuse_file_info_compat *fi); + void (*opendir) (fuse_req_t req, fuse_ino_t ino, + struct fuse_file_info_compat *fi); + void (*readdir) (fuse_req_t req, fuse_ino_t ino, size_t size, off_t off, + struct fuse_file_info_compat *fi); + void (*releasedir) (fuse_req_t req, fuse_ino_t ino, + struct fuse_file_info_compat *fi); + void (*fsyncdir) (fuse_req_t req, fuse_ino_t ino, int datasync, + struct fuse_file_info_compat *fi); + void (*statfs) (fuse_req_t req); + void (*setxattr) (fuse_req_t req, fuse_ino_t ino, const char *name, + const char *value, size_t size, int flags); + void (*getxattr) (fuse_req_t req, fuse_ino_t ino, const char *name, + size_t size); + void (*listxattr) (fuse_req_t req, fuse_ino_t ino, size_t size); + void (*removexattr) (fuse_req_t req, fuse_ino_t ino, const char *name); + void (*access) (fuse_req_t req, fuse_ino_t ino, int mask); + void (*create) (fuse_req_t req, fuse_ino_t parent, const char *name, + mode_t mode, struct fuse_file_info_compat *fi); }; int fuse_reply_statfs_compat(fuse_req_t req, const struct statfs *stbuf); int fuse_reply_open_compat(fuse_req_t req, - const struct fuse_file_info_compat *fi); + const struct fuse_file_info_compat *fi); struct fuse_session *fuse_lowlevel_new_compat(const char *opts, - const struct fuse_lowlevel_ops_compat *op, - size_t op_size, void *userdata); + const struct fuse_lowlevel_ops_compat *op, + size_t op_size, void *userdata); #endif /* __FreeBSD__ */ struct fuse_chan_ops_compat24 { - int (*receive)(struct fuse_chan *ch, char *buf, size_t size); - int (*send)(struct fuse_chan *ch, const struct iovec iov[], size_t count); - void (*destroy)(struct fuse_chan *ch); + int (*receive)(struct fuse_chan *ch, char *buf, size_t size); + int (*send)(struct fuse_chan *ch, const struct iovec iov[], + size_t count); + void (*destroy)(struct fuse_chan *ch); }; struct fuse_chan *fuse_chan_new_compat24(struct fuse_chan_ops_compat24 *op, - int fd, size_t bufsize, void *data); + int fd, size_t bufsize, void *data); int fuse_chan_receive(struct fuse_chan *ch, char *buf, size_t size); struct fuse_chan *fuse_kern_chan_new(int fd); diff --git a/include/fuse_opt.h b/include/fuse_opt.h index 6123d0b..7ae08af 100644 --- a/include/fuse_opt.h +++ b/include/fuse_opt.h @@ -1,9 +1,9 @@ /* - FUSE: Filesystem in Userspace - Copyright (C) 2001-2007 Miklos Szeredi + FUSE: Filesystem in Userspace + Copyright (C) 2001-2007 Miklos Szeredi - This program can be distributed under the terms of the GNU LGPLv2. - See the file COPYING.LIB. + This program can be distributed under the terms of the GNU LGPLv2. + See the file COPYING.LIB. */ #ifndef _FUSE_OPT_H_ @@ -41,7 +41,7 @@ extern "C" { * * - 'offsetof(struct foo, member)' actions i) and iii) * - * - -1 action ii) + * - -1 action ii) * * The 'offsetof()' macro is defined in the header. * @@ -52,7 +52,7 @@ extern "C" { * * The types of templates are: * - * 1) "-x", "-foo", "--foo", "--foo-bar", etc. These match only + * 1) "-x", "-foo", "--foo", "--foo-bar", etc. These match only * themselves. Invalid values are "--" and anything beginning * with "-o" * @@ -74,30 +74,30 @@ extern "C" { * with scanf(). */ struct fuse_opt { - /** Matching template and optional parameter formatting */ - const char *templ; + /** Matching template and optional parameter formatting */ + const char *templ; - /** - * Offset of variable within 'data' parameter of fuse_opt_parse() - * or -1 - */ - unsigned long offset; + /** + * Offset of variable within 'data' parameter of fuse_opt_parse() + * or -1 + */ + unsigned long offset; - /** - * Value to set the variable to, or to be passed as 'key' to the - * processing function. Ignored if template has a format - */ - int value; + /** + * Value to set the variable to, or to be passed as 'key' to the + * processing function. Ignored if template has a format + */ + int value; }; /** - * Key option. In case of a match, the processing function will be + * Key option. In case of a match, the processing function will be * called with the specified key. */ #define FUSE_OPT_KEY(templ, key) { templ, -1U, key } /** - * Last option. An array of 'struct fuse_opt' must end with a NULL + * Last option. An array of 'struct fuse_opt' must end with a NULL * template value */ #define FUSE_OPT_END { .templ = NULL } @@ -106,14 +106,14 @@ struct fuse_opt { * Argument list */ struct fuse_args { - /** Argument count */ - int argc; + /** Argument count */ + int argc; - /** Argument vector. NULL terminated */ - char **argv; + /** Argument vector. NULL terminated */ + char **argv; - /** Is 'argv' allocated? */ - int allocated; + /** Is 'argv' allocated? */ + int allocated; }; /** @@ -177,7 +177,7 @@ struct fuse_args { * @return -1 on error, 0 if arg is to be discarded, 1 if arg should be kept */ typedef int (*fuse_opt_proc_t)(void *data, const char *arg, int key, - struct fuse_args *outargs); + struct fuse_args *outargs); /** * Option parsing function @@ -200,7 +200,7 @@ typedef int (*fuse_opt_proc_t)(void *data, const char *arg, int key, * @return -1 on error, 0 on success */ int fuse_opt_parse(struct fuse_args *args, void *data, - const struct fuse_opt opts[], fuse_opt_proc_t proc); + const struct fuse_opt opts[], fuse_opt_proc_t proc); /** * Add an option to a comma separated option list diff --git a/include/ulockmgr.h b/include/ulockmgr.h index 61bc36b..ad55579 100644 --- a/include/ulockmgr.h +++ b/include/ulockmgr.h @@ -1,9 +1,9 @@ /* - libulockmgr: Userspace Lock Manager Library - Copyright (C) 2006 Miklos Szeredi + libulockmgr: Userspace Lock Manager Library + Copyright (C) 2006 Miklos Szeredi - This program can be distributed under the terms of the GNU LGPLv2. - See the file COPYING.LIB. + This program can be distributed under the terms of the GNU LGPLv2. + See the file COPYING.LIB. */ #include @@ -21,4 +21,4 @@ * @return 0 on success -errno on error */ int ulockmgr_op(int fd, int cmd, struct flock *lock, const void *owner, - size_t owner_len); + size_t owner_len); diff --git a/lib/fuse.c b/lib/fuse.c index d22e200..7bcbe76 100644 --- a/lib/fuse.c +++ b/lib/fuse.c @@ -1,9 +1,9 @@ /* - FUSE: Filesystem in Userspace - Copyright (C) 2001-2007 Miklos Szeredi + FUSE: Filesystem in Userspace + Copyright (C) 2001-2007 Miklos Szeredi - This program can be distributed under the terms of the GNU LGPLv2. - See the file COPYING.LIB + This program can be distributed under the terms of the GNU LGPLv2. + See the file COPYING.LIB */ @@ -40,109 +40,109 @@ #define OFFSET_MAX 0x7fffffffffffffffLL struct fuse_config { - unsigned int uid; - unsigned int gid; - unsigned int umask; - double entry_timeout; - double negative_timeout; - double attr_timeout; - double ac_attr_timeout; - int ac_attr_timeout_set; - int debug; - int hard_remove; - int use_ino; - int readdir_ino; - int set_mode; - int set_uid; - int set_gid; - int direct_io; - int kernel_cache; - int auto_cache; - int intr; - int intr_signal; - int help; - char *modules; + unsigned int uid; + unsigned int gid; + unsigned int umask; + double entry_timeout; + double negative_timeout; + double attr_timeout; + double ac_attr_timeout; + int ac_attr_timeout_set; + int debug; + int hard_remove; + int use_ino; + int readdir_ino; + int set_mode; + int set_uid; + int set_gid; + int direct_io; + int kernel_cache; + int auto_cache; + int intr; + int intr_signal; + int help; + char *modules; }; struct fuse_fs { - struct fuse_operations op; - struct fuse_module *m; - void *user_data; - int compat; + struct fuse_operations op; + struct fuse_module *m; + void *user_data; + int compat; }; struct fusemod_so { - void *handle; - int ctr; + void *handle; + int ctr; }; struct fuse { - struct fuse_session *se; - struct node **name_table; - size_t name_table_size; - struct node **id_table; - size_t id_table_size; - fuse_ino_t ctr; - unsigned int generation; - unsigned int hidectr; - pthread_mutex_t lock; - pthread_rwlock_t tree_lock; - struct fuse_config conf; - int intr_installed; - struct fuse_fs *fs; + struct fuse_session *se; + struct node **name_table; + size_t name_table_size; + struct node **id_table; + size_t id_table_size; + fuse_ino_t ctr; + unsigned int generation; + unsigned int hidectr; + pthread_mutex_t lock; + pthread_rwlock_t tree_lock; + struct fuse_config conf; + int intr_installed; + struct fuse_fs *fs; }; struct lock { - int type; - off_t start; - off_t end; - pid_t pid; - uint64_t owner; - struct lock *next; + int type; + off_t start; + off_t end; + pid_t pid; + uint64_t owner; + struct lock *next; }; struct node { - struct node *name_next; - struct node *id_next; - fuse_ino_t nodeid; - unsigned int generation; - int refctr; - struct node *parent; - char *name; - uint64_t nlookup; - int open_count; - int is_hidden; - struct timespec stat_updated; - struct timespec mtime; - off_t size; - int cache_valid; - struct lock *locks; + struct node *name_next; + struct node *id_next; + fuse_ino_t nodeid; + unsigned int generation; + int refctr; + struct node *parent; + char *name; + uint64_t nlookup; + int open_count; + int is_hidden; + struct timespec stat_updated; + struct timespec mtime; + off_t size; + int cache_valid; + struct lock *locks; }; struct fuse_dh { - pthread_mutex_t lock; - struct fuse *fuse; - fuse_req_t req; - char *contents; - int allocated; - unsigned len; - unsigned size; - unsigned needlen; - int filled; - uint64_t fh; - int error; - fuse_ino_t nodeid; + pthread_mutex_t lock; + struct fuse *fuse; + fuse_req_t req; + char *contents; + int allocated; + unsigned len; + unsigned size; + unsigned needlen; + int filled; + uint64_t fh; + int error; + fuse_ino_t nodeid; }; /* old dir handle */ struct fuse_dirhandle { - fuse_fill_dir_t filler; - void *buf; + fuse_fill_dir_t filler; + void *buf; }; struct fuse_context_i { - struct fuse_context ctx; - fuse_req_t req; + struct fuse_context ctx; + fuse_req_t req; }; static pthread_key_t fuse_context_key; @@ -153,1017 +153,1025 @@ static struct fuse_module *fuse_modules; static int fuse_load_so_name(const char *soname) { - struct fusemod_so *so; - - so = calloc(1, sizeof(struct fusemod_so)); - if (!so) { - fprintf(stderr, "fuse: memory allocation failed\n"); - return -1; - } - - fuse_current_so = so; - so->handle = dlopen(soname, RTLD_NOW); - fuse_current_so = NULL; - if (!so->handle) { - fprintf(stderr, "fuse: %s\n", dlerror()); - goto err; - } - if (!so->ctr) { - fprintf(stderr, "fuse: %s did not register any modules", soname); - goto err; - } - return 0; - - err: - if (so->handle) - dlclose(so->handle); - free(so); - return -1; + struct fusemod_so *so; + + so = calloc(1, sizeof(struct fusemod_so)); + if (!so) { + fprintf(stderr, "fuse: memory allocation failed\n"); + return -1; + } + + fuse_current_so = so; + so->handle = dlopen(soname, RTLD_NOW); + fuse_current_so = NULL; + if (!so->handle) { + fprintf(stderr, "fuse: %s\n", dlerror()); + goto err; + } + if (!so->ctr) { + fprintf(stderr, "fuse: %s did not register any modules", + soname); + goto err; + } + return 0; + +err: + if (so->handle) + dlclose(so->handle); + free(so); + return -1; } static int fuse_load_so_module(const char *module) { - int res; - char *soname = malloc(strlen(module) + 64); - if (!soname) { - fprintf(stderr, "fuse: memory allocation failed\n"); - return -1; - } - sprintf(soname, "libfusemod_%s.so", module); - res = fuse_load_so_name(soname); - free(soname); - return res; + int res; + char *soname = malloc(strlen(module) + 64); + if (!soname) { + fprintf(stderr, "fuse: memory allocation failed\n"); + return -1; + } + sprintf(soname, "libfusemod_%s.so", module); + res = fuse_load_so_name(soname); + free(soname); + return res; } static struct fuse_module *fuse_find_module(const char *module) { - struct fuse_module *m; - for (m = fuse_modules; m; m = m->next) { - if (strcmp(module, m->name) == 0) { - m->ctr++; - break; - } - } - return m; + struct fuse_module *m; + for (m = fuse_modules; m; m = m->next) { + if (strcmp(module, m->name) == 0) { + m->ctr++; + break; + } + } + return m; } static struct fuse_module *fuse_get_module(const char *module) { - struct fuse_module *m; + struct fuse_module *m; - pthread_mutex_lock(&fuse_context_lock); - m = fuse_find_module(module); - if (!m) { - int err = fuse_load_so_module(module); - if (!err) - m = fuse_find_module(module); - } - pthread_mutex_unlock(&fuse_context_lock); - return m; + pthread_mutex_lock(&fuse_context_lock); + m = fuse_find_module(module); + if (!m) { + int err = fuse_load_so_module(module); + if (!err) + m = fuse_find_module(module); + } + pthread_mutex_unlock(&fuse_context_lock); + return m; } static void fuse_put_module(struct fuse_module *m) { - pthread_mutex_lock(&fuse_context_lock); - assert(m->ctr > 0); - m->ctr--; - if (!m->ctr && m->so) { - struct fusemod_so *so = m->so; - assert(so->ctr > 0); - so->ctr--; - if (!so->ctr) { - struct fuse_module **mp; - for (mp = &fuse_modules; *mp;) { - if ((*mp)->so == so) - *mp = (*mp)->next; - else - mp = &(*mp)->next; - } - dlclose(so->handle); - free(so); - } - } - pthread_mutex_unlock(&fuse_context_lock); + pthread_mutex_lock(&fuse_context_lock); + assert(m->ctr > 0); + m->ctr--; + if (!m->ctr && m->so) { + struct fusemod_so *so = m->so; + assert(so->ctr > 0); + so->ctr--; + if (!so->ctr) { + struct fuse_module **mp; + for (mp = &fuse_modules; *mp;) { + if ((*mp)->so == so) + *mp = (*mp)->next; + else + mp = &(*mp)->next; + } + dlclose(so->handle); + free(so); + } + } + pthread_mutex_unlock(&fuse_context_lock); } static struct node *get_node_nocheck(struct fuse *f, fuse_ino_t nodeid) { - size_t hash = nodeid % f->id_table_size; - struct node *node; + size_t hash = nodeid % f->id_table_size; + struct node *node; - for (node = f->id_table[hash]; node != NULL; node = node->id_next) - if (node->nodeid == nodeid) - return node; + for (node = f->id_table[hash]; node != NULL; node = node->id_next) + if (node->nodeid == nodeid) + return node; - return NULL; + return NULL; } static struct node *get_node(struct fuse *f, fuse_ino_t nodeid) { - struct node *node = get_node_nocheck(f, nodeid); - if (!node) { - fprintf(stderr, "fuse internal error: node %llu not found\n", - (unsigned long long) nodeid); - abort(); - } - return node; + struct node *node = get_node_nocheck(f, nodeid); + if (!node) { + fprintf(stderr, "fuse internal error: node %llu not found\n", + (unsigned long long) nodeid); + abort(); + } + return node; } static void free_node(struct node *node) { - free(node->name); - free(node); + free(node->name); + free(node); } static void unhash_id(struct fuse *f, struct node *node) { - size_t hash = node->nodeid % f->id_table_size; - struct node **nodep = &f->id_table[hash]; + size_t hash = node->nodeid % f->id_table_size; + struct node **nodep = &f->id_table[hash]; - for (; *nodep != NULL; nodep = &(*nodep)->id_next) - if (*nodep == node) { - *nodep = node->id_next; - return; - } + for (; *nodep != NULL; nodep = &(*nodep)->id_next) + if (*nodep == node) { + *nodep = node->id_next; + return; + } } static void hash_id(struct fuse *f, struct node *node) { - size_t hash = node->nodeid % f->id_table_size; - node->id_next = f->id_table[hash]; - f->id_table[hash] = node; + size_t hash = node->nodeid % f->id_table_size; + node->id_next = f->id_table[hash]; + f->id_table[hash] = node; } static unsigned int name_hash(struct fuse *f, fuse_ino_t parent, - const char *name) + const char *name) { - unsigned int hash = *name; + unsigned int hash = *name; - if (hash) - for (name += 1; *name != '\0'; name++) - hash = (hash << 5) - hash + *name; + if (hash) + for (name += 1; *name != '\0'; name++) + hash = (hash << 5) - hash + *name; - return (hash + parent) % f->name_table_size; + return (hash + parent) % f->name_table_size; } static void unref_node(struct fuse *f, struct node *node); static void unhash_name(struct fuse *f, struct node *node) { - if (node->name) { - size_t hash = name_hash(f, node->parent->nodeid, node->name); - struct node **nodep = &f->name_table[hash]; - - for (; *nodep != NULL; nodep = &(*nodep)->name_next) - if (*nodep == node) { - *nodep = node->name_next; - node->name_next = NULL; - unref_node(f, node->parent); - free(node->name); - node->name = NULL; - node->parent = NULL; - return; - } - fprintf(stderr, "fuse internal error: unable to unhash node: %llu\n", - (unsigned long long) node->nodeid); - abort(); - } + if (node->name) { + size_t hash = name_hash(f, node->parent->nodeid, node->name); + struct node **nodep = &f->name_table[hash]; + + for (; *nodep != NULL; nodep = &(*nodep)->name_next) + if (*nodep == node) { + *nodep = node->name_next; + node->name_next = NULL; + unref_node(f, node->parent); + free(node->name); + node->name = NULL; + node->parent = NULL; + return; + } + fprintf(stderr, + "fuse internal error: unable to unhash node: %llu\n", + (unsigned long long) node->nodeid); + abort(); + } } static int hash_name(struct fuse *f, struct node *node, fuse_ino_t parentid, - const char *name) + const char *name) { - size_t hash = name_hash(f, parentid, name); - struct node *parent = get_node(f, parentid); - node->name = strdup(name); - if (node->name == NULL) - return -1; + size_t hash = name_hash(f, parentid, name); + struct node *parent = get_node(f, parentid); + node->name = strdup(name); + if (node->name == NULL) + return -1; - parent->refctr ++; - node->parent = parent; - node->name_next = f->name_table[hash]; - f->name_table[hash] = node; - return 0; + parent->refctr ++; + node->parent = parent; + node->name_next = f->name_table[hash]; + f->name_table[hash] = node; + return 0; } static void delete_node(struct fuse *f, struct node *node) { - if (f->conf.debug) - fprintf(stderr, "delete: %llu\n", (unsigned long long) node->nodeid); + if (f->conf.debug) + fprintf(stderr, "delete: %llu\n", + (unsigned long long) node->nodeid); - assert(!node->name); - unhash_id(f, node); - free_node(node); + assert(!node->name); + unhash_id(f, node); + free_node(node); } static void unref_node(struct fuse *f, struct node *node) { - assert(node->refctr > 0); - node->refctr --; - if (!node->refctr) - delete_node(f, node); + assert(node->refctr > 0); + node->refctr --; + if (!node->refctr) + delete_node(f, node); } static fuse_ino_t next_id(struct fuse *f) { - do { - f->ctr = (f->ctr + 1) & 0xffffffff; - if (!f->ctr) - f->generation ++; - } while (f->ctr == 0 || f->ctr == FUSE_UNKNOWN_INO || - get_node_nocheck(f, f->ctr) != NULL); - return f->ctr; + do { + f->ctr = (f->ctr + 1) & 0xffffffff; + if (!f->ctr) + f->generation ++; + } while (f->ctr == 0 || f->ctr == FUSE_UNKNOWN_INO || + get_node_nocheck(f, f->ctr) != NULL); + return f->ctr; } static struct node *lookup_node(struct fuse *f, fuse_ino_t parent, - const char *name) + const char *name) { - size_t hash = name_hash(f, parent, name); - struct node *node; + size_t hash = name_hash(f, parent, name); + struct node *node; - for (node = f->name_table[hash]; node != NULL; node = node->name_next) - if (node->parent->nodeid == parent && strcmp(node->name, name) == 0) - return node; + for (node = f->name_table[hash]; node != NULL; node = node->name_next) + if (node->parent->nodeid == parent && + strcmp(node->name, name) == 0) + return node; - return NULL; + return NULL; } static struct node *find_node(struct fuse *f, fuse_ino_t parent, - const char *name) -{ - struct node *node; - - pthread_mutex_lock(&f->lock); - node = lookup_node(f, parent, name); - if (node == NULL) { - node = (struct node *) calloc(1, sizeof(struct node)); - if (node == NULL) - goto out_err; - - node->refctr = 1; - node->nodeid = next_id(f); - node->open_count = 0; - node->is_hidden = 0; - node->generation = f->generation; - if (hash_name(f, node, parent, name) == -1) { - free(node); - node = NULL; - goto out_err; - } - hash_id(f, node); - } - node->nlookup ++; - out_err: - pthread_mutex_unlock(&f->lock); - return node; + const char *name) +{ + struct node *node; + + pthread_mutex_lock(&f->lock); + node = lookup_node(f, parent, name); + if (node == NULL) { + node = (struct node *) calloc(1, sizeof(struct node)); + if (node == NULL) + goto out_err; + + node->refctr = 1; + node->nodeid = next_id(f); + node->open_count = 0; + node->is_hidden = 0; + node->generation = f->generation; + if (hash_name(f, node, parent, name) == -1) { + free(node); + node = NULL; + goto out_err; + } + hash_id(f, node); + } + node->nlookup ++; +out_err: + pthread_mutex_unlock(&f->lock); + return node; } static char *add_name(char *buf, char *s, const char *name) { - size_t len = strlen(name); - s -= len; - if (s <= buf) { - fprintf(stderr, "fuse: path too long: ...%s\n", s + len); - return NULL; - } - strncpy(s, name, len); - s--; - *s = '/'; + size_t len = strlen(name); + s -= len; + if (s <= buf) { + fprintf(stderr, "fuse: path too long: ...%s\n", s + len); + return NULL; + } + strncpy(s, name, len); + s--; + *s = '/'; - return s; + return s; } static char *get_path_name(struct fuse *f, fuse_ino_t nodeid, const char *name) { - char buf[FUSE_MAX_PATH]; - char *s = buf + FUSE_MAX_PATH - 1; - struct node *node; + char buf[FUSE_MAX_PATH]; + char *s = buf + FUSE_MAX_PATH - 1; + struct node *node; - *s = '\0'; + *s = '\0'; - if (name != NULL) { - s = add_name(buf, s, name); - if (s == NULL) - return NULL; - } + if (name != NULL) { + s = add_name(buf, s, name); + if (s == NULL) + return NULL; + } - pthread_mutex_lock(&f->lock); - for (node = get_node(f, nodeid); node && node->nodeid != FUSE_ROOT_ID; - node = node->parent) { - if (node->name == NULL) { - s = NULL; - break; - } + pthread_mutex_lock(&f->lock); + for (node = get_node(f, nodeid); node && node->nodeid != FUSE_ROOT_ID; + node = node->parent) { + if (node->name == NULL) { + s = NULL; + break; + } - s = add_name(buf, s, node->name); - if (s == NULL) - break; - } - pthread_mutex_unlock(&f->lock); + s = add_name(buf, s, node->name); + if (s == NULL) + break; + } + pthread_mutex_unlock(&f->lock); - if (node == NULL || s == NULL) - return NULL; - else if (*s == '\0') - return strdup("/"); - else - return strdup(s); + if (node == NULL || s == NULL) + return NULL; + else if (*s == '\0') + return strdup("/"); + else + return strdup(s); } static char *get_path(struct fuse *f, fuse_ino_t nodeid) { - return get_path_name(f, nodeid, NULL); + return get_path_name(f, nodeid, NULL); } static void forget_node(struct fuse *f, fuse_ino_t nodeid, uint64_t nlookup) { - struct node *node; - if (nodeid == FUSE_ROOT_ID) - return; - pthread_mutex_lock(&f->lock); - node = get_node(f, nodeid); - assert(node->nlookup >= nlookup); - node->nlookup -= nlookup; - if (!node->nlookup) { - unhash_name(f, node); - unref_node(f, node); - } - pthread_mutex_unlock(&f->lock); + struct node *node; + if (nodeid == FUSE_ROOT_ID) + return; + pthread_mutex_lock(&f->lock); + node = get_node(f, nodeid); + assert(node->nlookup >= nlookup); + node->nlookup -= nlookup; + if (!node->nlookup) { + unhash_name(f, node); + unref_node(f, node); + } + pthread_mutex_unlock(&f->lock); } static void remove_node(struct fuse *f, fuse_ino_t dir, const char *name) { - struct node *node; + struct node *node; - pthread_mutex_lock(&f->lock); - node = lookup_node(f, dir, name); - if (node != NULL) - unhash_name(f, node); - pthread_mutex_unlock(&f->lock); + pthread_mutex_lock(&f->lock); + node = lookup_node(f, dir, name); + if (node != NULL) + unhash_name(f, node); + pthread_mutex_unlock(&f->lock); } static int rename_node(struct fuse *f, fuse_ino_t olddir, const char *oldname, - fuse_ino_t newdir, const char *newname, int hide) -{ - struct node *node; - struct node *newnode; - int err = 0; - - pthread_mutex_lock(&f->lock); - node = lookup_node(f, olddir, oldname); - newnode = lookup_node(f, newdir, newname); - if (node == NULL) - goto out; - - if (newnode != NULL) { - if (hide) { - fprintf(stderr, "fuse: hidden file got created during hiding\n"); - err = -EBUSY; - goto out; - } - unhash_name(f, newnode); - } - - unhash_name(f, node); - if (hash_name(f, node, newdir, newname) == -1) { - err = -ENOMEM; - goto out; - } - - if (hide) - node->is_hidden = 1; + fuse_ino_t newdir, const char *newname, int hide) +{ + struct node *node; + struct node *newnode; + int err = 0; + + pthread_mutex_lock(&f->lock); + node = lookup_node(f, olddir, oldname); + newnode = lookup_node(f, newdir, newname); + if (node == NULL) + goto out; + + if (newnode != NULL) { + if (hide) { + fprintf(stderr, "fuse: hidden file got created during hiding\n"); + err = -EBUSY; + goto out; + } + unhash_name(f, newnode); + } + + unhash_name(f, node); + if (hash_name(f, node, newdir, newname) == -1) { + err = -ENOMEM; + goto out; + } + + if (hide) + node->is_hidden = 1; - out: - pthread_mutex_unlock(&f->lock); - return err; +out: + pthread_mutex_unlock(&f->lock); + return err; } static void set_stat(struct fuse *f, fuse_ino_t nodeid, struct stat *stbuf) { - if (!f->conf.use_ino) - stbuf->st_ino = nodeid; - if (f->conf.set_mode) - stbuf->st_mode = (stbuf->st_mode & S_IFMT) | (0777 & ~f->conf.umask); - if (f->conf.set_uid) - stbuf->st_uid = f->conf.uid; - if (f->conf.set_gid) - stbuf->st_gid = f->conf.gid; + if (!f->conf.use_ino) + stbuf->st_ino = nodeid; + if (f->conf.set_mode) + stbuf->st_mode = (stbuf->st_mode & S_IFMT) | + (0777 & ~f->conf.umask); + if (f->conf.set_uid) + stbuf->st_uid = f->conf.uid; + if (f->conf.set_gid) + stbuf->st_gid = f->conf.gid; } static struct fuse *req_fuse(fuse_req_t req) { - return (struct fuse *) fuse_req_userdata(req); + return (struct fuse *) fuse_req_userdata(req); } static void fuse_intr_sighandler(int sig) { - (void) sig; - /* Nothing to do */ + (void) sig; + /* Nothing to do */ } struct fuse_intr_data { - pthread_t id; - pthread_cond_t cond; - int finished; + pthread_t id; + pthread_cond_t cond; + int finished; }; static void fuse_interrupt(fuse_req_t req, void *d_) { - struct fuse_intr_data *d = d_; - struct fuse *f = req_fuse(req); + struct fuse_intr_data *d = d_; + struct fuse *f = req_fuse(req); - if (d->id == pthread_self()) - return; + if (d->id == pthread_self()) + return; - pthread_mutex_lock(&f->lock); - while (!d->finished) { - struct timeval now; - struct timespec timeout; + pthread_mutex_lock(&f->lock); + while (!d->finished) { + struct timeval now; + struct timespec timeout; - pthread_kill(d->id, f->conf.intr_signal); - gettimeofday(&now, NULL); - timeout.tv_sec = now.tv_sec + 1; - timeout.tv_nsec = now.tv_usec * 1000; - pthread_cond_timedwait(&d->cond, &f->lock, &timeout); - } - pthread_mutex_unlock(&f->lock); + pthread_kill(d->id, f->conf.intr_signal); + gettimeofday(&now, NULL); + timeout.tv_sec = now.tv_sec + 1; + timeout.tv_nsec = now.tv_usec * 1000; + pthread_cond_timedwait(&d->cond, &f->lock, &timeout); + } + pthread_mutex_unlock(&f->lock); } static void fuse_do_finish_interrupt(struct fuse *f, fuse_req_t req, - struct fuse_intr_data *d) + struct fuse_intr_data *d) { - pthread_mutex_lock(&f->lock); - d->finished = 1; - pthread_cond_broadcast(&d->cond); - pthread_mutex_unlock(&f->lock); - fuse_req_interrupt_func(req, NULL, NULL); - pthread_cond_destroy(&d->cond); + pthread_mutex_lock(&f->lock); + d->finished = 1; + pthread_cond_broadcast(&d->cond); + pthread_mutex_unlock(&f->lock); + fuse_req_interrupt_func(req, NULL, NULL); + pthread_cond_destroy(&d->cond); } static void fuse_do_prepare_interrupt(fuse_req_t req, struct fuse_intr_data *d) { - d->id = pthread_self(); - pthread_cond_init(&d->cond, NULL); - d->finished = 0; - fuse_req_interrupt_func(req, fuse_interrupt, d); + d->id = pthread_self(); + pthread_cond_init(&d->cond, NULL); + d->finished = 0; + fuse_req_interrupt_func(req, fuse_interrupt, d); } static inline void fuse_finish_interrupt(struct fuse *f, fuse_req_t req, - struct fuse_intr_data *d) + struct fuse_intr_data *d) { - if (f->conf.intr) - fuse_do_finish_interrupt(f, req, d); + if (f->conf.intr) + fuse_do_finish_interrupt(f, req, d); } static inline void fuse_prepare_interrupt(struct fuse *f, fuse_req_t req, - struct fuse_intr_data *d) + struct fuse_intr_data *d) { - if (f->conf.intr) - fuse_do_prepare_interrupt(req, d); + if (f->conf.intr) + fuse_do_prepare_interrupt(req, d); } #ifndef __FreeBSD__ static int fuse_compat_open(struct fuse_fs *fs, const char *path, - struct fuse_file_info *fi) -{ - int err; - if (!fs->compat || fs->compat >= 25) - err = fs->op.open(path, fi); - else if (fs->compat == 22) { - struct fuse_file_info_compat tmp; - memcpy(&tmp, fi, sizeof(tmp)); - err = ((struct fuse_operations_compat22 *) &fs->op)->open(path, &tmp); - memcpy(fi, &tmp, sizeof(tmp)); - fi->fh = tmp.fh; - } else - err = ((struct fuse_operations_compat2 *) &fs->op) - ->open(path, fi->flags); - return err; + struct fuse_file_info *fi) +{ + int err; + if (!fs->compat || fs->compat >= 25) + err = fs->op.open(path, fi); + else if (fs->compat == 22) { + struct fuse_file_info_compat tmp; + memcpy(&tmp, fi, sizeof(tmp)); + err = ((struct fuse_operations_compat22 *) &fs->op)->open(path, + &tmp); + memcpy(fi, &tmp, sizeof(tmp)); + fi->fh = tmp.fh; + } else + err = ((struct fuse_operations_compat2 *) &fs->op) + ->open(path, fi->flags); + return err; } static int fuse_compat_release(struct fuse_fs *fs, const char *path, - struct fuse_file_info *fi) + struct fuse_file_info *fi) { - if (!fs->compat || fs->compat >= 22) - return fs->op.release(path, fi); - else - return ((struct fuse_operations_compat2 *) &fs->op) - ->release(path, fi->flags); + if (!fs->compat || fs->compat >= 22) + return fs->op.release(path, fi); + else + return ((struct fuse_operations_compat2 *) &fs->op) + ->release(path, fi->flags); } static int fuse_compat_opendir(struct fuse_fs *fs, const char *path, - struct fuse_file_info *fi) -{ - if (!fs->compat || fs->compat >= 25) - return fs->op.opendir(path, fi); - else { - int err; - struct fuse_file_info_compat tmp; - memcpy(&tmp, fi, sizeof(tmp)); - err = ((struct fuse_operations_compat22 *) &fs->op) - ->opendir(path, &tmp); - memcpy(fi, &tmp, sizeof(tmp)); - fi->fh = tmp.fh; - return err; - } + struct fuse_file_info *fi) +{ + if (!fs->compat || fs->compat >= 25) + return fs->op.opendir(path, fi); + else { + int err; + struct fuse_file_info_compat tmp; + memcpy(&tmp, fi, sizeof(tmp)); + err = ((struct fuse_operations_compat22 *) &fs->op) + ->opendir(path, &tmp); + memcpy(fi, &tmp, sizeof(tmp)); + fi->fh = tmp.fh; + return err; + } } static void convert_statfs_compat(struct fuse_statfs_compat1 *compatbuf, - struct statvfs *stbuf) + struct statvfs *stbuf) { - stbuf->f_bsize = compatbuf->block_size; - stbuf->f_blocks = compatbuf->blocks; - stbuf->f_bfree = compatbuf->blocks_free; - stbuf->f_bavail = compatbuf->blocks_free; - stbuf->f_files = compatbuf->files; - stbuf->f_ffree = compatbuf->files_free; - stbuf->f_namemax = compatbuf->namelen; + stbuf->f_bsize = compatbuf->block_size; + stbuf->f_blocks = compatbuf->blocks; + stbuf->f_bfree = compatbuf->blocks_free; + stbuf->f_bavail = compatbuf->blocks_free; + stbuf->f_files = compatbuf->files; + stbuf->f_ffree = compatbuf->files_free; + stbuf->f_namemax = compatbuf->namelen; } static void convert_statfs_old(struct statfs *oldbuf, struct statvfs *stbuf) { - stbuf->f_bsize = oldbuf->f_bsize; - stbuf->f_blocks = oldbuf->f_blocks; - stbuf->f_bfree = oldbuf->f_bfree; - stbuf->f_bavail = oldbuf->f_bavail; - stbuf->f_files = oldbuf->f_files; - stbuf->f_ffree = oldbuf->f_ffree; - stbuf->f_namemax = oldbuf->f_namelen; + stbuf->f_bsize = oldbuf->f_bsize; + stbuf->f_blocks = oldbuf->f_blocks; + stbuf->f_bfree = oldbuf->f_bfree; + stbuf->f_bavail = oldbuf->f_bavail; + stbuf->f_files = oldbuf->f_files; + stbuf->f_ffree = oldbuf->f_ffree; + stbuf->f_namemax = oldbuf->f_namelen; } static int fuse_compat_statfs(struct fuse_fs *fs, const char *path, - struct statvfs *buf) -{ - int err; - - if (!fs->compat || fs->compat >= 25) { - err = fs->op.statfs(fs->compat == 25 ? "/" : path, buf); - } else if (fs->compat > 11) { - struct statfs oldbuf; - err = ((struct fuse_operations_compat22 *) &fs->op) - ->statfs("/", &oldbuf); - if (!err) - convert_statfs_old(&oldbuf, buf); - } else { - struct fuse_statfs_compat1 compatbuf; - memset(&compatbuf, 0, sizeof(struct fuse_statfs_compat1)); - err = ((struct fuse_operations_compat1 *) &fs->op)->statfs(&compatbuf); - if (!err) - convert_statfs_compat(&compatbuf, buf); - } - return err; + struct statvfs *buf) +{ + int err; + + if (!fs->compat || fs->compat >= 25) { + err = fs->op.statfs(fs->compat == 25 ? "/" : path, buf); + } else if (fs->compat > 11) { + struct statfs oldbuf; + err = ((struct fuse_operations_compat22 *) &fs->op) + ->statfs("/", &oldbuf); + if (!err) + convert_statfs_old(&oldbuf, buf); + } else { + struct fuse_statfs_compat1 compatbuf; + memset(&compatbuf, 0, sizeof(struct fuse_statfs_compat1)); + err = ((struct fuse_operations_compat1 *) &fs->op) + ->statfs(&compatbuf); + if (!err) + convert_statfs_compat(&compatbuf, buf); + } + return err; } #else /* __FreeBSD__ */ static inline int fuse_compat_open(struct fuse_fs *fs, char *path, - struct fuse_file_info *fi) + struct fuse_file_info *fi) { - return fs->op.open(path, fi); + return fs->op.open(path, fi); } static inline int fuse_compat_release(struct fuse_fs *fs, const char *path, - struct fuse_file_info *fi) + struct fuse_file_info *fi) { - return fs->op.release(path, fi); + return fs->op.release(path, fi); } static inline int fuse_compat_opendir(struct fuse_fs *fs, const char *path, - struct fuse_file_info *fi) + struct fuse_file_info *fi) { - return fs->op.opendir(path, fi); + return fs->op.opendir(path, fi); } static inline int fuse_compat_statfs(struct fuse_fs *fs, const char *path, - struct statvfs *buf) + struct statvfs *buf) { - return fs->op.statfs(fs->compat == 25 ? "/" : path, buf); + return fs->op.statfs(fs->compat == 25 ? "/" : path, buf); } #endif /* __FreeBSD__ */ int fuse_fs_getattr(struct fuse_fs *fs, const char *path, struct stat *buf) { - fuse_get_context()->private_data = fs->user_data; - if (fs->op.getattr) - return fs->op.getattr(path, buf); - else - return -ENOSYS; + fuse_get_context()->private_data = fs->user_data; + if (fs->op.getattr) + return fs->op.getattr(path, buf); + else + return -ENOSYS; } int fuse_fs_fgetattr(struct fuse_fs *fs, const char *path, struct stat *buf, - struct fuse_file_info *fi) + struct fuse_file_info *fi) { - fuse_get_context()->private_data = fs->user_data; - if (fs->op.fgetattr) - return fs->op.fgetattr(path, buf, fi); - else if (fs->op.getattr) - return fs->op.getattr(path, buf); - else - return -ENOSYS; + fuse_get_context()->private_data = fs->user_data; + if (fs->op.fgetattr) + return fs->op.fgetattr(path, buf, fi); + else if (fs->op.getattr) + return fs->op.getattr(path, buf); + else + return -ENOSYS; } int fuse_fs_rename(struct fuse_fs *fs, const char *oldpath, - const char *newpath) + const char *newpath) { - fuse_get_context()->private_data = fs->user_data; - if (fs->op.rename) - return fs->op.rename(oldpath, newpath); - else - return -ENOSYS; + fuse_get_context()->private_data = fs->user_data; + if (fs->op.rename) + return fs->op.rename(oldpath, newpath); + else + return -ENOSYS; } int fuse_fs_unlink(struct fuse_fs *fs, const char *path) { - fuse_get_context()->private_data = fs->user_data; - if (fs->op.unlink) - return fs->op.unlink(path); - else - return -ENOSYS; + fuse_get_context()->private_data = fs->user_data; + if (fs->op.unlink) + return fs->op.unlink(path); + else + return -ENOSYS; } int fuse_fs_rmdir(struct fuse_fs *fs, const char *path) { - fuse_get_context()->private_data = fs->user_data; - if (fs->op.rmdir) - return fs->op.rmdir(path); - else - return -ENOSYS; + fuse_get_context()->private_data = fs->user_data; + if (fs->op.rmdir) + return fs->op.rmdir(path); + else + return -ENOSYS; } int fuse_fs_symlink(struct fuse_fs *fs, const char *linkname, const char *path) { - fuse_get_context()->private_data = fs->user_data; - if (fs->op.symlink) - return fs->op.symlink(linkname, path); - else - return -ENOSYS; + fuse_get_context()->private_data = fs->user_data; + if (fs->op.symlink) + return fs->op.symlink(linkname, path); + else + return -ENOSYS; } int fuse_fs_link(struct fuse_fs *fs, const char *oldpath, const char *newpath) { - fuse_get_context()->private_data = fs->user_data; - if (fs->op.link) - return fs->op.link(oldpath, newpath); - else - return -ENOSYS; + fuse_get_context()->private_data = fs->user_data; + if (fs->op.link) + return fs->op.link(oldpath, newpath); + else + return -ENOSYS; } -int fuse_fs_release(struct fuse_fs *fs, const char *path, - struct fuse_file_info *fi) +int fuse_fs_release(struct fuse_fs *fs, const char *path, + struct fuse_file_info *fi) { - fuse_get_context()->private_data = fs->user_data; - if (fs->op.release) - return fuse_compat_release(fs, path, fi); - else - return 0; + fuse_get_context()->private_data = fs->user_data; + if (fs->op.release) + return fuse_compat_release(fs, path, fi); + else + return 0; } int fuse_fs_opendir(struct fuse_fs *fs, const char *path, - struct fuse_file_info *fi) + struct fuse_file_info *fi) { - fuse_get_context()->private_data = fs->user_data; - if (fs->op.opendir) - return fuse_compat_opendir(fs, path, fi); - else - return 0; + fuse_get_context()->private_data = fs->user_data; + if (fs->op.opendir) + return fuse_compat_opendir(fs, path, fi); + else + return 0; } int fuse_fs_open(struct fuse_fs *fs, const char *path, - struct fuse_file_info *fi) + struct fuse_file_info *fi) { - fuse_get_context()->private_data = fs->user_data; - if (fs->op.open) - return fuse_compat_open(fs, path, fi); - else - return 0; + fuse_get_context()->private_data = fs->user_data; + if (fs->op.open) + return fuse_compat_open(fs, path, fi); + else + return 0; } int fuse_fs_read(struct fuse_fs *fs, const char *path, char *buf, size_t size, - off_t off, struct fuse_file_info *fi) + off_t off, struct fuse_file_info *fi) { - fuse_get_context()->private_data = fs->user_data; - if (fs->op.read) - return fs->op.read(path, buf, size, off, fi); - else - return -ENOSYS; + fuse_get_context()->private_data = fs->user_data; + if (fs->op.read) + return fs->op.read(path, buf, size, off, fi); + else + return -ENOSYS; } int fuse_fs_write(struct fuse_fs *fs, const char *path, const char *buf, - size_t size, off_t off, struct fuse_file_info *fi) + size_t size, off_t off, struct fuse_file_info *fi) { - fuse_get_context()->private_data = fs->user_data; - if (fs->op.write) - return fs->op.write(path, buf, size, off, fi); - else - return -ENOSYS; + fuse_get_context()->private_data = fs->user_data; + if (fs->op.write) + return fs->op.write(path, buf, size, off, fi); + else + return -ENOSYS; } int fuse_fs_fsync(struct fuse_fs *fs, const char *path, int datasync, - struct fuse_file_info *fi) + struct fuse_file_info *fi) { - fuse_get_context()->private_data = fs->user_data; - if (fs->op.fsync) - return fs->op.fsync(path, datasync, fi); - else - return -ENOSYS; + fuse_get_context()->private_data = fs->user_data; + if (fs->op.fsync) + return fs->op.fsync(path, datasync, fi); + else + return -ENOSYS; } int fuse_fs_fsyncdir(struct fuse_fs *fs, const char *path, int datasync, - struct fuse_file_info *fi) + struct fuse_file_info *fi) { - fuse_get_context()->private_data = fs->user_data; - if (fs->op.fsyncdir) - return fs->op.fsyncdir(path, datasync, fi); - else - return -ENOSYS; + fuse_get_context()->private_data = fs->user_data; + if (fs->op.fsyncdir) + return fs->op.fsyncdir(path, datasync, fi); + else + return -ENOSYS; } int fuse_fs_flush(struct fuse_fs *fs, const char *path, - struct fuse_file_info *fi) + struct fuse_file_info *fi) { - fuse_get_context()->private_data = fs->user_data; - if (fs->op.flush) - return fs->op.flush(path, fi); - else - return -ENOSYS; + fuse_get_context()->private_data = fs->user_data; + if (fs->op.flush) + return fs->op.flush(path, fi); + else + return -ENOSYS; } int fuse_fs_statfs(struct fuse_fs *fs, const char *path, struct statvfs *buf) { - fuse_get_context()->private_data = fs->user_data; - if (fs->op.statfs) - return fuse_compat_statfs(fs, path, buf); - else { - buf->f_namemax = 255; - buf->f_bsize = 512; - return 0; - } + fuse_get_context()->private_data = fs->user_data; + if (fs->op.statfs) + return fuse_compat_statfs(fs, path, buf); + else { + buf->f_namemax = 255; + buf->f_bsize = 512; + return 0; + } } int fuse_fs_releasedir(struct fuse_fs *fs, const char *path, - struct fuse_file_info *fi) + struct fuse_file_info *fi) { - fuse_get_context()->private_data = fs->user_data; - if (fs->op.releasedir) - return fs->op.releasedir(path, fi); - else - return 0; + fuse_get_context()->private_data = fs->user_data; + if (fs->op.releasedir) + return fs->op.releasedir(path, fi); + else + return 0; } static int fill_dir_old(struct fuse_dirhandle *dh, const char *name, int type, - ino_t ino) + ino_t ino) { - int res; - struct stat stbuf; + int res; + struct stat stbuf; - memset(&stbuf, 0, sizeof(stbuf)); - stbuf.st_mode = type << 12; - stbuf.st_ino = ino; + memset(&stbuf, 0, sizeof(stbuf)); + stbuf.st_mode = type << 12; + stbuf.st_ino = ino; - res = dh->filler(dh->buf, name, &stbuf, 0); - return res ? -ENOMEM : 0; + res = dh->filler(dh->buf, name, &stbuf, 0); + return res ? -ENOMEM : 0; } int fuse_fs_readdir(struct fuse_fs *fs, const char *path, void *buf, - fuse_fill_dir_t filler, off_t off, - struct fuse_file_info *fi) + fuse_fill_dir_t filler, off_t off, + struct fuse_file_info *fi) { - fuse_get_context()->private_data = fs->user_data; - if (fs->op.readdir) - return fs->op.readdir(path, buf, filler, off, fi); - else if (fs->op.getdir) { - struct fuse_dirhandle dh; - dh.filler = filler; - dh.buf = buf; - return fs->op.getdir(path, &dh, fill_dir_old); - } else - return -ENOSYS; + fuse_get_context()->private_data = fs->user_data; + if (fs->op.readdir) + return fs->op.readdir(path, buf, filler, off, fi); + else if (fs->op.getdir) { + struct fuse_dirhandle dh; + dh.filler = filler; + dh.buf = buf; + return fs->op.getdir(path, &dh, fill_dir_old); + } else + return -ENOSYS; } int fuse_fs_create(struct fuse_fs *fs, const char *path, mode_t mode, - struct fuse_file_info *fi) + struct fuse_file_info *fi) { - fuse_get_context()->private_data = fs->user_data; - if (fs->op.create) - return fs->op.create(path, mode, fi); - else - return -ENOSYS; + fuse_get_context()->private_data = fs->user_data; + if (fs->op.create) + return fs->op.create(path, mode, fi); + else + return -ENOSYS; } int fuse_fs_lock(struct fuse_fs *fs, const char *path, - struct fuse_file_info *fi, int cmd, struct flock *lock) + struct fuse_file_info *fi, int cmd, struct flock *lock) { - fuse_get_context()->private_data = fs->user_data; - if (fs->op.lock) - return fs->op.lock(path, fi, cmd, lock); - else - return -ENOSYS; + fuse_get_context()->private_data = fs->user_data; + if (fs->op.lock) + return fs->op.lock(path, fi, cmd, lock); + else + return -ENOSYS; } int fuse_fs_chown(struct fuse_fs *fs, const char *path, uid_t uid, gid_t gid) { - fuse_get_context()->private_data = fs->user_data; - if (fs->op.chown) - return fs->op.chown(path, uid, gid); - else - return -ENOSYS; + fuse_get_context()->private_data = fs->user_data; + if (fs->op.chown) + return fs->op.chown(path, uid, gid); + else + return -ENOSYS; } int fuse_fs_truncate(struct fuse_fs *fs, const char *path, off_t size) { - fuse_get_context()->private_data = fs->user_data; - if (fs->op.truncate) - return fs->op.truncate(path, size); - else - return -ENOSYS; + fuse_get_context()->private_data = fs->user_data; + if (fs->op.truncate) + return fs->op.truncate(path, size); + else + return -ENOSYS; } int fuse_fs_ftruncate(struct fuse_fs *fs, const char *path, off_t size, - struct fuse_file_info *fi) + struct fuse_file_info *fi) { - fuse_get_context()->private_data = fs->user_data; - if (fs->op.ftruncate) - return fs->op.ftruncate(path, size, fi); - else if (fs->op.truncate) - return fs->op.truncate(path, size); - else - return -ENOSYS; + fuse_get_context()->private_data = fs->user_data; + if (fs->op.ftruncate) + return fs->op.ftruncate(path, size, fi); + else if (fs->op.truncate) + return fs->op.truncate(path, size); + else + return -ENOSYS; } int fuse_fs_utimens(struct fuse_fs *fs, const char *path, - const struct timespec tv[2]) + const struct timespec tv[2]) { - fuse_get_context()->private_data = fs->user_data; - if (fs->op.utimens) - return fs->op.utimens(path, tv); - else if(fs->op.utime) { - struct utimbuf buf; - buf.actime = tv[0].tv_sec; - buf.modtime = tv[1].tv_sec; - return fs->op.utime(path, &buf); - } else - return -ENOSYS; + fuse_get_context()->private_data = fs->user_data; + if (fs->op.utimens) + return fs->op.utimens(path, tv); + else if(fs->op.utime) { + struct utimbuf buf; + buf.actime = tv[0].tv_sec; + buf.modtime = tv[1].tv_sec; + return fs->op.utime(path, &buf); + } else + return -ENOSYS; } int fuse_fs_access(struct fuse_fs *fs, const char *path, int mask) { - fuse_get_context()->private_data = fs->user_data; - if (fs->op.access) - return fs->op.access(path, mask); - else - return -ENOSYS; + fuse_get_context()->private_data = fs->user_data; + if (fs->op.access) + return fs->op.access(path, mask); + else + return -ENOSYS; } int fuse_fs_readlink(struct fuse_fs *fs, const char *path, char *buf, - size_t len) + size_t len) { - fuse_get_context()->private_data = fs->user_data; - if (fs->op.readlink) - return fs->op.readlink(path, buf, len); - else - return -ENOSYS; + fuse_get_context()->private_data = fs->user_data; + if (fs->op.readlink) + return fs->op.readlink(path, buf, len); + else + return -ENOSYS; } int fuse_fs_mknod(struct fuse_fs *fs, const char *path, mode_t mode, - dev_t rdev) + dev_t rdev) { - fuse_get_context()->private_data = fs->user_data; - if (fs->op.mknod) - return fs->op.mknod(path, mode, rdev); - else - return -ENOSYS; + fuse_get_context()->private_data = fs->user_data; + if (fs->op.mknod) + return fs->op.mknod(path, mode, rdev); + else + return -ENOSYS; } int fuse_fs_mkdir(struct fuse_fs *fs, const char *path, mode_t mode) { - fuse_get_context()->private_data = fs->user_data; - if (fs->op.mkdir) - return fs->op.mkdir(path, mode); - else - return -ENOSYS; + fuse_get_context()->private_data = fs->user_data; + if (fs->op.mkdir) + return fs->op.mkdir(path, mode); + else + return -ENOSYS; } int fuse_fs_setxattr(struct fuse_fs *fs, const char *path, const char *name, - const char *value, size_t size, int flags) + const char *value, size_t size, int flags) { - fuse_get_context()->private_data = fs->user_data; - if (fs->op.setxattr) - return fs->op.setxattr(path, name, value, size, flags); - else - return -ENOSYS; + fuse_get_context()->private_data = fs->user_data; + if (fs->op.setxattr) + return fs->op.setxattr(path, name, value, size, flags); + else + return -ENOSYS; } int fuse_fs_getxattr(struct fuse_fs *fs, const char *path, const char *name, - char *value, size_t size) + char *value, size_t size) { - fuse_get_context()->private_data = fs->user_data; - if (fs->op.getxattr) - return fs->op.getxattr(path, name, value, size); - else - return -ENOSYS; + fuse_get_context()->private_data = fs->user_data; + if (fs->op.getxattr) + return fs->op.getxattr(path, name, value, size); + else + return -ENOSYS; } int fuse_fs_listxattr(struct fuse_fs *fs, const char *path, char *list, - size_t size) + size_t size) { - fuse_get_context()->private_data = fs->user_data; - if (fs->op.listxattr) - return fs->op.listxattr(path, list, size); - else - return -ENOSYS; + fuse_get_context()->private_data = fs->user_data; + if (fs->op.listxattr) + return fs->op.listxattr(path, list, size); + else + return -ENOSYS; } int fuse_fs_bmap(struct fuse_fs *fs, const char *path, size_t blocksize, - uint64_t *idx) + uint64_t *idx) { - fuse_get_context()->private_data = fs->user_data; - if (fs->op.bmap) - return fs->op.bmap(path, blocksize, idx); - else - return -ENOSYS; + fuse_get_context()->private_data = fs->user_data; + if (fs->op.bmap) + return fs->op.bmap(path, blocksize, idx); + else + return -ENOSYS; } int fuse_fs_removexattr(struct fuse_fs *fs, const char *path, const char *name) { - fuse_get_context()->private_data = fs->user_data; - if (fs->op.removexattr) - return fs->op.removexattr(path, name); - else - return -ENOSYS; + fuse_get_context()->private_data = fs->user_data; + if (fs->op.removexattr) + return fs->op.removexattr(path, name); + else + return -ENOSYS; } static int is_open(struct fuse *f, fuse_ino_t dir, const char *name) { - struct node *node; - int isopen = 0; - pthread_mutex_lock(&f->lock); - node = lookup_node(f, dir, name); - if (node && node->open_count > 0) - isopen = 1; - pthread_mutex_unlock(&f->lock); - return isopen; + struct node *node; + int isopen = 0; + pthread_mutex_lock(&f->lock); + node = lookup_node(f, dir, name); + if (node && node->open_count > 0) + isopen = 1; + pthread_mutex_unlock(&f->lock); + return isopen; } static char *hidden_name(struct fuse *f, fuse_ino_t dir, const char *oldname, - char *newname, size_t bufsize) -{ - struct stat buf; - struct node *node; - struct node *newnode; - char *newpath; - int res; - int failctr = 10; - - do { - pthread_mutex_lock(&f->lock); - node = lookup_node(f, dir, oldname); - if (node == NULL) { - pthread_mutex_unlock(&f->lock); - return NULL; - } - do { - f->hidectr ++; - snprintf(newname, bufsize, ".fuse_hidden%08x%08x", - (unsigned int) node->nodeid, f->hidectr); - newnode = lookup_node(f, dir, newname); - } while(newnode); - pthread_mutex_unlock(&f->lock); - - newpath = get_path_name(f, dir, newname); - if (!newpath) - break; - - res = fuse_fs_getattr(f->fs, newpath, &buf); - if (res == -ENOENT) - break; - free(newpath); - newpath = NULL; - } while(res == 0 && --failctr); - - return newpath; + char *newname, size_t bufsize) +{ + struct stat buf; + struct node *node; + struct node *newnode; + char *newpath; + int res; + int failctr = 10; + + do { + pthread_mutex_lock(&f->lock); + node = lookup_node(f, dir, oldname); + if (node == NULL) { + pthread_mutex_unlock(&f->lock); + return NULL; + } + do { + f->hidectr ++; + snprintf(newname, bufsize, ".fuse_hidden%08x%08x", + (unsigned int) node->nodeid, f->hidectr); + newnode = lookup_node(f, dir, newname); + } while(newnode); + pthread_mutex_unlock(&f->lock); + + newpath = get_path_name(f, dir, newname); + if (!newpath) + break; + + res = fuse_fs_getattr(f->fs, newpath, &buf); + if (res == -ENOENT) + break; + free(newpath); + newpath = NULL; + } while(res == 0 && --failctr); + + return newpath; } static int hide_node(struct fuse *f, const char *oldpath, - fuse_ino_t dir, const char *oldname) + fuse_ino_t dir, const char *oldname) { - char newname[64]; - char *newpath; - int err = -EBUSY; + char newname[64]; + char *newpath; + int err = -EBUSY; - newpath = hidden_name(f, dir, oldname, newname, sizeof(newname)); - if (newpath) { - err = fuse_fs_rename(f->fs, oldpath, newpath); - if (!err) - err = rename_node(f, dir, oldname, dir, newname, 1); - free(newpath); - } - return err; + newpath = hidden_name(f, dir, oldname, newname, sizeof(newname)); + if (newpath) { + err = fuse_fs_rename(f->fs, oldpath, newpath); + if (!err) + err = rename_node(f, dir, oldname, dir, newname, 1); + free(newpath); + } + return err; } static int mtime_eq(const struct stat *stbuf, const struct timespec *ts) { - return stbuf->st_mtime == ts->tv_sec && ST_MTIM_NSEC(stbuf) == ts->tv_nsec; + return stbuf->st_mtime == ts->tv_sec && + ST_MTIM_NSEC(stbuf) == ts->tv_nsec; } #ifndef CLOCK_MONOTONIC @@ -1172,2122 +1180,2153 @@ static int mtime_eq(const struct stat *stbuf, const struct timespec *ts) static void curr_time(struct timespec *now) { - static clockid_t clockid = CLOCK_MONOTONIC; - int res = clock_gettime(clockid, now); - if (res == -1 && errno == EINVAL) { - clockid = CLOCK_REALTIME; - res = clock_gettime(clockid, now); - } - if (res == -1) { - perror("fuse: clock_gettime"); - abort(); - } + static clockid_t clockid = CLOCK_MONOTONIC; + int res = clock_gettime(clockid, now); + if (res == -1 && errno == EINVAL) { + clockid = CLOCK_REALTIME; + res = clock_gettime(clockid, now); + } + if (res == -1) { + perror("fuse: clock_gettime"); + abort(); + } } static void update_stat(struct node *node, const struct stat *stbuf) { - if (node->cache_valid && (!mtime_eq(stbuf, &node->mtime) || - stbuf->st_size != node->size)) - node->cache_valid = 0; - node->mtime.tv_sec = stbuf->st_mtime; - node->mtime.tv_nsec = ST_MTIM_NSEC(stbuf); - node->size = stbuf->st_size; - curr_time(&node->stat_updated); + if (node->cache_valid && (!mtime_eq(stbuf, &node->mtime) || + stbuf->st_size != node->size)) + node->cache_valid = 0; + node->mtime.tv_sec = stbuf->st_mtime; + node->mtime.tv_nsec = ST_MTIM_NSEC(stbuf); + node->size = stbuf->st_size; + curr_time(&node->stat_updated); } static int lookup_path(struct fuse *f, fuse_ino_t nodeid, - const char *name, const char *path, - struct fuse_entry_param *e, struct fuse_file_info *fi) -{ - int res; - - memset(e, 0, sizeof(struct fuse_entry_param)); - if (fi) - res = fuse_fs_fgetattr(f->fs, path, &e->attr, fi); - else - res = fuse_fs_getattr(f->fs, path, &e->attr); - if (res == 0) { - struct node *node; - - node = find_node(f, nodeid, name); - if (node == NULL) - res = -ENOMEM; - else { - e->ino = node->nodeid; - e->generation = node->generation; - e->entry_timeout = f->conf.entry_timeout; - e->attr_timeout = f->conf.attr_timeout; - if (f->conf.auto_cache) { - pthread_mutex_lock(&f->lock); - update_stat(node, &e->attr); - pthread_mutex_unlock(&f->lock); - } - set_stat(f, e->ino, &e->attr); - if (f->conf.debug) - fprintf(stderr, " NODEID: %lu\n", (unsigned long) e->ino); - } - } - return res; + const char *name, const char *path, + struct fuse_entry_param *e, struct fuse_file_info *fi) +{ + int res; + + memset(e, 0, sizeof(struct fuse_entry_param)); + if (fi) + res = fuse_fs_fgetattr(f->fs, path, &e->attr, fi); + else + res = fuse_fs_getattr(f->fs, path, &e->attr); + if (res == 0) { + struct node *node; + + node = find_node(f, nodeid, name); + if (node == NULL) + res = -ENOMEM; + else { + e->ino = node->nodeid; + e->generation = node->generation; + e->entry_timeout = f->conf.entry_timeout; + e->attr_timeout = f->conf.attr_timeout; + if (f->conf.auto_cache) { + pthread_mutex_lock(&f->lock); + update_stat(node, &e->attr); + pthread_mutex_unlock(&f->lock); + } + set_stat(f, e->ino, &e->attr); + if (f->conf.debug) + fprintf(stderr, " NODEID: %lu\n", + (unsigned long) e->ino); + } + } + return res; } static struct fuse_context_i *fuse_get_context_internal(void) { - struct fuse_context_i *c; - - c = (struct fuse_context_i *) pthread_getspecific(fuse_context_key); - if (c == NULL) { - c = (struct fuse_context_i *) malloc(sizeof(struct fuse_context_i)); - if (c == NULL) { - /* This is hard to deal with properly, so just abort. If - memory is so low that the context cannot be allocated, - there's not much hope for the filesystem anyway */ - fprintf(stderr, "fuse: failed to allocate thread specific data\n"); - abort(); - } - pthread_setspecific(fuse_context_key, c); - } - return c; + struct fuse_context_i *c; + + c = (struct fuse_context_i *) pthread_getspecific(fuse_context_key); + if (c == NULL) { + c = (struct fuse_context_i *) + malloc(sizeof(struct fuse_context_i)); + if (c == NULL) { + /* This is hard to deal with properly, so just + abort. If memory is so low that the + context cannot be allocated, there's not + much hope for the filesystem anyway */ + fprintf(stderr, "fuse: failed to allocate thread specific data\n"); + abort(); + } + pthread_setspecific(fuse_context_key, c); + } + return c; } static void fuse_freecontext(void *data) { - free(data); + free(data); } static int fuse_create_context_key(void) { - int err = 0; - pthread_mutex_lock(&fuse_context_lock); - if (!fuse_context_ref) { - err = pthread_key_create(&fuse_context_key, fuse_freecontext); - if (err) { - fprintf(stderr, "fuse: failed to create thread specific key: %s\n", - strerror(err)); - pthread_mutex_unlock(&fuse_context_lock); - return -1; - } - } - fuse_context_ref++; - pthread_mutex_unlock(&fuse_context_lock); - return 0; + int err = 0; + pthread_mutex_lock(&fuse_context_lock); + if (!fuse_context_ref) { + err = pthread_key_create(&fuse_context_key, fuse_freecontext); + if (err) { + fprintf(stderr, "fuse: failed to create thread specific key: %s\n", + strerror(err)); + pthread_mutex_unlock(&fuse_context_lock); + return -1; + } + } + fuse_context_ref++; + pthread_mutex_unlock(&fuse_context_lock); + return 0; } static void fuse_delete_context_key(void) { - pthread_mutex_lock(&fuse_context_lock); - fuse_context_ref--; - if (!fuse_context_ref) { - free(pthread_getspecific(fuse_context_key)); - pthread_key_delete(fuse_context_key); - } - pthread_mutex_unlock(&fuse_context_lock); + pthread_mutex_lock(&fuse_context_lock); + fuse_context_ref--; + if (!fuse_context_ref) { + free(pthread_getspecific(fuse_context_key)); + pthread_key_delete(fuse_context_key); + } + pthread_mutex_unlock(&fuse_context_lock); } static struct fuse *req_fuse_prepare(fuse_req_t req) { - struct fuse_context_i *c = fuse_get_context_internal(); - const struct fuse_ctx *ctx = fuse_req_ctx(req); - c->req = req; - c->ctx.fuse = req_fuse(req); - c->ctx.uid = ctx->uid; - c->ctx.gid = ctx->gid; - c->ctx.pid = ctx->pid; - return c->ctx.fuse; + struct fuse_context_i *c = fuse_get_context_internal(); + const struct fuse_ctx *ctx = fuse_req_ctx(req); + c->req = req; + c->ctx.fuse = req_fuse(req); + c->ctx.uid = ctx->uid; + c->ctx.gid = ctx->gid; + c->ctx.pid = ctx->pid; + return c->ctx.fuse; } static inline void reply_err(fuse_req_t req, int err) { - /* fuse_reply_err() uses non-negated errno values */ - fuse_reply_err(req, -err); + /* fuse_reply_err() uses non-negated errno values */ + fuse_reply_err(req, -err); } static void reply_entry(fuse_req_t req, const struct fuse_entry_param *e, - int err) + int err) { - if (!err) { - struct fuse *f = req_fuse(req); - if (fuse_reply_entry(req, e) == -ENOENT) - forget_node(f, e->ino, 1); - } else - reply_err(req, err); + if (!err) { + struct fuse *f = req_fuse(req); + if (fuse_reply_entry(req, e) == -ENOENT) + forget_node(f, e->ino, 1); + } else + reply_err(req, err); } void fuse_fs_init(struct fuse_fs *fs, struct fuse_conn_info *conn) { - fuse_get_context()->private_data = fs->user_data; - if (fs->op.init) - fs->user_data = fs->op.init(conn); + fuse_get_context()->private_data = fs->user_data; + if (fs->op.init) + fs->user_data = fs->op.init(conn); } static void fuse_lib_init(void *data, struct fuse_conn_info *conn) { - struct fuse *f = (struct fuse *) data; - struct fuse_context_i *c = fuse_get_context_internal(); + struct fuse *f = (struct fuse *) data; + struct fuse_context_i *c = fuse_get_context_internal(); - memset(c, 0, sizeof(*c)); - c->ctx.fuse = f; - fuse_fs_init(f->fs, conn); + memset(c, 0, sizeof(*c)); + c->ctx.fuse = f; + fuse_fs_init(f->fs, conn); } void fuse_fs_destroy(struct fuse_fs *fs) { - fuse_get_context()->private_data = fs->user_data; - if (fs->op.destroy) - fs->op.destroy(fs->user_data); - if (fs->m) - fuse_put_module(fs->m); - free(fs); + fuse_get_context()->private_data = fs->user_data; + if (fs->op.destroy) + fs->op.destroy(fs->user_data); + if (fs->m) + fuse_put_module(fs->m); + free(fs); } static void fuse_lib_destroy(void *data) { - struct fuse *f = (struct fuse *) data; - struct fuse_context_i *c = fuse_get_context_internal(); + struct fuse *f = (struct fuse *) data; + struct fuse_context_i *c = fuse_get_context_internal(); - memset(c, 0, sizeof(*c)); - c->ctx.fuse = f; - fuse_fs_destroy(f->fs); - f->fs = NULL; + memset(c, 0, sizeof(*c)); + c->ctx.fuse = f; + fuse_fs_destroy(f->fs); + f->fs = NULL; } static void fuse_lib_lookup(fuse_req_t req, fuse_ino_t parent, - const char *name) -{ - struct fuse *f = req_fuse_prepare(req); - struct fuse_entry_param e; - char *path; - int err; - - err = -ENOENT; - pthread_rwlock_rdlock(&f->tree_lock); - path = get_path_name(f, parent, name); - if (path != NULL) { - struct fuse_intr_data d; - if (f->conf.debug) - fprintf(stderr, "LOOKUP %s\n", path); - fuse_prepare_interrupt(f, req, &d); - err = lookup_path(f, parent, name, path, &e, NULL); - if (err == -ENOENT && f->conf.negative_timeout != 0.0) { - e.ino = 0; - e.entry_timeout = f->conf.negative_timeout; - err = 0; - } - fuse_finish_interrupt(f, req, &d); - free(path); - } - pthread_rwlock_unlock(&f->tree_lock); - reply_entry(req, &e, err); + const char *name) +{ + struct fuse *f = req_fuse_prepare(req); + struct fuse_entry_param e; + char *path; + int err; + + err = -ENOENT; + pthread_rwlock_rdlock(&f->tree_lock); + path = get_path_name(f, parent, name); + if (path != NULL) { + struct fuse_intr_data d; + if (f->conf.debug) + fprintf(stderr, "LOOKUP %s\n", path); + fuse_prepare_interrupt(f, req, &d); + err = lookup_path(f, parent, name, path, &e, NULL); + if (err == -ENOENT && f->conf.negative_timeout != 0.0) { + e.ino = 0; + e.entry_timeout = f->conf.negative_timeout; + err = 0; + } + fuse_finish_interrupt(f, req, &d); + free(path); + } + pthread_rwlock_unlock(&f->tree_lock); + reply_entry(req, &e, err); } static void fuse_lib_forget(fuse_req_t req, fuse_ino_t ino, - unsigned long nlookup) + unsigned long nlookup) { - struct fuse *f = req_fuse(req); - if (f->conf.debug) - fprintf(stderr, "FORGET %llu/%lu\n", (unsigned long long)ino, nlookup); - forget_node(f, ino, nlookup); - fuse_reply_none(req); + struct fuse *f = req_fuse(req); + if (f->conf.debug) + fprintf(stderr, "FORGET %llu/%lu\n", (unsigned long long)ino, + nlookup); + forget_node(f, ino, nlookup); + fuse_reply_none(req); } static void fuse_lib_getattr(fuse_req_t req, fuse_ino_t ino, - struct fuse_file_info *fi) -{ - struct fuse *f = req_fuse_prepare(req); - struct stat buf; - char *path; - int err; - - (void) fi; - memset(&buf, 0, sizeof(buf)); - - err = -ENOENT; - pthread_rwlock_rdlock(&f->tree_lock); - path = get_path(f, ino); - if (path != NULL) { - struct fuse_intr_data d; - fuse_prepare_interrupt(f, req, &d); - err = fuse_fs_getattr(f->fs, path, &buf); - fuse_finish_interrupt(f, req, &d); - free(path); - } - pthread_rwlock_unlock(&f->tree_lock); - if (!err) { - if (f->conf.auto_cache) { - pthread_mutex_lock(&f->lock); - update_stat(get_node(f, ino), &buf); - pthread_mutex_unlock(&f->lock); - } - set_stat(f, ino, &buf); - fuse_reply_attr(req, &buf, f->conf.attr_timeout); - } else - reply_err(req, err); + struct fuse_file_info *fi) +{ + struct fuse *f = req_fuse_prepare(req); + struct stat buf; + char *path; + int err; + + (void) fi; + memset(&buf, 0, sizeof(buf)); + + err = -ENOENT; + pthread_rwlock_rdlock(&f->tree_lock); + path = get_path(f, ino); + if (path != NULL) { + struct fuse_intr_data d; + fuse_prepare_interrupt(f, req, &d); + err = fuse_fs_getattr(f->fs, path, &buf); + fuse_finish_interrupt(f, req, &d); + free(path); + } + pthread_rwlock_unlock(&f->tree_lock); + if (!err) { + if (f->conf.auto_cache) { + pthread_mutex_lock(&f->lock); + update_stat(get_node(f, ino), &buf); + pthread_mutex_unlock(&f->lock); + } + set_stat(f, ino, &buf); + fuse_reply_attr(req, &buf, f->conf.attr_timeout); + } else + reply_err(req, err); } int fuse_fs_chmod(struct fuse_fs *fs, const char *path, mode_t mode) { - fuse_get_context()->private_data = fs->user_data; - if (fs->op.chmod) - return fs->op.chmod(path, mode); - else - return -ENOSYS; + fuse_get_context()->private_data = fs->user_data; + if (fs->op.chmod) + return fs->op.chmod(path, mode); + else + return -ENOSYS; } static void fuse_lib_setattr(fuse_req_t req, fuse_ino_t ino, struct stat *attr, - int valid, struct fuse_file_info *fi) -{ - struct fuse *f = req_fuse_prepare(req); - struct stat buf; - char *path; - int err; - - err = -ENOENT; - pthread_rwlock_rdlock(&f->tree_lock); - path = get_path(f, ino); - if (path != NULL) { - struct fuse_intr_data d; - fuse_prepare_interrupt(f, req, &d); - err = 0; - if (!err && (valid & FUSE_SET_ATTR_MODE)) - err = fuse_fs_chmod(f->fs, path, attr->st_mode); - if (!err && (valid & (FUSE_SET_ATTR_UID | FUSE_SET_ATTR_GID))) { - uid_t uid = - (valid & FUSE_SET_ATTR_UID) ? attr->st_uid : (uid_t) -1; - gid_t gid = - (valid & FUSE_SET_ATTR_GID) ? attr->st_gid : (gid_t) -1; - err = fuse_fs_chown(f->fs, path, uid, gid); - } - if (!err && (valid & FUSE_SET_ATTR_SIZE)) { - if (fi) - err = fuse_fs_ftruncate(f->fs, path, attr->st_size, fi); - else - err = fuse_fs_truncate(f->fs, path, attr->st_size); - } - if (!err && (valid & (FUSE_SET_ATTR_ATIME | FUSE_SET_ATTR_MTIME)) == - (FUSE_SET_ATTR_ATIME | FUSE_SET_ATTR_MTIME)) { - struct timespec tv[2]; - tv[0].tv_sec = attr->st_atime; - tv[0].tv_nsec = ST_ATIM_NSEC(attr); - tv[1].tv_sec = attr->st_mtime; - tv[1].tv_nsec = ST_MTIM_NSEC(attr); - err = fuse_fs_utimens(f->fs, path, tv); - } - if (!err) - err = fuse_fs_getattr(f->fs, path, &buf); - fuse_finish_interrupt(f, req, &d); - free(path); - } - pthread_rwlock_unlock(&f->tree_lock); - if (!err) { - if (f->conf.auto_cache) { - pthread_mutex_lock(&f->lock); - update_stat(get_node(f, ino), &buf); - pthread_mutex_unlock(&f->lock); - } - set_stat(f, ino, &buf); - fuse_reply_attr(req, &buf, f->conf.attr_timeout); - } else - reply_err(req, err); + int valid, struct fuse_file_info *fi) +{ + struct fuse *f = req_fuse_prepare(req); + struct stat buf; + char *path; + int err; + + err = -ENOENT; + pthread_rwlock_rdlock(&f->tree_lock); + path = get_path(f, ino); + if (path != NULL) { + struct fuse_intr_data d; + fuse_prepare_interrupt(f, req, &d); + err = 0; + if (!err && (valid & FUSE_SET_ATTR_MODE)) + err = fuse_fs_chmod(f->fs, path, attr->st_mode); + if (!err && (valid & (FUSE_SET_ATTR_UID | FUSE_SET_ATTR_GID))) { + uid_t uid = (valid & FUSE_SET_ATTR_UID) ? + attr->st_uid : (uid_t) -1; + gid_t gid = (valid & FUSE_SET_ATTR_GID) ? + attr->st_gid : (gid_t) -1; + err = fuse_fs_chown(f->fs, path, uid, gid); + } + if (!err && (valid & FUSE_SET_ATTR_SIZE)) { + if (fi) + err = fuse_fs_ftruncate(f->fs, path, + attr->st_size, fi); + else + err = fuse_fs_truncate(f->fs, path, + attr->st_size); + } + if (!err && + (valid & (FUSE_SET_ATTR_ATIME | FUSE_SET_ATTR_MTIME)) == + (FUSE_SET_ATTR_ATIME | FUSE_SET_ATTR_MTIME)) { + struct timespec tv[2]; + tv[0].tv_sec = attr->st_atime; + tv[0].tv_nsec = ST_ATIM_NSEC(attr); + tv[1].tv_sec = attr->st_mtime; + tv[1].tv_nsec = ST_MTIM_NSEC(attr); + err = fuse_fs_utimens(f->fs, path, tv); + } + if (!err) + err = fuse_fs_getattr(f->fs, path, &buf); + fuse_finish_interrupt(f, req, &d); + free(path); + } + pthread_rwlock_unlock(&f->tree_lock); + if (!err) { + if (f->conf.auto_cache) { + pthread_mutex_lock(&f->lock); + update_stat(get_node(f, ino), &buf); + pthread_mutex_unlock(&f->lock); + } + set_stat(f, ino, &buf); + fuse_reply_attr(req, &buf, f->conf.attr_timeout); + } else + reply_err(req, err); } static void fuse_lib_access(fuse_req_t req, fuse_ino_t ino, int mask) { - 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) { - struct fuse_intr_data d; - if (f->conf.debug) - fprintf(stderr, "ACCESS %s 0%o\n", path, mask); - fuse_prepare_interrupt(f, req, &d); - err = fuse_fs_access(f->fs, path, mask); - fuse_finish_interrupt(f, req, &d); - free(path); - } - pthread_rwlock_unlock(&f->tree_lock); - reply_err(req, err); + 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) { + struct fuse_intr_data d; + if (f->conf.debug) + fprintf(stderr, "ACCESS %s 0%o\n", path, mask); + fuse_prepare_interrupt(f, req, &d); + err = fuse_fs_access(f->fs, path, mask); + fuse_finish_interrupt(f, req, &d); + free(path); + } + pthread_rwlock_unlock(&f->tree_lock); + reply_err(req, err); } static void fuse_lib_readlink(fuse_req_t req, fuse_ino_t ino) { - struct fuse *f = req_fuse_prepare(req); - char linkname[PATH_MAX + 1]; - char *path; - int err; - - err = -ENOENT; - pthread_rwlock_rdlock(&f->tree_lock); - path = get_path(f, ino); - if (path != NULL) { - struct fuse_intr_data d; - fuse_prepare_interrupt(f, req, &d); - err = fuse_fs_readlink(f->fs, path, linkname, sizeof(linkname)); - fuse_finish_interrupt(f, req, &d); - free(path); - } - pthread_rwlock_unlock(&f->tree_lock); - if (!err) { - linkname[PATH_MAX] = '\0'; - fuse_reply_readlink(req, linkname); - } else - reply_err(req, err); + struct fuse *f = req_fuse_prepare(req); + char linkname[PATH_MAX + 1]; + char *path; + int err; + + err = -ENOENT; + pthread_rwlock_rdlock(&f->tree_lock); + path = get_path(f, ino); + if (path != NULL) { + struct fuse_intr_data d; + fuse_prepare_interrupt(f, req, &d); + err = fuse_fs_readlink(f->fs, path, linkname, sizeof(linkname)); + fuse_finish_interrupt(f, req, &d); + free(path); + } + pthread_rwlock_unlock(&f->tree_lock); + if (!err) { + linkname[PATH_MAX] = '\0'; + fuse_reply_readlink(req, linkname); + } else + reply_err(req, err); } static void fuse_lib_mknod(fuse_req_t req, fuse_ino_t parent, const char *name, - mode_t mode, dev_t rdev) -{ - struct fuse *f = req_fuse_prepare(req); - struct fuse_entry_param e; - char *path; - int err; - - err = -ENOENT; - pthread_rwlock_rdlock(&f->tree_lock); - path = get_path_name(f, parent, name); - if (path) { - struct fuse_intr_data d; - if (f->conf.debug) - fprintf(stderr, "MKNOD %s\n", path); - fuse_prepare_interrupt(f, req, &d); - err = -ENOSYS; - if (S_ISREG(mode)) { - struct fuse_file_info fi; - - memset(&fi, 0, sizeof(fi)); - fi.flags = O_CREAT | O_EXCL | O_WRONLY; - err = fuse_fs_create(f->fs, path, mode, &fi); - if (!err) { - err = lookup_path(f, parent, name, path, &e, &fi); - fuse_fs_release(f->fs, path, &fi); - } - } - if (err == -ENOSYS) { - err = fuse_fs_mknod(f->fs, path, mode, rdev); - if (!err) - err = lookup_path(f, parent, name, path, &e, NULL); - } - fuse_finish_interrupt(f, req, &d); - free(path); - } - pthread_rwlock_unlock(&f->tree_lock); - reply_entry(req, &e, err); + mode_t mode, dev_t rdev) +{ + struct fuse *f = req_fuse_prepare(req); + struct fuse_entry_param e; + char *path; + int err; + + err = -ENOENT; + pthread_rwlock_rdlock(&f->tree_lock); + path = get_path_name(f, parent, name); + if (path) { + struct fuse_intr_data d; + if (f->conf.debug) + fprintf(stderr, "MKNOD %s\n", path); + fuse_prepare_interrupt(f, req, &d); + err = -ENOSYS; + if (S_ISREG(mode)) { + struct fuse_file_info fi; + + memset(&fi, 0, sizeof(fi)); + fi.flags = O_CREAT | O_EXCL | O_WRONLY; + err = fuse_fs_create(f->fs, path, mode, &fi); + if (!err) { + err = lookup_path(f, parent, name, path, &e, + &fi); + fuse_fs_release(f->fs, path, &fi); + } + } + if (err == -ENOSYS) { + err = fuse_fs_mknod(f->fs, path, mode, rdev); + if (!err) + err = lookup_path(f, parent, name, path, &e, + NULL); + } + fuse_finish_interrupt(f, req, &d); + free(path); + } + pthread_rwlock_unlock(&f->tree_lock); + reply_entry(req, &e, err); } static void fuse_lib_mkdir(fuse_req_t req, fuse_ino_t parent, const char *name, - mode_t mode) -{ - struct fuse *f = req_fuse_prepare(req); - struct fuse_entry_param e; - char *path; - int err; - - err = -ENOENT; - pthread_rwlock_rdlock(&f->tree_lock); - path = get_path_name(f, parent, name); - if (path != NULL) { - struct fuse_intr_data d; - if (f->conf.debug) - fprintf(stderr, "MKDIR %s\n", path); - fuse_prepare_interrupt(f, req, &d); - err = fuse_fs_mkdir(f->fs, path, mode); - if (!err) - err = lookup_path(f, parent, name, path, &e, NULL); - fuse_finish_interrupt(f, req, &d); - free(path); - } - pthread_rwlock_unlock(&f->tree_lock); - reply_entry(req, &e, err); + mode_t mode) +{ + struct fuse *f = req_fuse_prepare(req); + struct fuse_entry_param e; + char *path; + int err; + + err = -ENOENT; + pthread_rwlock_rdlock(&f->tree_lock); + path = get_path_name(f, parent, name); + if (path != NULL) { + struct fuse_intr_data d; + if (f->conf.debug) + fprintf(stderr, "MKDIR %s\n", path); + fuse_prepare_interrupt(f, req, &d); + err = fuse_fs_mkdir(f->fs, path, mode); + if (!err) + err = lookup_path(f, parent, name, path, &e, NULL); + fuse_finish_interrupt(f, req, &d); + free(path); + } + pthread_rwlock_unlock(&f->tree_lock); + reply_entry(req, &e, err); } static void fuse_lib_unlink(fuse_req_t req, fuse_ino_t parent, - const char *name) -{ - struct fuse *f = req_fuse_prepare(req); - char *path; - int err; - - err = -ENOENT; - pthread_rwlock_wrlock(&f->tree_lock); - path = get_path_name(f, parent, name); - if (path != NULL) { - struct fuse_intr_data d; - if (f->conf.debug) - fprintf(stderr, "UNLINK %s\n", path); - fuse_prepare_interrupt(f, req, &d); - if (!f->conf.hard_remove && is_open(f, parent, name)) - err = hide_node(f, path, parent, name); - else { - err = fuse_fs_unlink(f->fs, path); - if (!err) - remove_node(f, parent, name); - } - fuse_finish_interrupt(f, req, &d); - free(path); - } - pthread_rwlock_unlock(&f->tree_lock); - reply_err(req, err); + const char *name) +{ + struct fuse *f = req_fuse_prepare(req); + char *path; + int err; + + err = -ENOENT; + pthread_rwlock_wrlock(&f->tree_lock); + path = get_path_name(f, parent, name); + if (path != NULL) { + struct fuse_intr_data d; + if (f->conf.debug) + fprintf(stderr, "UNLINK %s\n", path); + fuse_prepare_interrupt(f, req, &d); + if (!f->conf.hard_remove && is_open(f, parent, name)) + err = hide_node(f, path, parent, name); + else { + err = fuse_fs_unlink(f->fs, path); + if (!err) + remove_node(f, parent, name); + } + fuse_finish_interrupt(f, req, &d); + free(path); + } + pthread_rwlock_unlock(&f->tree_lock); + reply_err(req, err); } static void fuse_lib_rmdir(fuse_req_t req, fuse_ino_t parent, const char *name) { - struct fuse *f = req_fuse_prepare(req); - char *path; - int err; - - err = -ENOENT; - pthread_rwlock_wrlock(&f->tree_lock); - path = get_path_name(f, parent, name); - if (path != NULL) { - struct fuse_intr_data d; - if (f->conf.debug) - fprintf(stderr, "RMDIR %s\n", path); - fuse_prepare_interrupt(f, req, &d); - err = fuse_fs_rmdir(f->fs, path); - fuse_finish_interrupt(f, req, &d); - if (!err) - remove_node(f, parent, name); - free(path); - } - pthread_rwlock_unlock(&f->tree_lock); - reply_err(req, err); + struct fuse *f = req_fuse_prepare(req); + char *path; + int err; + + err = -ENOENT; + pthread_rwlock_wrlock(&f->tree_lock); + path = get_path_name(f, parent, name); + if (path != NULL) { + struct fuse_intr_data d; + if (f->conf.debug) + fprintf(stderr, "RMDIR %s\n", path); + fuse_prepare_interrupt(f, req, &d); + err = fuse_fs_rmdir(f->fs, path); + fuse_finish_interrupt(f, req, &d); + if (!err) + remove_node(f, parent, name); + free(path); + } + pthread_rwlock_unlock(&f->tree_lock); + reply_err(req, err); } static void fuse_lib_symlink(fuse_req_t req, const char *linkname, - fuse_ino_t parent, const char *name) -{ - struct fuse *f = req_fuse_prepare(req); - struct fuse_entry_param e; - char *path; - int err; - - err = -ENOENT; - pthread_rwlock_rdlock(&f->tree_lock); - path = get_path_name(f, parent, name); - if (path != NULL) { - struct fuse_intr_data d; - if (f->conf.debug) - fprintf(stderr, "SYMLINK %s\n", path); - fuse_prepare_interrupt(f, req, &d); - err = fuse_fs_symlink(f->fs, linkname, path); - if (!err) - err = lookup_path(f, parent, name, path, &e, NULL); - fuse_finish_interrupt(f, req, &d); - free(path); - } - pthread_rwlock_unlock(&f->tree_lock); - reply_entry(req, &e, err); + fuse_ino_t parent, const char *name) +{ + struct fuse *f = req_fuse_prepare(req); + struct fuse_entry_param e; + char *path; + int err; + + err = -ENOENT; + pthread_rwlock_rdlock(&f->tree_lock); + path = get_path_name(f, parent, name); + if (path != NULL) { + struct fuse_intr_data d; + if (f->conf.debug) + fprintf(stderr, "SYMLINK %s\n", path); + fuse_prepare_interrupt(f, req, &d); + err = fuse_fs_symlink(f->fs, linkname, path); + if (!err) + err = lookup_path(f, parent, name, path, &e, NULL); + fuse_finish_interrupt(f, req, &d); + free(path); + } + pthread_rwlock_unlock(&f->tree_lock); + reply_entry(req, &e, err); } static void fuse_lib_rename(fuse_req_t req, fuse_ino_t olddir, - const char *oldname, fuse_ino_t newdir, - const char *newname) -{ - struct fuse *f = req_fuse_prepare(req); - char *oldpath; - char *newpath; - int err; - - err = -ENOENT; - pthread_rwlock_wrlock(&f->tree_lock); - oldpath = get_path_name(f, olddir, oldname); - if (oldpath != NULL) { - newpath = get_path_name(f, newdir, newname); - if (newpath != NULL) { - struct fuse_intr_data d; - if (f->conf.debug) - fprintf(stderr, "RENAME %s -> %s\n", oldpath, newpath); - err = 0; - fuse_prepare_interrupt(f, req, &d); - if (!f->conf.hard_remove && is_open(f, newdir, newname)) - err = hide_node(f, newpath, newdir, newname); - if (!err) { - err = fuse_fs_rename(f->fs, oldpath, newpath); - if (!err) - err = rename_node(f, olddir, oldname, newdir, newname, 0); - } - fuse_finish_interrupt(f, req, &d); - free(newpath); - } - free(oldpath); - } - pthread_rwlock_unlock(&f->tree_lock); - reply_err(req, err); + const char *oldname, fuse_ino_t newdir, + const char *newname) +{ + struct fuse *f = req_fuse_prepare(req); + char *oldpath; + char *newpath; + int err; + + err = -ENOENT; + pthread_rwlock_wrlock(&f->tree_lock); + oldpath = get_path_name(f, olddir, oldname); + if (oldpath != NULL) { + newpath = get_path_name(f, newdir, newname); + if (newpath != NULL) { + struct fuse_intr_data d; + if (f->conf.debug) + fprintf(stderr, "RENAME %s -> %s\n", oldpath, + newpath); + err = 0; + fuse_prepare_interrupt(f, req, &d); + if (!f->conf.hard_remove && is_open(f, newdir, newname)) + err = hide_node(f, newpath, newdir, newname); + if (!err) { + err = fuse_fs_rename(f->fs, oldpath, newpath); + if (!err) + err = rename_node(f, olddir, oldname, + newdir, newname, 0); + } + fuse_finish_interrupt(f, req, &d); + free(newpath); + } + free(oldpath); + } + pthread_rwlock_unlock(&f->tree_lock); + reply_err(req, err); } static void fuse_lib_link(fuse_req_t req, fuse_ino_t ino, fuse_ino_t newparent, - const char *newname) -{ - struct fuse *f = req_fuse_prepare(req); - struct fuse_entry_param e; - char *oldpath; - char *newpath; - int err; - - err = -ENOENT; - pthread_rwlock_rdlock(&f->tree_lock); - oldpath = get_path(f, ino); - if (oldpath != NULL) { - newpath = get_path_name(f, newparent, newname); - if (newpath != NULL) { - struct fuse_intr_data d; - if (f->conf.debug) - fprintf(stderr, "LINK %s\n", newpath); - fuse_prepare_interrupt(f, req, &d); - err = fuse_fs_link(f->fs, oldpath, newpath); - if (!err) - err = lookup_path(f, newparent, newname, newpath, &e, NULL); - fuse_finish_interrupt(f, req, &d); - free(newpath); - } - free(oldpath); - } - pthread_rwlock_unlock(&f->tree_lock); - reply_entry(req, &e, err); + const char *newname) +{ + struct fuse *f = req_fuse_prepare(req); + struct fuse_entry_param e; + char *oldpath; + char *newpath; + int err; + + err = -ENOENT; + pthread_rwlock_rdlock(&f->tree_lock); + oldpath = get_path(f, ino); + if (oldpath != NULL) { + newpath = get_path_name(f, newparent, newname); + if (newpath != NULL) { + struct fuse_intr_data d; + if (f->conf.debug) + fprintf(stderr, "LINK %s\n", newpath); + fuse_prepare_interrupt(f, req, &d); + err = fuse_fs_link(f->fs, oldpath, newpath); + if (!err) + err = lookup_path(f, newparent, newname, + newpath, &e, NULL); + fuse_finish_interrupt(f, req, &d); + free(newpath); + } + free(oldpath); + } + pthread_rwlock_unlock(&f->tree_lock); + reply_entry(req, &e, err); } static void fuse_do_release(struct fuse *f, fuse_ino_t ino, const char *path, - struct fuse_file_info *fi) + struct fuse_file_info *fi) { - struct node *node; - int unlink_hidden = 0; + struct node *node; + int unlink_hidden = 0; - fuse_fs_release(f->fs, path ? path : "-", fi); + fuse_fs_release(f->fs, path ? path : "-", fi); - pthread_mutex_lock(&f->lock); - node = get_node(f, ino); - assert(node->open_count > 0); - --node->open_count; - if (node->is_hidden && !node->open_count) { - unlink_hidden = 1; - node->is_hidden = 0; - } - pthread_mutex_unlock(&f->lock); + pthread_mutex_lock(&f->lock); + node = get_node(f, ino); + assert(node->open_count > 0); + --node->open_count; + if (node->is_hidden && !node->open_count) { + unlink_hidden = 1; + node->is_hidden = 0; + } + pthread_mutex_unlock(&f->lock); - if(unlink_hidden && path) - fuse_fs_unlink(f->fs, path); + if(unlink_hidden && path) + fuse_fs_unlink(f->fs, path); } static void fuse_lib_create(fuse_req_t req, fuse_ino_t parent, - const char *name, mode_t mode, - struct fuse_file_info *fi) -{ - struct fuse *f = req_fuse_prepare(req); - struct fuse_intr_data d; - struct fuse_entry_param e; - char *path; - int err; - - err = -ENOENT; - pthread_rwlock_rdlock(&f->tree_lock); - path = get_path_name(f, parent, name); - if (path) { - fuse_prepare_interrupt(f, req, &d); - err = fuse_fs_create(f->fs, path, mode, fi); - if (!err) { - err = lookup_path(f, parent, name, path, &e, fi); - if (err) - fuse_fs_release(f->fs, path, fi); - else if (!S_ISREG(e.attr.st_mode)) { - err = -EIO; - fuse_fs_release(f->fs, path, fi); - forget_node(f, e.ino, 1); - } else { - if (f->conf.direct_io) - fi->direct_io = 1; - if (f->conf.kernel_cache) - fi->keep_cache = 1; - - } - } - fuse_finish_interrupt(f, req, &d); - } - if (!err) { - pthread_mutex_lock(&f->lock); - get_node(f, e.ino)->open_count++; - pthread_mutex_unlock(&f->lock); - if (fuse_reply_create(req, &e, fi) == -ENOENT) { - /* The open syscall was interrupted, so it must be cancelled */ - fuse_prepare_interrupt(f, req, &d); - fuse_do_release(f, e.ino, path, fi); - fuse_finish_interrupt(f, req, &d); - forget_node(f, e.ino, 1); - } else if (f->conf.debug) { - fprintf(stderr, " CREATE[%llu] flags: 0x%x %s\n", - (unsigned long long) fi->fh, fi->flags, path); - } - } else - reply_err(req, err); - - if (path) - free(path); - - pthread_rwlock_unlock(&f->tree_lock); + const char *name, mode_t mode, + struct fuse_file_info *fi) +{ + struct fuse *f = req_fuse_prepare(req); + struct fuse_intr_data d; + struct fuse_entry_param e; + char *path; + int err; + + err = -ENOENT; + pthread_rwlock_rdlock(&f->tree_lock); + path = get_path_name(f, parent, name); + if (path) { + fuse_prepare_interrupt(f, req, &d); + err = fuse_fs_create(f->fs, path, mode, fi); + if (!err) { + err = lookup_path(f, parent, name, path, &e, fi); + if (err) + fuse_fs_release(f->fs, path, fi); + else if (!S_ISREG(e.attr.st_mode)) { + err = -EIO; + fuse_fs_release(f->fs, path, fi); + forget_node(f, e.ino, 1); + } else { + if (f->conf.direct_io) + fi->direct_io = 1; + if (f->conf.kernel_cache) + fi->keep_cache = 1; + + } + } + fuse_finish_interrupt(f, req, &d); + } + if (!err) { + pthread_mutex_lock(&f->lock); + get_node(f, e.ino)->open_count++; + pthread_mutex_unlock(&f->lock); + if (fuse_reply_create(req, &e, fi) == -ENOENT) { + /* The open syscall was interrupted, so it + must be cancelled */ + fuse_prepare_interrupt(f, req, &d); + fuse_do_release(f, e.ino, path, fi); + fuse_finish_interrupt(f, req, &d); + forget_node(f, e.ino, 1); + } else if (f->conf.debug) { + fprintf(stderr, " CREATE[%llu] flags: 0x%x %s\n", + (unsigned long long) fi->fh, fi->flags, path); + } + } else + reply_err(req, err); + + if (path) + free(path); + + pthread_rwlock_unlock(&f->tree_lock); } static double diff_timespec(const struct timespec *t1, - const struct timespec *t2) + const struct timespec *t2) { - return (t1->tv_sec - t2->tv_sec) + - ((double) t1->tv_nsec - (double) t2->tv_nsec) / 1000000000.0; + return (t1->tv_sec - t2->tv_sec) + + ((double) t1->tv_nsec - (double) t2->tv_nsec) / 1000000000.0; } static void open_auto_cache(struct fuse *f, fuse_ino_t ino, const char *path, - struct fuse_file_info *fi) -{ - struct node *node; - - pthread_mutex_lock(&f->lock); - node = get_node(f, ino); - if (node->cache_valid) { - struct timespec now; - - curr_time(&now); - if (diff_timespec(&now, &node->stat_updated) > f->conf.ac_attr_timeout) { - struct stat stbuf; - int err; - pthread_mutex_unlock(&f->lock); - err = fuse_fs_fgetattr(f->fs, path, &stbuf, fi); - pthread_mutex_lock(&f->lock); - if (!err) - update_stat(node, &stbuf); - else - node->cache_valid = 0; - } - } - if (node->cache_valid) - fi->keep_cache = 1; - - node->cache_valid = 1; - pthread_mutex_unlock(&f->lock); + struct fuse_file_info *fi) +{ + struct node *node; + + pthread_mutex_lock(&f->lock); + node = get_node(f, ino); + if (node->cache_valid) { + struct timespec now; + + curr_time(&now); + if (diff_timespec(&now, &node->stat_updated) > + f->conf.ac_attr_timeout) { + struct stat stbuf; + int err; + pthread_mutex_unlock(&f->lock); + err = fuse_fs_fgetattr(f->fs, path, &stbuf, fi); + pthread_mutex_lock(&f->lock); + if (!err) + update_stat(node, &stbuf); + else + node->cache_valid = 0; + } + } + if (node->cache_valid) + fi->keep_cache = 1; + + node->cache_valid = 1; + pthread_mutex_unlock(&f->lock); } static void fuse_lib_open(fuse_req_t req, fuse_ino_t ino, - struct fuse_file_info *fi) -{ - struct fuse *f = req_fuse_prepare(req); - struct fuse_intr_data d; - char *path = NULL; - int err = 0; - - err = -ENOENT; - pthread_rwlock_rdlock(&f->tree_lock); - path = get_path(f, ino); - if (path) { - fuse_prepare_interrupt(f, req, &d); - err = fuse_fs_open(f->fs, path, fi); - if (!err) { - if (f->conf.direct_io) - fi->direct_io = 1; - if (f->conf.kernel_cache) - fi->keep_cache = 1; - - if (f->conf.auto_cache) - open_auto_cache(f, ino, path, fi); - } - fuse_finish_interrupt(f, req, &d); - } - if (!err) { - pthread_mutex_lock(&f->lock); - get_node(f, ino)->open_count++; - pthread_mutex_unlock(&f->lock); - if (fuse_reply_open(req, fi) == -ENOENT) { - /* The open syscall was interrupted, so it must be cancelled */ - fuse_prepare_interrupt(f, req, &d); - fuse_do_release(f, ino, path, fi); - fuse_finish_interrupt(f, req, &d); - } else if (f->conf.debug) { - fprintf(stderr, "OPEN[%llu] flags: 0x%x %s\n", - (unsigned long long) fi->fh, fi->flags, path); - } - } else - reply_err(req, err); - - if (path) - free(path); - pthread_rwlock_unlock(&f->tree_lock); + struct fuse_file_info *fi) +{ + struct fuse *f = req_fuse_prepare(req); + struct fuse_intr_data d; + char *path = NULL; + int err = 0; + + err = -ENOENT; + pthread_rwlock_rdlock(&f->tree_lock); + path = get_path(f, ino); + if (path) { + fuse_prepare_interrupt(f, req, &d); + err = fuse_fs_open(f->fs, path, fi); + if (!err) { + if (f->conf.direct_io) + fi->direct_io = 1; + if (f->conf.kernel_cache) + fi->keep_cache = 1; + + if (f->conf.auto_cache) + open_auto_cache(f, ino, path, fi); + } + fuse_finish_interrupt(f, req, &d); + } + if (!err) { + pthread_mutex_lock(&f->lock); + get_node(f, ino)->open_count++; + pthread_mutex_unlock(&f->lock); + if (fuse_reply_open(req, fi) == -ENOENT) { + /* The open syscall was interrupted, so it + must be cancelled */ + fuse_prepare_interrupt(f, req, &d); + fuse_do_release(f, ino, path, fi); + fuse_finish_interrupt(f, req, &d); + } else if (f->conf.debug) { + fprintf(stderr, "OPEN[%llu] flags: 0x%x %s\n", + (unsigned long long) fi->fh, fi->flags, path); + } + } else + reply_err(req, err); + + if (path) + free(path); + pthread_rwlock_unlock(&f->tree_lock); } static void fuse_lib_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) { - struct fuse_intr_data d; - if (f->conf.debug) - fprintf(stderr, "READ[%llu] %lu bytes from %llu\n", - (unsigned long long) fi->fh, (unsigned long) size, - (unsigned long long) off); - - fuse_prepare_interrupt(f, req, &d); - res = fuse_fs_read(f->fs, path, buf, size, off, fi); - fuse_finish_interrupt(f, req, &d); - free(path); - } - pthread_rwlock_unlock(&f->tree_lock); - - if (res >= 0) { - if (f->conf.debug) - fprintf(stderr, " READ[%llu] %u bytes\n", - (unsigned long long)fi->fh, res); - 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); + 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) { + struct fuse_intr_data d; + if (f->conf.debug) + fprintf(stderr, "READ[%llu] %lu bytes from %llu\n", + (unsigned long long) fi->fh, + (unsigned long) size, (unsigned long long) off); + + fuse_prepare_interrupt(f, req, &d); + res = fuse_fs_read(f->fs, path, buf, size, off, fi); + fuse_finish_interrupt(f, req, &d); + free(path); + } + pthread_rwlock_unlock(&f->tree_lock); + + if (res >= 0) { + if (f->conf.debug) + fprintf(stderr, " READ[%llu] %u bytes\n", + (unsigned long long)fi->fh, res); + 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_lib_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) { - struct fuse_intr_data d; - if (f->conf.debug) - fprintf(stderr, "WRITE%s[%llu] %lu bytes to %llu\n", - fi->writepage ? "PAGE" : "", (unsigned long long) fi->fh, - (unsigned long) size, (unsigned long long) off); - - fuse_prepare_interrupt(f, req, &d); - res = fuse_fs_write(f->fs, path, buf, size, off, fi); - fuse_finish_interrupt(f, req, &d); - free(path); - } - pthread_rwlock_unlock(&f->tree_lock); - - if (res >= 0) { - if (f->conf.debug) - fprintf(stderr, " WRITE%s[%llu] %u bytes\n", - fi->writepage ? "PAGE" : "", (unsigned long long) fi->fh, - res); - if ((size_t) res > size) - fprintf(stderr, "fuse: wrote too many bytes"); - fuse_reply_write(req, res); - } else - reply_err(req, res); + 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) { + struct fuse_intr_data d; + if (f->conf.debug) + fprintf(stderr, "WRITE%s[%llu] %lu bytes to %llu\n", + fi->writepage ? "PAGE" : "", + (unsigned long long) fi->fh, + (unsigned long) size, (unsigned long long) off); + + fuse_prepare_interrupt(f, req, &d); + res = fuse_fs_write(f->fs, path, buf, size, off, fi); + fuse_finish_interrupt(f, req, &d); + free(path); + } + pthread_rwlock_unlock(&f->tree_lock); + + if (res >= 0) { + if (f->conf.debug) + fprintf(stderr, " WRITE%s[%llu] %u bytes\n", + fi->writepage ? "PAGE" : "", + (unsigned long long) fi->fh, res); + 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_lib_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) { - struct fuse_intr_data d; - if (f->conf.debug) - fprintf(stderr, "FSYNC[%llu]\n", (unsigned long long) fi->fh); - fuse_prepare_interrupt(f, req, &d); - err = fuse_fs_fsync(f->fs, path, datasync, fi); - fuse_finish_interrupt(f, req, &d); - free(path); - } - pthread_rwlock_unlock(&f->tree_lock); - reply_err(req, err); + 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) { + struct fuse_intr_data d; + if (f->conf.debug) + fprintf(stderr, "FSYNC[%llu]\n", + (unsigned long long) fi->fh); + fuse_prepare_interrupt(f, req, &d); + err = fuse_fs_fsync(f->fs, path, datasync, fi); + fuse_finish_interrupt(f, req, &d); + free(path); + } + pthread_rwlock_unlock(&f->tree_lock); + reply_err(req, err); } static struct fuse_dh *get_dirhandle(const struct fuse_file_info *llfi, - struct fuse_file_info *fi) + struct fuse_file_info *fi) { - struct fuse_dh *dh = (struct fuse_dh *) (uintptr_t) llfi->fh; - memset(fi, 0, sizeof(struct fuse_file_info)); - fi->fh = dh->fh; - fi->fh_old = dh->fh; - return dh; + struct fuse_dh *dh = (struct fuse_dh *) (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_lib_opendir(fuse_req_t req, fuse_ino_t ino, - struct fuse_file_info *llfi) -{ - struct fuse *f = req_fuse_prepare(req); - struct fuse_intr_data d; - struct fuse_dh *dh; - struct fuse_file_info fi; - char *path; - int err; - - dh = (struct fuse_dh *) malloc(sizeof(struct fuse_dh)); - if (dh == NULL) { - reply_err(req, -ENOMEM); - return; - } - memset(dh, 0, sizeof(struct fuse_dh)); - dh->fuse = f; - dh->contents = NULL; - dh->len = 0; - dh->filled = 0; - dh->nodeid = ino; - fuse_mutex_init(&dh->lock); - - llfi->fh = (uintptr_t) dh; - - 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) { - fuse_prepare_interrupt(f, req, &d); - err = fuse_fs_opendir(f->fs, path, &fi); - fuse_finish_interrupt(f, req, &d); - dh->fh = fi.fh; - } - if (!err) { - if (fuse_reply_open(req, llfi) == -ENOENT) { - /* The opendir syscall was interrupted, so it must be cancelled */ - fuse_prepare_interrupt(f, req, &d); - fuse_fs_releasedir(f->fs, path, &fi); - fuse_finish_interrupt(f, req, &d); - pthread_mutex_destroy(&dh->lock); - free(dh); - } - } else { - reply_err(req, err); - free(dh); - } - free(path); - pthread_rwlock_unlock(&f->tree_lock); + struct fuse_file_info *llfi) +{ + struct fuse *f = req_fuse_prepare(req); + struct fuse_intr_data d; + struct fuse_dh *dh; + struct fuse_file_info fi; + char *path; + int err; + + dh = (struct fuse_dh *) malloc(sizeof(struct fuse_dh)); + if (dh == NULL) { + reply_err(req, -ENOMEM); + return; + } + memset(dh, 0, sizeof(struct fuse_dh)); + dh->fuse = f; + dh->contents = NULL; + dh->len = 0; + dh->filled = 0; + dh->nodeid = ino; + fuse_mutex_init(&dh->lock); + + llfi->fh = (uintptr_t) dh; + + 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) { + fuse_prepare_interrupt(f, req, &d); + err = fuse_fs_opendir(f->fs, path, &fi); + fuse_finish_interrupt(f, req, &d); + dh->fh = fi.fh; + } + if (!err) { + if (fuse_reply_open(req, llfi) == -ENOENT) { + /* The opendir syscall was interrupted, so it + must be cancelled */ + fuse_prepare_interrupt(f, req, &d); + fuse_fs_releasedir(f->fs, path, &fi); + fuse_finish_interrupt(f, req, &d); + pthread_mutex_destroy(&dh->lock); + free(dh); + } + } else { + reply_err(req, err); + free(dh); + } + free(path); + pthread_rwlock_unlock(&f->tree_lock); } static int extend_contents(struct fuse_dh *dh, unsigned minsize) { - if (minsize > dh->size) { - char *newptr; - unsigned newsize = dh->size; - if (!newsize) - newsize = 1024; - while (newsize < minsize) - newsize *= 2; - - newptr = (char *) realloc(dh->contents, newsize); - if (!newptr) { - dh->error = -ENOMEM; - return -1; - } - dh->contents = newptr; - dh->size = newsize; - } - return 0; + if (minsize > dh->size) { + char *newptr; + unsigned newsize = dh->size; + if (!newsize) + newsize = 1024; + while (newsize < minsize) + newsize *= 2; + + newptr = (char *) realloc(dh->contents, newsize); + if (!newptr) { + dh->error = -ENOMEM; + return -1; + } + dh->contents = newptr; + dh->size = newsize; + } + return 0; } static int fill_dir(void *dh_, const char *name, const struct stat *statp, - off_t off) -{ - struct fuse_dh *dh = (struct fuse_dh *) dh_; - struct stat stbuf; - size_t 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); - } - } - - if (off) { - if (extend_contents(dh, dh->needlen) == -1) - return 1; - - dh->filled = 0; - newlen = dh->len + fuse_add_direntry(dh->req, dh->contents + dh->len, - dh->needlen - dh->len, name, - &stbuf, off); - if (newlen > dh->needlen) - return 1; - } else { - newlen = dh->len + fuse_add_direntry(dh->req, NULL, 0, name, NULL, 0); - if (extend_contents(dh, newlen) == -1) - return 1; - - fuse_add_direntry(dh->req, dh->contents + dh->len, dh->size - dh->len, - name, &stbuf, newlen); - } - dh->len = newlen; - return 0; + off_t off) +{ + struct fuse_dh *dh = (struct fuse_dh *) dh_; + struct stat stbuf; + size_t 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); + } + } + + if (off) { + if (extend_contents(dh, dh->needlen) == -1) + return 1; + + dh->filled = 0; + newlen = dh->len + + fuse_add_direntry(dh->req, dh->contents + dh->len, + dh->needlen - dh->len, name, + &stbuf, off); + if (newlen > dh->needlen) + return 1; + } else { + newlen = dh->len + + fuse_add_direntry(dh->req, NULL, 0, name, NULL, 0); + if (extend_contents(dh, newlen) == -1) + return 1; + + fuse_add_direntry(dh->req, dh->contents + dh->len, + dh->size - dh->len, name, &stbuf, newlen); + } + dh->len = newlen; + return 0; } static int readdir_fill(struct fuse *f, fuse_req_t req, fuse_ino_t ino, - size_t size, off_t off, struct fuse_dh *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) { - struct fuse_intr_data d; - - dh->len = 0; - dh->error = 0; - dh->needlen = size; - dh->filled = 1; - dh->req = req; - fuse_prepare_interrupt(f, req, &d); - err = fuse_fs_readdir(f->fs, path, dh, fill_dir, off, fi); - fuse_finish_interrupt(f, req, &d); - dh->req = NULL; - if (!err) - err = dh->error; - if (err) - dh->filled = 0; - free(path); - } - pthread_rwlock_unlock(&f->tree_lock); - return err; + size_t size, off_t off, struct fuse_dh *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) { + struct fuse_intr_data d; + + dh->len = 0; + dh->error = 0; + dh->needlen = size; + dh->filled = 1; + dh->req = req; + fuse_prepare_interrupt(f, req, &d); + err = fuse_fs_readdir(f->fs, path, dh, fill_dir, off, fi); + fuse_finish_interrupt(f, req, &d); + dh->req = NULL; + if (!err) + err = dh->error; + if (err) + dh->filled = 0; + free(path); + } + pthread_rwlock_unlock(&f->tree_lock); + return err; } static void fuse_lib_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_dh *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); + off_t off, struct fuse_file_info *llfi) +{ + struct fuse *f = req_fuse_prepare(req); + struct fuse_file_info fi; + struct fuse_dh *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_lib_releasedir(fuse_req_t req, fuse_ino_t ino, - struct fuse_file_info *llfi) -{ - struct fuse *f = req_fuse_prepare(req); - struct fuse_intr_data d; - struct fuse_file_info fi; - struct fuse_dh *dh = get_dirhandle(llfi, &fi); - char *path; - - pthread_rwlock_rdlock(&f->tree_lock); - path = get_path(f, ino); - fuse_prepare_interrupt(f, req, &d); - fuse_fs_releasedir(f->fs, path ? path : "-", &fi); - fuse_finish_interrupt(f, req, &d); - if (path) - 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); + struct fuse_file_info *llfi) +{ + struct fuse *f = req_fuse_prepare(req); + struct fuse_intr_data d; + struct fuse_file_info fi; + struct fuse_dh *dh = get_dirhandle(llfi, &fi); + char *path; + + pthread_rwlock_rdlock(&f->tree_lock); + path = get_path(f, ino); + fuse_prepare_interrupt(f, req, &d); + fuse_fs_releasedir(f->fs, path ? path : "-", &fi); + fuse_finish_interrupt(f, req, &d); + if (path) + 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_lib_fsyncdir(fuse_req_t req, fuse_ino_t ino, int datasync, - struct fuse_file_info *llfi) + struct fuse_file_info *llfi) { - struct fuse *f = req_fuse_prepare(req); - struct fuse_file_info fi; - char *path; - int err; + struct fuse *f = req_fuse_prepare(req); + struct fuse_file_info fi; + char *path; + int err; - get_dirhandle(llfi, &fi); + get_dirhandle(llfi, &fi); - err = -ENOENT; - pthread_rwlock_rdlock(&f->tree_lock); - path = get_path(f, ino); - if (path != NULL) { - struct fuse_intr_data d; - fuse_prepare_interrupt(f, req, &d); - err = fuse_fs_fsyncdir(f->fs, path, datasync, &fi); - fuse_finish_interrupt(f, req, &d); - free(path); - } - pthread_rwlock_unlock(&f->tree_lock); - reply_err(req, err); + err = -ENOENT; + pthread_rwlock_rdlock(&f->tree_lock); + path = get_path(f, ino); + if (path != NULL) { + struct fuse_intr_data d; + fuse_prepare_interrupt(f, req, &d); + err = fuse_fs_fsyncdir(f->fs, path, datasync, &fi); + fuse_finish_interrupt(f, req, &d); + free(path); + } + pthread_rwlock_unlock(&f->tree_lock); + reply_err(req, err); } static void fuse_lib_statfs(fuse_req_t req, fuse_ino_t ino) { - struct fuse *f = req_fuse_prepare(req); - struct statvfs buf; - char *path; - int err; - - memset(&buf, 0, sizeof(buf)); - pthread_rwlock_rdlock(&f->tree_lock); - if (!ino) { - err = -ENOMEM; - path = strdup("/"); - } else { - err = -ENOENT; - path = get_path(f, ino); - } - if (path) { - struct fuse_intr_data d; - fuse_prepare_interrupt(f, req, &d); - err = fuse_fs_statfs(f->fs, path, &buf); - fuse_finish_interrupt(f, req, &d); - free(path); - } - pthread_rwlock_unlock(&f->tree_lock); - - if (!err) - fuse_reply_statfs(req, &buf); - else - reply_err(req, err); + struct fuse *f = req_fuse_prepare(req); + struct statvfs buf; + char *path; + int err; + + memset(&buf, 0, sizeof(buf)); + pthread_rwlock_rdlock(&f->tree_lock); + if (!ino) { + err = -ENOMEM; + path = strdup("/"); + } else { + err = -ENOENT; + path = get_path(f, ino); + } + if (path) { + struct fuse_intr_data d; + fuse_prepare_interrupt(f, req, &d); + err = fuse_fs_statfs(f->fs, path, &buf); + fuse_finish_interrupt(f, req, &d); + free(path); + } + pthread_rwlock_unlock(&f->tree_lock); + + if (!err) + fuse_reply_statfs(req, &buf); + else + reply_err(req, err); } static void fuse_lib_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) { - struct fuse_intr_data d; - fuse_prepare_interrupt(f, req, &d); - err = fuse_fs_setxattr(f->fs, path, name, value, size, flags); - fuse_finish_interrupt(f, req, &d); - free(path); - } - pthread_rwlock_unlock(&f->tree_lock); - reply_err(req, err); + 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) { + struct fuse_intr_data d; + fuse_prepare_interrupt(f, req, &d); + err = fuse_fs_setxattr(f->fs, 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) + const char *name, char *value, size_t size) { - int err; - char *path; + int err; + char *path; - err = -ENOENT; - pthread_rwlock_rdlock(&f->tree_lock); - path = get_path(f, ino); - if (path != NULL) { - struct fuse_intr_data d; - fuse_prepare_interrupt(f, req, &d); - err = fuse_fs_getxattr(f->fs, path, name, value, size); - fuse_finish_interrupt(f, req, &d); - free(path); - } - pthread_rwlock_unlock(&f->tree_lock); - return err; + err = -ENOENT; + pthread_rwlock_rdlock(&f->tree_lock); + path = get_path(f, ino); + if (path != NULL) { + struct fuse_intr_data d; + fuse_prepare_interrupt(f, req, &d); + err = fuse_fs_getxattr(f->fs, path, name, value, size); + fuse_finish_interrupt(f, req, &d); + free(path); + } + pthread_rwlock_unlock(&f->tree_lock); + return err; } static void fuse_lib_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); - } + 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 *list, size_t size) { - char *path; - int err; + char *path; + int err; - err = -ENOENT; - pthread_rwlock_rdlock(&f->tree_lock); - path = get_path(f, ino); - if (path != NULL) { - struct fuse_intr_data d; - fuse_prepare_interrupt(f, req, &d); - err = fuse_fs_listxattr(f->fs, path, list, size); - fuse_finish_interrupt(f, req, &d); - free(path); - } - pthread_rwlock_unlock(&f->tree_lock); - return err; + err = -ENOENT; + pthread_rwlock_rdlock(&f->tree_lock); + path = get_path(f, ino); + if (path != NULL) { + struct fuse_intr_data d; + fuse_prepare_interrupt(f, req, &d); + err = fuse_fs_listxattr(f->fs, path, list, size); + fuse_finish_interrupt(f, req, &d); + free(path); + } + pthread_rwlock_unlock(&f->tree_lock); + return err; } static void fuse_lib_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); - } + 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_lib_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) { - struct fuse_intr_data d; - fuse_prepare_interrupt(f, req, &d); - err = fuse_fs_removexattr(f->fs, path, name); - fuse_finish_interrupt(f, req, &d); - free(path); - } - pthread_rwlock_unlock(&f->tree_lock); - reply_err(req, err); + 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) { + struct fuse_intr_data d; + fuse_prepare_interrupt(f, req, &d); + err = fuse_fs_removexattr(f->fs, 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; + 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; + 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; + return l; } static void delete_lock(struct lock **lockp) { - struct lock *l = *lockp; - *lockp = l->next; - free(l); + struct lock *l = *lockp; + *lockp = l->next; + free(l); } static void insert_lock(struct lock **pos, struct lock *lock) { - lock->next = *pos; - *pos = 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; - } + 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; + 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; + 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; + 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 int fuse_flush_common(struct fuse *f, fuse_req_t req, fuse_ino_t ino, - const char *path, struct fuse_file_info *fi) -{ - struct fuse_intr_data d; - struct flock lock; - struct lock l; - int err; - int errlock; - - fuse_prepare_interrupt(f, req, &d); - memset(&lock, 0, sizeof(lock)); - lock.l_type = F_UNLCK; - lock.l_whence = SEEK_SET; - err = fuse_fs_flush(f->fs, path, fi); - errlock = fuse_fs_lock(f->fs, path, fi, F_SETLK, &lock); - fuse_finish_interrupt(f, req, &d); - - if (errlock != -ENOSYS) { - 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; - } - return err; + const char *path, struct fuse_file_info *fi) +{ + struct fuse_intr_data d; + struct flock lock; + struct lock l; + int err; + int errlock; + + fuse_prepare_interrupt(f, req, &d); + memset(&lock, 0, sizeof(lock)); + lock.l_type = F_UNLCK; + lock.l_whence = SEEK_SET; + err = fuse_fs_flush(f->fs, path, fi); + errlock = fuse_fs_lock(f->fs, path, fi, F_SETLK, &lock); + fuse_finish_interrupt(f, req, &d); + + if (errlock != -ENOSYS) { + 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; + } + return err; } static void fuse_lib_release(fuse_req_t req, fuse_ino_t ino, - struct fuse_file_info *fi) + struct fuse_file_info *fi) { - struct fuse *f = req_fuse_prepare(req); - struct fuse_intr_data d; - char *path; - int err = 0; + struct fuse *f = req_fuse_prepare(req); + struct fuse_intr_data d; + char *path; + int err = 0; - pthread_rwlock_rdlock(&f->tree_lock); - path = get_path(f, ino); - if (f->conf.debug) - fprintf(stderr, "RELEASE%s[%llu] flags: 0x%x\n", - fi->flush ? "+FLUSH" : "", - (unsigned long long) fi->fh, fi->flags); + pthread_rwlock_rdlock(&f->tree_lock); + path = get_path(f, ino); + if (f->conf.debug) + fprintf(stderr, "RELEASE%s[%llu] flags: 0x%x\n", + fi->flush ? "+FLUSH" : "", + (unsigned long long) fi->fh, fi->flags); - if (fi->flush) { - err = fuse_flush_common(f, req, ino, path, fi); - if (err == -ENOSYS) - err = 0; - } + if (fi->flush) { + err = fuse_flush_common(f, req, ino, path, fi); + if (err == -ENOSYS) + err = 0; + } - fuse_prepare_interrupt(f, req, &d); - fuse_do_release(f, ino, path, fi); - fuse_finish_interrupt(f, req, &d); - free(path); - pthread_rwlock_unlock(&f->tree_lock); + fuse_prepare_interrupt(f, req, &d); + fuse_do_release(f, ino, path, fi); + fuse_finish_interrupt(f, req, &d); + free(path); + pthread_rwlock_unlock(&f->tree_lock); - reply_err(req, err); + reply_err(req, err); } static void fuse_lib_flush(fuse_req_t req, fuse_ino_t ino, - struct fuse_file_info *fi) + struct fuse_file_info *fi) { - struct fuse *f = req_fuse_prepare(req); - char *path; - int err; + struct fuse *f = req_fuse_prepare(req); + char *path; + int err; - pthread_rwlock_rdlock(&f->tree_lock); - path = get_path(f, ino); - if (path && f->conf.debug) - fprintf(stderr, "FLUSH[%llu]\n", (unsigned long long) fi->fh); - err = fuse_flush_common(f, req, ino, path, fi); - free(path); - pthread_rwlock_unlock(&f->tree_lock); - reply_err(req, err); + pthread_rwlock_rdlock(&f->tree_lock); + path = get_path(f, ino); + if (path && f->conf.debug) + fprintf(stderr, "FLUSH[%llu]\n", (unsigned long long) fi->fh); + err = fuse_flush_common(f, req, ino, path, fi); + 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) { - struct fuse_intr_data d; - fuse_prepare_interrupt(f, req, &d); - err = fuse_fs_lock(f->fs, path, fi, cmd, lock); - fuse_finish_interrupt(f, req, &d); - free(path); - } - pthread_rwlock_unlock(&f->tree_lock); - return err; + 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) { + struct fuse_intr_data d; + fuse_prepare_interrupt(f, req, &d); + err = fuse_fs_lock(f->fs, path, fi, cmd, lock); + fuse_finish_interrupt(f, req, &d); + free(path); + } + pthread_rwlock_unlock(&f->tree_lock); + return err; } static void fuse_lib_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); + 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_lib_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_lock(&f->lock); - locks_insert(get_node(f, ino), &l); - pthread_mutex_unlock(&f->lock); - } - reply_err(req, err); + 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_lock(&f->lock); + locks_insert(get_node(f, ino), &l); + pthread_mutex_unlock(&f->lock); + } + reply_err(req, err); } static void fuse_lib_bmap(fuse_req_t req, fuse_ino_t ino, size_t blocksize, - uint64_t idx) -{ - struct fuse *f = req_fuse_prepare(req); - struct fuse_intr_data d; - char *path; - int err; - - err = -ENOENT; - pthread_rwlock_rdlock(&f->tree_lock); - path = get_path(f, ino); - if (path != NULL) { - fuse_prepare_interrupt(f, req, &d); - err = fuse_fs_bmap(f->fs, path, blocksize, &idx); - fuse_finish_interrupt(f, req, &d); - free(path); - } - pthread_rwlock_unlock(&f->tree_lock); - if (!err) - fuse_reply_bmap(req, idx); - else - reply_err(req, err); + uint64_t idx) +{ + struct fuse *f = req_fuse_prepare(req); + struct fuse_intr_data d; + char *path; + int err; + + err = -ENOENT; + pthread_rwlock_rdlock(&f->tree_lock); + path = get_path(f, ino); + if (path != NULL) { + fuse_prepare_interrupt(f, req, &d); + err = fuse_fs_bmap(f->fs, path, blocksize, &idx); + fuse_finish_interrupt(f, req, &d); + free(path); + } + pthread_rwlock_unlock(&f->tree_lock); + if (!err) + fuse_reply_bmap(req, idx); + else + reply_err(req, err); } static struct fuse_lowlevel_ops fuse_path_ops = { - .init = fuse_lib_init, - .destroy = fuse_lib_destroy, - .lookup = fuse_lib_lookup, - .forget = fuse_lib_forget, - .getattr = fuse_lib_getattr, - .setattr = fuse_lib_setattr, - .access = fuse_lib_access, - .readlink = fuse_lib_readlink, - .mknod = fuse_lib_mknod, - .mkdir = fuse_lib_mkdir, - .unlink = fuse_lib_unlink, - .rmdir = fuse_lib_rmdir, - .symlink = fuse_lib_symlink, - .rename = fuse_lib_rename, - .link = fuse_lib_link, - .create = fuse_lib_create, - .open = fuse_lib_open, - .read = fuse_lib_read, - .write = fuse_lib_write, - .flush = fuse_lib_flush, - .release = fuse_lib_release, - .fsync = fuse_lib_fsync, - .opendir = fuse_lib_opendir, - .readdir = fuse_lib_readdir, - .releasedir = fuse_lib_releasedir, - .fsyncdir = fuse_lib_fsyncdir, - .statfs = fuse_lib_statfs, - .setxattr = fuse_lib_setxattr, - .getxattr = fuse_lib_getxattr, - .listxattr = fuse_lib_listxattr, - .removexattr = fuse_lib_removexattr, - .getlk = fuse_lib_getlk, - .setlk = fuse_lib_setlk, - .bmap = fuse_lib_bmap, + .init = fuse_lib_init, + .destroy = fuse_lib_destroy, + .lookup = fuse_lib_lookup, + .forget = fuse_lib_forget, + .getattr = fuse_lib_getattr, + .setattr = fuse_lib_setattr, + .access = fuse_lib_access, + .readlink = fuse_lib_readlink, + .mknod = fuse_lib_mknod, + .mkdir = fuse_lib_mkdir, + .unlink = fuse_lib_unlink, + .rmdir = fuse_lib_rmdir, + .symlink = fuse_lib_symlink, + .rename = fuse_lib_rename, + .link = fuse_lib_link, + .create = fuse_lib_create, + .open = fuse_lib_open, + .read = fuse_lib_read, + .write = fuse_lib_write, + .flush = fuse_lib_flush, + .release = fuse_lib_release, + .fsync = fuse_lib_fsync, + .opendir = fuse_lib_opendir, + .readdir = fuse_lib_readdir, + .releasedir = fuse_lib_releasedir, + .fsyncdir = fuse_lib_fsyncdir, + .statfs = fuse_lib_statfs, + .setxattr = fuse_lib_setxattr, + .getxattr = fuse_lib_getxattr, + .listxattr = fuse_lib_listxattr, + .removexattr = fuse_lib_removexattr, + .getlk = fuse_lib_getlk, + .setlk = fuse_lib_setlk, + .bmap = fuse_lib_bmap, }; static void free_cmd(struct fuse_cmd *cmd) { - free(cmd->buf); - free(cmd); + free(cmd->buf); + free(cmd); } void fuse_process_cmd(struct fuse *f, struct fuse_cmd *cmd) { - fuse_session_process(f->se, cmd->buf, cmd->buflen, cmd->ch); - free_cmd(cmd); + fuse_session_process(f->se, cmd->buf, cmd->buflen, cmd->ch); + free_cmd(cmd); } int fuse_exited(struct fuse *f) { - return fuse_session_exited(f->se); + return fuse_session_exited(f->se); } struct fuse_session *fuse_get_session(struct fuse *f) { - return f->se; + return f->se; } static struct fuse_cmd *fuse_alloc_cmd(size_t bufsize) { - struct fuse_cmd *cmd = (struct fuse_cmd *) malloc(sizeof(*cmd)); - if (cmd == NULL) { - fprintf(stderr, "fuse: failed to allocate cmd\n"); - return NULL; - } - cmd->buf = (char *) malloc(bufsize); - if (cmd->buf == NULL) { - fprintf(stderr, "fuse: failed to allocate read buffer\n"); - free(cmd); - return NULL; - } - return cmd; + struct fuse_cmd *cmd = (struct fuse_cmd *) malloc(sizeof(*cmd)); + if (cmd == NULL) { + fprintf(stderr, "fuse: failed to allocate cmd\n"); + return NULL; + } + cmd->buf = (char *) malloc(bufsize); + if (cmd->buf == NULL) { + fprintf(stderr, "fuse: failed to allocate read buffer\n"); + free(cmd); + return NULL; + } + return cmd; } struct fuse_cmd *fuse_read_cmd(struct fuse *f) { - struct fuse_chan *ch = fuse_session_next_chan(f->se, NULL); - size_t bufsize = fuse_chan_bufsize(ch); - struct fuse_cmd *cmd = fuse_alloc_cmd(bufsize); - if (cmd != NULL) { - int res = fuse_chan_recv(&ch, cmd->buf, bufsize); - if (res <= 0) { - free_cmd(cmd); - if (res < 0 && res != -EINTR && res != -EAGAIN) - fuse_exit(f); - return NULL; - } - cmd->buflen = res; - cmd->ch = ch; - } - return cmd; + struct fuse_chan *ch = fuse_session_next_chan(f->se, NULL); + size_t bufsize = fuse_chan_bufsize(ch); + struct fuse_cmd *cmd = fuse_alloc_cmd(bufsize); + if (cmd != NULL) { + int res = fuse_chan_recv(&ch, cmd->buf, bufsize); + if (res <= 0) { + free_cmd(cmd); + if (res < 0 && res != -EINTR && res != -EAGAIN) + fuse_exit(f); + return NULL; + } + cmd->buflen = res; + cmd->ch = ch; + } + return cmd; } int fuse_loop(struct fuse *f) { - if (f) - return fuse_session_loop(f->se); - else - return -1; + if (f) + return fuse_session_loop(f->se); + else + return -1; } int fuse_invalidate(struct fuse *f, const char *path) { - (void) f; - (void) path; - return -EINVAL; + (void) f; + (void) path; + return -EINVAL; } void fuse_exit(struct fuse *f) { - fuse_session_exit(f->se); + fuse_session_exit(f->se); } struct fuse_context *fuse_get_context(void) { - return &fuse_get_context_internal()->ctx; + return &fuse_get_context_internal()->ctx; } int fuse_interrupted(void) { - return fuse_req_interrupted(fuse_get_context_internal()->req); + return fuse_req_interrupted(fuse_get_context_internal()->req); } void fuse_set_getcontext_func(struct fuse_context *(*func)(void)) { - (void) func; - /* no-op */ + (void) func; + /* no-op */ } enum { - KEY_HELP, + KEY_HELP, }; #define FUSE_LIB_OPT(t, p, v) { t, offsetof(struct fuse_config, p), v } static const struct fuse_opt fuse_lib_opts[] = { - FUSE_OPT_KEY("-h", KEY_HELP), - FUSE_OPT_KEY("--help", KEY_HELP), - FUSE_OPT_KEY("debug", FUSE_OPT_KEY_KEEP), - FUSE_OPT_KEY("-d", FUSE_OPT_KEY_KEEP), - FUSE_LIB_OPT("debug", debug, 1), - FUSE_LIB_OPT("-d", debug, 1), - FUSE_LIB_OPT("hard_remove", hard_remove, 1), - FUSE_LIB_OPT("use_ino", use_ino, 1), - FUSE_LIB_OPT("readdir_ino", readdir_ino, 1), - FUSE_LIB_OPT("direct_io", direct_io, 1), - FUSE_LIB_OPT("kernel_cache", kernel_cache, 1), - FUSE_LIB_OPT("auto_cache", auto_cache, 1), - FUSE_LIB_OPT("noauto_cache", auto_cache, 0), - FUSE_LIB_OPT("umask=", set_mode, 1), - FUSE_LIB_OPT("umask=%o", umask, 0), - FUSE_LIB_OPT("uid=", set_uid, 1), - FUSE_LIB_OPT("uid=%d", uid, 0), - FUSE_LIB_OPT("gid=", set_gid, 1), - FUSE_LIB_OPT("gid=%d", gid, 0), - FUSE_LIB_OPT("entry_timeout=%lf", entry_timeout, 0), - FUSE_LIB_OPT("attr_timeout=%lf", attr_timeout, 0), - FUSE_LIB_OPT("ac_attr_timeout=%lf", ac_attr_timeout, 0), - FUSE_LIB_OPT("ac_attr_timeout=", ac_attr_timeout_set, 1), - FUSE_LIB_OPT("negative_timeout=%lf", negative_timeout, 0), - FUSE_LIB_OPT("intr", intr, 1), - FUSE_LIB_OPT("intr_signal=%d", intr_signal, 0), - FUSE_LIB_OPT("modules=%s", modules, 0), - FUSE_OPT_END + FUSE_OPT_KEY("-h", KEY_HELP), + FUSE_OPT_KEY("--help", KEY_HELP), + FUSE_OPT_KEY("debug", FUSE_OPT_KEY_KEEP), + FUSE_OPT_KEY("-d", FUSE_OPT_KEY_KEEP), + FUSE_LIB_OPT("debug", debug, 1), + FUSE_LIB_OPT("-d", debug, 1), + FUSE_LIB_OPT("hard_remove", hard_remove, 1), + FUSE_LIB_OPT("use_ino", use_ino, 1), + FUSE_LIB_OPT("readdir_ino", readdir_ino, 1), + FUSE_LIB_OPT("direct_io", direct_io, 1), + FUSE_LIB_OPT("kernel_cache", kernel_cache, 1), + FUSE_LIB_OPT("auto_cache", auto_cache, 1), + FUSE_LIB_OPT("noauto_cache", auto_cache, 0), + FUSE_LIB_OPT("umask=", set_mode, 1), + FUSE_LIB_OPT("umask=%o", umask, 0), + FUSE_LIB_OPT("uid=", set_uid, 1), + FUSE_LIB_OPT("uid=%d", uid, 0), + FUSE_LIB_OPT("gid=", set_gid, 1), + FUSE_LIB_OPT("gid=%d", gid, 0), + FUSE_LIB_OPT("entry_timeout=%lf", entry_timeout, 0), + FUSE_LIB_OPT("attr_timeout=%lf", attr_timeout, 0), + FUSE_LIB_OPT("ac_attr_timeout=%lf", ac_attr_timeout, 0), + FUSE_LIB_OPT("ac_attr_timeout=", ac_attr_timeout_set, 1), + FUSE_LIB_OPT("negative_timeout=%lf", negative_timeout, 0), + FUSE_LIB_OPT("intr", intr, 1), + FUSE_LIB_OPT("intr_signal=%d", intr_signal, 0), + FUSE_LIB_OPT("modules=%s", modules, 0), + FUSE_OPT_END }; static void fuse_lib_help(void) { - fprintf(stderr, -" -o hard_remove immediate removal (don't hide files)\n" -" -o use_ino let filesystem set inode numbers\n" -" -o readdir_ino try to fill in d_ino in readdir\n" -" -o direct_io use direct I/O\n" -" -o kernel_cache cache files in kernel\n" -" -o [no]auto_cache enable caching based on modification times\n" -" -o umask=M set file permissions (octal)\n" -" -o uid=N set file owner\n" -" -o gid=N set file group\n" -" -o entry_timeout=T cache timeout for names (1.0s)\n" + fprintf(stderr, +" -o hard_remove immediate removal (don't hide files)\n" +" -o use_ino let filesystem set inode numbers\n" +" -o readdir_ino try to fill in d_ino in readdir\n" +" -o direct_io use direct I/O\n" +" -o kernel_cache cache files in kernel\n" +" -o [no]auto_cache enable caching based on modification times\n" +" -o umask=M set file permissions (octal)\n" +" -o uid=N set file owner\n" +" -o gid=N set file group\n" +" -o entry_timeout=T cache timeout for names (1.0s)\n" " -o negative_timeout=T cache timeout for deleted names (0.0s)\n" -" -o attr_timeout=T cache timeout for attributes (1.0s)\n" +" -o attr_timeout=T cache timeout for attributes (1.0s)\n" " -o ac_attr_timeout=T auto cache timeout for attributes (attr_timeout)\n" -" -o intr allow requests to be interrupted\n" -" -o intr_signal=NUM signal to send on interrupt (%i)\n" +" -o intr allow requests to be interrupted\n" +" -o intr_signal=NUM signal to send on interrupt (%i)\n" " -o modules=M1[:M2...] names of modules to push onto filesystem stack\n" "\n", FUSE_DEFAULT_INTR_SIGNAL); } static void fuse_lib_help_modules(void) { - struct fuse_module *m; - fprintf(stderr, "\nModule options:\n"); - pthread_mutex_lock(&fuse_context_lock); - for (m = fuse_modules; m; m = m->next) { - struct fuse_fs *fs = NULL; - struct fuse_fs *newfs; - struct fuse_args args = FUSE_ARGS_INIT(0, NULL); - if (fuse_opt_add_arg(&args, "") != -1 && - fuse_opt_add_arg(&args, "-h") != -1) { - fprintf(stderr, "\n[%s]\n", m->name); - newfs = m->factory(&args, &fs); - assert(newfs == NULL); - } - fuse_opt_free_args(&args); - } - pthread_mutex_unlock(&fuse_context_lock); + struct fuse_module *m; + fprintf(stderr, "\nModule options:\n"); + pthread_mutex_lock(&fuse_context_lock); + for (m = fuse_modules; m; m = m->next) { + struct fuse_fs *fs = NULL; + struct fuse_fs *newfs; + struct fuse_args args = FUSE_ARGS_INIT(0, NULL); + if (fuse_opt_add_arg(&args, "") != -1 && + fuse_opt_add_arg(&args, "-h") != -1) { + fprintf(stderr, "\n[%s]\n", m->name); + newfs = m->factory(&args, &fs); + assert(newfs == NULL); + } + fuse_opt_free_args(&args); + } + pthread_mutex_unlock(&fuse_context_lock); } static int fuse_lib_opt_proc(void *data, const char *arg, int key, - struct fuse_args *outargs) + struct fuse_args *outargs) { - (void) arg; (void) outargs; + (void) arg; (void) outargs; - if (key == KEY_HELP) { - struct fuse_config *conf = (struct fuse_config *) data; - fuse_lib_help(); - conf->help = 1; - } + if (key == KEY_HELP) { + struct fuse_config *conf = (struct fuse_config *) data; + fuse_lib_help(); + conf->help = 1; + } - return 1; + return 1; } int fuse_is_lib_option(const char *opt) { - return fuse_lowlevel_is_lib_option(opt) || - fuse_opt_match(fuse_lib_opts, opt); + return fuse_lowlevel_is_lib_option(opt) || + fuse_opt_match(fuse_lib_opts, opt); } static int fuse_init_intr_signal(int signum, int *installed) { - struct sigaction old_sa; + struct sigaction old_sa; - if (sigaction(signum, NULL, &old_sa) == -1) { - perror("fuse: cannot get old signal handler"); - return -1; - } + if (sigaction(signum, NULL, &old_sa) == -1) { + perror("fuse: cannot get old signal handler"); + return -1; + } - if (old_sa.sa_handler == SIG_DFL) { - struct sigaction sa; + if (old_sa.sa_handler == SIG_DFL) { + struct sigaction sa; - memset(&sa, 0, sizeof(struct sigaction)); - sa.sa_handler = fuse_intr_sighandler; - sigemptyset(&sa.sa_mask); + memset(&sa, 0, sizeof(struct sigaction)); + sa.sa_handler = fuse_intr_sighandler; + sigemptyset(&sa.sa_mask); - if (sigaction(signum, &sa, NULL) == -1) { - perror("fuse: cannot set interrupt signal handler"); - return -1; - } - *installed = 1; - } - return 0; + if (sigaction(signum, &sa, NULL) == -1) { + perror("fuse: cannot set interrupt signal handler"); + return -1; + } + *installed = 1; + } + return 0; } static void fuse_restore_intr_signal(int signum) { - struct sigaction sa; + struct sigaction sa; - memset(&sa, 0, sizeof(struct sigaction)); - sa.sa_handler = SIG_DFL; - sigaction(signum, &sa, NULL); + memset(&sa, 0, sizeof(struct sigaction)); + sa.sa_handler = SIG_DFL; + sigaction(signum, &sa, NULL); } static int fuse_push_module(struct fuse *f, const char *module, - struct fuse_args *args) + struct fuse_args *args) { - struct fuse_fs *fs[2] = { f->fs, NULL }; - struct fuse_fs *newfs; - struct fuse_module *m = fuse_get_module(module); + struct fuse_fs *fs[2] = { f->fs, NULL }; + struct fuse_fs *newfs; + struct fuse_module *m = fuse_get_module(module); - if (!m) - return -1; + if (!m) + return -1; - newfs = m->factory(args, fs); - if (!newfs) { - fuse_put_module(m); - return -1; - } - newfs->m = m; - f->fs = newfs; - return 0; + newfs = m->factory(args, fs); + if (!newfs) { + fuse_put_module(m); + return -1; + } + newfs->m = m; + f->fs = newfs; + return 0; } struct fuse_fs *fuse_fs_new(const struct fuse_operations *op, size_t op_size, - void *user_data) + void *user_data) { - struct fuse_fs *fs; + struct fuse_fs *fs; - if (sizeof(struct fuse_operations) < op_size) { - fprintf(stderr, "fuse: warning: library too old, some operations may not not work\n"); - op_size = sizeof(struct fuse_operations); - } + if (sizeof(struct fuse_operations) < op_size) { + fprintf(stderr, "fuse: warning: library too old, some operations may not not work\n"); + op_size = sizeof(struct fuse_operations); + } - fs = (struct fuse_fs *) calloc(1, sizeof(struct fuse_fs)); - if (!fs) { - fprintf(stderr, "fuse: failed to allocate fuse_fs object\n"); - return NULL; - } + fs = (struct fuse_fs *) calloc(1, sizeof(struct fuse_fs)); + if (!fs) { + fprintf(stderr, "fuse: failed to allocate fuse_fs object\n"); + return NULL; + } - fs->user_data = user_data; - if (op) - memcpy(&fs->op, op, op_size); - return fs; + fs->user_data = user_data; + if (op) + memcpy(&fs->op, op, op_size); + return fs; } struct fuse *fuse_new_common(struct fuse_chan *ch, struct fuse_args *args, - const struct fuse_operations *op, - size_t op_size, void *user_data, int compat) -{ - struct fuse *f; - struct node *root; - struct fuse_fs *fs; - struct fuse_lowlevel_ops llop = fuse_path_ops; - - if (fuse_create_context_key() == -1) - goto out; - - f = (struct fuse *) calloc(1, sizeof(struct fuse)); - if (f == NULL) { - fprintf(stderr, "fuse: failed to allocate fuse object\n"); - goto out_delete_context_key; - } - - fs = fuse_fs_new(op, op_size, user_data); - if (!fs) - goto out_free; - - fs->compat = compat; - f->fs = fs; - - /* Oh f**k, this is ugly! */ - if (!fs->op.lock) { - llop.getlk = NULL; - llop.setlk = NULL; - } - - f->conf.entry_timeout = 1.0; - f->conf.attr_timeout = 1.0; - f->conf.negative_timeout = 0.0; - f->conf.intr_signal = FUSE_DEFAULT_INTR_SIGNAL; - - if (fuse_opt_parse(args, &f->conf, fuse_lib_opts, fuse_lib_opt_proc) == -1) - goto out_free_fs; - - if (f->conf.modules) { - char *module; - char *next; - - for (module = f->conf.modules; module; module = next) { - char *p; - for (p = module; *p && *p != ':'; p++); - next = *p ? p + 1 : NULL; - *p = '\0'; - if (module[0] && fuse_push_module(f, module, args) == -1) - goto out_free_fs; - } - } - - if (!f->conf.ac_attr_timeout_set) - f->conf.ac_attr_timeout = f->conf.attr_timeout; + const struct fuse_operations *op, + size_t op_size, void *user_data, int compat) +{ + struct fuse *f; + struct node *root; + struct fuse_fs *fs; + struct fuse_lowlevel_ops llop = fuse_path_ops; + + if (fuse_create_context_key() == -1) + goto out; + + f = (struct fuse *) calloc(1, sizeof(struct fuse)); + if (f == NULL) { + fprintf(stderr, "fuse: failed to allocate fuse object\n"); + goto out_delete_context_key; + } + + fs = fuse_fs_new(op, op_size, user_data); + if (!fs) + goto out_free; + + fs->compat = compat; + f->fs = fs; + + /* Oh f**k, this is ugly! */ + if (!fs->op.lock) { + llop.getlk = NULL; + llop.setlk = NULL; + } + + f->conf.entry_timeout = 1.0; + f->conf.attr_timeout = 1.0; + f->conf.negative_timeout = 0.0; + f->conf.intr_signal = FUSE_DEFAULT_INTR_SIGNAL; + + if (fuse_opt_parse(args, &f->conf, fuse_lib_opts, + fuse_lib_opt_proc) == -1) + goto out_free_fs; + + if (f->conf.modules) { + char *module; + char *next; + + for (module = f->conf.modules; module; module = next) { + char *p; + for (p = module; *p && *p != ':'; p++); + next = *p ? p + 1 : NULL; + *p = '\0'; + if (module[0] && + fuse_push_module(f, module, args) == -1) + goto out_free_fs; + } + } + + if (!f->conf.ac_attr_timeout_set) + f->conf.ac_attr_timeout = f->conf.attr_timeout; #ifdef __FreeBSD__ - /* - * In FreeBSD, we always use these settings as inode numbers are needed to - * make getcwd(3) work. - */ - f->conf.readdir_ino = 1; + /* + * In FreeBSD, we always use these settings as inode numbers + * are needed to make getcwd(3) work. + */ + f->conf.readdir_ino = 1; #endif - if (compat && compat <= 25) { - if (fuse_sync_compat_args(args) == -1) - goto out_free_fs; - } - - f->se = fuse_lowlevel_new_common(args, &llop, sizeof(llop), f); - if (f->se == NULL) { - if (f->conf.help) - fuse_lib_help_modules(); - goto out_free_fs; - } - - fuse_session_add_chan(f->se, ch); - - f->ctr = 0; - f->generation = 0; - /* FIXME: Dynamic hash table */ - f->name_table_size = 14057; - f->name_table = (struct node **) - calloc(1, sizeof(struct node *) * f->name_table_size); - if (f->name_table == NULL) { - fprintf(stderr, "fuse: memory allocation failed\n"); - goto out_free_session; - } - - f->id_table_size = 14057; - f->id_table = (struct node **) - calloc(1, sizeof(struct node *) * f->id_table_size); - if (f->id_table == NULL) { - fprintf(stderr, "fuse: memory allocation failed\n"); - goto out_free_name_table; - } - - fuse_mutex_init(&f->lock); - pthread_rwlock_init(&f->tree_lock, NULL); - - root = (struct node *) calloc(1, sizeof(struct node)); - if (root == NULL) { - fprintf(stderr, "fuse: memory allocation failed\n"); - goto out_free_id_table; - } - - root->name = strdup("/"); - if (root->name == NULL) { - fprintf(stderr, "fuse: memory allocation failed\n"); - goto out_free_root; - } - - if (f->conf.intr && - fuse_init_intr_signal(f->conf.intr_signal, &f->intr_installed) == -1) - goto out_free_root_name; - - root->parent = NULL; - root->nodeid = FUSE_ROOT_ID; - root->generation = 0; - root->refctr = 1; - root->nlookup = 1; - hash_id(f, root); - - return f; - - out_free_root_name: - free(root->name); - out_free_root: - free(root); - out_free_id_table: - free(f->id_table); - out_free_name_table: - free(f->name_table); - out_free_session: - fuse_session_destroy(f->se); - out_free_fs: - /* Horrible compatibility hack to stop the destructor from being - called on the filesystem without init being called first */ - fs->op.destroy = NULL; - fuse_fs_destroy(f->fs); - free(f->conf.modules); - out_free: - free(f); - out_delete_context_key: - fuse_delete_context_key(); - out: - return NULL; + if (compat && compat <= 25) { + if (fuse_sync_compat_args(args) == -1) + goto out_free_fs; + } + + f->se = fuse_lowlevel_new_common(args, &llop, sizeof(llop), f); + if (f->se == NULL) { + if (f->conf.help) + fuse_lib_help_modules(); + goto out_free_fs; + } + + fuse_session_add_chan(f->se, ch); + + f->ctr = 0; + f->generation = 0; + /* FIXME: Dynamic hash table */ + f->name_table_size = 14057; + f->name_table = (struct node **) + calloc(1, sizeof(struct node *) * f->name_table_size); + if (f->name_table == NULL) { + fprintf(stderr, "fuse: memory allocation failed\n"); + goto out_free_session; + } + + f->id_table_size = 14057; + f->id_table = (struct node **) + calloc(1, sizeof(struct node *) * f->id_table_size); + if (f->id_table == NULL) { + fprintf(stderr, "fuse: memory allocation failed\n"); + goto out_free_name_table; + } + + fuse_mutex_init(&f->lock); + pthread_rwlock_init(&f->tree_lock, NULL); + + root = (struct node *) calloc(1, sizeof(struct node)); + if (root == NULL) { + fprintf(stderr, "fuse: memory allocation failed\n"); + goto out_free_id_table; + } + + root->name = strdup("/"); + if (root->name == NULL) { + fprintf(stderr, "fuse: memory allocation failed\n"); + goto out_free_root; + } + + if (f->conf.intr && + fuse_init_intr_signal(f->conf.intr_signal, + &f->intr_installed) == -1) + goto out_free_root_name; + + root->parent = NULL; + root->nodeid = FUSE_ROOT_ID; + root->generation = 0; + root->refctr = 1; + root->nlookup = 1; + hash_id(f, root); + + return f; + +out_free_root_name: + free(root->name); +out_free_root: + free(root); +out_free_id_table: + free(f->id_table); +out_free_name_table: + free(f->name_table); +out_free_session: + fuse_session_destroy(f->se); +out_free_fs: + /* Horrible compatibility hack to stop the destructor from being + called on the filesystem without init being called first */ + fs->op.destroy = NULL; + fuse_fs_destroy(f->fs); + free(f->conf.modules); +out_free: + free(f); +out_delete_context_key: + fuse_delete_context_key(); +out: + return NULL; } struct fuse *fuse_new(struct fuse_chan *ch, struct fuse_args *args, - const struct fuse_operations *op, size_t op_size, - void *user_data) + const struct fuse_operations *op, size_t op_size, + void *user_data) { - return fuse_new_common(ch, args, op, op_size, user_data, 0); + return fuse_new_common(ch, args, op, op_size, user_data, 0); } void fuse_destroy(struct fuse *f) { - size_t i; - - if (f->conf.intr && f->intr_installed) - fuse_restore_intr_signal(f->conf.intr_signal); - - if (f->fs) { - struct fuse_context_i *c = fuse_get_context_internal(); - - memset(c, 0, sizeof(*c)); - c->ctx.fuse = f; - - for (i = 0; i < f->id_table_size; i++) { - struct node *node; - - for (node = f->id_table[i]; node != NULL; node = node->id_next) { - if (node->is_hidden) { - char *path = get_path(f, node->nodeid); - if (path) { - fuse_fs_unlink(f->fs, path); - free(path); - } - } - } - } - } - for (i = 0; i < f->id_table_size; i++) { - struct node *node; - struct node *next; - - for (node = f->id_table[i]; node != NULL; node = next) { - next = node->id_next; - free_node(node); - } - } - free(f->id_table); - free(f->name_table); - pthread_mutex_destroy(&f->lock); - pthread_rwlock_destroy(&f->tree_lock); - fuse_session_destroy(f->se); - free(f->conf.modules); - free(f); - fuse_delete_context_key(); + size_t i; + + if (f->conf.intr && f->intr_installed) + fuse_restore_intr_signal(f->conf.intr_signal); + + if (f->fs) { + struct fuse_context_i *c = fuse_get_context_internal(); + + memset(c, 0, sizeof(*c)); + c->ctx.fuse = f; + + for (i = 0; i < f->id_table_size; i++) { + struct node *node; + + for (node = f->id_table[i]; node != NULL; + node = node->id_next) { + if (node->is_hidden) { + char *path = get_path(f, node->nodeid); + if (path) { + fuse_fs_unlink(f->fs, path); + free(path); + } + } + } + } + } + for (i = 0; i < f->id_table_size; i++) { + struct node *node; + struct node *next; + + for (node = f->id_table[i]; node != NULL; node = next) { + next = node->id_next; + free_node(node); + } + } + free(f->id_table); + free(f->name_table); + pthread_mutex_destroy(&f->lock); + pthread_rwlock_destroy(&f->tree_lock); + fuse_session_destroy(f->se); + free(f->conf.modules); + free(f); + fuse_delete_context_key(); } static struct fuse *fuse_new_common_compat25(int fd, struct fuse_args *args, - const struct fuse_operations *op, - size_t op_size, int compat) + const struct fuse_operations *op, + size_t op_size, int compat) { - struct fuse *f = NULL; - struct fuse_chan *ch = fuse_kern_chan_new(fd); + struct fuse *f = NULL; + struct fuse_chan *ch = fuse_kern_chan_new(fd); - if (ch) - f = fuse_new_common(ch, args, op, op_size, NULL, compat); + if (ch) + f = fuse_new_common(ch, args, op, op_size, NULL, compat); - return f; + return f; } /* called with fuse_context_lock held or during initialization (before main() has been called) */ void fuse_register_module(struct fuse_module *mod) { - mod->ctr = 0; - mod->so = fuse_current_so; - if (mod->so) - mod->so->ctr++; - mod->next = fuse_modules; - fuse_modules = mod; + mod->ctr = 0; + mod->so = fuse_current_so; + if (mod->so) + mod->so->ctr++; + mod->next = fuse_modules; + fuse_modules = mod; } #ifndef __FreeBSD__ static struct fuse *fuse_new_common_compat(int fd, const char *opts, - const struct fuse_operations *op, - size_t op_size, int compat) + const struct fuse_operations *op, + size_t op_size, int compat) { - struct fuse *f; - struct fuse_args args = FUSE_ARGS_INIT(0, NULL); + struct fuse *f; + struct fuse_args args = FUSE_ARGS_INIT(0, NULL); - if (fuse_opt_add_arg(&args, "") == -1) - return NULL; - if (opts && - (fuse_opt_add_arg(&args, "-o") == -1 || - fuse_opt_add_arg(&args, opts) == -1)) { - fuse_opt_free_args(&args); - return NULL; - } - f = fuse_new_common_compat25(fd, &args, op, op_size, compat); - fuse_opt_free_args(&args); + if (fuse_opt_add_arg(&args, "") == -1) + return NULL; + if (opts && + (fuse_opt_add_arg(&args, "-o") == -1 || + fuse_opt_add_arg(&args, opts) == -1)) { + fuse_opt_free_args(&args); + return NULL; + } + f = fuse_new_common_compat25(fd, &args, op, op_size, compat); + fuse_opt_free_args(&args); - return f; + return f; } struct fuse *fuse_new_compat22(int fd, const char *opts, - const struct fuse_operations_compat22 *op, - size_t op_size) + const struct fuse_operations_compat22 *op, + size_t op_size) { - return fuse_new_common_compat(fd, opts, (struct fuse_operations *) op, - op_size, 22); + return fuse_new_common_compat(fd, opts, (struct fuse_operations *) op, + op_size, 22); } struct fuse *fuse_new_compat2(int fd, const char *opts, - const struct fuse_operations_compat2 *op) + const struct fuse_operations_compat2 *op) { - return fuse_new_common_compat(fd, opts, (struct fuse_operations *) op, - sizeof(struct fuse_operations_compat2), 21); + return fuse_new_common_compat(fd, opts, (struct fuse_operations *) op, + sizeof(struct fuse_operations_compat2), + 21); } struct fuse *fuse_new_compat1(int fd, int flags, - const struct fuse_operations_compat1 *op) + const struct fuse_operations_compat1 *op) { - const char *opts = NULL; - if (flags & FUSE_DEBUG_COMPAT1) - opts = "debug"; - return fuse_new_common_compat(fd, opts, (struct fuse_operations *) op, - sizeof(struct fuse_operations_compat1), 11); + const char *opts = NULL; + if (flags & FUSE_DEBUG_COMPAT1) + opts = "debug"; + return fuse_new_common_compat(fd, opts, (struct fuse_operations *) op, + sizeof(struct fuse_operations_compat1), + 11); } FUSE_SYMVER(".symver fuse_exited,__fuse_exited@"); @@ -3300,11 +3339,11 @@ FUSE_SYMVER(".symver fuse_new_compat22,fuse_new@FUSE_2.2"); #endif /* __FreeBSD__ */ struct fuse *fuse_new_compat25(int fd, struct fuse_args *args, - const struct fuse_operations_compat25 *op, - size_t op_size) + const struct fuse_operations_compat25 *op, + size_t op_size) { - return fuse_new_common_compat25(fd, args, (struct fuse_operations *) op, - op_size, 25); + return fuse_new_common_compat25(fd, args, (struct fuse_operations *) op, + op_size, 25); } FUSE_SYMVER(".symver fuse_new_compat25,fuse_new@FUSE_2.5"); diff --git a/lib/fuse_i.h b/lib/fuse_i.h index 55ce048..ec6e5d6 100644 --- a/lib/fuse_i.h +++ b/lib/fuse_i.h @@ -1,9 +1,9 @@ /* - FUSE: Filesystem in Userspace - Copyright (C) 2001-2007 Miklos Szeredi + FUSE: Filesystem in Userspace + Copyright (C) 2001-2007 Miklos Szeredi - This program can be distributed under the terms of the GNU LGPLv2. - See the file COPYING.LIB + This program can be distributed under the terms of the GNU LGPLv2. + See the file COPYING.LIB */ #include "fuse.h" @@ -14,22 +14,22 @@ struct fuse_lowlevel_ops; struct fuse_req; struct fuse_cmd { - char *buf; - size_t buflen; - struct fuse_chan *ch; + char *buf; + size_t buflen; + struct fuse_chan *ch; }; struct fuse *fuse_new_common(struct fuse_chan *ch, struct fuse_args *args, - const struct fuse_operations *op, - size_t op_size, void *user_data, int compat); + const struct fuse_operations *op, + size_t op_size, void *user_data, int compat); int fuse_sync_compat_args(struct fuse_args *args); struct fuse_chan *fuse_kern_chan_new(int fd); struct fuse_session *fuse_lowlevel_new_common(struct fuse_args *args, - const struct fuse_lowlevel_ops *op, - size_t op_size, void *userdata); + const struct fuse_lowlevel_ops *op, + size_t op_size, void *userdata); void fuse_kern_unmount_compat22(const char *mountpoint); void fuse_kern_unmount(const char *mountpoint, int fd); diff --git a/lib/fuse_kern_chan.c b/lib/fuse_kern_chan.c index 49e88b7..03291c3 100644 --- a/lib/fuse_kern_chan.c +++ b/lib/fuse_kern_chan.c @@ -1,9 +1,9 @@ /* - FUSE: Filesystem in Userspace - Copyright (C) 2001-2007 Miklos Szeredi + FUSE: Filesystem in Userspace + Copyright (C) 2001-2007 Miklos Szeredi - This program can be distributed under the terms of the GNU LGPLv2. - See the file COPYING.LIB + This program can be distributed under the terms of the GNU LGPLv2. + See the file COPYING.LIB */ #include "fuse_lowlevel.h" @@ -16,80 +16,80 @@ #include static int fuse_kern_chan_receive(struct fuse_chan **chp, char *buf, - size_t size) + size_t size) { - struct fuse_chan *ch = *chp; - int err; - ssize_t res; - struct fuse_session *se = fuse_chan_session(ch); - assert(se != NULL); + struct fuse_chan *ch = *chp; + int err; + ssize_t res; + struct fuse_session *se = fuse_chan_session(ch); + assert(se != NULL); - restart: - res = read(fuse_chan_fd(ch), buf, size); - err = errno; +restart: + res = read(fuse_chan_fd(ch), buf, size); + err = errno; - if (fuse_session_exited(se)) - return 0; - if (res == -1) { - /* ENOENT means the operation was interrupted, it's safe - to restart */ - if (err == ENOENT) - goto restart; + if (fuse_session_exited(se)) + return 0; + if (res == -1) { + /* ENOENT means the operation was interrupted, it's safe + to restart */ + if (err == ENOENT) + goto restart; - if (err == ENODEV) { - fuse_session_exit(se); - return 0; - } - /* Errors occuring during normal operation: EINTR (read - interrupted), EAGAIN (nonblocking I/O), ENODEV (filesystem - umounted) */ - if (err != EINTR && err != EAGAIN) - perror("fuse: reading device"); - return -err; - } - if ((size_t) res < sizeof(struct fuse_in_header)) { - fprintf(stderr, "short read on fuse device\n"); - return -EIO; - } - return res; + if (err == ENODEV) { + fuse_session_exit(se); + return 0; + } + /* Errors occuring during normal operation: EINTR (read + interrupted), EAGAIN (nonblocking I/O), ENODEV (filesystem + umounted) */ + if (err != EINTR && err != EAGAIN) + perror("fuse: reading device"); + return -err; + } + if ((size_t) res < sizeof(struct fuse_in_header)) { + fprintf(stderr, "short read on fuse device\n"); + return -EIO; + } + return res; } static int fuse_kern_chan_send(struct fuse_chan *ch, const struct iovec iov[], - size_t count) + size_t count) { - if (iov) { - ssize_t res = writev(fuse_chan_fd(ch), iov, count); - int err = errno; + if (iov) { + ssize_t res = writev(fuse_chan_fd(ch), iov, count); + int err = errno; - if (res == -1) { - struct fuse_session *se = fuse_chan_session(ch); + if (res == -1) { + struct fuse_session *se = fuse_chan_session(ch); - assert(se != NULL); + assert(se != NULL); - /* ENOENT means the operation was interrupted */ - if (!fuse_session_exited(se) && err != ENOENT) - perror("fuse: writing device"); - return -err; - } - } - return 0; + /* ENOENT means the operation was interrupted */ + if (!fuse_session_exited(se) && err != ENOENT) + perror("fuse: writing device"); + return -err; + } + } + return 0; } static void fuse_kern_chan_destroy(struct fuse_chan *ch) { - close(fuse_chan_fd(ch)); + close(fuse_chan_fd(ch)); } #define MIN_BUFSIZE 0x21000 struct fuse_chan *fuse_kern_chan_new(int fd) { - struct fuse_chan_ops op = { - .receive = fuse_kern_chan_receive, - .send = fuse_kern_chan_send, - .destroy = fuse_kern_chan_destroy, - }; - size_t bufsize = getpagesize() + 0x1000; - bufsize = bufsize < MIN_BUFSIZE ? MIN_BUFSIZE : bufsize; - return fuse_chan_new(&op, fd, bufsize, NULL); + struct fuse_chan_ops op = { + .receive = fuse_kern_chan_receive, + .send = fuse_kern_chan_send, + .destroy = fuse_kern_chan_destroy, + }; + size_t bufsize = getpagesize() + 0x1000; + bufsize = bufsize < MIN_BUFSIZE ? MIN_BUFSIZE : bufsize; + return fuse_chan_new(&op, fd, bufsize, NULL); } diff --git a/lib/fuse_loop.c b/lib/fuse_loop.c index f7c17fa..104c5d4 100644 --- a/lib/fuse_loop.c +++ b/lib/fuse_loop.c @@ -1,9 +1,9 @@ /* - FUSE: Filesystem in Userspace - Copyright (C) 2001-2007 Miklos Szeredi + FUSE: Filesystem in Userspace + Copyright (C) 2001-2007 Miklos Szeredi - This program can be distributed under the terms of the GNU LGPLv2. - See the file COPYING.LIB + This program can be distributed under the terms of the GNU LGPLv2. + See the file COPYING.LIB */ #include "fuse_lowlevel.h" @@ -14,26 +14,26 @@ int fuse_session_loop(struct fuse_session *se) { - int res = 0; - struct fuse_chan *ch = fuse_session_next_chan(se, NULL); - size_t bufsize = fuse_chan_bufsize(ch); - char *buf = (char *) malloc(bufsize); - if (!buf) { - fprintf(stderr, "fuse: failed to allocate read buffer\n"); - return -1; - } + int res = 0; + struct fuse_chan *ch = fuse_session_next_chan(se, NULL); + size_t bufsize = fuse_chan_bufsize(ch); + char *buf = (char *) malloc(bufsize); + if (!buf) { + fprintf(stderr, "fuse: failed to allocate read buffer\n"); + return -1; + } - while (!fuse_session_exited(se)) { - struct fuse_chan *tmpch = ch; - res = fuse_chan_recv(&tmpch, buf, bufsize); - if (res == -EINTR) - continue; - if (res <= 0) - break; - fuse_session_process(se, buf, res, tmpch); - } + while (!fuse_session_exited(se)) { + struct fuse_chan *tmpch = ch; + res = fuse_chan_recv(&tmpch, buf, bufsize); + if (res == -EINTR) + continue; + if (res <= 0) + break; + fuse_session_process(se, buf, res, tmpch); + } - free(buf); - fuse_session_reset(se); - return res < 0 ? -1 : 0; + free(buf); + fuse_session_reset(se); + return res < 0 ? -1 : 0; } diff --git a/lib/fuse_loop_mt.c b/lib/fuse_loop_mt.c index 533d9c3..dba8dbc 100644 --- a/lib/fuse_loop_mt.c +++ b/lib/fuse_loop_mt.c @@ -1,9 +1,9 @@ /* - FUSE: Filesystem in Userspace - Copyright (C) 2001-2007 Miklos Szeredi + FUSE: Filesystem in Userspace + Copyright (C) 2001-2007 Miklos Szeredi - This program can be distributed under the terms of the GNU LGPLv2. - See the file COPYING.LIB. + This program can be distributed under the terms of the GNU LGPLv2. + See the file COPYING.LIB. */ #include "fuse_lowlevel.h" @@ -20,202 +20,203 @@ #include struct fuse_worker { - struct fuse_worker *prev; - struct fuse_worker *next; - pthread_t thread_id; - size_t bufsize; - char *buf; - struct fuse_mt *mt; + struct fuse_worker *prev; + struct fuse_worker *next; + pthread_t thread_id; + size_t bufsize; + char *buf; + struct fuse_mt *mt; }; struct fuse_mt { - pthread_mutex_t lock; - int numworker; - int numavail; - struct fuse_session *se; - struct fuse_chan *prevch; - struct fuse_worker main; - sem_t finish; - int exit; - int error; + pthread_mutex_t lock; + int numworker; + int numavail; + struct fuse_session *se; + struct fuse_chan *prevch; + struct fuse_worker main; + sem_t finish; + int exit; + int error; }; static void list_add_worker(struct fuse_worker *w, struct fuse_worker *next) { - struct fuse_worker *prev = next->prev; - w->next = next; - w->prev = prev; - prev->next = w; - next->prev = w; + struct fuse_worker *prev = next->prev; + w->next = next; + w->prev = prev; + prev->next = w; + next->prev = w; } static void list_del_worker(struct fuse_worker *w) { - struct fuse_worker *prev = w->prev; - struct fuse_worker *next = w->next; - prev->next = next; - next->prev = prev; + struct fuse_worker *prev = w->prev; + struct fuse_worker *next = w->next; + prev->next = next; + next->prev = prev; } static int fuse_start_thread(struct fuse_mt *mt); static void *fuse_do_work(void *data) { - struct fuse_worker *w = (struct fuse_worker *) data; - struct fuse_mt *mt = w->mt; - - while (!fuse_session_exited(mt->se)) { - int isforget = 0; - struct fuse_chan *ch = mt->prevch; - int res = fuse_chan_recv(&ch, w->buf, w->bufsize); - if (res == -EINTR) - continue; - if (res <= 0) { - if (res < 0) { - fuse_session_exit(mt->se); - mt->error = -1; - } - break; - } - - pthread_mutex_lock(&mt->lock); - if (mt->exit) { - pthread_mutex_unlock(&mt->lock); - return NULL; - } - - /* - * This disgusting hack is needed so that zillions of threads - * are not created on a burst of FORGET messages - */ - if (((struct fuse_in_header *) w->buf)->opcode == FUSE_FORGET) - isforget = 1; - - if (!isforget) - mt->numavail--; - if (mt->numavail == 0) - fuse_start_thread(mt); - pthread_mutex_unlock(&mt->lock); - - fuse_session_process(mt->se, w->buf, res, ch); - - pthread_mutex_lock(&mt->lock); - if (!isforget) - mt->numavail++; - if (mt->numavail > 10) { - if (mt->exit) { - pthread_mutex_unlock(&mt->lock); - return NULL; - } - list_del_worker(w); - mt->numavail--; - mt->numworker--; - pthread_mutex_unlock(&mt->lock); - - pthread_detach(w->thread_id); - free(w->buf); - free(w); - return NULL; - } - pthread_mutex_unlock(&mt->lock); - } - - sem_post(&mt->finish); - pause(); - - return NULL; + struct fuse_worker *w = (struct fuse_worker *) data; + struct fuse_mt *mt = w->mt; + + while (!fuse_session_exited(mt->se)) { + int isforget = 0; + struct fuse_chan *ch = mt->prevch; + int res = fuse_chan_recv(&ch, w->buf, w->bufsize); + if (res == -EINTR) + continue; + if (res <= 0) { + if (res < 0) { + fuse_session_exit(mt->se); + mt->error = -1; + } + break; + } + + pthread_mutex_lock(&mt->lock); + if (mt->exit) { + pthread_mutex_unlock(&mt->lock); + return NULL; + } + + /* + * This disgusting hack is needed so that zillions of threads + * are not created on a burst of FORGET messages + */ + if (((struct fuse_in_header *) w->buf)->opcode == FUSE_FORGET) + isforget = 1; + + if (!isforget) + mt->numavail--; + if (mt->numavail == 0) + fuse_start_thread(mt); + pthread_mutex_unlock(&mt->lock); + + fuse_session_process(mt->se, w->buf, res, ch); + + pthread_mutex_lock(&mt->lock); + if (!isforget) + mt->numavail++; + if (mt->numavail > 10) { + if (mt->exit) { + pthread_mutex_unlock(&mt->lock); + return NULL; + } + list_del_worker(w); + mt->numavail--; + mt->numworker--; + pthread_mutex_unlock(&mt->lock); + + pthread_detach(w->thread_id); + free(w->buf); + free(w); + return NULL; + } + pthread_mutex_unlock(&mt->lock); + } + + sem_post(&mt->finish); + pause(); + + return NULL; } static int fuse_start_thread(struct fuse_mt *mt) { - sigset_t oldset; - sigset_t newset; - int res; - struct fuse_worker *w = malloc(sizeof(struct fuse_worker)); - if (!w) { - fprintf(stderr, "fuse: failed to allocate worker structure\n"); - return -1; - } - memset(w, 0, sizeof(struct fuse_worker)); - w->bufsize = fuse_chan_bufsize(mt->prevch); - w->buf = malloc(w->bufsize); - w->mt = mt; - if (!w->buf) { - fprintf(stderr, "fuse: failed to allocate read buffer\n"); - free(w); - return -1; - } - - /* Disallow signal reception in worker threads */ - sigemptyset(&newset); - sigaddset(&newset, SIGTERM); - sigaddset(&newset, SIGINT); - sigaddset(&newset, SIGHUP); - sigaddset(&newset, SIGQUIT); - pthread_sigmask(SIG_BLOCK, &newset, &oldset); - res = pthread_create(&w->thread_id, NULL, fuse_do_work, w); - pthread_sigmask(SIG_SETMASK, &oldset, NULL); - if (res != 0) { - fprintf(stderr, "fuse: error creating thread: %s\n", strerror(res)); - free(w->buf); - free(w); - return -1; - } - list_add_worker(w, &mt->main); - mt->numavail ++; - mt->numworker ++; - - return 0; + sigset_t oldset; + sigset_t newset; + int res; + struct fuse_worker *w = malloc(sizeof(struct fuse_worker)); + if (!w) { + fprintf(stderr, "fuse: failed to allocate worker structure\n"); + return -1; + } + memset(w, 0, sizeof(struct fuse_worker)); + w->bufsize = fuse_chan_bufsize(mt->prevch); + w->buf = malloc(w->bufsize); + w->mt = mt; + if (!w->buf) { + fprintf(stderr, "fuse: failed to allocate read buffer\n"); + free(w); + return -1; + } + + /* Disallow signal reception in worker threads */ + sigemptyset(&newset); + sigaddset(&newset, SIGTERM); + sigaddset(&newset, SIGINT); + sigaddset(&newset, SIGHUP); + sigaddset(&newset, SIGQUIT); + pthread_sigmask(SIG_BLOCK, &newset, &oldset); + res = pthread_create(&w->thread_id, NULL, fuse_do_work, w); + pthread_sigmask(SIG_SETMASK, &oldset, NULL); + if (res != 0) { + fprintf(stderr, "fuse: error creating thread: %s\n", + strerror(res)); + free(w->buf); + free(w); + return -1; + } + list_add_worker(w, &mt->main); + mt->numavail ++; + mt->numworker ++; + + return 0; } static void fuse_join_worker(struct fuse_mt *mt, struct fuse_worker *w) { - pthread_join(w->thread_id, NULL); - pthread_mutex_lock(&mt->lock); - list_del_worker(w); - pthread_mutex_unlock(&mt->lock); - free(w->buf); - free(w); + pthread_join(w->thread_id, NULL); + pthread_mutex_lock(&mt->lock); + list_del_worker(w); + pthread_mutex_unlock(&mt->lock); + free(w->buf); + free(w); } int fuse_session_loop_mt(struct fuse_session *se) { - int err; - struct fuse_mt mt; - struct fuse_worker *w; - - memset(&mt, 0, sizeof(struct fuse_mt)); - mt.se = se; - mt.prevch = fuse_session_next_chan(se, NULL); - mt.error = 0; - mt.numworker = 0; - mt.numavail = 0; - mt.main.thread_id = pthread_self(); - mt.main.prev = mt.main.next = &mt.main; - sem_init(&mt.finish, 0, 0); - fuse_mutex_init(&mt.lock); - - pthread_mutex_lock(&mt.lock); - err = fuse_start_thread(&mt); - pthread_mutex_unlock(&mt.lock); - if (!err) { - /* sem_wait() is interruptible */ - while (!fuse_session_exited(se)) - sem_wait(&mt.finish); - - for (w = mt.main.next; w != &mt.main; w = w->next) - pthread_cancel(w->thread_id); - mt.exit = 1; - pthread_mutex_unlock(&mt.lock); - - while (mt.main.next != &mt.main) - fuse_join_worker(&mt, mt.main.next); - - err = mt.error; - } - - pthread_mutex_destroy(&mt.lock); - sem_destroy(&mt.finish); - fuse_session_reset(se); - return err; + int err; + struct fuse_mt mt; + struct fuse_worker *w; + + memset(&mt, 0, sizeof(struct fuse_mt)); + mt.se = se; + mt.prevch = fuse_session_next_chan(se, NULL); + mt.error = 0; + mt.numworker = 0; + mt.numavail = 0; + mt.main.thread_id = pthread_self(); + mt.main.prev = mt.main.next = &mt.main; + sem_init(&mt.finish, 0, 0); + fuse_mutex_init(&mt.lock); + + pthread_mutex_lock(&mt.lock); + err = fuse_start_thread(&mt); + pthread_mutex_unlock(&mt.lock); + if (!err) { + /* sem_wait() is interruptible */ + while (!fuse_session_exited(se)) + sem_wait(&mt.finish); + + for (w = mt.main.next; w != &mt.main; w = w->next) + pthread_cancel(w->thread_id); + mt.exit = 1; + pthread_mutex_unlock(&mt.lock); + + while (mt.main.next != &mt.main) + fuse_join_worker(&mt, mt.main.next); + + err = mt.error; + } + + pthread_mutex_destroy(&mt.lock); + sem_destroy(&mt.finish); + fuse_session_reset(se); + return err; } diff --git a/lib/fuse_lowlevel.c b/lib/fuse_lowlevel.c index d39a4a1..5c9dc56 100644 --- a/lib/fuse_lowlevel.c +++ b/lib/fuse_lowlevel.c @@ -1,9 +1,9 @@ /* - FUSE: Filesystem in Userspace - Copyright (C) 2001-2007 Miklos Szeredi + FUSE: Filesystem in Userspace + Copyright (C) 2001-2007 Miklos Szeredi - This program can be distributed under the terms of the GNU LGPLv2. - See the file COPYING.LIB + This program can be distributed under the terms of the GNU LGPLv2. + See the file COPYING.LIB */ #include "fuse_lowlevel.h" @@ -28,1225 +28,1234 @@ struct fuse_ll; struct fuse_req { - struct fuse_ll *f; - uint64_t unique; - int ctr; - pthread_mutex_t lock; - struct fuse_ctx ctx; - struct fuse_chan *ch; - int interrupted; - union { - struct { - uint64_t unique; - } i; - struct { - fuse_interrupt_func_t func; - void *data; - } ni; - } u; - struct fuse_req *next; - struct fuse_req *prev; + struct fuse_ll *f; + uint64_t unique; + int ctr; + pthread_mutex_t lock; + struct fuse_ctx ctx; + struct fuse_chan *ch; + int interrupted; + union { + struct { + uint64_t unique; + } i; + struct { + fuse_interrupt_func_t func; + void *data; + } ni; + } u; + struct fuse_req *next; + struct fuse_req *prev; }; struct fuse_ll { - int debug; - int allow_root; - struct fuse_lowlevel_ops op; - int got_init; - void *userdata; - uid_t owner; - struct fuse_conn_info conn; - struct fuse_req list; - struct fuse_req interrupts; - pthread_mutex_t lock; - int got_destroy; + int debug; + int allow_root; + struct fuse_lowlevel_ops op; + int got_init; + void *userdata; + uid_t owner; + struct fuse_conn_info conn; + struct fuse_req list; + struct fuse_req interrupts; + pthread_mutex_t lock; + int got_destroy; }; static void convert_stat(const struct stat *stbuf, struct fuse_attr *attr) { - attr->ino = stbuf->st_ino; - attr->mode = stbuf->st_mode; - attr->nlink = stbuf->st_nlink; - attr->uid = stbuf->st_uid; - attr->gid = stbuf->st_gid; - attr->rdev = stbuf->st_rdev; - attr->size = stbuf->st_size; - attr->blocks = stbuf->st_blocks; - attr->atime = stbuf->st_atime; - attr->mtime = stbuf->st_mtime; - attr->ctime = stbuf->st_ctime; - attr->atimensec = ST_ATIM_NSEC(stbuf); - attr->mtimensec = ST_MTIM_NSEC(stbuf); - attr->ctimensec = ST_CTIM_NSEC(stbuf); + attr->ino = stbuf->st_ino; + attr->mode = stbuf->st_mode; + attr->nlink = stbuf->st_nlink; + attr->uid = stbuf->st_uid; + attr->gid = stbuf->st_gid; + attr->rdev = stbuf->st_rdev; + attr->size = stbuf->st_size; + attr->blocks = stbuf->st_blocks; + attr->atime = stbuf->st_atime; + attr->mtime = stbuf->st_mtime; + attr->ctime = stbuf->st_ctime; + attr->atimensec = ST_ATIM_NSEC(stbuf); + attr->mtimensec = ST_MTIM_NSEC(stbuf); + attr->ctimensec = ST_CTIM_NSEC(stbuf); } static void convert_attr(const struct fuse_setattr_in *attr, struct stat *stbuf) { - stbuf->st_mode = attr->mode; - stbuf->st_uid = attr->uid; - stbuf->st_gid = attr->gid; - stbuf->st_size = attr->size; - stbuf->st_atime = attr->atime; - stbuf->st_mtime = attr->mtime; - ST_ATIM_NSEC_SET(stbuf, attr->atimensec); - ST_MTIM_NSEC_SET(stbuf, attr->mtimensec); + stbuf->st_mode = attr->mode; + stbuf->st_uid = attr->uid; + stbuf->st_gid = attr->gid; + stbuf->st_size = attr->size; + stbuf->st_atime = attr->atime; + stbuf->st_mtime = attr->mtime; + ST_ATIM_NSEC_SET(stbuf, attr->atimensec); + ST_MTIM_NSEC_SET(stbuf, attr->mtimensec); } -static size_t iov_length(const struct iovec *iov, size_t count) +static size_t iov_length(const struct iovec *iov, size_t count) { - size_t seg; - size_t ret = 0; + size_t seg; + size_t ret = 0; - for (seg = 0; seg < count; seg++) - ret += iov[seg].iov_len; - return ret; + for (seg = 0; seg < count; seg++) + ret += iov[seg].iov_len; + return ret; } static void list_init_req(struct fuse_req *req) { - req->next = req; - req->prev = req; + req->next = req; + req->prev = req; } static void list_del_req(struct fuse_req *req) { - struct fuse_req *prev = req->prev; - struct fuse_req *next = req->next; - prev->next = next; - next->prev = prev; + struct fuse_req *prev = req->prev; + struct fuse_req *next = req->next; + prev->next = next; + next->prev = prev; } static void list_add_req(struct fuse_req *req, struct fuse_req *next) { - struct fuse_req *prev = next->prev; - req->next = next; - req->prev = prev; - prev->next = req; - next->prev = req; + struct fuse_req *prev = next->prev; + req->next = next; + req->prev = prev; + prev->next = req; + next->prev = req; } static void destroy_req(fuse_req_t req) { - pthread_mutex_destroy(&req->lock); - free(req); + pthread_mutex_destroy(&req->lock); + free(req); } static void free_req(fuse_req_t req) { - int ctr; - struct fuse_ll *f = req->f; + int ctr; + struct fuse_ll *f = req->f; - pthread_mutex_lock(&req->lock); - req->u.ni.func = NULL; - req->u.ni.data = NULL; - pthread_mutex_unlock(&req->lock); + pthread_mutex_lock(&req->lock); + req->u.ni.func = NULL; + req->u.ni.data = NULL; + pthread_mutex_unlock(&req->lock); - pthread_mutex_lock(&f->lock); - list_del_req(req); - ctr = --req->ctr; - pthread_mutex_unlock(&f->lock); - if (!ctr) - destroy_req(req); + pthread_mutex_lock(&f->lock); + list_del_req(req); + ctr = --req->ctr; + pthread_mutex_unlock(&f->lock); + if (!ctr) + destroy_req(req); } static int send_reply_iov(fuse_req_t req, int error, struct iovec *iov, - int count) + int count) { - struct fuse_out_header out; - int res; + struct fuse_out_header out; + int res; - if (error <= -1000 || error > 0) { - fprintf(stderr, "fuse: bad error value: %i\n", error); - error = -ERANGE; - } + if (error <= -1000 || error > 0) { + fprintf(stderr, "fuse: bad error value: %i\n", error); + error = -ERANGE; + } - out.unique = req->unique; - out.error = error; - iov[0].iov_base = &out; - iov[0].iov_len = sizeof(struct fuse_out_header); - out.len = iov_length(iov, count); + out.unique = req->unique; + out.error = error; + iov[0].iov_base = &out; + iov[0].iov_len = sizeof(struct fuse_out_header); + out.len = iov_length(iov, count); - if (req->f->debug) - fprintf(stderr, " unique: %llu, error: %i (%s), outsize: %i\n", - (unsigned long long) out.unique, out.error, - strerror(-out.error), out.len); - res = fuse_chan_send(req->ch, iov, count); - free_req(req); + if (req->f->debug) + fprintf(stderr, + " unique: %llu, error: %i (%s), outsize: %i\n", + (unsigned long long) out.unique, out.error, + strerror(-out.error), out.len); + res = fuse_chan_send(req->ch, iov, count); + free_req(req); - return res; + return res; } static int send_reply(fuse_req_t req, int error, const void *arg, - size_t argsize) + size_t argsize) { - struct iovec iov[2]; - int count = 1; - if (argsize) { - iov[1].iov_base = (void *) arg; - iov[1].iov_len = argsize; - count++; - } - return send_reply_iov(req, error, iov, count); + struct iovec iov[2]; + int count = 1; + if (argsize) { + iov[1].iov_base = (void *) arg; + iov[1].iov_len = argsize; + count++; + } + return send_reply_iov(req, error, iov, count); } int fuse_reply_iov(fuse_req_t req, const struct iovec *iov, int count) { - int res; - struct iovec *padded_iov; + int res; + struct iovec *padded_iov; - padded_iov = malloc((count + 1) * sizeof(struct iovec)); - if (padded_iov == NULL) - return fuse_reply_err(req, -ENOMEM); + padded_iov = malloc((count + 1) * sizeof(struct iovec)); + if (padded_iov == NULL) + return fuse_reply_err(req, -ENOMEM); - memcpy(padded_iov + 1, iov, count * sizeof(struct iovec)); - count++; + memcpy(padded_iov + 1, iov, count * sizeof(struct iovec)); + count++; - res = send_reply_iov(req, 0, padded_iov, count); - free(padded_iov); + res = send_reply_iov(req, 0, padded_iov, count); + free(padded_iov); - return res; + return res; } size_t fuse_dirent_size(size_t namelen) { - return FUSE_DIRENT_ALIGN(FUSE_NAME_OFFSET + namelen); + return FUSE_DIRENT_ALIGN(FUSE_NAME_OFFSET + namelen); } char *fuse_add_dirent(char *buf, const char *name, const struct stat *stbuf, - off_t off) + off_t off) { - unsigned namelen = strlen(name); - unsigned entlen = FUSE_NAME_OFFSET + namelen; - unsigned entsize = fuse_dirent_size(namelen); - unsigned padlen = entsize - entlen; - struct fuse_dirent *dirent = (struct fuse_dirent *) buf; + unsigned namelen = strlen(name); + unsigned entlen = FUSE_NAME_OFFSET + namelen; + unsigned entsize = fuse_dirent_size(namelen); + unsigned padlen = entsize - entlen; + struct fuse_dirent *dirent = (struct fuse_dirent *) buf; - dirent->ino = stbuf->st_ino; - dirent->off = off; - dirent->namelen = namelen; - dirent->type = (stbuf->st_mode & 0170000) >> 12; - strncpy(dirent->name, name, namelen); - if (padlen) - memset(buf + entlen, 0, padlen); + dirent->ino = stbuf->st_ino; + dirent->off = off; + dirent->namelen = namelen; + dirent->type = (stbuf->st_mode & 0170000) >> 12; + strncpy(dirent->name, name, namelen); + if (padlen) + memset(buf + entlen, 0, padlen); - return buf + entsize; + return buf + entsize; } size_t fuse_add_direntry(fuse_req_t req, char *buf, size_t bufsize, - const char *name, const struct stat *stbuf, off_t off) + const char *name, const struct stat *stbuf, off_t off) { - size_t entsize; + size_t entsize; - (void) req; - entsize = fuse_dirent_size(strlen(name)); - if (entsize <= bufsize && buf) - fuse_add_dirent(buf, name, stbuf, off); - return entsize; + (void) req; + entsize = fuse_dirent_size(strlen(name)); + if (entsize <= bufsize && buf) + fuse_add_dirent(buf, name, stbuf, off); + return entsize; } static void convert_statfs(const struct statvfs *stbuf, - struct fuse_kstatfs *kstatfs) + struct fuse_kstatfs *kstatfs) { - kstatfs->bsize = stbuf->f_bsize; - kstatfs->frsize = stbuf->f_frsize; - kstatfs->blocks = stbuf->f_blocks; - kstatfs->bfree = stbuf->f_bfree; - kstatfs->bavail = stbuf->f_bavail; - kstatfs->files = stbuf->f_files; - kstatfs->ffree = stbuf->f_ffree; - kstatfs->namelen = stbuf->f_namemax; + kstatfs->bsize = stbuf->f_bsize; + kstatfs->frsize = stbuf->f_frsize; + kstatfs->blocks = stbuf->f_blocks; + kstatfs->bfree = stbuf->f_bfree; + kstatfs->bavail = stbuf->f_bavail; + kstatfs->files = stbuf->f_files; + kstatfs->ffree = stbuf->f_ffree; + kstatfs->namelen = stbuf->f_namemax; } static int send_reply_ok(fuse_req_t req, const void *arg, size_t argsize) { - return send_reply(req, 0, arg, argsize); + return send_reply(req, 0, arg, argsize); } int fuse_reply_err(fuse_req_t req, int err) { - return send_reply(req, -err, NULL, 0); + return send_reply(req, -err, NULL, 0); } void fuse_reply_none(fuse_req_t req) { - fuse_chan_send(req->ch, NULL, 0); - free_req(req); + fuse_chan_send(req->ch, NULL, 0); + free_req(req); } static unsigned long calc_timeout_sec(double t) { - if (t > (double) ULONG_MAX) - return ULONG_MAX; - else if (t < 0.0) - return 0; - else - return (unsigned long) t; + if (t > (double) ULONG_MAX) + return ULONG_MAX; + else if (t < 0.0) + return 0; + else + return (unsigned long) t; } static unsigned int calc_timeout_nsec(double t) { - double f = t - (double) calc_timeout_sec(t); - if (f < 0.0) - return 0; - else if (f >= 0.999999999) - return 999999999; - else - return (unsigned int) (f * 1.0e9); + double f = t - (double) calc_timeout_sec(t); + if (f < 0.0) + return 0; + else if (f >= 0.999999999) + return 999999999; + else + return (unsigned int) (f * 1.0e9); } static void fill_entry(struct fuse_entry_out *arg, - const struct fuse_entry_param *e) + const struct fuse_entry_param *e) { - arg->nodeid = e->ino; - arg->generation = e->generation; - arg->entry_valid = calc_timeout_sec(e->entry_timeout); - arg->entry_valid_nsec = calc_timeout_nsec(e->entry_timeout); - arg->attr_valid = calc_timeout_sec(e->attr_timeout); - arg->attr_valid_nsec = calc_timeout_nsec(e->attr_timeout); - convert_stat(&e->attr, &arg->attr); + arg->nodeid = e->ino; + arg->generation = e->generation; + arg->entry_valid = calc_timeout_sec(e->entry_timeout); + arg->entry_valid_nsec = calc_timeout_nsec(e->entry_timeout); + arg->attr_valid = calc_timeout_sec(e->attr_timeout); + arg->attr_valid_nsec = calc_timeout_nsec(e->attr_timeout); + convert_stat(&e->attr, &arg->attr); } static void fill_open(struct fuse_open_out *arg, - const struct fuse_file_info *f) + const struct fuse_file_info *f) { - arg->fh = f->fh; - if (f->direct_io) - arg->open_flags |= FOPEN_DIRECT_IO; - if (f->keep_cache) - arg->open_flags |= FOPEN_KEEP_CACHE; + arg->fh = f->fh; + if (f->direct_io) + arg->open_flags |= FOPEN_DIRECT_IO; + if (f->keep_cache) + arg->open_flags |= FOPEN_KEEP_CACHE; } int fuse_reply_entry(fuse_req_t req, const struct fuse_entry_param *e) { - struct fuse_entry_out arg; + struct fuse_entry_out arg; - /* before ABI 7.4 e->ino == 0 was invalid, only ENOENT meant - negative entry */ - if (!e->ino && req->f->conn.proto_minor < 4) - return fuse_reply_err(req, ENOENT); + /* before ABI 7.4 e->ino == 0 was invalid, only ENOENT meant + negative entry */ + if (!e->ino && req->f->conn.proto_minor < 4) + return fuse_reply_err(req, ENOENT); - memset(&arg, 0, sizeof(arg)); - fill_entry(&arg, e); - return send_reply_ok(req, &arg, sizeof(arg)); + memset(&arg, 0, sizeof(arg)); + fill_entry(&arg, e); + return send_reply_ok(req, &arg, sizeof(arg)); } int fuse_reply_create(fuse_req_t req, const struct fuse_entry_param *e, - const struct fuse_file_info *f) + const struct fuse_file_info *f) { - struct { - struct fuse_entry_out e; - struct fuse_open_out o; - } arg; + struct { + struct fuse_entry_out e; + struct fuse_open_out o; + } arg; - memset(&arg, 0, sizeof(arg)); - fill_entry(&arg.e, e); - fill_open(&arg.o, f); - return send_reply_ok(req, &arg, sizeof(arg)); + memset(&arg, 0, sizeof(arg)); + fill_entry(&arg.e, e); + fill_open(&arg.o, f); + return send_reply_ok(req, &arg, sizeof(arg)); } int fuse_reply_attr(fuse_req_t req, const struct stat *attr, - double attr_timeout) + double attr_timeout) { - struct fuse_attr_out arg; + struct fuse_attr_out arg; - memset(&arg, 0, sizeof(arg)); - arg.attr_valid = calc_timeout_sec(attr_timeout); - arg.attr_valid_nsec = calc_timeout_nsec(attr_timeout); - convert_stat(attr, &arg.attr); + memset(&arg, 0, sizeof(arg)); + arg.attr_valid = calc_timeout_sec(attr_timeout); + arg.attr_valid_nsec = calc_timeout_nsec(attr_timeout); + convert_stat(attr, &arg.attr); - return send_reply_ok(req, &arg, sizeof(arg)); + return send_reply_ok(req, &arg, sizeof(arg)); } int fuse_reply_readlink(fuse_req_t req, const char *linkname) { - return send_reply_ok(req, linkname, strlen(linkname)); + return send_reply_ok(req, linkname, strlen(linkname)); } int fuse_reply_open(fuse_req_t req, const struct fuse_file_info *f) { - struct fuse_open_out arg; + struct fuse_open_out arg; - memset(&arg, 0, sizeof(arg)); - fill_open(&arg, f); - return send_reply_ok(req, &arg, sizeof(arg)); + memset(&arg, 0, sizeof(arg)); + fill_open(&arg, f); + return send_reply_ok(req, &arg, sizeof(arg)); } int fuse_reply_write(fuse_req_t req, size_t count) { - struct fuse_write_out arg; + struct fuse_write_out arg; - memset(&arg, 0, sizeof(arg)); - arg.size = count; + memset(&arg, 0, sizeof(arg)); + arg.size = count; - return send_reply_ok(req, &arg, sizeof(arg)); + return send_reply_ok(req, &arg, sizeof(arg)); } int fuse_reply_buf(fuse_req_t req, const char *buf, size_t size) { - return send_reply_ok(req, buf, size); + return send_reply_ok(req, buf, size); } int fuse_reply_statfs(fuse_req_t req, const struct statvfs *stbuf) { - struct fuse_statfs_out arg; - size_t size = req->f->conn.proto_minor < 4 ? FUSE_COMPAT_STATFS_SIZE : sizeof(arg); + struct fuse_statfs_out arg; + size_t size = req->f->conn.proto_minor < 4 ? + FUSE_COMPAT_STATFS_SIZE : sizeof(arg); - memset(&arg, 0, sizeof(arg)); - convert_statfs(stbuf, &arg.st); + memset(&arg, 0, sizeof(arg)); + convert_statfs(stbuf, &arg.st); - return send_reply_ok(req, &arg, size); + return send_reply_ok(req, &arg, size); } int fuse_reply_xattr(fuse_req_t req, size_t count) { - struct fuse_getxattr_out arg; + struct fuse_getxattr_out arg; - memset(&arg, 0, sizeof(arg)); - arg.size = count; + memset(&arg, 0, sizeof(arg)); + arg.size = count; - return send_reply_ok(req, &arg, sizeof(arg)); + return send_reply_ok(req, &arg, sizeof(arg)); } int fuse_reply_lock(fuse_req_t req, struct flock *lock) { - struct fuse_lk_out arg; + struct fuse_lk_out arg; - memset(&arg, 0, sizeof(arg)); - arg.lk.type = lock->l_type; - if (lock->l_type != F_UNLCK) { - arg.lk.start = lock->l_start; - if (lock->l_len == 0) - arg.lk.end = OFFSET_MAX; - else - arg.lk.end = lock->l_start + lock->l_len - 1; - } - arg.lk.pid = lock->l_pid; - return send_reply_ok(req, &arg, sizeof(arg)); + memset(&arg, 0, sizeof(arg)); + arg.lk.type = lock->l_type; + if (lock->l_type != F_UNLCK) { + arg.lk.start = lock->l_start; + if (lock->l_len == 0) + arg.lk.end = OFFSET_MAX; + else + arg.lk.end = lock->l_start + lock->l_len - 1; + } + arg.lk.pid = lock->l_pid; + return send_reply_ok(req, &arg, sizeof(arg)); } int fuse_reply_bmap(fuse_req_t req, uint64_t idx) { - struct fuse_bmap_out arg; + struct fuse_bmap_out arg; - memset(&arg, 0, sizeof(arg)); - arg.block = idx; + memset(&arg, 0, sizeof(arg)); + arg.block = idx; - return send_reply_ok(req, &arg, sizeof(arg)); + return send_reply_ok(req, &arg, sizeof(arg)); } static void do_lookup(fuse_req_t req, fuse_ino_t nodeid, const void *inarg) { - char *name = (char *) inarg; + char *name = (char *) inarg; - if (req->f->op.lookup) - req->f->op.lookup(req, nodeid, name); - else - fuse_reply_err(req, ENOSYS); + if (req->f->op.lookup) + req->f->op.lookup(req, nodeid, name); + else + fuse_reply_err(req, ENOSYS); } static void do_forget(fuse_req_t req, fuse_ino_t nodeid, const void *inarg) { - struct fuse_forget_in *arg = (struct fuse_forget_in *) inarg; + struct fuse_forget_in *arg = (struct fuse_forget_in *) inarg; - if (req->f->op.forget) - req->f->op.forget(req, nodeid, arg->nlookup); - else - fuse_reply_none(req); + if (req->f->op.forget) + req->f->op.forget(req, nodeid, arg->nlookup); + else + fuse_reply_none(req); } static void do_getattr(fuse_req_t req, fuse_ino_t nodeid, const void *inarg) { - (void) inarg; + (void) inarg; - if (req->f->op.getattr) - req->f->op.getattr(req, nodeid, NULL); - else - fuse_reply_err(req, ENOSYS); + if (req->f->op.getattr) + req->f->op.getattr(req, nodeid, NULL); + else + fuse_reply_err(req, ENOSYS); } static void do_setattr(fuse_req_t req, fuse_ino_t nodeid, const void *inarg) { - struct fuse_setattr_in *arg = (struct fuse_setattr_in *) inarg; - - if (req->f->op.setattr) { - struct fuse_file_info *fi = NULL; - struct fuse_file_info fi_store; - struct stat stbuf; - memset(&stbuf, 0, sizeof(stbuf)); - convert_attr(arg, &stbuf); - if (arg->valid & FATTR_FH) { - arg->valid &= ~FATTR_FH; - memset(&fi_store, 0, sizeof(fi_store)); - fi = &fi_store; - fi->fh = arg->fh; - fi->fh_old = fi->fh; - } - req->f->op.setattr(req, nodeid, &stbuf, arg->valid, fi); - } else - fuse_reply_err(req, ENOSYS); + struct fuse_setattr_in *arg = (struct fuse_setattr_in *) inarg; + + if (req->f->op.setattr) { + struct fuse_file_info *fi = NULL; + struct fuse_file_info fi_store; + struct stat stbuf; + memset(&stbuf, 0, sizeof(stbuf)); + convert_attr(arg, &stbuf); + if (arg->valid & FATTR_FH) { + arg->valid &= ~FATTR_FH; + memset(&fi_store, 0, sizeof(fi_store)); + fi = &fi_store; + fi->fh = arg->fh; + fi->fh_old = fi->fh; + } + req->f->op.setattr(req, nodeid, &stbuf, arg->valid, fi); + } else + fuse_reply_err(req, ENOSYS); } static void do_access(fuse_req_t req, fuse_ino_t nodeid, const void *inarg) { - struct fuse_access_in *arg = (struct fuse_access_in *) inarg; + struct fuse_access_in *arg = (struct fuse_access_in *) inarg; - if (req->f->op.access) - req->f->op.access(req, nodeid, arg->mask); - else - fuse_reply_err(req, ENOSYS); + if (req->f->op.access) + req->f->op.access(req, nodeid, arg->mask); + else + fuse_reply_err(req, ENOSYS); } static void do_readlink(fuse_req_t req, fuse_ino_t nodeid, const void *inarg) { - (void) inarg; + (void) inarg; - if (req->f->op.readlink) - req->f->op.readlink(req, nodeid); - else - fuse_reply_err(req, ENOSYS); + if (req->f->op.readlink) + req->f->op.readlink(req, nodeid); + else + fuse_reply_err(req, ENOSYS); } static void do_mknod(fuse_req_t req, fuse_ino_t nodeid, const void *inarg) { - struct fuse_mknod_in *arg = (struct fuse_mknod_in *) inarg; + struct fuse_mknod_in *arg = (struct fuse_mknod_in *) inarg; - if (req->f->op.mknod) - req->f->op.mknod(req, nodeid, PARAM(arg), arg->mode, arg->rdev); - else - fuse_reply_err(req, ENOSYS); + if (req->f->op.mknod) + req->f->op.mknod(req, nodeid, PARAM(arg), arg->mode, arg->rdev); + else + fuse_reply_err(req, ENOSYS); } static void do_mkdir(fuse_req_t req, fuse_ino_t nodeid, const void *inarg) { - struct fuse_mkdir_in *arg = (struct fuse_mkdir_in *) inarg; + struct fuse_mkdir_in *arg = (struct fuse_mkdir_in *) inarg; - if (req->f->op.mkdir) - req->f->op.mkdir(req, nodeid, PARAM(arg), arg->mode); - else - fuse_reply_err(req, ENOSYS); + if (req->f->op.mkdir) + req->f->op.mkdir(req, nodeid, PARAM(arg), arg->mode); + else + fuse_reply_err(req, ENOSYS); } static void do_unlink(fuse_req_t req, fuse_ino_t nodeid, const void *inarg) { - char *name = (char *) inarg; + char *name = (char *) inarg; - if (req->f->op.unlink) - req->f->op.unlink(req, nodeid, name); - else - fuse_reply_err(req, ENOSYS); + if (req->f->op.unlink) + req->f->op.unlink(req, nodeid, name); + else + fuse_reply_err(req, ENOSYS); } static void do_rmdir(fuse_req_t req, fuse_ino_t nodeid, const void *inarg) { - char *name = (char *) inarg; + char *name = (char *) inarg; - if (req->f->op.rmdir) - req->f->op.rmdir(req, nodeid, name); - else - fuse_reply_err(req, ENOSYS); + if (req->f->op.rmdir) + req->f->op.rmdir(req, nodeid, name); + else + fuse_reply_err(req, ENOSYS); } static void do_symlink(fuse_req_t req, fuse_ino_t nodeid, const void *inarg) { - char *name = (char *) inarg; - char *linkname = ((char *) inarg) + strlen((char *) inarg) + 1; + char *name = (char *) inarg; + char *linkname = ((char *) inarg) + strlen((char *) inarg) + 1; - if (req->f->op.symlink) - req->f->op.symlink(req, linkname, nodeid, name); - else - fuse_reply_err(req, ENOSYS); + if (req->f->op.symlink) + req->f->op.symlink(req, linkname, nodeid, name); + else + fuse_reply_err(req, ENOSYS); } static void do_rename(fuse_req_t req, fuse_ino_t nodeid, const void *inarg) { - struct fuse_rename_in *arg = (struct fuse_rename_in *) inarg; - char *oldname = PARAM(arg); - char *newname = oldname + strlen(oldname) + 1; + struct fuse_rename_in *arg = (struct fuse_rename_in *) inarg; + char *oldname = PARAM(arg); + char *newname = oldname + strlen(oldname) + 1; - if (req->f->op.rename) - req->f->op.rename(req, nodeid, oldname, arg->newdir, newname); - else - fuse_reply_err(req, ENOSYS); + if (req->f->op.rename) + req->f->op.rename(req, nodeid, oldname, arg->newdir, newname); + else + fuse_reply_err(req, ENOSYS); } static void do_link(fuse_req_t req, fuse_ino_t nodeid, const void *inarg) { - struct fuse_link_in *arg = (struct fuse_link_in *) inarg; + struct fuse_link_in *arg = (struct fuse_link_in *) inarg; - if (req->f->op.link) - req->f->op.link(req, arg->oldnodeid, nodeid, PARAM(arg)); - else - fuse_reply_err(req, ENOSYS); + if (req->f->op.link) + req->f->op.link(req, arg->oldnodeid, nodeid, PARAM(arg)); + else + fuse_reply_err(req, ENOSYS); } static void do_create(fuse_req_t req, fuse_ino_t nodeid, const void *inarg) { - struct fuse_open_in *arg = (struct fuse_open_in *) inarg; + struct fuse_open_in *arg = (struct fuse_open_in *) inarg; - if (req->f->op.create) { - struct fuse_file_info fi; + if (req->f->op.create) { + struct fuse_file_info fi; - memset(&fi, 0, sizeof(fi)); - fi.flags = arg->flags; + memset(&fi, 0, sizeof(fi)); + fi.flags = arg->flags; - req->f->op.create(req, nodeid, PARAM(arg), arg->mode, &fi); - } else - fuse_reply_err(req, ENOSYS); + req->f->op.create(req, nodeid, PARAM(arg), arg->mode, &fi); + } else + fuse_reply_err(req, ENOSYS); } static void do_open(fuse_req_t req, fuse_ino_t nodeid, const void *inarg) { - struct fuse_open_in *arg = (struct fuse_open_in *) inarg; - struct fuse_file_info fi; + struct fuse_open_in *arg = (struct fuse_open_in *) inarg; + struct fuse_file_info fi; - memset(&fi, 0, sizeof(fi)); - fi.flags = arg->flags; + memset(&fi, 0, sizeof(fi)); + fi.flags = arg->flags; - if (req->f->op.open) - req->f->op.open(req, nodeid, &fi); - else - fuse_reply_open(req, &fi); + if (req->f->op.open) + req->f->op.open(req, nodeid, &fi); + else + fuse_reply_open(req, &fi); } static void do_read(fuse_req_t req, fuse_ino_t nodeid, const void *inarg) { - struct fuse_read_in *arg = (struct fuse_read_in *) inarg; + struct fuse_read_in *arg = (struct fuse_read_in *) inarg; - if (req->f->op.read) { - struct fuse_file_info fi; + if (req->f->op.read) { + struct fuse_file_info fi; - memset(&fi, 0, sizeof(fi)); - fi.fh = arg->fh; - fi.fh_old = fi.fh; - req->f->op.read(req, nodeid, arg->size, arg->offset, &fi); - } else - fuse_reply_err(req, ENOSYS); + memset(&fi, 0, sizeof(fi)); + fi.fh = arg->fh; + fi.fh_old = fi.fh; + req->f->op.read(req, nodeid, arg->size, arg->offset, &fi); + } else + fuse_reply_err(req, ENOSYS); } static void do_write(fuse_req_t req, fuse_ino_t nodeid, const void *inarg) { - struct fuse_write_in *arg = (struct fuse_write_in *) inarg; - struct fuse_file_info fi; + struct fuse_write_in *arg = (struct fuse_write_in *) inarg; + struct fuse_file_info fi; - memset(&fi, 0, sizeof(fi)); - fi.fh = arg->fh; - fi.fh_old = fi.fh; - fi.writepage = arg->write_flags & 1; + memset(&fi, 0, sizeof(fi)); + fi.fh = arg->fh; + fi.fh_old = fi.fh; + fi.writepage = arg->write_flags & 1; - if (req->f->op.write) - req->f->op.write(req, nodeid, PARAM(arg), arg->size, arg->offset, &fi); - else - fuse_reply_err(req, ENOSYS); + if (req->f->op.write) + req->f->op.write(req, nodeid, PARAM(arg), arg->size, + arg->offset, &fi); + else + fuse_reply_err(req, ENOSYS); } static void do_flush(fuse_req_t req, fuse_ino_t nodeid, const void *inarg) { - struct fuse_flush_in *arg = (struct fuse_flush_in *) inarg; - struct fuse_file_info fi; + struct fuse_flush_in *arg = (struct fuse_flush_in *) inarg; + struct fuse_file_info fi; - memset(&fi, 0, sizeof(fi)); - fi.fh = arg->fh; - fi.fh_old = fi.fh; - fi.flush = 1; - if (req->f->conn.proto_minor >= 7) - fi.lock_owner = arg->lock_owner; + memset(&fi, 0, sizeof(fi)); + fi.fh = arg->fh; + fi.fh_old = fi.fh; + fi.flush = 1; + if (req->f->conn.proto_minor >= 7) + fi.lock_owner = arg->lock_owner; - if (req->f->op.flush) - req->f->op.flush(req, nodeid, &fi); - else - fuse_reply_err(req, ENOSYS); + if (req->f->op.flush) + req->f->op.flush(req, nodeid, &fi); + else + fuse_reply_err(req, ENOSYS); } static void do_release(fuse_req_t req, fuse_ino_t nodeid, const void *inarg) { - struct fuse_release_in *arg = (struct fuse_release_in *) inarg; - struct fuse_file_info fi; + struct fuse_release_in *arg = (struct fuse_release_in *) inarg; + struct fuse_file_info fi; - memset(&fi, 0, sizeof(fi)); - fi.flags = arg->flags; - fi.fh = arg->fh; - fi.fh_old = fi.fh; - if (req->f->conn.proto_minor >= 8) { - fi.flush = (arg->release_flags & FUSE_RELEASE_FLUSH) ? 1 : 0; - fi.lock_owner = arg->lock_owner; - } + memset(&fi, 0, sizeof(fi)); + fi.flags = arg->flags; + fi.fh = arg->fh; + fi.fh_old = fi.fh; + if (req->f->conn.proto_minor >= 8) { + fi.flush = (arg->release_flags & FUSE_RELEASE_FLUSH) ? 1 : 0; + fi.lock_owner = arg->lock_owner; + } - if (req->f->op.release) - req->f->op.release(req, nodeid, &fi); - else - fuse_reply_err(req, 0); + if (req->f->op.release) + req->f->op.release(req, nodeid, &fi); + else + fuse_reply_err(req, 0); } static void do_fsync(fuse_req_t req, fuse_ino_t nodeid, const void *inarg) { - struct fuse_fsync_in *arg = (struct fuse_fsync_in *) inarg; - struct fuse_file_info fi; + struct fuse_fsync_in *arg = (struct fuse_fsync_in *) inarg; + struct fuse_file_info fi; - memset(&fi, 0, sizeof(fi)); - fi.fh = arg->fh; - fi.fh_old = fi.fh; + memset(&fi, 0, sizeof(fi)); + fi.fh = arg->fh; + fi.fh_old = fi.fh; - if (req->f->op.fsync) - req->f->op.fsync(req, nodeid, arg->fsync_flags & 1, &fi); - else - fuse_reply_err(req, ENOSYS); + if (req->f->op.fsync) + req->f->op.fsync(req, nodeid, arg->fsync_flags & 1, &fi); + else + fuse_reply_err(req, ENOSYS); } static void do_opendir(fuse_req_t req, fuse_ino_t nodeid, const void *inarg) { - struct fuse_open_in *arg = (struct fuse_open_in *) inarg; - struct fuse_file_info fi; + struct fuse_open_in *arg = (struct fuse_open_in *) inarg; + struct fuse_file_info fi; - memset(&fi, 0, sizeof(fi)); - fi.flags = arg->flags; + memset(&fi, 0, sizeof(fi)); + fi.flags = arg->flags; - if (req->f->op.opendir) - req->f->op.opendir(req, nodeid, &fi); - else - fuse_reply_open(req, &fi); + if (req->f->op.opendir) + req->f->op.opendir(req, nodeid, &fi); + else + fuse_reply_open(req, &fi); } static void do_readdir(fuse_req_t req, fuse_ino_t nodeid, const void *inarg) { - struct fuse_read_in *arg = (struct fuse_read_in *) inarg; - struct fuse_file_info fi; + struct fuse_read_in *arg = (struct fuse_read_in *) inarg; + struct fuse_file_info fi; - memset(&fi, 0, sizeof(fi)); - fi.fh = arg->fh; - fi.fh_old = fi.fh; + memset(&fi, 0, sizeof(fi)); + fi.fh = arg->fh; + fi.fh_old = fi.fh; - if (req->f->op.readdir) - req->f->op.readdir(req, nodeid, arg->size, arg->offset, &fi); - else - fuse_reply_err(req, ENOSYS); + if (req->f->op.readdir) + req->f->op.readdir(req, nodeid, arg->size, arg->offset, &fi); + else + fuse_reply_err(req, ENOSYS); } static void do_releasedir(fuse_req_t req, fuse_ino_t nodeid, const void *inarg) { - struct fuse_release_in *arg = (struct fuse_release_in *) inarg; - struct fuse_file_info fi; + struct fuse_release_in *arg = (struct fuse_release_in *) inarg; + struct fuse_file_info fi; - memset(&fi, 0, sizeof(fi)); - fi.flags = arg->flags; - fi.fh = arg->fh; - fi.fh_old = fi.fh; + memset(&fi, 0, sizeof(fi)); + fi.flags = arg->flags; + fi.fh = arg->fh; + fi.fh_old = fi.fh; - if (req->f->op.releasedir) - req->f->op.releasedir(req, nodeid, &fi); - else - fuse_reply_err(req, 0); + if (req->f->op.releasedir) + req->f->op.releasedir(req, nodeid, &fi); + else + fuse_reply_err(req, 0); } static void do_fsyncdir(fuse_req_t req, fuse_ino_t nodeid, const void *inarg) { - struct fuse_fsync_in *arg = (struct fuse_fsync_in *) inarg; - struct fuse_file_info fi; + struct fuse_fsync_in *arg = (struct fuse_fsync_in *) inarg; + struct fuse_file_info fi; - memset(&fi, 0, sizeof(fi)); - fi.fh = arg->fh; - fi.fh_old = fi.fh; + memset(&fi, 0, sizeof(fi)); + fi.fh = arg->fh; + fi.fh_old = fi.fh; - if (req->f->op.fsyncdir) - req->f->op.fsyncdir(req, nodeid, arg->fsync_flags & 1, &fi); - else - fuse_reply_err(req, ENOSYS); + if (req->f->op.fsyncdir) + req->f->op.fsyncdir(req, nodeid, arg->fsync_flags & 1, &fi); + else + fuse_reply_err(req, ENOSYS); } static void do_statfs(fuse_req_t req, fuse_ino_t nodeid, const void *inarg) { - (void) nodeid; - (void) inarg; + (void) nodeid; + (void) inarg; - if (req->f->op.statfs) - req->f->op.statfs(req, nodeid); - else { - struct statvfs buf = { - .f_namemax = 255, - .f_bsize = 512, - }; - fuse_reply_statfs(req, &buf); - } + if (req->f->op.statfs) + req->f->op.statfs(req, nodeid); + else { + struct statvfs buf = { + .f_namemax = 255, + .f_bsize = 512, + }; + fuse_reply_statfs(req, &buf); + } } static void do_setxattr(fuse_req_t req, fuse_ino_t nodeid, const void *inarg) { - struct fuse_setxattr_in *arg = (struct fuse_setxattr_in *) inarg; - char *name = PARAM(arg); - char *value = name + strlen(name) + 1; + struct fuse_setxattr_in *arg = (struct fuse_setxattr_in *) inarg; + char *name = PARAM(arg); + char *value = name + strlen(name) + 1; - if (req->f->op.setxattr) - req->f->op.setxattr(req, nodeid, name, value, arg->size, arg->flags); - else - fuse_reply_err(req, ENOSYS); + if (req->f->op.setxattr) + req->f->op.setxattr(req, nodeid, name, value, arg->size, + arg->flags); + else + fuse_reply_err(req, ENOSYS); } static void do_getxattr(fuse_req_t req, fuse_ino_t nodeid, const void *inarg) { - struct fuse_getxattr_in *arg = (struct fuse_getxattr_in *) inarg; + struct fuse_getxattr_in *arg = (struct fuse_getxattr_in *) inarg; - if (req->f->op.getxattr) - req->f->op.getxattr(req, nodeid, PARAM(arg), arg->size); - else - fuse_reply_err(req, ENOSYS); + if (req->f->op.getxattr) + req->f->op.getxattr(req, nodeid, PARAM(arg), arg->size); + else + fuse_reply_err(req, ENOSYS); } static void do_listxattr(fuse_req_t req, fuse_ino_t nodeid, const void *inarg) { - struct fuse_getxattr_in *arg = (struct fuse_getxattr_in *) inarg; + struct fuse_getxattr_in *arg = (struct fuse_getxattr_in *) inarg; - if (req->f->op.listxattr) - req->f->op.listxattr(req, nodeid, arg->size); - else - fuse_reply_err(req, ENOSYS); + if (req->f->op.listxattr) + req->f->op.listxattr(req, nodeid, arg->size); + else + fuse_reply_err(req, ENOSYS); } static void do_removexattr(fuse_req_t req, fuse_ino_t nodeid, const void *inarg) { - char *name = (char *) inarg; + char *name = (char *) inarg; - if (req->f->op.removexattr) - req->f->op.removexattr(req, nodeid, name); - else - fuse_reply_err(req, ENOSYS); + if (req->f->op.removexattr) + req->f->op.removexattr(req, nodeid, name); + else + fuse_reply_err(req, ENOSYS); } static void convert_fuse_file_lock(struct fuse_file_lock *fl, - struct flock *flock) + struct flock *flock) { - memset(flock, 0, sizeof(struct flock)); - flock->l_type = fl->type; - flock->l_whence = SEEK_SET; - flock->l_start = fl->start; - if (fl->end == OFFSET_MAX) - flock->l_len = 0; - else - flock->l_len = fl->end - fl->start + 1; - flock->l_pid = fl->pid; + memset(flock, 0, sizeof(struct flock)); + flock->l_type = fl->type; + flock->l_whence = SEEK_SET; + flock->l_start = fl->start; + if (fl->end == OFFSET_MAX) + flock->l_len = 0; + else + flock->l_len = fl->end - fl->start + 1; + flock->l_pid = fl->pid; } static void do_getlk(fuse_req_t req, fuse_ino_t nodeid, const void *inarg) { - struct fuse_lk_in *arg = (struct fuse_lk_in *) inarg; - struct fuse_file_info fi; - struct flock flock; + struct fuse_lk_in *arg = (struct fuse_lk_in *) inarg; + struct fuse_file_info fi; + struct flock flock; - memset(&fi, 0, sizeof(fi)); - fi.fh = arg->fh; - fi.lock_owner = arg->owner; + memset(&fi, 0, sizeof(fi)); + fi.fh = arg->fh; + fi.lock_owner = arg->owner; - convert_fuse_file_lock(&arg->lk, &flock); - if (req->f->op.getlk) - req->f->op.getlk(req, nodeid, &fi, &flock); - else - fuse_reply_err(req, ENOSYS); + convert_fuse_file_lock(&arg->lk, &flock); + if (req->f->op.getlk) + req->f->op.getlk(req, nodeid, &fi, &flock); + else + fuse_reply_err(req, ENOSYS); } static void do_setlk_common(fuse_req_t req, fuse_ino_t nodeid, - const void *inarg, int sleep) + const void *inarg, int sleep) { - struct fuse_lk_in *arg = (struct fuse_lk_in *) inarg; - struct fuse_file_info fi; - struct flock flock; + struct fuse_lk_in *arg = (struct fuse_lk_in *) inarg; + struct fuse_file_info fi; + struct flock flock; - memset(&fi, 0, sizeof(fi)); - fi.fh = arg->fh; - fi.lock_owner = arg->owner; + memset(&fi, 0, sizeof(fi)); + fi.fh = arg->fh; + fi.lock_owner = arg->owner; - convert_fuse_file_lock(&arg->lk, &flock); - if (req->f->op.setlk) - req->f->op.setlk(req, nodeid, &fi, &flock, sleep); - else - fuse_reply_err(req, ENOSYS); + convert_fuse_file_lock(&arg->lk, &flock); + if (req->f->op.setlk) + req->f->op.setlk(req, nodeid, &fi, &flock, sleep); + else + fuse_reply_err(req, ENOSYS); } static void do_setlk(fuse_req_t req, fuse_ino_t nodeid, const void *inarg) { - do_setlk_common(req, nodeid, inarg, 0); + do_setlk_common(req, nodeid, inarg, 0); } static void do_setlkw(fuse_req_t req, fuse_ino_t nodeid, const void *inarg) { - do_setlk_common(req, nodeid, inarg, 1); + do_setlk_common(req, nodeid, inarg, 1); } static int find_interrupted(struct fuse_ll *f, struct fuse_req *req) { - struct fuse_req *curr; - - for (curr = f->list.next; curr != &f->list; curr = curr->next) { - if (curr->unique == req->u.i.unique) { - curr->ctr++; - pthread_mutex_unlock(&f->lock); - - /* Ugh, ugly locking */ - pthread_mutex_lock(&curr->lock); - pthread_mutex_lock(&f->lock); - curr->interrupted = 1; - pthread_mutex_unlock(&f->lock); - if (curr->u.ni.func) - curr->u.ni.func(curr, curr->u.ni.data); - pthread_mutex_unlock(&curr->lock); - - pthread_mutex_lock(&f->lock); - curr->ctr--; - if (!curr->ctr) - destroy_req(curr); - - return 1; - } - } - for (curr = f->interrupts.next; curr != &f->interrupts; - curr = curr->next) { - if (curr->u.i.unique == req->u.i.unique) - return 1; - } - return 0; + struct fuse_req *curr; + + for (curr = f->list.next; curr != &f->list; curr = curr->next) { + if (curr->unique == req->u.i.unique) { + curr->ctr++; + pthread_mutex_unlock(&f->lock); + + /* Ugh, ugly locking */ + pthread_mutex_lock(&curr->lock); + pthread_mutex_lock(&f->lock); + curr->interrupted = 1; + pthread_mutex_unlock(&f->lock); + if (curr->u.ni.func) + curr->u.ni.func(curr, curr->u.ni.data); + pthread_mutex_unlock(&curr->lock); + + pthread_mutex_lock(&f->lock); + curr->ctr--; + if (!curr->ctr) + destroy_req(curr); + + return 1; + } + } + for (curr = f->interrupts.next; curr != &f->interrupts; + curr = curr->next) { + if (curr->u.i.unique == req->u.i.unique) + return 1; + } + return 0; } static void do_interrupt(fuse_req_t req, fuse_ino_t nodeid, const void *inarg) { - struct fuse_interrupt_in *arg = (struct fuse_interrupt_in *) inarg; - struct fuse_ll *f = req->f; + struct fuse_interrupt_in *arg = (struct fuse_interrupt_in *) inarg; + struct fuse_ll *f = req->f; - (void) nodeid; - if (f->debug) - fprintf(stderr, "INTERRUPT: %llu\n", (unsigned long long) arg->unique); + (void) nodeid; + if (f->debug) + fprintf(stderr, "INTERRUPT: %llu\n", + (unsigned long long) arg->unique); - req->u.i.unique = arg->unique; + req->u.i.unique = arg->unique; - pthread_mutex_lock(&f->lock); - if (find_interrupted(f, req)) - destroy_req(req); - else - list_add_req(req, &f->interrupts); - pthread_mutex_unlock(&f->lock); + pthread_mutex_lock(&f->lock); + if (find_interrupted(f, req)) + destroy_req(req); + else + list_add_req(req, &f->interrupts); + pthread_mutex_unlock(&f->lock); } static struct fuse_req *check_interrupt(struct fuse_ll *f, struct fuse_req *req) { - struct fuse_req *curr; - - for (curr = f->interrupts.next; curr != &f->interrupts; curr = curr->next) { - if (curr->u.i.unique == req->unique) { - req->interrupted = 1; - list_del_req(curr); - free(curr); - return NULL; - } - } - curr = f->interrupts.next; - if (curr != &f->interrupts) { - list_del_req(curr); - list_init_req(curr); - return curr; - } else - return NULL; + struct fuse_req *curr; + + for (curr = f->interrupts.next; curr != &f->interrupts; + curr = curr->next) { + if (curr->u.i.unique == req->unique) { + req->interrupted = 1; + list_del_req(curr); + free(curr); + return NULL; + } + } + curr = f->interrupts.next; + if (curr != &f->interrupts) { + list_del_req(curr); + list_init_req(curr); + return curr; + } else + return NULL; } static void do_bmap(fuse_req_t req, fuse_ino_t nodeid, const void *inarg) { - struct fuse_bmap_in *arg = (struct fuse_bmap_in *) inarg; + struct fuse_bmap_in *arg = (struct fuse_bmap_in *) inarg; - if (req->f->op.bmap) - req->f->op.bmap(req, nodeid, arg->blocksize, arg->block); - else - fuse_reply_err(req, ENOSYS); + if (req->f->op.bmap) + req->f->op.bmap(req, nodeid, arg->blocksize, arg->block); + else + fuse_reply_err(req, ENOSYS); } static void do_init(fuse_req_t req, fuse_ino_t nodeid, const void *inarg) { - struct fuse_init_in *arg = (struct fuse_init_in *) inarg; - struct fuse_init_out outarg; - struct fuse_ll *f = req->f; - size_t bufsize = fuse_chan_bufsize(req->ch); - - (void) nodeid; - if (f->debug) { - fprintf(stderr, "INIT: %u.%u\n", arg->major, arg->minor); - if (arg->major > 7 || (arg->major == 7 && arg->minor >= 6)) { - fprintf(stderr, "flags=0x%08x\n", arg->flags); - fprintf(stderr, "max_readahead=0x%08x\n", arg->max_readahead); - } - } - f->conn.proto_major = arg->major; - f->conn.proto_minor = arg->minor; - - if (arg->major < 7) { - fprintf(stderr, "fuse: unsupported protocol version: %u.%u\n", - arg->major, arg->minor); - fuse_reply_err(req, EPROTO); - return; - } - - if (arg->major > 7 || (arg->major == 7 && arg->minor >= 6)) { - if (f->conn.async_read) - f->conn.async_read = arg->flags & FUSE_ASYNC_READ; - if (arg->max_readahead < f->conn.max_readahead) - f->conn.max_readahead = arg->max_readahead; - } else { - f->conn.async_read = 0; - f->conn.max_readahead = 0; - } - - if (bufsize < FUSE_MIN_READ_BUFFER) { - fprintf(stderr, "fuse: warning: buffer size too small: %zu\n", - bufsize); - bufsize = FUSE_MIN_READ_BUFFER; - } - - bufsize -= 4096; - if (bufsize < f->conn.max_write) - f->conn.max_write = bufsize; - - f->got_init = 1; - if (f->op.init) - f->op.init(f->userdata, &f->conn); - - memset(&outarg, 0, sizeof(outarg)); - outarg.major = FUSE_KERNEL_VERSION; - outarg.minor = FUSE_KERNEL_MINOR_VERSION; - if (f->conn.async_read) - outarg.flags |= FUSE_ASYNC_READ; - if (f->op.getlk && f->op.setlk) - outarg.flags |= FUSE_POSIX_LOCKS; - outarg.max_readahead = f->conn.max_readahead; - outarg.max_write = f->conn.max_write; - - if (f->debug) { - fprintf(stderr, " INIT: %u.%u\n", outarg.major, outarg.minor); - fprintf(stderr, " flags=0x%08x\n", outarg.flags); - fprintf(stderr, " max_readahead=0x%08x\n", outarg.max_readahead); - fprintf(stderr, " max_write=0x%08x\n", outarg.max_write); - } - - send_reply_ok(req, &outarg, arg->minor < 5 ? 8 : sizeof(outarg)); + struct fuse_init_in *arg = (struct fuse_init_in *) inarg; + struct fuse_init_out outarg; + struct fuse_ll *f = req->f; + size_t bufsize = fuse_chan_bufsize(req->ch); + + (void) nodeid; + if (f->debug) { + fprintf(stderr, "INIT: %u.%u\n", arg->major, arg->minor); + if (arg->major > 7 || (arg->major == 7 && arg->minor >= 6)) { + fprintf(stderr, "flags=0x%08x\n", arg->flags); + fprintf(stderr, "max_readahead=0x%08x\n", + arg->max_readahead); + } + } + f->conn.proto_major = arg->major; + f->conn.proto_minor = arg->minor; + + if (arg->major < 7) { + fprintf(stderr, "fuse: unsupported protocol version: %u.%u\n", + arg->major, arg->minor); + fuse_reply_err(req, EPROTO); + return; + } + + if (arg->major > 7 || (arg->major == 7 && arg->minor >= 6)) { + if (f->conn.async_read) + f->conn.async_read = arg->flags & FUSE_ASYNC_READ; + if (arg->max_readahead < f->conn.max_readahead) + f->conn.max_readahead = arg->max_readahead; + } else { + f->conn.async_read = 0; + f->conn.max_readahead = 0; + } + + if (bufsize < FUSE_MIN_READ_BUFFER) { + fprintf(stderr, "fuse: warning: buffer size too small: %zu\n", + bufsize); + bufsize = FUSE_MIN_READ_BUFFER; + } + + bufsize -= 4096; + if (bufsize < f->conn.max_write) + f->conn.max_write = bufsize; + + f->got_init = 1; + if (f->op.init) + f->op.init(f->userdata, &f->conn); + + memset(&outarg, 0, sizeof(outarg)); + outarg.major = FUSE_KERNEL_VERSION; + outarg.minor = FUSE_KERNEL_MINOR_VERSION; + if (f->conn.async_read) + outarg.flags |= FUSE_ASYNC_READ; + if (f->op.getlk && f->op.setlk) + outarg.flags |= FUSE_POSIX_LOCKS; + outarg.max_readahead = f->conn.max_readahead; + outarg.max_write = f->conn.max_write; + + if (f->debug) { + fprintf(stderr, " INIT: %u.%u\n", outarg.major, outarg.minor); + fprintf(stderr, " flags=0x%08x\n", outarg.flags); + fprintf(stderr, " max_readahead=0x%08x\n", + outarg.max_readahead); + fprintf(stderr, " max_write=0x%08x\n", outarg.max_write); + } + + send_reply_ok(req, &outarg, arg->minor < 5 ? 8 : sizeof(outarg)); } static void do_destroy(fuse_req_t req, fuse_ino_t nodeid, const void *inarg) { - struct fuse_ll *f = req->f; + struct fuse_ll *f = req->f; - (void) nodeid; - (void) inarg; + (void) nodeid; + (void) inarg; - f->got_destroy = 1; - if (f->op.destroy) - f->op.destroy(f->userdata); + f->got_destroy = 1; + if (f->op.destroy) + f->op.destroy(f->userdata); - send_reply_ok(req, NULL, 0); + send_reply_ok(req, NULL, 0); } void *fuse_req_userdata(fuse_req_t req) { - return req->f->userdata; + return req->f->userdata; } const struct fuse_ctx *fuse_req_ctx(fuse_req_t req) { - return &req->ctx; + return &req->ctx; } void fuse_req_interrupt_func(fuse_req_t req, fuse_interrupt_func_t func, - void *data) + void *data) { - pthread_mutex_lock(&req->lock); - req->u.ni.func = func; - req->u.ni.data = data; - if (req->interrupted && func) - func(req, data); - pthread_mutex_unlock(&req->lock); + pthread_mutex_lock(&req->lock); + req->u.ni.func = func; + req->u.ni.data = data; + if (req->interrupted && func) + func(req, data); + pthread_mutex_unlock(&req->lock); } int fuse_req_interrupted(fuse_req_t req) { - int interrupted; + int interrupted; - pthread_mutex_lock(&req->f->lock); - interrupted = req->interrupted; - pthread_mutex_unlock(&req->f->lock); + pthread_mutex_lock(&req->f->lock); + interrupted = req->interrupted; + pthread_mutex_unlock(&req->f->lock); - return interrupted; + return interrupted; } static struct { - void (*func)(fuse_req_t, fuse_ino_t, const void *); - const char *name; + void (*func)(fuse_req_t, fuse_ino_t, const void *); + const char *name; } fuse_ll_ops[] = { - [FUSE_LOOKUP] = { do_lookup, "LOOKUP" }, - [FUSE_FORGET] = { do_forget, "FORGET" }, - [FUSE_GETATTR] = { do_getattr, "GETATTR" }, - [FUSE_SETATTR] = { do_setattr, "SETATTR" }, - [FUSE_READLINK] = { do_readlink, "READLINK" }, - [FUSE_SYMLINK] = { do_symlink, "SYMLINK" }, - [FUSE_MKNOD] = { do_mknod, "MKNOD" }, - [FUSE_MKDIR] = { do_mkdir, "MKDIR" }, - [FUSE_UNLINK] = { do_unlink, "UNLINK" }, - [FUSE_RMDIR] = { do_rmdir, "RMDIR" }, - [FUSE_RENAME] = { do_rename, "RENAME" }, - [FUSE_LINK] = { do_link, "LINK" }, - [FUSE_OPEN] = { do_open, "OPEN" }, - [FUSE_READ] = { do_read, "READ" }, - [FUSE_WRITE] = { do_write, "WRITE" }, - [FUSE_STATFS] = { do_statfs, "STATFS" }, - [FUSE_RELEASE] = { do_release, "RELEASE" }, - [FUSE_FSYNC] = { do_fsync, "FSYNC" }, - [FUSE_SETXATTR] = { do_setxattr, "SETXATTR" }, - [FUSE_GETXATTR] = { do_getxattr, "GETXATTR" }, - [FUSE_LISTXATTR] = { do_listxattr, "LISTXATTR" }, - [FUSE_REMOVEXATTR] = { do_removexattr, "REMOVEXATTR" }, - [FUSE_FLUSH] = { do_flush, "FLUSH" }, - [FUSE_INIT] = { do_init, "INIT" }, - [FUSE_OPENDIR] = { do_opendir, "OPENDIR" }, - [FUSE_READDIR] = { do_readdir, "READDIR" }, - [FUSE_RELEASEDIR] = { do_releasedir, "RELEASEDIR" }, - [FUSE_FSYNCDIR] = { do_fsyncdir, "FSYNCDIR" }, - [FUSE_GETLK] = { do_getlk, "GETLK" }, - [FUSE_SETLK] = { do_setlk, "SETLK" }, - [FUSE_SETLKW] = { do_setlkw, "SETLKW" }, - [FUSE_ACCESS] = { do_access, "ACCESS" }, - [FUSE_CREATE] = { do_create, "CREATE" }, - [FUSE_INTERRUPT] = { do_interrupt, "INTERRUPT" }, - [FUSE_BMAP] = { do_bmap, "BMAP" }, - [FUSE_DESTROY] = { do_destroy, "DESTROY" }, + [FUSE_LOOKUP] = { do_lookup, "LOOKUP" }, + [FUSE_FORGET] = { do_forget, "FORGET" }, + [FUSE_GETATTR] = { do_getattr, "GETATTR" }, + [FUSE_SETATTR] = { do_setattr, "SETATTR" }, + [FUSE_READLINK] = { do_readlink, "READLINK" }, + [FUSE_SYMLINK] = { do_symlink, "SYMLINK" }, + [FUSE_MKNOD] = { do_mknod, "MKNOD" }, + [FUSE_MKDIR] = { do_mkdir, "MKDIR" }, + [FUSE_UNLINK] = { do_unlink, "UNLINK" }, + [FUSE_RMDIR] = { do_rmdir, "RMDIR" }, + [FUSE_RENAME] = { do_rename, "RENAME" }, + [FUSE_LINK] = { do_link, "LINK" }, + [FUSE_OPEN] = { do_open, "OPEN" }, + [FUSE_READ] = { do_read, "READ" }, + [FUSE_WRITE] = { do_write, "WRITE" }, + [FUSE_STATFS] = { do_statfs, "STATFS" }, + [FUSE_RELEASE] = { do_release, "RELEASE" }, + [FUSE_FSYNC] = { do_fsync, "FSYNC" }, + [FUSE_SETXATTR] = { do_setxattr, "SETXATTR" }, + [FUSE_GETXATTR] = { do_getxattr, "GETXATTR" }, + [FUSE_LISTXATTR] = { do_listxattr, "LISTXATTR" }, + [FUSE_REMOVEXATTR] = { do_removexattr, "REMOVEXATTR" }, + [FUSE_FLUSH] = { do_flush, "FLUSH" }, + [FUSE_INIT] = { do_init, "INIT" }, + [FUSE_OPENDIR] = { do_opendir, "OPENDIR" }, + [FUSE_READDIR] = { do_readdir, "READDIR" }, + [FUSE_RELEASEDIR] = { do_releasedir, "RELEASEDIR" }, + [FUSE_FSYNCDIR] = { do_fsyncdir, "FSYNCDIR" }, + [FUSE_GETLK] = { do_getlk, "GETLK" }, + [FUSE_SETLK] = { do_setlk, "SETLK" }, + [FUSE_SETLKW] = { do_setlkw, "SETLKW" }, + [FUSE_ACCESS] = { do_access, "ACCESS" }, + [FUSE_CREATE] = { do_create, "CREATE" }, + [FUSE_INTERRUPT] = { do_interrupt, "INTERRUPT" }, + [FUSE_BMAP] = { do_bmap, "BMAP" }, + [FUSE_DESTROY] = { do_destroy, "DESTROY" }, }; #define FUSE_MAXOP (sizeof(fuse_ll_ops) / sizeof(fuse_ll_ops[0])) static const char *opname(enum fuse_opcode opcode) { - if (opcode >= FUSE_MAXOP || !fuse_ll_ops[opcode].name) - return "???"; - else - return fuse_ll_ops[opcode].name; + if (opcode >= FUSE_MAXOP || !fuse_ll_ops[opcode].name) + return "???"; + else + return fuse_ll_ops[opcode].name; } static void fuse_ll_process(void *data, const char *buf, size_t len, - struct fuse_chan *ch) -{ - struct fuse_ll *f = (struct fuse_ll *) data; - struct fuse_in_header *in = (struct fuse_in_header *) buf; - const void *inarg = buf + sizeof(struct fuse_in_header); - struct fuse_req *req; - - if (f->debug) - fprintf(stderr, "unique: %llu, opcode: %s (%i), nodeid: %lu, insize: %zu\n", - (unsigned long long) in->unique, - opname((enum fuse_opcode) in->opcode), in->opcode, - (unsigned long) in->nodeid, len); - - req = (struct fuse_req *) calloc(1, sizeof(struct fuse_req)); - if (req == NULL) { - fprintf(stderr, "fuse: failed to allocate request\n"); - return; - } - - req->f = f; - req->unique = in->unique; - req->ctx.uid = in->uid; - req->ctx.gid = in->gid; - req->ctx.pid = in->pid; - req->ch = ch; - req->ctr = 1; - list_init_req(req); - fuse_mutex_init(&req->lock); - - if (!f->got_init && in->opcode != FUSE_INIT) - fuse_reply_err(req, EIO); - else if (f->allow_root && in->uid != f->owner && in->uid != 0 && - in->opcode != FUSE_INIT && in->opcode != FUSE_READ && - in->opcode != FUSE_WRITE && in->opcode != FUSE_FSYNC && - in->opcode != FUSE_RELEASE && in->opcode != FUSE_READDIR && - in->opcode != FUSE_FSYNCDIR && in->opcode != FUSE_RELEASEDIR) { - fuse_reply_err(req, EACCES); - } else if (in->opcode >= FUSE_MAXOP || !fuse_ll_ops[in->opcode].func) - fuse_reply_err(req, ENOSYS); - else { - if (in->opcode != FUSE_INTERRUPT) { - struct fuse_req *intr; - pthread_mutex_lock(&f->lock); - intr = check_interrupt(f, req); - list_add_req(req, &f->list); - pthread_mutex_unlock(&f->lock); - if (intr) - fuse_reply_err(intr, EAGAIN); - } - fuse_ll_ops[in->opcode].func(req, in->nodeid, inarg); - } + struct fuse_chan *ch) +{ + struct fuse_ll *f = (struct fuse_ll *) data; + struct fuse_in_header *in = (struct fuse_in_header *) buf; + const void *inarg = buf + sizeof(struct fuse_in_header); + struct fuse_req *req; + + if (f->debug) + fprintf(stderr, + "unique: %llu, opcode: %s (%i), nodeid: %lu, insize: %zu\n", + (unsigned long long) in->unique, + opname((enum fuse_opcode) in->opcode), in->opcode, + (unsigned long) in->nodeid, len); + + req = (struct fuse_req *) calloc(1, sizeof(struct fuse_req)); + if (req == NULL) { + fprintf(stderr, "fuse: failed to allocate request\n"); + return; + } + + req->f = f; + req->unique = in->unique; + req->ctx.uid = in->uid; + req->ctx.gid = in->gid; + req->ctx.pid = in->pid; + req->ch = ch; + req->ctr = 1; + list_init_req(req); + fuse_mutex_init(&req->lock); + + if (!f->got_init && in->opcode != FUSE_INIT) + fuse_reply_err(req, EIO); + else if (f->allow_root && in->uid != f->owner && in->uid != 0 && + in->opcode != FUSE_INIT && in->opcode != FUSE_READ && + in->opcode != FUSE_WRITE && in->opcode != FUSE_FSYNC && + in->opcode != FUSE_RELEASE && in->opcode != FUSE_READDIR && + in->opcode != FUSE_FSYNCDIR && in->opcode != FUSE_RELEASEDIR) { + fuse_reply_err(req, EACCES); + } else if (in->opcode >= FUSE_MAXOP || !fuse_ll_ops[in->opcode].func) + fuse_reply_err(req, ENOSYS); + else { + if (in->opcode != FUSE_INTERRUPT) { + struct fuse_req *intr; + pthread_mutex_lock(&f->lock); + intr = check_interrupt(f, req); + list_add_req(req, &f->list); + pthread_mutex_unlock(&f->lock); + if (intr) + fuse_reply_err(intr, EAGAIN); + } + fuse_ll_ops[in->opcode].func(req, in->nodeid, inarg); + } } enum { - KEY_HELP, - KEY_VERSION, + KEY_HELP, + KEY_VERSION, }; static struct fuse_opt fuse_ll_opts[] = { - { "debug", offsetof(struct fuse_ll, debug), 1 }, - { "-d", offsetof(struct fuse_ll, debug), 1 }, - { "allow_root", offsetof(struct fuse_ll, allow_root), 1 }, - { "max_write=%u", offsetof(struct fuse_ll, conn.max_write), 0 }, - { "max_readahead=%u", offsetof(struct fuse_ll, conn.max_readahead), 0 }, - { "async_read", offsetof(struct fuse_ll, conn.async_read), 1 }, - { "sync_read", offsetof(struct fuse_ll, conn.async_read), 0 }, - FUSE_OPT_KEY("max_read=", FUSE_OPT_KEY_DISCARD), - FUSE_OPT_KEY("-h", KEY_HELP), - FUSE_OPT_KEY("--help", KEY_HELP), - FUSE_OPT_KEY("-V", KEY_VERSION), - FUSE_OPT_KEY("--version", KEY_VERSION), - FUSE_OPT_END + { "debug", offsetof(struct fuse_ll, debug), 1 }, + { "-d", offsetof(struct fuse_ll, debug), 1 }, + { "allow_root", offsetof(struct fuse_ll, allow_root), 1 }, + { "max_write=%u", offsetof(struct fuse_ll, conn.max_write), 0 }, + { "max_readahead=%u", offsetof(struct fuse_ll, conn.max_readahead), 0 }, + { "async_read", offsetof(struct fuse_ll, conn.async_read), 1 }, + { "sync_read", offsetof(struct fuse_ll, conn.async_read), 0 }, + FUSE_OPT_KEY("max_read=", FUSE_OPT_KEY_DISCARD), + FUSE_OPT_KEY("-h", KEY_HELP), + FUSE_OPT_KEY("--help", KEY_HELP), + FUSE_OPT_KEY("-V", KEY_VERSION), + FUSE_OPT_KEY("--version", KEY_VERSION), + FUSE_OPT_END }; static void fuse_ll_version(void) { - fprintf(stderr, "using FUSE kernel interface version %i.%i\n", - FUSE_KERNEL_VERSION, FUSE_KERNEL_MINOR_VERSION); + fprintf(stderr, "using FUSE kernel interface version %i.%i\n", + FUSE_KERNEL_VERSION, FUSE_KERNEL_MINOR_VERSION); } static void fuse_ll_help(void) { - fprintf(stderr, -" -o max_write=N set maximum size of write requests\n" -" -o max_readahead=N set maximum readahead\n" -" -o async_read perform reads asynchronously (default)\n" -" -o sync_read perform reads synchronously\n"); + fprintf(stderr, +" -o max_write=N set maximum size of write requests\n" +" -o max_readahead=N set maximum readahead\n" +" -o async_read perform reads asynchronously (default)\n" +" -o sync_read perform reads synchronously\n"); } static int fuse_ll_opt_proc(void *data, const char *arg, int key, - struct fuse_args *outargs) + struct fuse_args *outargs) { - (void) data; (void) outargs; + (void) data; (void) outargs; - switch (key) { - case KEY_HELP: - fuse_ll_help(); - break; + switch (key) { + case KEY_HELP: + fuse_ll_help(); + break; - case KEY_VERSION: - fuse_ll_version(); - break; + case KEY_VERSION: + fuse_ll_version(); + break; - default: - fprintf(stderr, "fuse: unknown option `%s'\n", arg); - } + default: + fprintf(stderr, "fuse: unknown option `%s'\n", arg); + } - return -1; + return -1; } int fuse_lowlevel_is_lib_option(const char *opt) { - return fuse_opt_match(fuse_ll_opts, opt); + return fuse_opt_match(fuse_ll_opts, opt); } static void fuse_ll_destroy(void *data) { - struct fuse_ll *f = (struct fuse_ll *) data; + struct fuse_ll *f = (struct fuse_ll *) data; - if (f->got_init && !f->got_destroy) { - if (f->op.destroy) - f->op.destroy(f->userdata); - } + if (f->got_init && !f->got_destroy) { + if (f->op.destroy) + f->op.destroy(f->userdata); + } - pthread_mutex_destroy(&f->lock); - free(f); + pthread_mutex_destroy(&f->lock); + free(f); } /* @@ -1255,158 +1264,158 @@ static void fuse_ll_destroy(void *data) * version of a symbol to internal references. */ struct fuse_session *fuse_lowlevel_new_common(struct fuse_args *args, - const struct fuse_lowlevel_ops *op, - size_t op_size, void *userdata) + const struct fuse_lowlevel_ops *op, + size_t op_size, void *userdata) { - struct fuse_ll *f; - struct fuse_session *se; - struct fuse_session_ops sop = { - .process = fuse_ll_process, - .destroy = fuse_ll_destroy, - }; + struct fuse_ll *f; + struct fuse_session *se; + struct fuse_session_ops sop = { + .process = fuse_ll_process, + .destroy = fuse_ll_destroy, + }; - if (sizeof(struct fuse_lowlevel_ops) < op_size) { - fprintf(stderr, "fuse: warning: library too old, some operations may not work\n"); - op_size = sizeof(struct fuse_lowlevel_ops); - } + if (sizeof(struct fuse_lowlevel_ops) < op_size) { + fprintf(stderr, "fuse: warning: library too old, some operations may not work\n"); + op_size = sizeof(struct fuse_lowlevel_ops); + } - f = (struct fuse_ll *) calloc(1, sizeof(struct fuse_ll)); - if (f == NULL) { - fprintf(stderr, "fuse: failed to allocate fuse object\n"); - goto out; - } + f = (struct fuse_ll *) calloc(1, sizeof(struct fuse_ll)); + if (f == NULL) { + fprintf(stderr, "fuse: failed to allocate fuse object\n"); + goto out; + } - f->conn.async_read = 1; - f->conn.max_write = UINT_MAX; - f->conn.max_readahead = UINT_MAX; - list_init_req(&f->list); - list_init_req(&f->interrupts); - fuse_mutex_init(&f->lock); + f->conn.async_read = 1; + f->conn.max_write = UINT_MAX; + f->conn.max_readahead = UINT_MAX; + list_init_req(&f->list); + list_init_req(&f->interrupts); + fuse_mutex_init(&f->lock); - if (fuse_opt_parse(args, f, fuse_ll_opts, fuse_ll_opt_proc) == -1) - goto out_free; + if (fuse_opt_parse(args, f, fuse_ll_opts, fuse_ll_opt_proc) == -1) + goto out_free; - memcpy(&f->op, op, op_size); - f->owner = getuid(); - f->userdata = userdata; + memcpy(&f->op, op, op_size); + f->owner = getuid(); + f->userdata = userdata; - se = fuse_session_new(&sop, f); - if (!se) - goto out_free; + se = fuse_session_new(&sop, f); + if (!se) + goto out_free; - return se; + return se; - out_free: - free(f); - out: - return NULL; +out_free: + free(f); +out: + return NULL; } struct fuse_session *fuse_lowlevel_new(struct fuse_args *args, - const struct fuse_lowlevel_ops *op, - size_t op_size, void *userdata) + const struct fuse_lowlevel_ops *op, + size_t op_size, void *userdata) { - return fuse_lowlevel_new_common(args, op, op_size, userdata); + return fuse_lowlevel_new_common(args, op, op_size, userdata); } #ifndef __FreeBSD__ static void fill_open_compat(struct fuse_open_out *arg, - const struct fuse_file_info_compat *f) + const struct fuse_file_info_compat *f) { - arg->fh = f->fh; - if (f->direct_io) - arg->open_flags |= FOPEN_DIRECT_IO; - if (f->keep_cache) - arg->open_flags |= FOPEN_KEEP_CACHE; + arg->fh = f->fh; + if (f->direct_io) + arg->open_flags |= FOPEN_DIRECT_IO; + if (f->keep_cache) + arg->open_flags |= FOPEN_KEEP_CACHE; } static void convert_statfs_compat(const struct statfs *compatbuf, - struct statvfs *buf) + struct statvfs *buf) { - buf->f_bsize = compatbuf->f_bsize; - buf->f_blocks = compatbuf->f_blocks; - buf->f_bfree = compatbuf->f_bfree; - buf->f_bavail = compatbuf->f_bavail; - buf->f_files = compatbuf->f_files; - buf->f_ffree = compatbuf->f_ffree; - buf->f_namemax = compatbuf->f_namelen; + buf->f_bsize = compatbuf->f_bsize; + buf->f_blocks = compatbuf->f_blocks; + buf->f_bfree = compatbuf->f_bfree; + buf->f_bavail = compatbuf->f_bavail; + buf->f_files = compatbuf->f_files; + buf->f_ffree = compatbuf->f_ffree; + buf->f_namemax = compatbuf->f_namelen; } int fuse_reply_open_compat(fuse_req_t req, - const struct fuse_file_info_compat *f) + const struct fuse_file_info_compat *f) { - struct fuse_open_out arg; + struct fuse_open_out arg; - memset(&arg, 0, sizeof(arg)); - fill_open_compat(&arg, f); - return send_reply_ok(req, &arg, sizeof(arg)); + memset(&arg, 0, sizeof(arg)); + fill_open_compat(&arg, f); + return send_reply_ok(req, &arg, sizeof(arg)); } int fuse_reply_statfs_compat(fuse_req_t req, const struct statfs *stbuf) { - struct statvfs newbuf; + struct statvfs newbuf; - memset(&newbuf, 0, sizeof(newbuf)); - convert_statfs_compat(stbuf, &newbuf); + memset(&newbuf, 0, sizeof(newbuf)); + convert_statfs_compat(stbuf, &newbuf); - return fuse_reply_statfs(req, &newbuf); + return fuse_reply_statfs(req, &newbuf); } struct fuse_session *fuse_lowlevel_new_compat(const char *opts, - const struct fuse_lowlevel_ops_compat *op, - size_t op_size, void *userdata) + const struct fuse_lowlevel_ops_compat *op, + size_t op_size, void *userdata) { - struct fuse_session *se; - struct fuse_args args = FUSE_ARGS_INIT(0, NULL); + struct fuse_session *se; + struct fuse_args args = FUSE_ARGS_INIT(0, NULL); - if (opts && - (fuse_opt_add_arg(&args, "") == -1 || - fuse_opt_add_arg(&args, "-o") == -1 || - fuse_opt_add_arg(&args, opts) == -1)) { - fuse_opt_free_args(&args); - return NULL; - } - se = fuse_lowlevel_new(&args, (const struct fuse_lowlevel_ops *) op, - op_size, userdata); - fuse_opt_free_args(&args); + if (opts && + (fuse_opt_add_arg(&args, "") == -1 || + fuse_opt_add_arg(&args, "-o") == -1 || + fuse_opt_add_arg(&args, opts) == -1)) { + fuse_opt_free_args(&args); + return NULL; + } + se = fuse_lowlevel_new(&args, (const struct fuse_lowlevel_ops *) op, + op_size, userdata); + fuse_opt_free_args(&args); - return se; + return se; } struct fuse_ll_compat_conf { - unsigned max_read; - int set_max_read; + unsigned max_read; + int set_max_read; }; static const struct fuse_opt fuse_ll_opts_compat[] = { - { "max_read=", offsetof(struct fuse_ll_compat_conf, set_max_read), 1 }, - { "max_read=%u", offsetof(struct fuse_ll_compat_conf, max_read), 0 }, - FUSE_OPT_KEY("max_read=", FUSE_OPT_KEY_KEEP), - FUSE_OPT_END + { "max_read=", offsetof(struct fuse_ll_compat_conf, set_max_read), 1 }, + { "max_read=%u", offsetof(struct fuse_ll_compat_conf, max_read), 0 }, + FUSE_OPT_KEY("max_read=", FUSE_OPT_KEY_KEEP), + FUSE_OPT_END }; int fuse_sync_compat_args(struct fuse_args *args) { - struct fuse_ll_compat_conf conf; + struct fuse_ll_compat_conf conf; - memset(&conf, 0, sizeof(conf)); - if (fuse_opt_parse(args, &conf, fuse_ll_opts_compat, NULL) == -1) - return -1; + memset(&conf, 0, sizeof(conf)); + if (fuse_opt_parse(args, &conf, fuse_ll_opts_compat, NULL) == -1) + return -1; - if (fuse_opt_insert_arg(args, 1, "-osync_read")) - return -1; + if (fuse_opt_insert_arg(args, 1, "-osync_read")) + return -1; - if (conf.set_max_read) { - char tmpbuf[64]; + if (conf.set_max_read) { + char tmpbuf[64]; - sprintf(tmpbuf, "-omax_readahead=%u", conf.max_read); - if (fuse_opt_insert_arg(args, 1, tmpbuf) == -1) - return -1; - } - return 0; + sprintf(tmpbuf, "-omax_readahead=%u", conf.max_read); + if (fuse_opt_insert_arg(args, 1, tmpbuf) == -1) + return -1; + } + return 0; } FUSE_SYMVER(".symver fuse_reply_statfs_compat,fuse_reply_statfs@FUSE_2.4"); @@ -1417,22 +1426,22 @@ FUSE_SYMVER(".symver fuse_lowlevel_new_compat,fuse_lowlevel_new@FUSE_2.4"); int fuse_sync_compat_args(struct fuse_args *args) { - (void) args; - return 0; + (void) args; + return 0; } #endif /* __FreeBSD__ */ struct fuse_session *fuse_lowlevel_new_compat25(struct fuse_args *args, - const struct fuse_lowlevel_ops_compat25 *op, - size_t op_size, void *userdata) + const struct fuse_lowlevel_ops_compat25 *op, + size_t op_size, void *userdata) { - if (fuse_sync_compat_args(args) == -1) - return NULL; + if (fuse_sync_compat_args(args) == -1) + return NULL; - return fuse_lowlevel_new_common(args, - (const struct fuse_lowlevel_ops *) op, - op_size, userdata); + return fuse_lowlevel_new_common(args, + (const struct fuse_lowlevel_ops *) op, + op_size, userdata); } FUSE_SYMVER(".symver fuse_lowlevel_new_compat25,fuse_lowlevel_new@FUSE_2.5"); diff --git a/lib/fuse_misc.h b/lib/fuse_misc.h index 4f5236a..c2cfee1 100644 --- a/lib/fuse_misc.h +++ b/lib/fuse_misc.h @@ -1,9 +1,9 @@ /* - FUSE: Filesystem in Userspace - Copyright (C) 2001-2007 Miklos Szeredi + FUSE: Filesystem in Userspace + Copyright (C) 2001-2007 Miklos Szeredi - This program can be distributed under the terms of the GNU LGPLv2. - See the file COPYING.LIB + This program can be distributed under the terms of the GNU LGPLv2. + See the file COPYING.LIB */ #include "config.h" @@ -22,11 +22,11 @@ /* Is this hack still needed? */ static inline void fuse_mutex_init(pthread_mutex_t *mut) { - pthread_mutexattr_t attr; - pthread_mutexattr_init(&attr); - pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_ADAPTIVE_NP); - pthread_mutex_init(mut, &attr); - pthread_mutexattr_destroy(&attr); + pthread_mutexattr_t attr; + pthread_mutexattr_init(&attr); + pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_ADAPTIVE_NP); + pthread_mutex_init(mut, &attr); + pthread_mutexattr_destroy(&attr); } #endif diff --git a/lib/fuse_mt.c b/lib/fuse_mt.c index cbdc1a3..95c3a5c 100644 --- a/lib/fuse_mt.c +++ b/lib/fuse_mt.c @@ -1,9 +1,9 @@ /* - FUSE: Filesystem in Userspace - Copyright (C) 2001-2007 Miklos Szeredi + FUSE: Filesystem in Userspace + Copyright (C) 2001-2007 Miklos Szeredi - This program can be distributed under the terms of the GNU LGPLv2. - See the file COPYING.LIB. + This program can be distributed under the terms of the GNU LGPLv2. + See the file COPYING.LIB. */ #include "fuse_i.h" @@ -17,100 +17,100 @@ #include struct procdata { - struct fuse *f; - struct fuse_chan *prevch; - struct fuse_session *prevse; - fuse_processor_t proc; - void *data; + struct fuse *f; + struct fuse_chan *prevch; + struct fuse_session *prevse; + fuse_processor_t proc; + void *data; }; static void mt_session_proc(void *data, const char *buf, size_t len, - struct fuse_chan *ch) + struct fuse_chan *ch) { - struct procdata *pd = (struct procdata *) data; - struct fuse_cmd *cmd = *(struct fuse_cmd **) buf; + struct procdata *pd = (struct procdata *) data; + struct fuse_cmd *cmd = *(struct fuse_cmd **) buf; - (void) len; - (void) ch; - pd->proc(pd->f, cmd, pd->data); + (void) len; + (void) ch; + pd->proc(pd->f, cmd, pd->data); } static void mt_session_exit(void *data, int val) { - struct procdata *pd = (struct procdata *) data; - if (val) - fuse_session_exit(pd->prevse); - else - fuse_session_reset(pd->prevse); + struct procdata *pd = (struct procdata *) data; + if (val) + fuse_session_exit(pd->prevse); + else + fuse_session_reset(pd->prevse); } static int mt_session_exited(void *data) { - struct procdata *pd = (struct procdata *) data; - return fuse_session_exited(pd->prevse); + struct procdata *pd = (struct procdata *) data; + return fuse_session_exited(pd->prevse); } static int mt_chan_receive(struct fuse_chan **chp, char *buf, size_t size) { - struct fuse_cmd *cmd; - struct procdata *pd = (struct procdata *) fuse_chan_data(*chp); + struct fuse_cmd *cmd; + struct procdata *pd = (struct procdata *) fuse_chan_data(*chp); - assert(size >= sizeof(cmd)); + assert(size >= sizeof(cmd)); - cmd = fuse_read_cmd(pd->f); - if (cmd == NULL) - return 0; + cmd = fuse_read_cmd(pd->f); + if (cmd == NULL) + return 0; - *(struct fuse_cmd **) buf = cmd; + *(struct fuse_cmd **) buf = cmd; - return sizeof(cmd); + return sizeof(cmd); } int fuse_loop_mt_proc(struct fuse *f, fuse_processor_t proc, void *data) { - int res; - struct procdata pd; - struct fuse_session *prevse = fuse_get_session(f); - struct fuse_session *se; - struct fuse_chan *prevch = fuse_session_next_chan(prevse, NULL); - struct fuse_chan *ch; - struct fuse_session_ops sop = { - .exit = mt_session_exit, - .exited = mt_session_exited, - .process = mt_session_proc, - }; - struct fuse_chan_ops cop = { - .receive = mt_chan_receive, - }; - - pd.f = f; - pd.prevch = prevch; - pd.prevse = prevse; - pd.proc = proc; - pd.data = data; - - se = fuse_session_new(&sop, &pd); - if (se == NULL) - return -1; - - ch = fuse_chan_new(&cop, fuse_chan_fd(prevch), sizeof(struct fuse_cmd *), - &pd); - if (ch == NULL) { - fuse_session_destroy(se); - return -1; - } - fuse_session_add_chan(se, ch); - res = fuse_session_loop_mt(se); - fuse_session_destroy(se); - return res; + int res; + struct procdata pd; + struct fuse_session *prevse = fuse_get_session(f); + struct fuse_session *se; + struct fuse_chan *prevch = fuse_session_next_chan(prevse, NULL); + struct fuse_chan *ch; + struct fuse_session_ops sop = { + .exit = mt_session_exit, + .exited = mt_session_exited, + .process = mt_session_proc, + }; + struct fuse_chan_ops cop = { + .receive = mt_chan_receive, + }; + + pd.f = f; + pd.prevch = prevch; + pd.prevse = prevse; + pd.proc = proc; + pd.data = data; + + se = fuse_session_new(&sop, &pd); + if (se == NULL) + return -1; + + ch = fuse_chan_new(&cop, fuse_chan_fd(prevch), + sizeof(struct fuse_cmd *), &pd); + if (ch == NULL) { + fuse_session_destroy(se); + return -1; + } + fuse_session_add_chan(se, ch); + res = fuse_session_loop_mt(se); + fuse_session_destroy(se); + return res; } int fuse_loop_mt(struct fuse *f) { - if (f == NULL) - return -1; + if (f == NULL) + return -1; - return fuse_session_loop_mt(fuse_get_session(f)); + return fuse_session_loop_mt(fuse_get_session(f)); } FUSE_SYMVER(".symver fuse_loop_mt_proc,__fuse_loop_mt@"); diff --git a/lib/fuse_opt.c b/lib/fuse_opt.c index d10e624..8a9019b 100644 --- a/lib/fuse_opt.c +++ b/lib/fuse_opt.c @@ -1,9 +1,9 @@ /* - FUSE: Filesystem in Userspace - Copyright (C) 2001-2007 Miklos Szeredi + FUSE: Filesystem in Userspace + Copyright (C) 2001-2007 Miklos Szeredi - This program can be distributed under the terms of the GNU LGPLv2. - See the file COPYING.LIB + This program can be distributed under the terms of the GNU LGPLv2. + See the file COPYING.LIB */ #include "fuse_opt.h" @@ -15,71 +15,71 @@ #include struct fuse_opt_context { - void *data; - const struct fuse_opt *opt; - fuse_opt_proc_t proc; - int argctr; - int argc; - char **argv; - struct fuse_args outargs; - char *opts; - int nonopt; + void *data; + const struct fuse_opt *opt; + fuse_opt_proc_t proc; + int argctr; + int argc; + char **argv; + struct fuse_args outargs; + char *opts; + int nonopt; }; void fuse_opt_free_args(struct fuse_args *args) { - if (args) { - if (args->argv && args->allocated) { - int i; - for (i = 0; i < args->argc; i++) - free(args->argv[i]); - free(args->argv); - } - args->argc = 0; - args->argv = NULL; - args->allocated = 0; - } + if (args) { + if (args->argv && args->allocated) { + int i; + for (i = 0; i < args->argc; i++) + free(args->argv[i]); + free(args->argv); + } + args->argc = 0; + args->argv = NULL; + args->allocated = 0; + } } static int alloc_failed(void) { - fprintf(stderr, "fuse: memory allocation failed\n"); - return -1; + fprintf(stderr, "fuse: memory allocation failed\n"); + return -1; } int fuse_opt_add_arg(struct fuse_args *args, const char *arg) { - char **newargv; - char *newarg; + char **newargv; + char *newarg; - assert(!args->argv || args->allocated); + assert(!args->argv || args->allocated); - newargv = realloc(args->argv, (args->argc + 2) * sizeof(char *)); - newarg = newargv ? strdup(arg) : NULL; - if (!newargv || !newarg) - return alloc_failed(); + newargv = realloc(args->argv, (args->argc + 2) * sizeof(char *)); + newarg = newargv ? strdup(arg) : NULL; + if (!newargv || !newarg) + return alloc_failed(); - args->argv = newargv; - args->allocated = 1; - args->argv[args->argc++] = newarg; - args->argv[args->argc] = NULL; - return 0; + args->argv = newargv; + args->allocated = 1; + args->argv[args->argc++] = newarg; + args->argv[args->argc] = NULL; + return 0; } static int fuse_opt_insert_arg_common(struct fuse_args *args, int pos, const char *arg) { - assert(pos <= args->argc); - if (fuse_opt_add_arg(args, arg) == -1) - return -1; - - if (pos != args->argc - 1) { - char *newarg = args->argv[args->argc - 1]; - memmove(&args->argv[pos + 1], &args->argv[pos], - sizeof(char *) * (args->argc - pos - 1)); - args->argv[pos] = newarg; - } - return 0; + assert(pos <= args->argc); + if (fuse_opt_add_arg(args, arg) == -1) + return -1; + + if (pos != args->argc - 1) { + char *newarg = args->argv[args->argc - 1]; + memmove(&args->argv[pos + 1], &args->argv[pos], + sizeof(char *) * (args->argc - pos - 1)); + args->argv[pos] = newarg; + } + return 0; } int fuse_opt_insert_arg(struct fuse_args *args, int pos, const char *arg) @@ -96,288 +96,290 @@ int fuse_opt_insert_arg_compat(struct fuse_args *args, int pos, const char *arg) static int next_arg(struct fuse_opt_context *ctx, const char *opt) { - if (ctx->argctr + 1 >= ctx->argc) { - fprintf(stderr, "fuse: missing argument after `%s'\n", opt); - return -1; - } - ctx->argctr++; - return 0; + if (ctx->argctr + 1 >= ctx->argc) { + fprintf(stderr, "fuse: missing argument after `%s'\n", opt); + return -1; + } + ctx->argctr++; + return 0; } static int add_arg(struct fuse_opt_context *ctx, const char *arg) { - return fuse_opt_add_arg(&ctx->outargs, arg); + return fuse_opt_add_arg(&ctx->outargs, arg); } int fuse_opt_add_opt(char **opts, const char *opt) { - char *newopts; - if (!*opts) - newopts = strdup(opt); - else { - unsigned oldlen = strlen(*opts); - newopts = realloc(*opts, oldlen + 1 + strlen(opt) + 1); - if (newopts) { - newopts[oldlen] = ','; - strcpy(newopts + oldlen + 1, opt); - } - } - if (!newopts) - return alloc_failed(); - - *opts = newopts; - return 0; + char *newopts; + if (!*opts) + newopts = strdup(opt); + else { + unsigned oldlen = strlen(*opts); + newopts = realloc(*opts, oldlen + 1 + strlen(opt) + 1); + if (newopts) { + newopts[oldlen] = ','; + strcpy(newopts + oldlen + 1, opt); + } + } + if (!newopts) + return alloc_failed(); + + *opts = newopts; + return 0; } static int add_opt(struct fuse_opt_context *ctx, const char *opt) { - return fuse_opt_add_opt(&ctx->opts, opt); + return fuse_opt_add_opt(&ctx->opts, opt); } static int call_proc(struct fuse_opt_context *ctx, const char *arg, int key, - int iso) + int iso) { - if (key == FUSE_OPT_KEY_DISCARD) - return 0; - - if (key != FUSE_OPT_KEY_KEEP && ctx->proc) { - int res = ctx->proc(ctx->data, arg, key, &ctx->outargs); - if (res == -1 || !res) - return res; - } - if (iso) - return add_opt(ctx, arg); - else - return add_arg(ctx, arg); + if (key == FUSE_OPT_KEY_DISCARD) + return 0; + + if (key != FUSE_OPT_KEY_KEEP && ctx->proc) { + int res = ctx->proc(ctx->data, arg, key, &ctx->outargs); + if (res == -1 || !res) + return res; + } + if (iso) + return add_opt(ctx, arg); + else + return add_arg(ctx, arg); } static int match_template(const char *t, const char *arg, unsigned *sepp) { - int arglen = strlen(arg); - const char *sep = strchr(t, '='); - sep = sep ? sep : strchr(t, ' '); - if (sep && (!sep[1] || sep[1] == '%')) { - int tlen = sep - t; - if (sep[0] == '=') - tlen ++; - if (arglen >= tlen && strncmp(arg, t, tlen) == 0) { - *sepp = sep - t; - return 1; - } - } - if (strcmp(t, arg) == 0) { - *sepp = 0; - return 1; - } - return 0; + int arglen = strlen(arg); + const char *sep = strchr(t, '='); + sep = sep ? sep : strchr(t, ' '); + if (sep && (!sep[1] || sep[1] == '%')) { + int tlen = sep - t; + if (sep[0] == '=') + tlen ++; + if (arglen >= tlen && strncmp(arg, t, tlen) == 0) { + *sepp = sep - t; + return 1; + } + } + if (strcmp(t, arg) == 0) { + *sepp = 0; + return 1; + } + return 0; } static const struct fuse_opt *find_opt(const struct fuse_opt *opt, - const char *arg, unsigned *sepp) + const char *arg, unsigned *sepp) { - for (; opt && opt->templ; opt++) - if (match_template(opt->templ, arg, sepp)) - return opt; - return NULL; + for (; opt && opt->templ; opt++) + if (match_template(opt->templ, arg, sepp)) + return opt; + return NULL; } int fuse_opt_match(const struct fuse_opt *opts, const char *opt) { - unsigned dummy; - return find_opt(opts, opt, &dummy) ? 1 : 0; + unsigned dummy; + return find_opt(opts, opt, &dummy) ? 1 : 0; } static int process_opt_param(void *var, const char *format, const char *param, - const char *arg) + const char *arg) { - assert(format[0] == '%'); - if (format[1] == 's') { - char *copy = strdup(param); - if (!copy) - return alloc_failed(); - - *(char **) var = copy; - } else { - if (sscanf(param, format, var) != 1) { - fprintf(stderr, "fuse: invalid parameter in option `%s'\n", arg); - return -1; - } - } - return 0; + assert(format[0] == '%'); + if (format[1] == 's') { + char *copy = strdup(param); + if (!copy) + return alloc_failed(); + + *(char **) var = copy; + } else { + if (sscanf(param, format, var) != 1) { + fprintf(stderr, "fuse: invalid parameter in option `%s'\n", arg); + return -1; + } + } + return 0; } static int process_opt(struct fuse_opt_context *ctx, - const struct fuse_opt *opt, unsigned sep, - const char *arg, int iso) + const struct fuse_opt *opt, unsigned sep, + const char *arg, int iso) { - if (opt->offset == -1U) { - if (call_proc(ctx, arg, opt->value, iso) == -1) - return -1; - } else { - void *var = ctx->data + opt->offset; - if (sep && opt->templ[sep + 1]) { - const char *param = arg + sep; - if (opt->templ[sep] == '=') - param ++; - if (process_opt_param(var, opt->templ + sep + 1, - param, arg) == -1) - return -1; - } else - *(int *)var = opt->value; - } - return 0; + if (opt->offset == -1U) { + if (call_proc(ctx, arg, opt->value, iso) == -1) + return -1; + } else { + void *var = ctx->data + opt->offset; + if (sep && opt->templ[sep + 1]) { + const char *param = arg + sep; + if (opt->templ[sep] == '=') + param ++; + if (process_opt_param(var, opt->templ + sep + 1, + param, arg) == -1) + return -1; + } else + *(int *)var = opt->value; + } + return 0; } static int process_opt_sep_arg(struct fuse_opt_context *ctx, - const struct fuse_opt *opt, unsigned sep, - const char *arg, int iso) + const struct fuse_opt *opt, unsigned sep, + const char *arg, int iso) { - int res; - char *newarg; - char *param; + int res; + char *newarg; + char *param; - if (next_arg(ctx, arg) == -1) - return -1; + if (next_arg(ctx, arg) == -1) + return -1; - param = ctx->argv[ctx->argctr]; - newarg = malloc(sep + strlen(param) + 1); - if (!newarg) - return alloc_failed(); + param = ctx->argv[ctx->argctr]; + newarg = malloc(sep + strlen(param) + 1); + if (!newarg) + return alloc_failed(); - memcpy(newarg, arg, sep); - strcpy(newarg + sep, param); - res = process_opt(ctx, opt, sep, newarg, iso); - free(newarg); + memcpy(newarg, arg, sep); + strcpy(newarg + sep, param); + res = process_opt(ctx, opt, sep, newarg, iso); + free(newarg); - return res; + return res; } static int process_gopt(struct fuse_opt_context *ctx, const char *arg, int iso) { - unsigned sep; - const struct fuse_opt *opt = find_opt(ctx->opt, arg, &sep); - if (opt) { - for (; opt; opt = find_opt(opt + 1, arg, &sep)) { - int res; - if (sep && opt->templ[sep] == ' ' && !arg[sep]) - res = process_opt_sep_arg(ctx, opt, sep, arg, iso); - else - res = process_opt(ctx, opt, sep, arg, iso); - if (res == -1) - return -1; - } - return 0; - } else - return call_proc(ctx, arg, FUSE_OPT_KEY_OPT, iso); + unsigned sep; + const struct fuse_opt *opt = find_opt(ctx->opt, arg, &sep); + if (opt) { + for (; opt; opt = find_opt(opt + 1, arg, &sep)) { + int res; + if (sep && opt->templ[sep] == ' ' && !arg[sep]) + res = process_opt_sep_arg(ctx, opt, sep, arg, + iso); + else + res = process_opt(ctx, opt, sep, arg, iso); + if (res == -1) + return -1; + } + return 0; + } else + return call_proc(ctx, arg, FUSE_OPT_KEY_OPT, iso); } static int process_real_option_group(struct fuse_opt_context *ctx, char *opts) { - char *sep; - - do { - int res; - sep = strchr(opts, ','); - if (sep) - *sep = '\0'; - res = process_gopt(ctx, opts, 1); - if (res == -1) - return -1; - opts = sep + 1; - } while (sep); - - return 0; + char *sep; + + do { + int res; + sep = strchr(opts, ','); + if (sep) + *sep = '\0'; + res = process_gopt(ctx, opts, 1); + if (res == -1) + return -1; + opts = sep + 1; + } while (sep); + + return 0; } static int process_option_group(struct fuse_opt_context *ctx, const char *opts) { - int res; - char *copy; - const char *sep = strchr(opts, ','); - if (!sep) - return process_gopt(ctx, opts, 1); - - copy = strdup(opts); - if (!copy) { - fprintf(stderr, "fuse: memory allocation failed\n"); - return -1; - } - res = process_real_option_group(ctx, copy); - free(copy); - return res; + int res; + char *copy; + const char *sep = strchr(opts, ','); + if (!sep) + return process_gopt(ctx, opts, 1); + + copy = strdup(opts); + if (!copy) { + fprintf(stderr, "fuse: memory allocation failed\n"); + return -1; + } + res = process_real_option_group(ctx, copy); + free(copy); + return res; } static int process_one(struct fuse_opt_context *ctx, const char *arg) { - if (ctx->nonopt || arg[0] != '-') - return call_proc(ctx, arg, FUSE_OPT_KEY_NONOPT, 0); - else if (arg[1] == 'o') { - if (arg[2]) - return process_option_group(ctx, arg + 2); - else { - if (next_arg(ctx, arg) == -1) - return -1; - - return process_option_group(ctx, ctx->argv[ctx->argctr]); - } - } else if (arg[1] == '-' && !arg[2]) { - if (add_arg(ctx, arg) == -1) - return -1; - ctx->nonopt = ctx->outargs.argc; - return 0; - } else - return process_gopt(ctx, arg, 0); + if (ctx->nonopt || arg[0] != '-') + return call_proc(ctx, arg, FUSE_OPT_KEY_NONOPT, 0); + else if (arg[1] == 'o') { + if (arg[2]) + return process_option_group(ctx, arg + 2); + else { + if (next_arg(ctx, arg) == -1) + return -1; + + return process_option_group(ctx, + ctx->argv[ctx->argctr]); + } + } else if (arg[1] == '-' && !arg[2]) { + if (add_arg(ctx, arg) == -1) + return -1; + ctx->nonopt = ctx->outargs.argc; + return 0; + } else + return process_gopt(ctx, arg, 0); } static int opt_parse(struct fuse_opt_context *ctx) { - if (ctx->argc) { - if (add_arg(ctx, ctx->argv[0]) == -1) - return -1; - } - - for (ctx->argctr = 1; ctx->argctr < ctx->argc; ctx->argctr++) - if (process_one(ctx, ctx->argv[ctx->argctr]) == -1) - return -1; - - if (ctx->opts) { - if (fuse_opt_insert_arg(&ctx->outargs, 1, "-o") == -1 || - fuse_opt_insert_arg(&ctx->outargs, 2, ctx->opts) == -1) - return -1; - } - if (ctx->nonopt && ctx->nonopt == ctx->outargs.argc) { - free(ctx->outargs.argv[ctx->outargs.argc - 1]); - ctx->outargs.argv[--ctx->outargs.argc] = NULL; - } - - return 0; + if (ctx->argc) { + if (add_arg(ctx, ctx->argv[0]) == -1) + return -1; + } + + for (ctx->argctr = 1; ctx->argctr < ctx->argc; ctx->argctr++) + if (process_one(ctx, ctx->argv[ctx->argctr]) == -1) + return -1; + + if (ctx->opts) { + if (fuse_opt_insert_arg(&ctx->outargs, 1, "-o") == -1 || + fuse_opt_insert_arg(&ctx->outargs, 2, ctx->opts) == -1) + return -1; + } + if (ctx->nonopt && ctx->nonopt == ctx->outargs.argc) { + free(ctx->outargs.argv[ctx->outargs.argc - 1]); + ctx->outargs.argv[--ctx->outargs.argc] = NULL; + } + + return 0; } int fuse_opt_parse(struct fuse_args *args, void *data, - const struct fuse_opt opts[], fuse_opt_proc_t proc) + const struct fuse_opt opts[], fuse_opt_proc_t proc) { - int res; - struct fuse_opt_context ctx = { - .data = data, - .opt = opts, - .proc = proc, - }; - - if (!args || !args->argv || !args->argc) - return 0; - - ctx.argc = args->argc; - ctx.argv = args->argv; - - res = opt_parse(&ctx); - if (res != -1) { - struct fuse_args tmp = *args; - *args = ctx.outargs; - ctx.outargs = tmp; - } - free(ctx.opts); - fuse_opt_free_args(&ctx.outargs); - return res; + int res; + struct fuse_opt_context ctx = { + .data = data, + .opt = opts, + .proc = proc, + }; + + if (!args || !args->argv || !args->argc) + return 0; + + ctx.argc = args->argc; + ctx.argv = args->argv; + + res = opt_parse(&ctx); + if (res != -1) { + struct fuse_args tmp = *args; + *args = ctx.outargs; + ctx.outargs = tmp; + } + free(ctx.opts); + fuse_opt_free_args(&ctx.outargs); + return res; } /* This symbol version was mistakenly added to the version script */ diff --git a/lib/fuse_session.c b/lib/fuse_session.c index cf2e20b..5efedd9 100644 --- a/lib/fuse_session.c +++ b/lib/fuse_session.c @@ -1,9 +1,9 @@ /* - FUSE: Filesystem in Userspace - Copyright (C) 2001-2007 Miklos Szeredi + FUSE: Filesystem in Userspace + Copyright (C) 2001-2007 Miklos Szeredi - This program can be distributed under the terms of the GNU LGPLv2. - See the file COPYING.LIB + This program can be distributed under the terms of the GNU LGPLv2. + See the file COPYING.LIB */ #include "fuse_lowlevel.h" @@ -18,190 +18,191 @@ #include struct fuse_session { - struct fuse_session_ops op; + struct fuse_session_ops op; - void *data; + void *data; - volatile int exited; + volatile int exited; - struct fuse_chan *ch; + struct fuse_chan *ch; }; struct fuse_chan { - struct fuse_chan_ops op; + struct fuse_chan_ops op; - struct fuse_session *se; + struct fuse_session *se; - int fd; + int fd; - size_t bufsize; + size_t bufsize; - void *data; + void *data; - int compat; + int compat; }; struct fuse_session *fuse_session_new(struct fuse_session_ops *op, void *data) { - struct fuse_session *se = (struct fuse_session *) malloc(sizeof(*se)); - if (se == NULL) { - fprintf(stderr, "fuse: failed to allocate session\n"); - return NULL; - } + struct fuse_session *se = (struct fuse_session *) malloc(sizeof(*se)); + if (se == NULL) { + fprintf(stderr, "fuse: failed to allocate session\n"); + return NULL; + } - memset(se, 0, sizeof(*se)); - se->op = *op; - se->data = data; + memset(se, 0, sizeof(*se)); + se->op = *op; + se->data = data; - return se; + return se; } void fuse_session_add_chan(struct fuse_session *se, struct fuse_chan *ch) { - assert(se->ch == NULL); - assert(ch->se == NULL); - se->ch = ch; - ch->se = se; + assert(se->ch == NULL); + assert(ch->se == NULL); + se->ch = ch; + ch->se = se; } void fuse_session_remove_chan(struct fuse_chan *ch) { - struct fuse_session *se = ch->se; - if (se) { - assert(se->ch == ch); - se->ch = NULL; - ch->se = NULL; - } + struct fuse_session *se = ch->se; + if (se) { + assert(se->ch == ch); + se->ch = NULL; + ch->se = NULL; + } } struct fuse_chan *fuse_session_next_chan(struct fuse_session *se, - struct fuse_chan *ch) + struct fuse_chan *ch) { - assert(ch == NULL || ch == se->ch); - if (ch == NULL) - return se->ch; - else - return NULL; + assert(ch == NULL || ch == se->ch); + if (ch == NULL) + return se->ch; + else + return NULL; } void fuse_session_process(struct fuse_session *se, const char *buf, size_t len, - struct fuse_chan *ch) + struct fuse_chan *ch) { - se->op.process(se->data, buf, len, ch); + se->op.process(se->data, buf, len, ch); } void fuse_session_destroy(struct fuse_session *se) { - if (se->op.destroy) - se->op.destroy(se->data); - if (se->ch != NULL) - fuse_chan_destroy(se->ch); - free(se); + if (se->op.destroy) + se->op.destroy(se->data); + if (se->ch != NULL) + fuse_chan_destroy(se->ch); + free(se); } void fuse_session_exit(struct fuse_session *se) { - if (se->op.exit) - se->op.exit(se->data, 1); - se->exited = 1; + if (se->op.exit) + se->op.exit(se->data, 1); + se->exited = 1; } void fuse_session_reset(struct fuse_session *se) { - if (se->op.exit) - se->op.exit(se->data, 0); - se->exited = 0; + if (se->op.exit) + se->op.exit(se->data, 0); + se->exited = 0; } int fuse_session_exited(struct fuse_session *se) { - if (se->op.exited) - return se->op.exited(se->data); - else - return se->exited; + if (se->op.exited) + return se->op.exited(se->data); + else + return se->exited; } static struct fuse_chan *fuse_chan_new_common(struct fuse_chan_ops *op, int fd, - size_t bufsize, void *data, int compat) + size_t bufsize, void *data, + int compat) { - struct fuse_chan *ch = (struct fuse_chan *) malloc(sizeof(*ch)); - if (ch == NULL) { - fprintf(stderr, "fuse: failed to allocate channel\n"); - return NULL; - } + struct fuse_chan *ch = (struct fuse_chan *) malloc(sizeof(*ch)); + if (ch == NULL) { + fprintf(stderr, "fuse: failed to allocate channel\n"); + return NULL; + } - memset(ch, 0, sizeof(*ch)); - ch->op = *op; - ch->fd = fd; - ch->bufsize = bufsize; - ch->data = data; - ch->compat = compat; + memset(ch, 0, sizeof(*ch)); + ch->op = *op; + ch->fd = fd; + ch->bufsize = bufsize; + ch->data = data; + ch->compat = compat; - return ch; + return ch; } struct fuse_chan *fuse_chan_new(struct fuse_chan_ops *op, int fd, - size_t bufsize, void *data) + size_t bufsize, void *data) { - return fuse_chan_new_common(op, fd, bufsize, data, 0); + return fuse_chan_new_common(op, fd, bufsize, data, 0); } struct fuse_chan *fuse_chan_new_compat24(struct fuse_chan_ops_compat24 *op, - int fd, size_t bufsize, void *data) + int fd, size_t bufsize, void *data) { - return fuse_chan_new_common((struct fuse_chan_ops *) op, fd, bufsize, - data, 24); + return fuse_chan_new_common((struct fuse_chan_ops *) op, fd, bufsize, + data, 24); } int fuse_chan_fd(struct fuse_chan *ch) { - return ch->fd; + return ch->fd; } size_t fuse_chan_bufsize(struct fuse_chan *ch) { - return ch->bufsize; + return ch->bufsize; } void *fuse_chan_data(struct fuse_chan *ch) { - return ch->data; + return ch->data; } struct fuse_session *fuse_chan_session(struct fuse_chan *ch) { - return ch->se; + return ch->se; } int fuse_chan_recv(struct fuse_chan **chp, char *buf, size_t size) { - struct fuse_chan *ch = *chp; - if (ch->compat) - return ((struct fuse_chan_ops_compat24 *) &ch->op) - ->receive(ch, buf, size); - else - return ch->op.receive(chp, buf, size); + struct fuse_chan *ch = *chp; + if (ch->compat) + return ((struct fuse_chan_ops_compat24 *) &ch->op) + ->receive(ch, buf, size); + else + return ch->op.receive(chp, buf, size); } int fuse_chan_receive(struct fuse_chan *ch, char *buf, size_t size) { - int res; + int res; - res = fuse_chan_recv(&ch, buf, size); - return res >= 0 ? res : (res != -EINTR && res != -EAGAIN) ? -1 : 0; + res = fuse_chan_recv(&ch, buf, size); + return res >= 0 ? res : (res != -EINTR && res != -EAGAIN) ? -1 : 0; } int fuse_chan_send(struct fuse_chan *ch, const struct iovec iov[], size_t count) { - return ch->op.send(ch, iov, count); + return ch->op.send(ch, iov, count); } void fuse_chan_destroy(struct fuse_chan *ch) { - fuse_session_remove_chan(ch); - if (ch->op.destroy) - ch->op.destroy(ch); - free(ch); + fuse_session_remove_chan(ch); + if (ch->op.destroy) + ch->op.destroy(ch); + free(ch); } #ifndef __FreeBSD__ diff --git a/lib/fuse_signals.c b/lib/fuse_signals.c index 25998bf..88ac39e 100644 --- a/lib/fuse_signals.c +++ b/lib/fuse_signals.c @@ -1,9 +1,9 @@ /* - FUSE: Filesystem in Userspace - Copyright (C) 2001-2007 Miklos Szeredi + FUSE: Filesystem in Userspace + Copyright (C) 2001-2007 Miklos Szeredi - This program can be distributed under the terms of the GNU LGPLv2. - See the file COPYING.LIB + This program can be distributed under the terms of the GNU LGPLv2. + See the file COPYING.LIB */ #include "fuse_lowlevel.h" @@ -16,57 +16,57 @@ static struct fuse_session *fuse_instance; static void exit_handler(int sig) { - (void) sig; - if (fuse_instance) - fuse_session_exit(fuse_instance); + (void) sig; + if (fuse_instance) + fuse_session_exit(fuse_instance); } static int set_one_signal_handler(int sig, void (*handler)(int)) { - struct sigaction sa; - struct sigaction old_sa; + struct sigaction sa; + struct sigaction old_sa; - memset(&sa, 0, sizeof(struct sigaction)); - sa.sa_handler = handler; - sigemptyset(&(sa.sa_mask)); - sa.sa_flags = 0; + memset(&sa, 0, sizeof(struct sigaction)); + sa.sa_handler = handler; + sigemptyset(&(sa.sa_mask)); + sa.sa_flags = 0; - if (sigaction(sig, NULL, &old_sa) == -1) { - perror("fuse: cannot get old signal handler"); - return -1; - } + if (sigaction(sig, NULL, &old_sa) == -1) { + perror("fuse: cannot get old signal handler"); + return -1; + } - if (old_sa.sa_handler == SIG_DFL && - sigaction(sig, &sa, NULL) == -1) { - perror("fuse: cannot set signal handler"); - return -1; - } - return 0; + if (old_sa.sa_handler == SIG_DFL && + sigaction(sig, &sa, NULL) == -1) { + perror("fuse: cannot set signal handler"); + return -1; + } + return 0; } int fuse_set_signal_handlers(struct fuse_session *se) { - if (set_one_signal_handler(SIGHUP, exit_handler) == -1 || - set_one_signal_handler(SIGINT, exit_handler) == -1 || - set_one_signal_handler(SIGTERM, exit_handler) == -1 || - set_one_signal_handler(SIGPIPE, SIG_IGN) == -1) - return -1; + if (set_one_signal_handler(SIGHUP, exit_handler) == -1 || + set_one_signal_handler(SIGINT, exit_handler) == -1 || + set_one_signal_handler(SIGTERM, exit_handler) == -1 || + set_one_signal_handler(SIGPIPE, SIG_IGN) == -1) + return -1; - fuse_instance = se; - return 0; + fuse_instance = se; + return 0; } void fuse_remove_signal_handlers(struct fuse_session *se) { - if (fuse_instance != se) - fprintf(stderr, - "fuse: fuse_remove_signal_handlers: unknown session\n"); - else - fuse_instance = NULL; + if (fuse_instance != se) + fprintf(stderr, + "fuse: fuse_remove_signal_handlers: unknown session\n"); + else + fuse_instance = NULL; - set_one_signal_handler(SIGHUP, SIG_DFL); - set_one_signal_handler(SIGINT, SIG_DFL); - set_one_signal_handler(SIGTERM, SIG_DFL); - set_one_signal_handler(SIGPIPE, SIG_DFL); + set_one_signal_handler(SIGHUP, SIG_DFL); + set_one_signal_handler(SIGINT, SIG_DFL); + set_one_signal_handler(SIGTERM, SIG_DFL); + set_one_signal_handler(SIGPIPE, SIG_DFL); } diff --git a/lib/helper.c b/lib/helper.c index fbbf4b2..a175ee9 100644 --- a/lib/helper.c +++ b/lib/helper.c @@ -1,9 +1,9 @@ /* - FUSE: Filesystem in Userspace - Copyright (C) 2001-2007 Miklos Szeredi + FUSE: Filesystem in Userspace + Copyright (C) 2001-2007 Miklos Szeredi - This program can be distributed under the terms of the GNU LGPLv2. - See the file COPYING.LIB. + This program can be distributed under the terms of the GNU LGPLv2. + See the file COPYING.LIB. */ #include "config.h" @@ -22,333 +22,336 @@ #include enum { - KEY_HELP, - KEY_HELP_NOHEADER, - KEY_VERSION, + KEY_HELP, + KEY_HELP_NOHEADER, + KEY_VERSION, }; struct helper_opts { - int singlethread; - int foreground; - int nodefault_subtype; - char *mountpoint; + int singlethread; + int foreground; + int nodefault_subtype; + char *mountpoint; }; #define FUSE_HELPER_OPT(t, p) { t, offsetof(struct helper_opts, p), 1 } static const struct fuse_opt fuse_helper_opts[] = { - FUSE_HELPER_OPT("-d", foreground), - FUSE_HELPER_OPT("debug", foreground), - FUSE_HELPER_OPT("-f", foreground), - FUSE_HELPER_OPT("-s", singlethread), - FUSE_HELPER_OPT("fsname=", nodefault_subtype), - FUSE_HELPER_OPT("subtype=", nodefault_subtype), - - FUSE_OPT_KEY("-h", KEY_HELP), - FUSE_OPT_KEY("--help", KEY_HELP), - FUSE_OPT_KEY("-ho", KEY_HELP_NOHEADER), - FUSE_OPT_KEY("-V", KEY_VERSION), - FUSE_OPT_KEY("--version", KEY_VERSION), - FUSE_OPT_KEY("-d", FUSE_OPT_KEY_KEEP), - FUSE_OPT_KEY("debug", FUSE_OPT_KEY_KEEP), - FUSE_OPT_KEY("fsname=", FUSE_OPT_KEY_KEEP), - FUSE_OPT_KEY("subtype=", FUSE_OPT_KEY_KEEP), - FUSE_OPT_END + FUSE_HELPER_OPT("-d", foreground), + FUSE_HELPER_OPT("debug", foreground), + FUSE_HELPER_OPT("-f", foreground), + FUSE_HELPER_OPT("-s", singlethread), + FUSE_HELPER_OPT("fsname=", nodefault_subtype), + FUSE_HELPER_OPT("subtype=", nodefault_subtype), + + FUSE_OPT_KEY("-h", KEY_HELP), + FUSE_OPT_KEY("--help", KEY_HELP), + FUSE_OPT_KEY("-ho", KEY_HELP_NOHEADER), + FUSE_OPT_KEY("-V", KEY_VERSION), + FUSE_OPT_KEY("--version", KEY_VERSION), + FUSE_OPT_KEY("-d", FUSE_OPT_KEY_KEEP), + FUSE_OPT_KEY("debug", FUSE_OPT_KEY_KEEP), + FUSE_OPT_KEY("fsname=", FUSE_OPT_KEY_KEEP), + FUSE_OPT_KEY("subtype=", FUSE_OPT_KEY_KEEP), + FUSE_OPT_END }; static void usage(const char *progname) { - fprintf(stderr, - "usage: %s mountpoint [options]\n\n", progname); - fprintf(stderr, - "general options:\n" - " -o opt,[opt...] mount options\n" - " -h --help print help\n" - " -V --version print version\n" - "\n"); + fprintf(stderr, + "usage: %s mountpoint [options]\n\n", progname); + fprintf(stderr, + "general options:\n" + " -o opt,[opt...] mount options\n" + " -h --help print help\n" + " -V --version print version\n" + "\n"); } static void helper_help(void) { - fprintf(stderr, - "FUSE options:\n" - " -d -o debug enable debug output (implies -f)\n" - " -f foreground operation\n" - " -s disable multi-threaded operation\n" - "\n" - ); + fprintf(stderr, + "FUSE options:\n" + " -d -o debug enable debug output (implies -f)\n" + " -f foreground operation\n" + " -s disable multi-threaded operation\n" + "\n" + ); } static void helper_version(void) { - fprintf(stderr, "FUSE library version: %s\n", PACKAGE_VERSION); + fprintf(stderr, "FUSE library version: %s\n", PACKAGE_VERSION); } static int fuse_helper_opt_proc(void *data, const char *arg, int key, - struct fuse_args *outargs) + struct fuse_args *outargs) { - struct helper_opts *hopts = data; - - switch (key) { - case KEY_HELP: - usage(outargs->argv[0]); - /* fall through */ - - case KEY_HELP_NOHEADER: - helper_help(); - return fuse_opt_add_arg(outargs, "-h"); - - case KEY_VERSION: - helper_version(); - return 1; - - case FUSE_OPT_KEY_NONOPT: - if (!hopts->mountpoint) { - char mountpoint[PATH_MAX]; - if (realpath(arg, mountpoint) == NULL) { - fprintf(stderr, "fuse: bad mount point `%s': %s\n", arg, strerror(errno)); - return -1; - } - return fuse_opt_add_opt(&hopts->mountpoint, mountpoint); - } else { - fprintf(stderr, "fuse: invalid argument `%s'\n", arg); - return -1; - } - - default: - return 1; - } + struct helper_opts *hopts = data; + + switch (key) { + case KEY_HELP: + usage(outargs->argv[0]); + /* fall through */ + + case KEY_HELP_NOHEADER: + helper_help(); + return fuse_opt_add_arg(outargs, "-h"); + + case KEY_VERSION: + helper_version(); + return 1; + + case FUSE_OPT_KEY_NONOPT: + if (!hopts->mountpoint) { + char mountpoint[PATH_MAX]; + if (realpath(arg, mountpoint) == NULL) { + fprintf(stderr, + "fuse: bad mount point `%s': %s\n", + arg, strerror(errno)); + return -1; + } + return fuse_opt_add_opt(&hopts->mountpoint, mountpoint); + } else { + fprintf(stderr, "fuse: invalid argument `%s'\n", arg); + return -1; + } + + default: + return 1; + } } static int add_default_subtype(const char *progname, struct fuse_args *args) { - int res; - char *subtype_opt; - const char *basename = strrchr(progname, '/'); - if (basename == NULL) - basename = progname; - else if (basename[1] != '\0') - basename++; - - subtype_opt = (char *) malloc(strlen(basename) + 64); - if (subtype_opt == NULL) { - fprintf(stderr, "fuse: memory allocation failed\n"); - return -1; - } - sprintf(subtype_opt, "-osubtype=%s", basename); - res = fuse_opt_add_arg(args, subtype_opt); - free(subtype_opt); - return res; + int res; + char *subtype_opt; + const char *basename = strrchr(progname, '/'); + if (basename == NULL) + basename = progname; + else if (basename[1] != '\0') + basename++; + + subtype_opt = (char *) malloc(strlen(basename) + 64); + if (subtype_opt == NULL) { + fprintf(stderr, "fuse: memory allocation failed\n"); + return -1; + } + sprintf(subtype_opt, "-osubtype=%s", basename); + res = fuse_opt_add_arg(args, subtype_opt); + free(subtype_opt); + return res; } int fuse_parse_cmdline(struct fuse_args *args, char **mountpoint, - int *multithreaded, int *foreground) + int *multithreaded, int *foreground) { - int res; - struct helper_opts hopts; - - memset(&hopts, 0, sizeof(hopts)); - res = fuse_opt_parse(args, &hopts, fuse_helper_opts, fuse_helper_opt_proc); - if (res == -1) - return -1; - - if (!hopts.nodefault_subtype) { - res = add_default_subtype(args->argv[0], args); - if (res == -1) - goto err; - } - if (mountpoint) - *mountpoint = hopts.mountpoint; - else - free(hopts.mountpoint); - - if (multithreaded) - *multithreaded = !hopts.singlethread; - if (foreground) - *foreground = hopts.foreground; - return 0; - - err: - free(hopts.mountpoint); - return -1; + int res; + struct helper_opts hopts; + + memset(&hopts, 0, sizeof(hopts)); + res = fuse_opt_parse(args, &hopts, fuse_helper_opts, + fuse_helper_opt_proc); + if (res == -1) + return -1; + + if (!hopts.nodefault_subtype) { + res = add_default_subtype(args->argv[0], args); + if (res == -1) + goto err; + } + if (mountpoint) + *mountpoint = hopts.mountpoint; + else + free(hopts.mountpoint); + + if (multithreaded) + *multithreaded = !hopts.singlethread; + if (foreground) + *foreground = hopts.foreground; + return 0; + +err: + free(hopts.mountpoint); + return -1; } int fuse_daemonize(int foreground) { - int res; - - if (!foreground) { - res = daemon(0, 0); - if (res == -1) { - perror("fuse: failed to daemonize program\n"); - return -1; - } - } - return 0; + int res; + + if (!foreground) { + res = daemon(0, 0); + if (res == -1) { + perror("fuse: failed to daemonize program\n"); + return -1; + } + } + return 0; } static struct fuse_chan *fuse_mount_common(const char *mountpoint, - struct fuse_args *args) + struct fuse_args *args) { - struct fuse_chan *ch; - int fd; - - /* - * Make sure file descriptors 0, 1 and 2 are open, otherwise chaos - * would ensue. - */ - do { - fd = open("/dev/null", O_RDWR); - if (fd > 2) - close(fd); - } while (fd >= 0 && fd <= 2); - - fd = fuse_mount_compat25(mountpoint, args); - if (fd == -1) - return NULL; - - ch = fuse_kern_chan_new(fd); - if (!ch) - fuse_kern_unmount(mountpoint, fd); - - return ch; + struct fuse_chan *ch; + int fd; + + /* + * Make sure file descriptors 0, 1 and 2 are open, otherwise chaos + * would ensue. + */ + do { + fd = open("/dev/null", O_RDWR); + if (fd > 2) + close(fd); + } while (fd >= 0 && fd <= 2); + + fd = fuse_mount_compat25(mountpoint, args); + if (fd == -1) + return NULL; + + ch = fuse_kern_chan_new(fd); + if (!ch) + fuse_kern_unmount(mountpoint, fd); + + return ch; } struct fuse_chan *fuse_mount(const char *mountpoint, struct fuse_args *args) { - return fuse_mount_common(mountpoint, args); + return fuse_mount_common(mountpoint, args); } static void fuse_unmount_common(const char *mountpoint, struct fuse_chan *ch) { - int fd = ch ? fuse_chan_fd(ch) : -1; - fuse_kern_unmount(mountpoint, fd); - fuse_chan_destroy(ch); + int fd = ch ? fuse_chan_fd(ch) : -1; + fuse_kern_unmount(mountpoint, fd); + fuse_chan_destroy(ch); } void fuse_unmount(const char *mountpoint, struct fuse_chan *ch) { - fuse_unmount_common(mountpoint, ch); + fuse_unmount_common(mountpoint, ch); } static struct fuse *fuse_setup_common(int argc, char *argv[], - const struct fuse_operations *op, - size_t op_size, - char **mountpoint, - int *multithreaded, - int *fd, - void *user_data, - int compat) + const struct fuse_operations *op, + size_t op_size, + char **mountpoint, + int *multithreaded, + int *fd, + void *user_data, + int compat) { - struct fuse_args args = FUSE_ARGS_INIT(argc, argv); - struct fuse_chan *ch; - struct fuse *fuse; - int foreground; - int res; - - res = fuse_parse_cmdline(&args, mountpoint, multithreaded, &foreground); - if (res == -1) - return NULL; - - ch = fuse_mount_common(*mountpoint, &args); - if (!ch) { - fuse_opt_free_args(&args); - goto err_free; - } - - fuse = fuse_new_common(ch, &args, op, op_size, user_data, compat); - fuse_opt_free_args(&args); - if (fuse == NULL) - goto err_unmount; - - res = fuse_daemonize(foreground); - if (res == -1) - goto err_unmount; - - res = fuse_set_signal_handlers(fuse_get_session(fuse)); - if (res == -1) - goto err_unmount; - - if (fd) - *fd = fuse_chan_fd(ch); - - return fuse; - - err_unmount: - fuse_unmount_common(*mountpoint, ch); - if (fuse) - fuse_destroy(fuse); - err_free: - free(*mountpoint); - return NULL; + struct fuse_args args = FUSE_ARGS_INIT(argc, argv); + struct fuse_chan *ch; + struct fuse *fuse; + int foreground; + int res; + + res = fuse_parse_cmdline(&args, mountpoint, multithreaded, &foreground); + if (res == -1) + return NULL; + + ch = fuse_mount_common(*mountpoint, &args); + if (!ch) { + fuse_opt_free_args(&args); + goto err_free; + } + + fuse = fuse_new_common(ch, &args, op, op_size, user_data, compat); + fuse_opt_free_args(&args); + if (fuse == NULL) + goto err_unmount; + + res = fuse_daemonize(foreground); + if (res == -1) + goto err_unmount; + + res = fuse_set_signal_handlers(fuse_get_session(fuse)); + if (res == -1) + goto err_unmount; + + if (fd) + *fd = fuse_chan_fd(ch); + + return fuse; + +err_unmount: + fuse_unmount_common(*mountpoint, ch); + if (fuse) + fuse_destroy(fuse); +err_free: + free(*mountpoint); + return NULL; } struct fuse *fuse_setup(int argc, char *argv[], - const struct fuse_operations *op, size_t op_size, - char **mountpoint, int *multithreaded, void *user_data) + const struct fuse_operations *op, size_t op_size, + char **mountpoint, int *multithreaded, void *user_data) { - return fuse_setup_common(argc, argv, op, op_size, mountpoint, - multithreaded, NULL, user_data, 0); + return fuse_setup_common(argc, argv, op, op_size, mountpoint, + multithreaded, NULL, user_data, 0); } static void fuse_teardown_common(struct fuse *fuse, char *mountpoint) { - struct fuse_session *se = fuse_get_session(fuse); - struct fuse_chan *ch = fuse_session_next_chan(se, NULL); - fuse_remove_signal_handlers(se); - fuse_unmount_common(mountpoint, ch); - fuse_destroy(fuse); - free(mountpoint); + struct fuse_session *se = fuse_get_session(fuse); + struct fuse_chan *ch = fuse_session_next_chan(se, NULL); + fuse_remove_signal_handlers(se); + fuse_unmount_common(mountpoint, ch); + fuse_destroy(fuse); + free(mountpoint); } void fuse_teardown(struct fuse *fuse, char *mountpoint) { - fuse_teardown_common(fuse, mountpoint); + fuse_teardown_common(fuse, mountpoint); } static int fuse_main_common(int argc, char *argv[], - const struct fuse_operations *op, size_t op_size, - void *user_data, int compat) + const struct fuse_operations *op, size_t op_size, + void *user_data, int compat) { - struct fuse *fuse; - char *mountpoint; - int multithreaded; - int res; - - fuse = fuse_setup_common(argc, argv, op, op_size, &mountpoint, - &multithreaded, NULL, user_data, compat); - if (fuse == NULL) - return 1; - - if (multithreaded) - res = fuse_loop_mt(fuse); - else - res = fuse_loop(fuse); - - fuse_teardown_common(fuse, mountpoint); - if (res == -1) - return 1; - - return 0; + struct fuse *fuse; + char *mountpoint; + int multithreaded; + int res; + + fuse = fuse_setup_common(argc, argv, op, op_size, &mountpoint, + &multithreaded, NULL, user_data, compat); + if (fuse == NULL) + return 1; + + if (multithreaded) + res = fuse_loop_mt(fuse); + else + res = fuse_loop(fuse); + + fuse_teardown_common(fuse, mountpoint); + if (res == -1) + return 1; + + return 0; } int fuse_main_real(int argc, char *argv[], const struct fuse_operations *op, - size_t op_size, void *user_data) + size_t op_size, void *user_data) { - return fuse_main_common(argc, argv, op, op_size, user_data, 0); + return fuse_main_common(argc, argv, op, op_size, user_data, 0); } #undef fuse_main int fuse_main(void); int fuse_main(void) { - fprintf(stderr, "fuse_main(): This function does not exist\n"); - return -1; + fprintf(stderr, "fuse_main(): This function does not exist\n"); + return -1; } int fuse_version(void) { - return FUSE_VERSION; + return FUSE_VERSION; } #include "fuse_compat.h" @@ -356,51 +359,53 @@ int fuse_version(void) #ifndef __FreeBSD__ struct fuse *fuse_setup_compat22(int argc, char *argv[], - const struct fuse_operations_compat22 *op, - size_t op_size, char **mountpoint, - int *multithreaded, int *fd) + const struct fuse_operations_compat22 *op, + size_t op_size, char **mountpoint, + int *multithreaded, int *fd) { - return fuse_setup_common(argc, argv, (struct fuse_operations *) op, - op_size, mountpoint, multithreaded, fd, NULL, 22); + return fuse_setup_common(argc, argv, (struct fuse_operations *) op, + op_size, mountpoint, multithreaded, fd, NULL, + 22); } struct fuse *fuse_setup_compat2(int argc, char *argv[], - const struct fuse_operations_compat2 *op, - char **mountpoint, int *multithreaded, - int *fd) + const struct fuse_operations_compat2 *op, + char **mountpoint, int *multithreaded, + int *fd) { - return fuse_setup_common(argc, argv, (struct fuse_operations *) op, - sizeof(struct fuse_operations_compat2), - mountpoint, multithreaded, fd, NULL, 21); + return fuse_setup_common(argc, argv, (struct fuse_operations *) op, + sizeof(struct fuse_operations_compat2), + mountpoint, multithreaded, fd, NULL, 21); } int fuse_main_real_compat22(int argc, char *argv[], - const struct fuse_operations_compat22 *op, - size_t op_size) + const struct fuse_operations_compat22 *op, + size_t op_size) { - return fuse_main_common(argc, argv, (struct fuse_operations *) op, op_size, - NULL, 22); + return fuse_main_common(argc, argv, (struct fuse_operations *) op, + op_size, NULL, 22); } void fuse_main_compat1(int argc, char *argv[], - const struct fuse_operations_compat1 *op) + const struct fuse_operations_compat1 *op) { - fuse_main_common(argc, argv, (struct fuse_operations *) op, - sizeof(struct fuse_operations_compat1), NULL, 11); + fuse_main_common(argc, argv, (struct fuse_operations *) op, + sizeof(struct fuse_operations_compat1), NULL, 11); } int fuse_main_compat2(int argc, char *argv[], - const struct fuse_operations_compat2 *op) + const struct fuse_operations_compat2 *op) { - return fuse_main_common(argc, argv, (struct fuse_operations *) op, - sizeof(struct fuse_operations_compat2), NULL, 21); + return fuse_main_common(argc, argv, (struct fuse_operations *) op, + sizeof(struct fuse_operations_compat2), NULL, + 21); } int fuse_mount_compat1(const char *mountpoint, const char *args[]) { - /* just ignore mount args for now */ - (void) args; - return fuse_mount_compat22(mountpoint, NULL); + /* just ignore mount args for now */ + (void) args; + return fuse_mount_compat22(mountpoint, NULL); } FUSE_SYMVER(".symver fuse_setup_compat2,__fuse_setup@"); @@ -413,31 +418,32 @@ FUSE_SYMVER(".symver fuse_main_real_compat22,fuse_main_real@FUSE_2.2"); struct fuse *fuse_setup_compat25(int argc, char *argv[], - const struct fuse_operations_compat25 *op, - size_t op_size, char **mountpoint, - int *multithreaded, int *fd) + const struct fuse_operations_compat25 *op, + size_t op_size, char **mountpoint, + int *multithreaded, int *fd) { - return fuse_setup_common(argc, argv, (struct fuse_operations *) op, - op_size, mountpoint, multithreaded, fd, NULL, 25); + return fuse_setup_common(argc, argv, (struct fuse_operations *) op, + op_size, mountpoint, multithreaded, fd, NULL, + 25); } int fuse_main_real_compat25(int argc, char *argv[], - const struct fuse_operations_compat25 *op, - size_t op_size) + const struct fuse_operations_compat25 *op, + size_t op_size) { - return fuse_main_common(argc, argv, (struct fuse_operations *) op, op_size, - NULL, 25); + return fuse_main_common(argc, argv, (struct fuse_operations *) op, + op_size, NULL, 25); } void fuse_teardown_compat22(struct fuse *fuse, int fd, char *mountpoint) { - (void) fd; - fuse_teardown_common(fuse, mountpoint); + (void) fd; + fuse_teardown_common(fuse, mountpoint); } int fuse_mount_compat25(const char *mountpoint, struct fuse_args *args) { - return fuse_kern_mount(mountpoint, args); + return fuse_kern_mount(mountpoint, args); } FUSE_SYMVER(".symver fuse_setup_compat25,fuse_setup@FUSE_2.5"); diff --git a/lib/modules/iconv.c b/lib/modules/iconv.c index 350a472..c0e2b80 100644 --- a/lib/modules/iconv.c +++ b/lib/modules/iconv.c @@ -1,9 +1,9 @@ /* - fuse iconv module: file name charset conversion - Copyright (C) 2007 Miklos Szeredi + fuse iconv module: file name charset conversion + Copyright (C) 2007 Miklos Szeredi - This program can be distributed under the terms of the GNU LGPLv2. - See the file COPYING.LIB + This program can be distributed under the terms of the GNU LGPLv2. + See the file COPYING.LIB */ #define FUSE_USE_VERSION 26 @@ -20,689 +20,690 @@ #include struct iconv { - struct fuse_fs *next; - pthread_mutex_t lock; - char *from_code; - char *to_code; - iconv_t tofs; - iconv_t fromfs; + struct fuse_fs *next; + pthread_mutex_t lock; + char *from_code; + char *to_code; + iconv_t tofs; + iconv_t fromfs; }; struct iconv_dh { - struct iconv *ic; - void *prev_buf; - fuse_fill_dir_t prev_filler; + struct iconv *ic; + void *prev_buf; + fuse_fill_dir_t prev_filler; }; static struct iconv *iconv_get(void) { - return fuse_get_context()->private_data; + return fuse_get_context()->private_data; } static int iconv_convpath(struct iconv *ic, const char *path, char **newpathp, - int fromfs) -{ - size_t pathlen = strlen(path); - size_t newpathlen = pathlen * 4; - char *newpath = malloc(newpathlen + 1); - size_t plen = newpathlen; - char *p = newpath; - size_t res; - int err; - - if (!newpath) - return -ENOMEM; - - pthread_mutex_lock(&ic->lock); - do { - res = iconv(fromfs ? ic->fromfs : ic->tofs, (char **) &path, &pathlen, - &p, &plen); - if (res == (size_t) -1) { - char *tmp; - size_t inc; - - err = -EILSEQ; - if (errno != E2BIG) - goto err; - - inc = (pathlen + 1) * 4; - newpathlen += inc; - tmp = realloc(newpath, newpathlen + 1); - err = -ENOMEM; - if (!tmp) - goto err; - - p = tmp + (p - newpath); - plen += inc; - newpath = tmp; - } - } while (res == (size_t) -1); - pthread_mutex_unlock(&ic->lock); - *p = '\0'; - *newpathp = newpath; - return 0; - - err: - iconv(fromfs ? ic->fromfs : ic->tofs, NULL, NULL, NULL, NULL); - pthread_mutex_unlock(&ic->lock); - free(newpath); - return err; + int fromfs) +{ + size_t pathlen = strlen(path); + size_t newpathlen = pathlen * 4; + char *newpath = malloc(newpathlen + 1); + size_t plen = newpathlen; + char *p = newpath; + size_t res; + int err; + + if (!newpath) + return -ENOMEM; + + pthread_mutex_lock(&ic->lock); + do { + res = iconv(fromfs ? ic->fromfs : ic->tofs, (char **) &path, + &pathlen, &p, &plen); + if (res == (size_t) -1) { + char *tmp; + size_t inc; + + err = -EILSEQ; + if (errno != E2BIG) + goto err; + + inc = (pathlen + 1) * 4; + newpathlen += inc; + tmp = realloc(newpath, newpathlen + 1); + err = -ENOMEM; + if (!tmp) + goto err; + + p = tmp + (p - newpath); + plen += inc; + newpath = tmp; + } + } while (res == (size_t) -1); + pthread_mutex_unlock(&ic->lock); + *p = '\0'; + *newpathp = newpath; + return 0; + +err: + iconv(fromfs ? ic->fromfs : ic->tofs, NULL, NULL, NULL, NULL); + pthread_mutex_unlock(&ic->lock); + free(newpath); + return err; } static int iconv_getattr(const char *path, struct stat *stbuf) { - struct iconv *ic = iconv_get(); - char *newpath; - int err = iconv_convpath(ic, path, &newpath, 0); - if (!err) { - err = fuse_fs_getattr(ic->next, newpath, stbuf); - free(newpath); - } - return err; + struct iconv *ic = iconv_get(); + char *newpath; + int err = iconv_convpath(ic, path, &newpath, 0); + if (!err) { + err = fuse_fs_getattr(ic->next, newpath, stbuf); + free(newpath); + } + return err; } static int iconv_fgetattr(const char *path, struct stat *stbuf, - struct fuse_file_info *fi) + struct fuse_file_info *fi) { - struct iconv *ic = iconv_get(); - char *newpath; - int err = iconv_convpath(ic, path, &newpath, 0); - if (!err) { - err = fuse_fs_fgetattr(ic->next, newpath, stbuf, fi); - free(newpath); - } - return err; + struct iconv *ic = iconv_get(); + char *newpath; + int err = iconv_convpath(ic, path, &newpath, 0); + if (!err) { + err = fuse_fs_fgetattr(ic->next, newpath, stbuf, fi); + free(newpath); + } + return err; } static int iconv_access(const char *path, int mask) { - struct iconv *ic = iconv_get(); - char *newpath; - int err = iconv_convpath(ic, path, &newpath, 0); - if (!err) { - err = fuse_fs_access(ic->next, newpath, mask); - free(newpath); - } - return err; + struct iconv *ic = iconv_get(); + char *newpath; + int err = iconv_convpath(ic, path, &newpath, 0); + if (!err) { + err = fuse_fs_access(ic->next, newpath, mask); + free(newpath); + } + return err; } static int iconv_readlink(const char *path, char *buf, size_t size) { - struct iconv *ic = iconv_get(); - char *newpath; - int err = iconv_convpath(ic, path, &newpath, 0); - if (!err) { - err = fuse_fs_readlink(ic->next, newpath, buf, size); - if (!err) { - char *newlink; - err = iconv_convpath(ic, buf, &newlink, 1); - if (!err) { - strncpy(buf, newlink, size - 1); - buf[size - 1] = '\0'; - free(newlink); - } - } - free(newpath); - } - return err; + struct iconv *ic = iconv_get(); + char *newpath; + int err = iconv_convpath(ic, path, &newpath, 0); + if (!err) { + err = fuse_fs_readlink(ic->next, newpath, buf, size); + if (!err) { + char *newlink; + err = iconv_convpath(ic, buf, &newlink, 1); + if (!err) { + strncpy(buf, newlink, size - 1); + buf[size - 1] = '\0'; + free(newlink); + } + } + free(newpath); + } + return err; } static int iconv_opendir(const char *path, struct fuse_file_info *fi) { - struct iconv *ic = iconv_get(); - char *newpath; - int err = iconv_convpath(ic, path, &newpath, 0); - if (!err) { - err = fuse_fs_opendir(ic->next, newpath, fi); - free(newpath); - } - return err; + struct iconv *ic = iconv_get(); + char *newpath; + int err = iconv_convpath(ic, path, &newpath, 0); + if (!err) { + err = fuse_fs_opendir(ic->next, newpath, fi); + free(newpath); + } + return err; } static int iconv_dir_fill(void *buf, const char *name, - const struct stat *stbuf, off_t off) + const struct stat *stbuf, off_t off) { - struct iconv_dh *dh = buf; - char *newname; - int res = 0; - if (iconv_convpath(dh->ic, name, &newname, 1) == 0) { - res = dh->prev_filler(dh->prev_buf, newname, stbuf, off); - free(newname); - } - return res; + struct iconv_dh *dh = buf; + char *newname; + int res = 0; + if (iconv_convpath(dh->ic, name, &newname, 1) == 0) { + res = dh->prev_filler(dh->prev_buf, newname, stbuf, off); + free(newname); + } + return res; } static int iconv_readdir(const char *path, void *buf, fuse_fill_dir_t filler, - off_t offset, struct fuse_file_info *fi) -{ - struct iconv *ic = iconv_get(); - char *newpath; - int err = iconv_convpath(ic, path, &newpath, 0); - if (!err) { - struct iconv_dh dh; - dh.ic = ic; - dh.prev_buf = buf; - dh.prev_filler = filler; - err = fuse_fs_readdir(ic->next, newpath, &dh, iconv_dir_fill, offset, - fi); - free(newpath); - } - return err; + off_t offset, struct fuse_file_info *fi) +{ + struct iconv *ic = iconv_get(); + char *newpath; + int err = iconv_convpath(ic, path, &newpath, 0); + if (!err) { + struct iconv_dh dh; + dh.ic = ic; + dh.prev_buf = buf; + dh.prev_filler = filler; + err = fuse_fs_readdir(ic->next, newpath, &dh, iconv_dir_fill, + offset, fi); + free(newpath); + } + return err; } static int iconv_releasedir(const char *path, struct fuse_file_info *fi) { - struct iconv *ic = iconv_get(); - char *newpath; - int err = iconv_convpath(ic, path, &newpath, 0); - if (!err) { - err = fuse_fs_releasedir(ic->next, newpath, fi); - free(newpath); - } - return err; + struct iconv *ic = iconv_get(); + char *newpath; + int err = iconv_convpath(ic, path, &newpath, 0); + if (!err) { + err = fuse_fs_releasedir(ic->next, newpath, fi); + free(newpath); + } + return err; } static int iconv_mknod(const char *path, mode_t mode, dev_t rdev) { - struct iconv *ic = iconv_get(); - char *newpath; - int err = iconv_convpath(ic, path, &newpath, 0); - if (!err) { - err = fuse_fs_mknod(ic->next, newpath, mode, rdev); - free(newpath); - } - return err; + struct iconv *ic = iconv_get(); + char *newpath; + int err = iconv_convpath(ic, path, &newpath, 0); + if (!err) { + err = fuse_fs_mknod(ic->next, newpath, mode, rdev); + free(newpath); + } + return err; } static int iconv_mkdir(const char *path, mode_t mode) { - struct iconv *ic = iconv_get(); - char *newpath; - int err = iconv_convpath(ic, path, &newpath, 0); - if (!err) { - err = fuse_fs_mkdir(ic->next, newpath, mode); - free(newpath); - } - return err; + struct iconv *ic = iconv_get(); + char *newpath; + int err = iconv_convpath(ic, path, &newpath, 0); + if (!err) { + err = fuse_fs_mkdir(ic->next, newpath, mode); + free(newpath); + } + return err; } static int iconv_unlink(const char *path) { - struct iconv *ic = iconv_get(); - char *newpath; - int err = iconv_convpath(ic, path, &newpath, 0); - if (!err) { - err = fuse_fs_unlink(ic->next, newpath); - free(newpath); - } - return err; + struct iconv *ic = iconv_get(); + char *newpath; + int err = iconv_convpath(ic, path, &newpath, 0); + if (!err) { + err = fuse_fs_unlink(ic->next, newpath); + free(newpath); + } + return err; } static int iconv_rmdir(const char *path) { - struct iconv *ic = iconv_get(); - char *newpath; - int err = iconv_convpath(ic, path, &newpath, 0); - if (!err) { - err = fuse_fs_rmdir(ic->next, newpath); - free(newpath); - } - return err; + struct iconv *ic = iconv_get(); + char *newpath; + int err = iconv_convpath(ic, path, &newpath, 0); + if (!err) { + err = fuse_fs_rmdir(ic->next, newpath); + free(newpath); + } + return err; } static int iconv_symlink(const char *from, const char *to) { - struct iconv *ic = iconv_get(); - char *newfrom; - char *newto; - int err = iconv_convpath(ic, from, &newfrom, 0); - if (!err) { - err = iconv_convpath(ic, to, &newto, 0); - if (!err) { - err = fuse_fs_symlink(ic->next, newfrom, newto); - free(newto); - } - free(newfrom); - } - return err; + struct iconv *ic = iconv_get(); + char *newfrom; + char *newto; + int err = iconv_convpath(ic, from, &newfrom, 0); + if (!err) { + err = iconv_convpath(ic, to, &newto, 0); + if (!err) { + err = fuse_fs_symlink(ic->next, newfrom, newto); + free(newto); + } + free(newfrom); + } + return err; } static int iconv_rename(const char *from, const char *to) { - struct iconv *ic = iconv_get(); - char *newfrom; - char *newto; - int err = iconv_convpath(ic, from, &newfrom, 0); - if (!err) { - err = iconv_convpath(ic, to, &newto, 0); - if (!err) { - err = fuse_fs_rename(ic->next, newfrom, newto); - free(newto); - } - free(newfrom); - } - return err; + struct iconv *ic = iconv_get(); + char *newfrom; + char *newto; + int err = iconv_convpath(ic, from, &newfrom, 0); + if (!err) { + err = iconv_convpath(ic, to, &newto, 0); + if (!err) { + err = fuse_fs_rename(ic->next, newfrom, newto); + free(newto); + } + free(newfrom); + } + return err; } static int iconv_link(const char *from, const char *to) { - struct iconv *ic = iconv_get(); - char *newfrom; - char *newto; - int err = iconv_convpath(ic, from, &newfrom, 0); - if (!err) { - err = iconv_convpath(ic, to, &newto, 0); - if (!err) { - err = fuse_fs_link(ic->next, newfrom, newto); - free(newto); - } - free(newfrom); - } - return err; + struct iconv *ic = iconv_get(); + char *newfrom; + char *newto; + int err = iconv_convpath(ic, from, &newfrom, 0); + if (!err) { + err = iconv_convpath(ic, to, &newto, 0); + if (!err) { + err = fuse_fs_link(ic->next, newfrom, newto); + free(newto); + } + free(newfrom); + } + return err; } static int iconv_chmod(const char *path, mode_t mode) { - struct iconv *ic = iconv_get(); - char *newpath; - int err = iconv_convpath(ic, path, &newpath, 0); - if (!err) { - err = fuse_fs_chmod(ic->next, newpath, mode); - free(newpath); - } - return err; + struct iconv *ic = iconv_get(); + char *newpath; + int err = iconv_convpath(ic, path, &newpath, 0); + if (!err) { + err = fuse_fs_chmod(ic->next, newpath, mode); + free(newpath); + } + return err; } static int iconv_chown(const char *path, uid_t uid, gid_t gid) { - struct iconv *ic = iconv_get(); - char *newpath; - int err = iconv_convpath(ic, path, &newpath, 0); - if (!err) { - err = fuse_fs_chown(ic->next, newpath, uid, gid); - free(newpath); - } - return err; + struct iconv *ic = iconv_get(); + char *newpath; + int err = iconv_convpath(ic, path, &newpath, 0); + if (!err) { + err = fuse_fs_chown(ic->next, newpath, uid, gid); + free(newpath); + } + return err; } static int iconv_truncate(const char *path, off_t size) { - struct iconv *ic = iconv_get(); - char *newpath; - int err = iconv_convpath(ic, path, &newpath, 0); - if (!err) { - err = fuse_fs_truncate(ic->next, newpath, size); - free(newpath); - } - return err; + struct iconv *ic = iconv_get(); + char *newpath; + int err = iconv_convpath(ic, path, &newpath, 0); + if (!err) { + err = fuse_fs_truncate(ic->next, newpath, size); + free(newpath); + } + return err; } static int iconv_ftruncate(const char *path, off_t size, - struct fuse_file_info *fi) + struct fuse_file_info *fi) { - struct iconv *ic = iconv_get(); - char *newpath; - int err = iconv_convpath(ic, path, &newpath, 0); - if (!err) { - err = fuse_fs_ftruncate(ic->next, newpath, size, fi); - free(newpath); - } - return err; + struct iconv *ic = iconv_get(); + char *newpath; + int err = iconv_convpath(ic, path, &newpath, 0); + if (!err) { + err = fuse_fs_ftruncate(ic->next, newpath, size, fi); + free(newpath); + } + return err; } static int iconv_utimens(const char *path, const struct timespec ts[2]) { - struct iconv *ic = iconv_get(); - char *newpath; - int err = iconv_convpath(ic, path, &newpath, 0); - if (!err) { - err = fuse_fs_utimens(ic->next, newpath, ts); - free(newpath); - } - return err; + struct iconv *ic = iconv_get(); + char *newpath; + int err = iconv_convpath(ic, path, &newpath, 0); + if (!err) { + err = fuse_fs_utimens(ic->next, newpath, ts); + free(newpath); + } + return err; } static int iconv_create(const char *path, mode_t mode, - struct fuse_file_info *fi) + struct fuse_file_info *fi) { - struct iconv *ic = iconv_get(); - char *newpath; - int err = iconv_convpath(ic, path, &newpath, 0); - if (!err) { - err = fuse_fs_create(ic->next, newpath, mode, fi); - free(newpath); - } - return err; + struct iconv *ic = iconv_get(); + char *newpath; + int err = iconv_convpath(ic, path, &newpath, 0); + if (!err) { + err = fuse_fs_create(ic->next, newpath, mode, fi); + free(newpath); + } + return err; } static int iconv_open_file(const char *path, struct fuse_file_info *fi) { - struct iconv *ic = iconv_get(); - char *newpath; - int err = iconv_convpath(ic, path, &newpath, 0); - if (!err) { - err = fuse_fs_open(ic->next, newpath, fi); - free(newpath); - } - return err; + struct iconv *ic = iconv_get(); + char *newpath; + int err = iconv_convpath(ic, path, &newpath, 0); + if (!err) { + err = fuse_fs_open(ic->next, newpath, fi); + free(newpath); + } + return err; } static int iconv_read(const char *path, char *buf, size_t size, off_t offset, - struct fuse_file_info *fi) + struct fuse_file_info *fi) { - struct iconv *ic = iconv_get(); - char *newpath; - int err = iconv_convpath(ic, path, &newpath, 0); - if (!err) { - err = fuse_fs_read(ic->next, newpath, buf, size, offset, fi); - free(newpath); - } - return err; + struct iconv *ic = iconv_get(); + char *newpath; + int err = iconv_convpath(ic, path, &newpath, 0); + if (!err) { + err = fuse_fs_read(ic->next, newpath, buf, size, offset, fi); + free(newpath); + } + return err; } static int iconv_write(const char *path, const char *buf, size_t size, - off_t offset, struct fuse_file_info *fi) + off_t offset, struct fuse_file_info *fi) { - struct iconv *ic = iconv_get(); - char *newpath; - int err = iconv_convpath(ic, path, &newpath, 0); - if (!err) { - err = fuse_fs_write(ic->next, newpath, buf, size, offset, fi); - free(newpath); - } - return err; + struct iconv *ic = iconv_get(); + char *newpath; + int err = iconv_convpath(ic, path, &newpath, 0); + if (!err) { + err = fuse_fs_write(ic->next, newpath, buf, size, offset, fi); + free(newpath); + } + return err; } static int iconv_statfs(const char *path, struct statvfs *stbuf) { - struct iconv *ic = iconv_get(); - char *newpath; - int err = iconv_convpath(ic, path, &newpath, 0); - if (!err) { - err = fuse_fs_statfs(ic->next, newpath, stbuf); - free(newpath); - } - return err; + struct iconv *ic = iconv_get(); + char *newpath; + int err = iconv_convpath(ic, path, &newpath, 0); + if (!err) { + err = fuse_fs_statfs(ic->next, newpath, stbuf); + free(newpath); + } + return err; } static int iconv_flush(const char *path, struct fuse_file_info *fi) { - struct iconv *ic = iconv_get(); - char *newpath; - int err = iconv_convpath(ic, path, &newpath, 0); - if (!err) { - err = fuse_fs_flush(ic->next, newpath, fi); - free(newpath); - } - return err; + struct iconv *ic = iconv_get(); + char *newpath; + int err = iconv_convpath(ic, path, &newpath, 0); + if (!err) { + err = fuse_fs_flush(ic->next, newpath, fi); + free(newpath); + } + return err; } static int iconv_release(const char *path, struct fuse_file_info *fi) { - struct iconv *ic = iconv_get(); - char *newpath; - int err = iconv_convpath(ic, path, &newpath, 0); - if (!err) { - err = fuse_fs_release(ic->next, newpath, fi); - free(newpath); - } - return err; + struct iconv *ic = iconv_get(); + char *newpath; + int err = iconv_convpath(ic, path, &newpath, 0); + if (!err) { + err = fuse_fs_release(ic->next, newpath, fi); + free(newpath); + } + return err; } static int iconv_fsync(const char *path, int isdatasync, - struct fuse_file_info *fi) + struct fuse_file_info *fi) { - struct iconv *ic = iconv_get(); - char *newpath; - int err = iconv_convpath(ic, path, &newpath, 0); - if (!err) { - err = fuse_fs_fsync(ic->next, newpath, isdatasync, fi); - free(newpath); - } - return err; + struct iconv *ic = iconv_get(); + char *newpath; + int err = iconv_convpath(ic, path, &newpath, 0); + if (!err) { + err = fuse_fs_fsync(ic->next, newpath, isdatasync, fi); + free(newpath); + } + return err; } static int iconv_fsyncdir(const char *path, int isdatasync, - struct fuse_file_info *fi) + struct fuse_file_info *fi) { - struct iconv *ic = iconv_get(); - char *newpath; - int err = iconv_convpath(ic, path, &newpath, 0); - if (!err) { - err = fuse_fs_fsyncdir(ic->next, newpath, isdatasync, fi); - free(newpath); - } - return err; + struct iconv *ic = iconv_get(); + char *newpath; + int err = iconv_convpath(ic, path, &newpath, 0); + if (!err) { + err = fuse_fs_fsyncdir(ic->next, newpath, isdatasync, fi); + free(newpath); + } + return err; } static int iconv_setxattr(const char *path, const char *name, - const char *value, size_t size, int flags) + const char *value, size_t size, int flags) { - struct iconv *ic = iconv_get(); - char *newpath; - int err = iconv_convpath(ic, path, &newpath, 0); - if (!err) { - err = fuse_fs_setxattr(ic->next, newpath, name, value, size, flags); - free(newpath); - } - return err; + struct iconv *ic = iconv_get(); + char *newpath; + int err = iconv_convpath(ic, path, &newpath, 0); + if (!err) { + err = fuse_fs_setxattr(ic->next, newpath, name, value, size, + flags); + free(newpath); + } + return err; } static int iconv_getxattr(const char *path, const char *name, char *value, - size_t size) + size_t size) { - struct iconv *ic = iconv_get(); - char *newpath; - int err = iconv_convpath(ic, path, &newpath, 0); - if (!err) { - err = fuse_fs_getxattr(ic->next, newpath, name, value, size); - free(newpath); - } - return err; + struct iconv *ic = iconv_get(); + char *newpath; + int err = iconv_convpath(ic, path, &newpath, 0); + if (!err) { + err = fuse_fs_getxattr(ic->next, newpath, name, value, size); + free(newpath); + } + return err; } static int iconv_listxattr(const char *path, char *list, size_t size) { - struct iconv *ic = iconv_get(); - char *newpath; - int err = iconv_convpath(ic, path, &newpath, 0); - if (!err) { - err = fuse_fs_listxattr(ic->next, newpath, list, size); - free(newpath); - } - return err; + struct iconv *ic = iconv_get(); + char *newpath; + int err = iconv_convpath(ic, path, &newpath, 0); + if (!err) { + err = fuse_fs_listxattr(ic->next, newpath, list, size); + free(newpath); + } + return err; } static int iconv_removexattr(const char *path, const char *name) { - struct iconv *ic = iconv_get(); - char *newpath; - int err = iconv_convpath(ic, path, &newpath, 0); - if (!err) { - err = fuse_fs_removexattr(ic->next, newpath, name); - free(newpath); - } - return err; + struct iconv *ic = iconv_get(); + char *newpath; + int err = iconv_convpath(ic, path, &newpath, 0); + if (!err) { + err = fuse_fs_removexattr(ic->next, newpath, name); + free(newpath); + } + return err; } static int iconv_lock(const char *path, struct fuse_file_info *fi, int cmd, - struct flock *lock) + struct flock *lock) { - struct iconv *ic = iconv_get(); - char *newpath; - int err = iconv_convpath(ic, path, &newpath, 0); - if (!err) { - err = fuse_fs_lock(ic->next, newpath, fi, cmd, lock); - free(newpath); - } - return err; + struct iconv *ic = iconv_get(); + char *newpath; + int err = iconv_convpath(ic, path, &newpath, 0); + if (!err) { + err = fuse_fs_lock(ic->next, newpath, fi, cmd, lock); + free(newpath); + } + return err; } static int iconv_bmap(const char *path, size_t blocksize, uint64_t *idx) { - struct iconv *ic = iconv_get(); - char *newpath; - int err = iconv_convpath(ic, path, &newpath, 0); - if (!err) { - err = fuse_fs_bmap(ic->next, newpath, blocksize, idx); - free(newpath); - } - return err; + struct iconv *ic = iconv_get(); + char *newpath; + int err = iconv_convpath(ic, path, &newpath, 0); + if (!err) { + err = fuse_fs_bmap(ic->next, newpath, blocksize, idx); + free(newpath); + } + return err; } static void *iconv_init(struct fuse_conn_info *conn) { - struct iconv *ic = iconv_get(); - fuse_fs_init(ic->next, conn); - return ic; + struct iconv *ic = iconv_get(); + fuse_fs_init(ic->next, conn); + return ic; } static void iconv_destroy(void *data) { - struct iconv *ic = data; - fuse_fs_destroy(ic->next); - iconv_close(ic->tofs); - iconv_close(ic->fromfs); - pthread_mutex_destroy(&ic->lock); - free(ic->from_code); - free(ic->to_code); - free(ic); + struct iconv *ic = data; + fuse_fs_destroy(ic->next); + iconv_close(ic->tofs); + iconv_close(ic->fromfs); + pthread_mutex_destroy(&ic->lock); + free(ic->from_code); + free(ic->to_code); + free(ic); } static struct fuse_operations iconv_oper = { - .destroy = iconv_destroy, - .init = iconv_init, - .getattr = iconv_getattr, - .fgetattr = iconv_fgetattr, - .access = iconv_access, - .readlink = iconv_readlink, - .opendir = iconv_opendir, - .readdir = iconv_readdir, - .releasedir = iconv_releasedir, - .mknod = iconv_mknod, - .mkdir = iconv_mkdir, - .symlink = iconv_symlink, - .unlink = iconv_unlink, - .rmdir = iconv_rmdir, - .rename = iconv_rename, - .link = iconv_link, - .chmod = iconv_chmod, - .chown = iconv_chown, - .truncate = iconv_truncate, - .ftruncate = iconv_ftruncate, - .utimens = iconv_utimens, - .create = iconv_create, - .open = iconv_open_file, - .read = iconv_read, - .write = iconv_write, - .statfs = iconv_statfs, - .flush = iconv_flush, - .release = iconv_release, - .fsync = iconv_fsync, - .fsyncdir = iconv_fsyncdir, - .setxattr = iconv_setxattr, - .getxattr = iconv_getxattr, - .listxattr = iconv_listxattr, - .removexattr= iconv_removexattr, - .lock = iconv_lock, - .bmap = iconv_bmap, + .destroy = iconv_destroy, + .init = iconv_init, + .getattr = iconv_getattr, + .fgetattr = iconv_fgetattr, + .access = iconv_access, + .readlink = iconv_readlink, + .opendir = iconv_opendir, + .readdir = iconv_readdir, + .releasedir = iconv_releasedir, + .mknod = iconv_mknod, + .mkdir = iconv_mkdir, + .symlink = iconv_symlink, + .unlink = iconv_unlink, + .rmdir = iconv_rmdir, + .rename = iconv_rename, + .link = iconv_link, + .chmod = iconv_chmod, + .chown = iconv_chown, + .truncate = iconv_truncate, + .ftruncate = iconv_ftruncate, + .utimens = iconv_utimens, + .create = iconv_create, + .open = iconv_open_file, + .read = iconv_read, + .write = iconv_write, + .statfs = iconv_statfs, + .flush = iconv_flush, + .release = iconv_release, + .fsync = iconv_fsync, + .fsyncdir = iconv_fsyncdir, + .setxattr = iconv_setxattr, + .getxattr = iconv_getxattr, + .listxattr = iconv_listxattr, + .removexattr = iconv_removexattr, + .lock = iconv_lock, + .bmap = iconv_bmap, }; static struct fuse_opt iconv_opts[] = { - FUSE_OPT_KEY("-h", 0), - FUSE_OPT_KEY("--help", 0), - { "from_code=%s", offsetof(struct iconv, from_code), 0 }, - { "to_code=%s", offsetof(struct iconv, to_code), 1 }, - FUSE_OPT_END + FUSE_OPT_KEY("-h", 0), + FUSE_OPT_KEY("--help", 0), + { "from_code=%s", offsetof(struct iconv, from_code), 0 }, + { "to_code=%s", offsetof(struct iconv, to_code), 1 }, + FUSE_OPT_END }; static void iconv_help(void) { - char *old = strdup(setlocale(LC_CTYPE, "")); - char *charmap = strdup(nl_langinfo(CODESET)); - setlocale(LC_CTYPE, old); - free(old); - fprintf(stderr, + char *old = strdup(setlocale(LC_CTYPE, "")); + char *charmap = strdup(nl_langinfo(CODESET)); + setlocale(LC_CTYPE, old); + free(old); + fprintf(stderr, " -o from_code=CHARSET original encoding of file names (default: UTF-8)\n" -" -o to_code=CHARSET new encoding of the file names (default: %s)\n", - charmap); - free(charmap); +" -o to_code=CHARSET new encoding of the file names (default: %s)\n", + charmap); + free(charmap); } static int iconv_opt_proc(void *data, const char *arg, int key, - struct fuse_args *outargs) + struct fuse_args *outargs) { - (void) data; (void) arg; (void) outargs; + (void) data; (void) arg; (void) outargs; - if (!key) { - iconv_help(); - return -1; - } + if (!key) { + iconv_help(); + return -1; + } - return 1; + return 1; } static struct fuse_fs *iconv_new(struct fuse_args *args, - struct fuse_fs *next[]) -{ - struct fuse_fs *fs; - struct iconv *ic; - char *old = NULL; - const char *from; - const char *to; - - ic = calloc(1, sizeof(struct iconv)); - if (ic == NULL) { - fprintf(stderr, "fuse-iconv: memory allocation failed\n"); - return NULL; - } - - if (fuse_opt_parse(args, ic, iconv_opts, iconv_opt_proc) == -1) - goto out_free; - - if (!next[0] || next[1]) { - fprintf(stderr, "fuse-iconv: exactly one next filesystem required\n"); - goto out_free; - } - - from = ic->from_code ? ic->from_code : "UTF-8"; - to = ic->to_code ? ic->to_code : ""; - /* FIXME: detect charset equivalence? */ - if (!to[0]) - old = strdup(setlocale(LC_CTYPE, "")); - ic->tofs = iconv_open(from, to); - if (ic->tofs == (iconv_t) -1) { - fprintf(stderr, "fuse-iconv: cannot convert from %s to %s\n", - to, from); - goto out_free; - } - ic->fromfs = iconv_open(to, from); - if (ic->tofs == (iconv_t) -1) { - fprintf(stderr, "fuse-iconv: cannot convert from %s to %s\n", - from, to); - goto out_iconv_close_to; - } - if (old) { - setlocale(LC_CTYPE, old); - free(old); - } - - ic->next = next[0]; - fs = fuse_fs_new(&iconv_oper, sizeof(iconv_oper), ic); - if (!fs) - goto out_iconv_close_from; - - return fs; - - out_iconv_close_from: - iconv_close(ic->fromfs); - out_iconv_close_to: - iconv_close(ic->tofs); - out_free: - free(ic->from_code); - free(ic->to_code); - free(ic); - return NULL; + struct fuse_fs *next[]) +{ + struct fuse_fs *fs; + struct iconv *ic; + char *old = NULL; + const char *from; + const char *to; + + ic = calloc(1, sizeof(struct iconv)); + if (ic == NULL) { + fprintf(stderr, "fuse-iconv: memory allocation failed\n"); + return NULL; + } + + if (fuse_opt_parse(args, ic, iconv_opts, iconv_opt_proc) == -1) + goto out_free; + + if (!next[0] || next[1]) { + fprintf(stderr, "fuse-iconv: exactly one next filesystem required\n"); + goto out_free; + } + + from = ic->from_code ? ic->from_code : "UTF-8"; + to = ic->to_code ? ic->to_code : ""; + /* FIXME: detect charset equivalence? */ + if (!to[0]) + old = strdup(setlocale(LC_CTYPE, "")); + ic->tofs = iconv_open(from, to); + if (ic->tofs == (iconv_t) -1) { + fprintf(stderr, "fuse-iconv: cannot convert from %s to %s\n", + to, from); + goto out_free; + } + ic->fromfs = iconv_open(to, from); + if (ic->tofs == (iconv_t) -1) { + fprintf(stderr, "fuse-iconv: cannot convert from %s to %s\n", + from, to); + goto out_iconv_close_to; + } + if (old) { + setlocale(LC_CTYPE, old); + free(old); + } + + ic->next = next[0]; + fs = fuse_fs_new(&iconv_oper, sizeof(iconv_oper), ic); + if (!fs) + goto out_iconv_close_from; + + return fs; + +out_iconv_close_from: + iconv_close(ic->fromfs); +out_iconv_close_to: + iconv_close(ic->tofs); +out_free: + free(ic->from_code); + free(ic->to_code); + free(ic); + return NULL; } FUSE_REGISTER_MODULE(iconv, iconv_new); diff --git a/lib/modules/subdir.c b/lib/modules/subdir.c index f22c023..6f7b187 100644 --- a/lib/modules/subdir.c +++ b/lib/modules/subdir.c @@ -1,9 +1,9 @@ /* - fuse subdir module: offset paths with a base directory - Copyright (C) 2007 Miklos Szeredi + fuse subdir module: offset paths with a base directory + Copyright (C) 2007 Miklos Szeredi - This program can be distributed under the terms of the GNU LGPLv2. - See the file COPYING.LIB + This program can be distributed under the terms of the GNU LGPLv2. + See the file COPYING.LIB */ #define FUSE_USE_VERSION 26 @@ -16,647 +16,650 @@ #include struct subdir { - char *base; - size_t baselen; - int rellinks; - struct fuse_fs *next; + char *base; + size_t baselen; + int rellinks; + struct fuse_fs *next; }; static struct subdir *subdir_get(void) { - return fuse_get_context()->private_data; + return fuse_get_context()->private_data; } static char *subdir_addpath(struct subdir *d, const char *path) { - unsigned newlen = d->baselen + strlen(path); - char *newpath = malloc(newlen + 2); - if (newpath) { - if (path[0] == '/') - path++; - strcpy(newpath, d->base); - strcpy(newpath + d->baselen, path); - if (!newpath[0]) - strcpy(newpath, "."); - } - return newpath; + unsigned newlen = d->baselen + strlen(path); + char *newpath = malloc(newlen + 2); + if (newpath) { + if (path[0] == '/') + path++; + strcpy(newpath, d->base); + strcpy(newpath + d->baselen, path); + if (!newpath[0]) + strcpy(newpath, "."); + } + return newpath; } static int subdir_getattr(const char *path, struct stat *stbuf) { - struct subdir *d = subdir_get(); - char *newpath = subdir_addpath(d, path); - int err = -ENOMEM; - if (newpath) { - err = fuse_fs_getattr(d->next, newpath, stbuf); - free(newpath); - } - return err; + struct subdir *d = subdir_get(); + char *newpath = subdir_addpath(d, path); + int err = -ENOMEM; + if (newpath) { + err = fuse_fs_getattr(d->next, newpath, stbuf); + free(newpath); + } + return err; } static int subdir_fgetattr(const char *path, struct stat *stbuf, - struct fuse_file_info *fi) + struct fuse_file_info *fi) { - struct subdir *d = subdir_get(); - char *newpath = subdir_addpath(d, path); - int err = -ENOMEM; - if (newpath) { - err = fuse_fs_fgetattr(d->next, newpath, stbuf, fi); - free(newpath); - } - return err; + struct subdir *d = subdir_get(); + char *newpath = subdir_addpath(d, path); + int err = -ENOMEM; + if (newpath) { + err = fuse_fs_fgetattr(d->next, newpath, stbuf, fi); + free(newpath); + } + return err; } static int subdir_access(const char *path, int mask) { - struct subdir *d = subdir_get(); - char *newpath = subdir_addpath(d, path); - int err = -ENOMEM; - if (newpath) { - err = fuse_fs_access(d->next, newpath, mask); - free(newpath); - } - return err; + struct subdir *d = subdir_get(); + char *newpath = subdir_addpath(d, path); + int err = -ENOMEM; + if (newpath) { + err = fuse_fs_access(d->next, newpath, mask); + free(newpath); + } + return err; } static int count_components(const char *p) { - int ctr; + int ctr; - for (; *p == '/'; p++); - for (ctr = 0; *p; ctr++) { - for (; *p && *p != '/'; p++); - for (; *p == '/'; p++); - } - return ctr; + for (; *p == '/'; p++); + for (ctr = 0; *p; ctr++) { + for (; *p && *p != '/'; p++); + for (; *p == '/'; p++); + } + return ctr; } static void strip_common(const char **sp, const char **tp) { - const char *s = *sp; - const char *t = *tp; - do { - for (; *s == '/'; s++); - for (; *t == '/'; t++); - *tp = t; - *sp = s; - for (; *s == *t && *s && *s != '/'; s++, t++); - } while ((*s == *t && *s) || (!*s && *t == '/') || (*s == '/' && !*t)); + const char *s = *sp; + const char *t = *tp; + do { + for (; *s == '/'; s++); + for (; *t == '/'; t++); + *tp = t; + *sp = s; + for (; *s == *t && *s && *s != '/'; s++, t++); + } while ((*s == *t && *s) || (!*s && *t == '/') || (*s == '/' && !*t)); } static void transform_symlink(struct subdir *d, const char *path, - char *buf, size_t size) + char *buf, size_t size) { - const char *l = buf; - size_t llen; - char *s; - int dotdots; - int i; + const char *l = buf; + size_t llen; + char *s; + int dotdots; + int i; - if (l[0] != '/' || d->base[0] != '/') - return; + if (l[0] != '/' || d->base[0] != '/') + return; - strip_common(&l, &path); - if (l - buf < (long) d->baselen) - return; + strip_common(&l, &path); + if (l - buf < (long) d->baselen) + return; - dotdots = count_components(path); - if (!dotdots) - return; - dotdots--; + dotdots = count_components(path); + if (!dotdots) + return; + dotdots--; - llen = strlen(l); - if (dotdots * 3 + llen + 2 > size) - return; + llen = strlen(l); + if (dotdots * 3 + llen + 2 > size) + return; - s = buf + dotdots * 3; - if (llen) - memmove(s, l, llen + 1); - else if (!dotdots) - strcpy(s, "."); - else - *s = '\0'; + s = buf + dotdots * 3; + if (llen) + memmove(s, l, llen + 1); + else if (!dotdots) + strcpy(s, "."); + else + *s = '\0'; - for (s = buf, i = 0; i < dotdots; i++, s += 3) - memcpy(s, "../", 3); + for (s = buf, i = 0; i < dotdots; i++, s += 3) + memcpy(s, "../", 3); } static int subdir_readlink(const char *path, char *buf, size_t size) { - struct subdir *d = subdir_get(); - char *newpath = subdir_addpath(d, path); - int err = -ENOMEM; - if (newpath) { - err = fuse_fs_readlink(d->next, newpath, buf, size); - if (!err && d->rellinks) - transform_symlink(d, newpath, buf, size); - free(newpath); - } - return err; + struct subdir *d = subdir_get(); + char *newpath = subdir_addpath(d, path); + int err = -ENOMEM; + if (newpath) { + err = fuse_fs_readlink(d->next, newpath, buf, size); + if (!err && d->rellinks) + transform_symlink(d, newpath, buf, size); + free(newpath); + } + return err; } static int subdir_opendir(const char *path, struct fuse_file_info *fi) { - struct subdir *d = subdir_get(); - char *newpath = subdir_addpath(d, path); - int err = -ENOMEM; - if (newpath) { - err = fuse_fs_opendir(d->next, newpath, fi); - free(newpath); - } - return err; + struct subdir *d = subdir_get(); + char *newpath = subdir_addpath(d, path); + int err = -ENOMEM; + if (newpath) { + err = fuse_fs_opendir(d->next, newpath, fi); + free(newpath); + } + return err; } static int subdir_readdir(const char *path, void *buf, - fuse_fill_dir_t filler, off_t offset, - struct fuse_file_info *fi) + fuse_fill_dir_t filler, off_t offset, + struct fuse_file_info *fi) { - struct subdir *d = subdir_get(); - char *newpath = subdir_addpath(d, path); - int err = -ENOMEM; - if (newpath) { - err = fuse_fs_readdir(d->next, newpath, buf, filler, offset, fi); - free(newpath); - } - return err; + struct subdir *d = subdir_get(); + char *newpath = subdir_addpath(d, path); + int err = -ENOMEM; + if (newpath) { + err = fuse_fs_readdir(d->next, newpath, buf, filler, offset, + fi); + free(newpath); + } + return err; } static int subdir_releasedir(const char *path, struct fuse_file_info *fi) { - struct subdir *d = subdir_get(); - char *newpath = subdir_addpath(d, path); - int err = -ENOMEM; - if (newpath) { - err = fuse_fs_releasedir(d->next, newpath, fi); - free(newpath); - } - return err; + struct subdir *d = subdir_get(); + char *newpath = subdir_addpath(d, path); + int err = -ENOMEM; + if (newpath) { + err = fuse_fs_releasedir(d->next, newpath, fi); + free(newpath); + } + return err; } static int subdir_mknod(const char *path, mode_t mode, dev_t rdev) { - struct subdir *d = subdir_get(); - char *newpath = subdir_addpath(d, path); - int err = -ENOMEM; - if (newpath) { - err = fuse_fs_mknod(d->next, newpath, mode, rdev); - free(newpath); - } - return err; + struct subdir *d = subdir_get(); + char *newpath = subdir_addpath(d, path); + int err = -ENOMEM; + if (newpath) { + err = fuse_fs_mknod(d->next, newpath, mode, rdev); + free(newpath); + } + return err; } static int subdir_mkdir(const char *path, mode_t mode) { - struct subdir *d = subdir_get(); - char *newpath = subdir_addpath(d, path); - int err = -ENOMEM; - if (newpath) { - err = fuse_fs_mkdir(d->next, newpath, mode); - free(newpath); - } - return err; + struct subdir *d = subdir_get(); + char *newpath = subdir_addpath(d, path); + int err = -ENOMEM; + if (newpath) { + err = fuse_fs_mkdir(d->next, newpath, mode); + free(newpath); + } + return err; } static int subdir_unlink(const char *path) { - struct subdir *d = subdir_get(); - char *newpath = subdir_addpath(d, path); - int err = -ENOMEM; - if (newpath) { - err = fuse_fs_unlink(d->next, newpath); - free(newpath); - } - return err; + struct subdir *d = subdir_get(); + char *newpath = subdir_addpath(d, path); + int err = -ENOMEM; + if (newpath) { + err = fuse_fs_unlink(d->next, newpath); + free(newpath); + } + return err; } static int subdir_rmdir(const char *path) { - struct subdir *d = subdir_get(); - char *newpath = subdir_addpath(d, path); - int err = -ENOMEM; - if (newpath) { - err = fuse_fs_rmdir(d->next, newpath); - free(newpath); - } - return err; + struct subdir *d = subdir_get(); + char *newpath = subdir_addpath(d, path); + int err = -ENOMEM; + if (newpath) { + err = fuse_fs_rmdir(d->next, newpath); + free(newpath); + } + return err; } static int subdir_symlink(const char *from, const char *path) { - struct subdir *d = subdir_get(); - char *newpath = subdir_addpath(d, path); - int err = -ENOMEM; - if (newpath) { - err = fuse_fs_symlink(d->next, from, newpath); - free(newpath); - } - return err; + struct subdir *d = subdir_get(); + char *newpath = subdir_addpath(d, path); + int err = -ENOMEM; + if (newpath) { + err = fuse_fs_symlink(d->next, from, newpath); + free(newpath); + } + return err; } static int subdir_rename(const char *from, const char *to) { - struct subdir *d = subdir_get(); - char *newfrom = subdir_addpath(d, from); - char *newto = subdir_addpath(d, to); - int err = -ENOMEM; - if (newfrom && newto) - err = fuse_fs_rename(d->next, newfrom, newto); - free(newfrom); - free(newto); - return err; + struct subdir *d = subdir_get(); + char *newfrom = subdir_addpath(d, from); + char *newto = subdir_addpath(d, to); + int err = -ENOMEM; + if (newfrom && newto) + err = fuse_fs_rename(d->next, newfrom, newto); + free(newfrom); + free(newto); + return err; } static int subdir_link(const char *from, const char *to) { - struct subdir *d = subdir_get(); - char *newfrom = subdir_addpath(d, from); - char *newto = subdir_addpath(d, to); - int err = -ENOMEM; - if (newfrom && newto) - err = fuse_fs_link(d->next, newfrom, newto); - free(newfrom); - free(newto); - return err; + struct subdir *d = subdir_get(); + char *newfrom = subdir_addpath(d, from); + char *newto = subdir_addpath(d, to); + int err = -ENOMEM; + if (newfrom && newto) + err = fuse_fs_link(d->next, newfrom, newto); + free(newfrom); + free(newto); + return err; } static int subdir_chmod(const char *path, mode_t mode) { - struct subdir *d = subdir_get(); - char *newpath = subdir_addpath(d, path); - int err = -ENOMEM; - if (newpath) { - err = fuse_fs_chmod(d->next, newpath, mode); - free(newpath); - } - return err; + struct subdir *d = subdir_get(); + char *newpath = subdir_addpath(d, path); + int err = -ENOMEM; + if (newpath) { + err = fuse_fs_chmod(d->next, newpath, mode); + free(newpath); + } + return err; } static int subdir_chown(const char *path, uid_t uid, gid_t gid) { - struct subdir *d = subdir_get(); - char *newpath = subdir_addpath(d, path); - int err = -ENOMEM; - if (newpath) { - err = fuse_fs_chown(d->next, newpath, uid, gid); - free(newpath); - } - return err; + struct subdir *d = subdir_get(); + char *newpath = subdir_addpath(d, path); + int err = -ENOMEM; + if (newpath) { + err = fuse_fs_chown(d->next, newpath, uid, gid); + free(newpath); + } + return err; } static int subdir_truncate(const char *path, off_t size) { - struct subdir *d = subdir_get(); - char *newpath = subdir_addpath(d, path); - int err = -ENOMEM; - if (newpath) { - err = fuse_fs_truncate(d->next, newpath, size); - free(newpath); - } - return err; + struct subdir *d = subdir_get(); + char *newpath = subdir_addpath(d, path); + int err = -ENOMEM; + if (newpath) { + err = fuse_fs_truncate(d->next, newpath, size); + free(newpath); + } + return err; } static int subdir_ftruncate(const char *path, off_t size, - struct fuse_file_info *fi) + struct fuse_file_info *fi) { - struct subdir *d = subdir_get(); - char *newpath = subdir_addpath(d, path); - int err = -ENOMEM; - if (newpath) { - err = fuse_fs_ftruncate(d->next, newpath, size, fi); - free(newpath); - } - return err; + struct subdir *d = subdir_get(); + char *newpath = subdir_addpath(d, path); + int err = -ENOMEM; + if (newpath) { + err = fuse_fs_ftruncate(d->next, newpath, size, fi); + free(newpath); + } + return err; } static int subdir_utimens(const char *path, const struct timespec ts[2]) { - struct subdir *d = subdir_get(); - char *newpath = subdir_addpath(d, path); - int err = -ENOMEM; - if (newpath) { - err = fuse_fs_utimens(d->next, newpath, ts); - free(newpath); - } - return err; + struct subdir *d = subdir_get(); + char *newpath = subdir_addpath(d, path); + int err = -ENOMEM; + if (newpath) { + err = fuse_fs_utimens(d->next, newpath, ts); + free(newpath); + } + return err; } -static int subdir_create(const char *path, mode_t mode, struct fuse_file_info *fi) +static int subdir_create(const char *path, mode_t mode, + struct fuse_file_info *fi) { - struct subdir *d = subdir_get(); - char *newpath = subdir_addpath(d, path); - int err = -ENOMEM; - if (newpath) { - err = fuse_fs_create(d->next, newpath, mode, fi); - free(newpath); - } - return err; + struct subdir *d = subdir_get(); + char *newpath = subdir_addpath(d, path); + int err = -ENOMEM; + if (newpath) { + err = fuse_fs_create(d->next, newpath, mode, fi); + free(newpath); + } + return err; } static int subdir_open(const char *path, struct fuse_file_info *fi) { - struct subdir *d = subdir_get(); - char *newpath = subdir_addpath(d, path); - int err = -ENOMEM; - if (newpath) { - err = fuse_fs_open(d->next, newpath, fi); - free(newpath); - } - return err; + struct subdir *d = subdir_get(); + char *newpath = subdir_addpath(d, path); + int err = -ENOMEM; + if (newpath) { + err = fuse_fs_open(d->next, newpath, fi); + free(newpath); + } + return err; } static int subdir_read(const char *path, char *buf, size_t size, off_t offset, - struct fuse_file_info *fi) + struct fuse_file_info *fi) { - struct subdir *d = subdir_get(); - char *newpath = subdir_addpath(d, path); - int err = -ENOMEM; - if (newpath) { - err = fuse_fs_read(d->next, newpath, buf, size, offset, fi); - free(newpath); - } - return err; + struct subdir *d = subdir_get(); + char *newpath = subdir_addpath(d, path); + int err = -ENOMEM; + if (newpath) { + err = fuse_fs_read(d->next, newpath, buf, size, offset, fi); + free(newpath); + } + return err; } static int subdir_write(const char *path, const char *buf, size_t size, - off_t offset, struct fuse_file_info *fi) + off_t offset, struct fuse_file_info *fi) { - struct subdir *d = subdir_get(); - char *newpath = subdir_addpath(d, path); - int err = -ENOMEM; - if (newpath) { - err = fuse_fs_write(d->next, newpath, buf, size, offset, fi); - free(newpath); - } - return err; + struct subdir *d = subdir_get(); + char *newpath = subdir_addpath(d, path); + int err = -ENOMEM; + if (newpath) { + err = fuse_fs_write(d->next, newpath, buf, size, offset, fi); + free(newpath); + } + return err; } static int subdir_statfs(const char *path, struct statvfs *stbuf) { - struct subdir *d = subdir_get(); - char *newpath = subdir_addpath(d, path); - int err = -ENOMEM; - if (newpath) { - err = fuse_fs_statfs(d->next, newpath, stbuf); - free(newpath); - } - return err; + struct subdir *d = subdir_get(); + char *newpath = subdir_addpath(d, path); + int err = -ENOMEM; + if (newpath) { + err = fuse_fs_statfs(d->next, newpath, stbuf); + free(newpath); + } + return err; } static int subdir_flush(const char *path, struct fuse_file_info *fi) { - struct subdir *d = subdir_get(); - char *newpath = subdir_addpath(d, path); - int err = -ENOMEM; - if (newpath) { - err = fuse_fs_flush(d->next, newpath, fi); - free(newpath); - } - return err; + struct subdir *d = subdir_get(); + char *newpath = subdir_addpath(d, path); + int err = -ENOMEM; + if (newpath) { + err = fuse_fs_flush(d->next, newpath, fi); + free(newpath); + } + return err; } static int subdir_release(const char *path, struct fuse_file_info *fi) { - struct subdir *d = subdir_get(); - char *newpath = subdir_addpath(d, path); - int err = -ENOMEM; - if (newpath) { - err = fuse_fs_release(d->next, newpath, fi); - free(newpath); - } - return err; + struct subdir *d = subdir_get(); + char *newpath = subdir_addpath(d, path); + int err = -ENOMEM; + if (newpath) { + err = fuse_fs_release(d->next, newpath, fi); + free(newpath); + } + return err; } static int subdir_fsync(const char *path, int isdatasync, - struct fuse_file_info *fi) + struct fuse_file_info *fi) { - struct subdir *d = subdir_get(); - char *newpath = subdir_addpath(d, path); - int err = -ENOMEM; - if (newpath) { - err = fuse_fs_fsync(d->next, newpath, isdatasync, fi); - free(newpath); - } - return err; + struct subdir *d = subdir_get(); + char *newpath = subdir_addpath(d, path); + int err = -ENOMEM; + if (newpath) { + err = fuse_fs_fsync(d->next, newpath, isdatasync, fi); + free(newpath); + } + return err; } static int subdir_fsyncdir(const char *path, int isdatasync, - struct fuse_file_info *fi) + struct fuse_file_info *fi) { - struct subdir *d = subdir_get(); - char *newpath = subdir_addpath(d, path); - int err = -ENOMEM; - if (newpath) { - err = fuse_fs_fsyncdir(d->next, newpath, isdatasync, fi); - free(newpath); - } - return err; + struct subdir *d = subdir_get(); + char *newpath = subdir_addpath(d, path); + int err = -ENOMEM; + if (newpath) { + err = fuse_fs_fsyncdir(d->next, newpath, isdatasync, fi); + free(newpath); + } + return err; } -static int subdir_setxattr(const char *path, const char *name, const char *value, - size_t size, int flags) +static int subdir_setxattr(const char *path, const char *name, + const char *value, size_t size, int flags) { - struct subdir *d = subdir_get(); - char *newpath = subdir_addpath(d, path); - int err = -ENOMEM; - if (newpath) { - err = fuse_fs_setxattr(d->next, newpath, name, value, size, flags); - free(newpath); - } - return err; + struct subdir *d = subdir_get(); + char *newpath = subdir_addpath(d, path); + int err = -ENOMEM; + if (newpath) { + err = fuse_fs_setxattr(d->next, newpath, name, value, size, + flags); + free(newpath); + } + return err; } static int subdir_getxattr(const char *path, const char *name, char *value, - size_t size) + size_t size) { - struct subdir *d = subdir_get(); - char *newpath = subdir_addpath(d, path); - int err = -ENOMEM; - if (newpath) { - err = fuse_fs_getxattr(d->next, newpath, name, value, size); - free(newpath); - } - return err; + struct subdir *d = subdir_get(); + char *newpath = subdir_addpath(d, path); + int err = -ENOMEM; + if (newpath) { + err = fuse_fs_getxattr(d->next, newpath, name, value, size); + free(newpath); + } + return err; } static int subdir_listxattr(const char *path, char *list, size_t size) { - struct subdir *d = subdir_get(); - char *newpath = subdir_addpath(d, path); - int err = -ENOMEM; - if (newpath) { - err = fuse_fs_listxattr(d->next, newpath, list, size); - free(newpath); - } - return err; + struct subdir *d = subdir_get(); + char *newpath = subdir_addpath(d, path); + int err = -ENOMEM; + if (newpath) { + err = fuse_fs_listxattr(d->next, newpath, list, size); + free(newpath); + } + return err; } static int subdir_removexattr(const char *path, const char *name) { - struct subdir *d = subdir_get(); - char *newpath = subdir_addpath(d, path); - int err = -ENOMEM; - if (newpath) { - err = fuse_fs_removexattr(d->next, newpath, name); - free(newpath); - } - return err; + struct subdir *d = subdir_get(); + char *newpath = subdir_addpath(d, path); + int err = -ENOMEM; + if (newpath) { + err = fuse_fs_removexattr(d->next, newpath, name); + free(newpath); + } + return err; } static int subdir_lock(const char *path, struct fuse_file_info *fi, int cmd, - struct flock *lock) + struct flock *lock) { - struct subdir *d = subdir_get(); - char *newpath = subdir_addpath(d, path); - int err = -ENOMEM; - if (newpath) { - err = fuse_fs_lock(d->next, newpath, fi, cmd, lock); - free(newpath); - } - return err; + struct subdir *d = subdir_get(); + char *newpath = subdir_addpath(d, path); + int err = -ENOMEM; + if (newpath) { + err = fuse_fs_lock(d->next, newpath, fi, cmd, lock); + free(newpath); + } + return err; } static int subdir_bmap(const char *path, size_t blocksize, uint64_t *idx) { - struct subdir *d = subdir_get(); - char *newpath = subdir_addpath(d, path); - int err = -ENOMEM; - if (newpath) { - err = fuse_fs_bmap(d->next, newpath, blocksize, idx); - free(newpath); - } - return err; + struct subdir *d = subdir_get(); + char *newpath = subdir_addpath(d, path); + int err = -ENOMEM; + if (newpath) { + err = fuse_fs_bmap(d->next, newpath, blocksize, idx); + free(newpath); + } + return err; } static void *subdir_init(struct fuse_conn_info *conn) { - struct subdir *d = subdir_get(); - fuse_fs_init(d->next, conn); - return d; + struct subdir *d = subdir_get(); + fuse_fs_init(d->next, conn); + return d; } static void subdir_destroy(void *data) { - struct subdir *d = data; - fuse_fs_destroy(d->next); - free(d->base); - free(d); + struct subdir *d = data; + fuse_fs_destroy(d->next); + free(d->base); + free(d); } static struct fuse_operations subdir_oper = { - .destroy = subdir_destroy, - .init = subdir_init, - .getattr = subdir_getattr, - .fgetattr = subdir_fgetattr, - .access = subdir_access, - .readlink = subdir_readlink, - .opendir = subdir_opendir, - .readdir = subdir_readdir, - .releasedir = subdir_releasedir, - .mknod = subdir_mknod, - .mkdir = subdir_mkdir, - .symlink = subdir_symlink, - .unlink = subdir_unlink, - .rmdir = subdir_rmdir, - .rename = subdir_rename, - .link = subdir_link, - .chmod = subdir_chmod, - .chown = subdir_chown, - .truncate = subdir_truncate, - .ftruncate = subdir_ftruncate, - .utimens = subdir_utimens, - .create = subdir_create, - .open = subdir_open, - .read = subdir_read, - .write = subdir_write, - .statfs = subdir_statfs, - .flush = subdir_flush, - .release = subdir_release, - .fsync = subdir_fsync, - .fsyncdir = subdir_fsyncdir, - .setxattr = subdir_setxattr, - .getxattr = subdir_getxattr, - .listxattr = subdir_listxattr, - .removexattr= subdir_removexattr, - .lock = subdir_lock, - .bmap = subdir_bmap, + .destroy = subdir_destroy, + .init = subdir_init, + .getattr = subdir_getattr, + .fgetattr = subdir_fgetattr, + .access = subdir_access, + .readlink = subdir_readlink, + .opendir = subdir_opendir, + .readdir = subdir_readdir, + .releasedir = subdir_releasedir, + .mknod = subdir_mknod, + .mkdir = subdir_mkdir, + .symlink = subdir_symlink, + .unlink = subdir_unlink, + .rmdir = subdir_rmdir, + .rename = subdir_rename, + .link = subdir_link, + .chmod = subdir_chmod, + .chown = subdir_chown, + .truncate = subdir_truncate, + .ftruncate = subdir_ftruncate, + .utimens = subdir_utimens, + .create = subdir_create, + .open = subdir_open, + .read = subdir_read, + .write = subdir_write, + .statfs = subdir_statfs, + .flush = subdir_flush, + .release = subdir_release, + .fsync = subdir_fsync, + .fsyncdir = subdir_fsyncdir, + .setxattr = subdir_setxattr, + .getxattr = subdir_getxattr, + .listxattr = subdir_listxattr, + .removexattr = subdir_removexattr, + .lock = subdir_lock, + .bmap = subdir_bmap, }; static struct fuse_opt subdir_opts[] = { - FUSE_OPT_KEY("-h", 0), - FUSE_OPT_KEY("--help", 0), - { "subdir=%s", offsetof(struct subdir, base), 0 }, - { "rellinks", offsetof(struct subdir, rellinks), 1 }, - { "norellinks", offsetof(struct subdir, rellinks), 0 }, - FUSE_OPT_END + FUSE_OPT_KEY("-h", 0), + FUSE_OPT_KEY("--help", 0), + { "subdir=%s", offsetof(struct subdir, base), 0 }, + { "rellinks", offsetof(struct subdir, rellinks), 1 }, + { "norellinks", offsetof(struct subdir, rellinks), 0 }, + FUSE_OPT_END }; static void subdir_help(void) { - fprintf(stderr, -" -o subdir=DIR prepend this directory to all paths (mandatory)\n" -" -o [no]rellinks transform absolute symlinks to relative\n"); + fprintf(stderr, +" -o subdir=DIR prepend this directory to all paths (mandatory)\n" +" -o [no]rellinks transform absolute symlinks to relative\n"); } static int subdir_opt_proc(void *data, const char *arg, int key, - struct fuse_args *outargs) + struct fuse_args *outargs) { - (void) data; (void) arg; (void) outargs; + (void) data; (void) arg; (void) outargs; - if (!key) { - subdir_help(); - return -1; - } + if (!key) { + subdir_help(); + return -1; + } - return 1; + return 1; } static struct fuse_fs *subdir_new(struct fuse_args *args, - struct fuse_fs *next[]) -{ - struct fuse_fs *fs; - struct subdir *d; - - d = calloc(1, sizeof(struct subdir)); - if (d == NULL) { - fprintf(stderr, "fuse-subdir: memory allocation failed\n"); - return NULL; - } - - if (fuse_opt_parse(args, d, subdir_opts, subdir_opt_proc) == -1) - goto out_free; - - if (!next[0] || next[1]) { - fprintf(stderr, "fuse-subdir: exactly one next filesystem required\n"); - goto out_free; - } - - if (!d->base) { - fprintf(stderr, "fuse-subdir: missing 'subdir' option\n"); - goto out_free; - } - - if (d->base[0] && d->base[strlen(d->base)-1] != '/') { - char *tmp = realloc(d->base, strlen(d->base) + 2); - if (!tmp) { - fprintf(stderr, "fuse-subdir: memory allocation failed\n"); - goto out_free; - } - d->base = tmp; - strcat(d->base, "/"); - } - d->baselen = strlen(d->base); - d->next = next[0]; - fs = fuse_fs_new(&subdir_oper, sizeof(subdir_oper), d); - if (!fs) - goto out_free; - return fs; - - out_free: - free(d->base); - free(d); - return NULL; + struct fuse_fs *next[]) +{ + struct fuse_fs *fs; + struct subdir *d; + + d = calloc(1, sizeof(struct subdir)); + if (d == NULL) { + fprintf(stderr, "fuse-subdir: memory allocation failed\n"); + return NULL; + } + + if (fuse_opt_parse(args, d, subdir_opts, subdir_opt_proc) == -1) + goto out_free; + + if (!next[0] || next[1]) { + fprintf(stderr, "fuse-subdir: exactly one next filesystem required\n"); + goto out_free; + } + + if (!d->base) { + fprintf(stderr, "fuse-subdir: missing 'subdir' option\n"); + goto out_free; + } + + if (d->base[0] && d->base[strlen(d->base)-1] != '/') { + char *tmp = realloc(d->base, strlen(d->base) + 2); + if (!tmp) { + fprintf(stderr, "fuse-subdir: memory allocation failed\n"); + goto out_free; + } + d->base = tmp; + strcat(d->base, "/"); + } + d->baselen = strlen(d->base); + d->next = next[0]; + fs = fuse_fs_new(&subdir_oper, sizeof(subdir_oper), d); + if (!fs) + goto out_free; + return fs; + +out_free: + free(d->base); + free(d); + return NULL; } FUSE_REGISTER_MODULE(subdir, subdir_new); diff --git a/lib/mount.c b/lib/mount.c index 8a5c5ab..14fbfb5 100644 --- a/lib/mount.c +++ b/lib/mount.c @@ -1,9 +1,9 @@ /* - FUSE: Filesystem in Userspace - Copyright (C) 2001-2007 Miklos Szeredi + FUSE: Filesystem in Userspace + Copyright (C) 2001-2007 Miklos Szeredi - This program can be distributed under the terms of the GNU LGPLv2. - See the file COPYING.LIB. + This program can be distributed under the terms of the GNU LGPLv2. + See the file COPYING.LIB. */ #include "config.h" @@ -25,8 +25,8 @@ #include #include -#define FUSERMOUNT_PROG "fusermount" -#define FUSE_COMMFD_ENV "_FUSE_COMMFD" +#define FUSERMOUNT_PROG "fusermount" +#define FUSE_COMMFD_ENV "_FUSE_COMMFD" #ifndef HAVE_FORK #define fork() vfork() @@ -37,551 +37,555 @@ #endif enum { - KEY_KERN_FLAG, - KEY_KERN_OPT, - KEY_FUSERMOUNT_OPT, - KEY_SUBTYPE_OPT, - KEY_MTAB_OPT, - KEY_ALLOW_ROOT, - KEY_RO, - KEY_HELP, - KEY_VERSION, + KEY_KERN_FLAG, + KEY_KERN_OPT, + KEY_FUSERMOUNT_OPT, + KEY_SUBTYPE_OPT, + KEY_MTAB_OPT, + KEY_ALLOW_ROOT, + KEY_RO, + KEY_HELP, + KEY_VERSION, }; struct mount_opts { - int allow_other; - int allow_root; - int ishelp; - int flags; - int nonempty; - int blkdev; - char *fsname; - char *subtype; - char *subtype_opt; - char *mtab_opts; - char *fusermount_opts; - char *kernel_opts; + int allow_other; + int allow_root; + int ishelp; + int flags; + int nonempty; + int blkdev; + char *fsname; + char *subtype; + char *subtype_opt; + char *mtab_opts; + char *fusermount_opts; + char *kernel_opts; }; #define FUSE_MOUNT_OPT(t, p) { t, offsetof(struct mount_opts, p), 1 } static const struct fuse_opt fuse_mount_opts[] = { - FUSE_MOUNT_OPT("allow_other", allow_other), - FUSE_MOUNT_OPT("allow_root", allow_root), - FUSE_MOUNT_OPT("nonempty", nonempty), - FUSE_MOUNT_OPT("blkdev", blkdev), - FUSE_MOUNT_OPT("fsname=%s", fsname), - FUSE_MOUNT_OPT("subtype=%s", subtype), - FUSE_OPT_KEY("allow_other", KEY_KERN_OPT), - FUSE_OPT_KEY("allow_root", KEY_ALLOW_ROOT), - FUSE_OPT_KEY("nonempty", KEY_FUSERMOUNT_OPT), - FUSE_OPT_KEY("blkdev", KEY_FUSERMOUNT_OPT), - FUSE_OPT_KEY("fsname=", KEY_FUSERMOUNT_OPT), - FUSE_OPT_KEY("subtype=", KEY_SUBTYPE_OPT), - FUSE_OPT_KEY("large_read", KEY_KERN_OPT), - FUSE_OPT_KEY("blksize=", KEY_KERN_OPT), - FUSE_OPT_KEY("default_permissions", KEY_KERN_OPT), - FUSE_OPT_KEY("max_read=", KEY_KERN_OPT), - FUSE_OPT_KEY("max_read=", FUSE_OPT_KEY_KEEP), - FUSE_OPT_KEY("user=", KEY_MTAB_OPT), - FUSE_OPT_KEY("-r", KEY_RO), - FUSE_OPT_KEY("ro", KEY_KERN_FLAG), - FUSE_OPT_KEY("rw", KEY_KERN_FLAG), - FUSE_OPT_KEY("suid", KEY_KERN_FLAG), - FUSE_OPT_KEY("nosuid", KEY_KERN_FLAG), - FUSE_OPT_KEY("dev", KEY_KERN_FLAG), - FUSE_OPT_KEY("nodev", KEY_KERN_FLAG), - FUSE_OPT_KEY("exec", KEY_KERN_FLAG), - FUSE_OPT_KEY("noexec", KEY_KERN_FLAG), - FUSE_OPT_KEY("async", KEY_KERN_FLAG), - FUSE_OPT_KEY("sync", KEY_KERN_FLAG), - FUSE_OPT_KEY("dirsync", KEY_KERN_FLAG), - FUSE_OPT_KEY("atime", KEY_KERN_FLAG), - FUSE_OPT_KEY("noatime", KEY_KERN_FLAG), - FUSE_OPT_KEY("-h", KEY_HELP), - FUSE_OPT_KEY("--help", KEY_HELP), - FUSE_OPT_KEY("-V", KEY_VERSION), - FUSE_OPT_KEY("--version", KEY_VERSION), - FUSE_OPT_END + FUSE_MOUNT_OPT("allow_other", allow_other), + FUSE_MOUNT_OPT("allow_root", allow_root), + FUSE_MOUNT_OPT("nonempty", nonempty), + FUSE_MOUNT_OPT("blkdev", blkdev), + FUSE_MOUNT_OPT("fsname=%s", fsname), + FUSE_MOUNT_OPT("subtype=%s", subtype), + FUSE_OPT_KEY("allow_other", KEY_KERN_OPT), + FUSE_OPT_KEY("allow_root", KEY_ALLOW_ROOT), + FUSE_OPT_KEY("nonempty", KEY_FUSERMOUNT_OPT), + FUSE_OPT_KEY("blkdev", KEY_FUSERMOUNT_OPT), + FUSE_OPT_KEY("fsname=", KEY_FUSERMOUNT_OPT), + FUSE_OPT_KEY("subtype=", KEY_SUBTYPE_OPT), + FUSE_OPT_KEY("large_read", KEY_KERN_OPT), + FUSE_OPT_KEY("blksize=", KEY_KERN_OPT), + FUSE_OPT_KEY("default_permissions", KEY_KERN_OPT), + FUSE_OPT_KEY("max_read=", KEY_KERN_OPT), + FUSE_OPT_KEY("max_read=", FUSE_OPT_KEY_KEEP), + FUSE_OPT_KEY("user=", KEY_MTAB_OPT), + FUSE_OPT_KEY("-r", KEY_RO), + FUSE_OPT_KEY("ro", KEY_KERN_FLAG), + FUSE_OPT_KEY("rw", KEY_KERN_FLAG), + FUSE_OPT_KEY("suid", KEY_KERN_FLAG), + FUSE_OPT_KEY("nosuid", KEY_KERN_FLAG), + FUSE_OPT_KEY("dev", KEY_KERN_FLAG), + FUSE_OPT_KEY("nodev", KEY_KERN_FLAG), + FUSE_OPT_KEY("exec", KEY_KERN_FLAG), + FUSE_OPT_KEY("noexec", KEY_KERN_FLAG), + FUSE_OPT_KEY("async", KEY_KERN_FLAG), + FUSE_OPT_KEY("sync", KEY_KERN_FLAG), + FUSE_OPT_KEY("dirsync", KEY_KERN_FLAG), + FUSE_OPT_KEY("atime", KEY_KERN_FLAG), + FUSE_OPT_KEY("noatime", KEY_KERN_FLAG), + FUSE_OPT_KEY("-h", KEY_HELP), + FUSE_OPT_KEY("--help", KEY_HELP), + FUSE_OPT_KEY("-V", KEY_VERSION), + FUSE_OPT_KEY("--version", KEY_VERSION), + FUSE_OPT_END }; static void mount_help(void) { - fprintf(stderr, - " -o allow_other allow access to other users\n" - " -o allow_root allow access to root\n" - " -o nonempty allow mounts over non-empty file/dir\n" - " -o default_permissions enable permission checking by kernel\n" - " -o fsname=NAME set filesystem name\n" - " -o subtype=NAME set filesystem type\n" - " -o large_read issue large read requests (2.4 only)\n" - " -o max_read=N set maximum size of read requests\n" - "\n" - ); + fprintf(stderr, +" -o allow_other allow access to other users\n" +" -o allow_root allow access to root\n" +" -o nonempty allow mounts over non-empty file/dir\n" +" -o default_permissions enable permission checking by kernel\n" +" -o fsname=NAME set filesystem name\n" +" -o subtype=NAME set filesystem type\n" +" -o large_read issue large read requests (2.4 only)\n" +" -o max_read=N set maximum size of read requests\n" +"\n"); } static void exec_fusermount(const char *argv[]) { - execv(FUSERMOUNT_DIR "/" FUSERMOUNT_PROG, (char **) argv); - execvp(FUSERMOUNT_PROG, (char **) argv); + execv(FUSERMOUNT_DIR "/" FUSERMOUNT_PROG, (char **) argv); + execvp(FUSERMOUNT_PROG, (char **) argv); } static void mount_version(void) { - int pid = fork(); - if (!pid) { - const char *argv[] = { FUSERMOUNT_PROG, "--version", NULL }; - exec_fusermount(argv); - _exit(1); - } else if (pid != -1) - waitpid(pid, NULL, 0); + int pid = fork(); + if (!pid) { + const char *argv[] = { FUSERMOUNT_PROG, "--version", NULL }; + exec_fusermount(argv); + _exit(1); + } else if (pid != -1) + waitpid(pid, NULL, 0); } struct mount_flags { - const char *opt; - unsigned long flag; - int on; + const char *opt; + unsigned long flag; + int on; }; static struct mount_flags mount_flags[] = { - {"rw", MS_RDONLY, 0}, - {"ro", MS_RDONLY, 1}, - {"suid", MS_NOSUID, 0}, - {"nosuid", MS_NOSUID, 1}, - {"dev", MS_NODEV, 0}, - {"nodev", MS_NODEV, 1}, - {"exec", MS_NOEXEC, 0}, - {"noexec", MS_NOEXEC, 1}, - {"async", MS_SYNCHRONOUS, 0}, - {"sync", MS_SYNCHRONOUS, 1}, - {"atime", MS_NOATIME, 0}, - {"noatime", MS_NOATIME, 1}, - {"dirsync", MS_DIRSYNC, 1}, - {NULL, 0, 0} + {"rw", MS_RDONLY, 0}, + {"ro", MS_RDONLY, 1}, + {"suid", MS_NOSUID, 0}, + {"nosuid", MS_NOSUID, 1}, + {"dev", MS_NODEV, 0}, + {"nodev", MS_NODEV, 1}, + {"exec", MS_NOEXEC, 0}, + {"noexec", MS_NOEXEC, 1}, + {"async", MS_SYNCHRONOUS, 0}, + {"sync", MS_SYNCHRONOUS, 1}, + {"atime", MS_NOATIME, 0}, + {"noatime", MS_NOATIME, 1}, + {"dirsync", MS_DIRSYNC, 1}, + {NULL, 0, 0} }; static void set_mount_flag(const char *s, int *flags) { - int i; - - for (i = 0; mount_flags[i].opt != NULL; i++) { - const char *opt = mount_flags[i].opt; - if (strcmp(opt, s) == 0) { - if (mount_flags[i].on) - *flags |= mount_flags[i].flag; - else - *flags &= ~mount_flags[i].flag; - return; - } - } - fprintf(stderr, "fuse: internal error, can't find mount flag\n"); - abort(); + int i; + + for (i = 0; mount_flags[i].opt != NULL; i++) { + const char *opt = mount_flags[i].opt; + if (strcmp(opt, s) == 0) { + if (mount_flags[i].on) + *flags |= mount_flags[i].flag; + else + *flags &= ~mount_flags[i].flag; + return; + } + } + fprintf(stderr, "fuse: internal error, can't find mount flag\n"); + abort(); } static int fuse_mount_opt_proc(void *data, const char *arg, int key, - struct fuse_args *outargs) + struct fuse_args *outargs) { - struct mount_opts *mo = data; - - switch (key) { - case KEY_ALLOW_ROOT: - if (fuse_opt_add_opt(&mo->kernel_opts, "allow_other") == -1 || - fuse_opt_add_arg(outargs, "-oallow_root") == -1) - return -1; - return 0; - - case KEY_RO: - arg = "ro"; - /* fall through */ - case KEY_KERN_FLAG: - set_mount_flag(arg, &mo->flags); - return 0; - - case KEY_KERN_OPT: - return fuse_opt_add_opt(&mo->kernel_opts, arg); - - case KEY_FUSERMOUNT_OPT: - return fuse_opt_add_opt(&mo->fusermount_opts, arg); - - case KEY_SUBTYPE_OPT: - return fuse_opt_add_opt(&mo->subtype_opt, arg); - - case KEY_MTAB_OPT: - return fuse_opt_add_opt(&mo->mtab_opts, arg); - - case KEY_HELP: - mount_help(); - mo->ishelp = 1; - break; - - case KEY_VERSION: - mount_version(); - mo->ishelp = 1; - break; - } - return 1; + struct mount_opts *mo = data; + + switch (key) { + case KEY_ALLOW_ROOT: + if (fuse_opt_add_opt(&mo->kernel_opts, "allow_other") == -1 || + fuse_opt_add_arg(outargs, "-oallow_root") == -1) + return -1; + return 0; + + case KEY_RO: + arg = "ro"; + /* fall through */ + case KEY_KERN_FLAG: + set_mount_flag(arg, &mo->flags); + return 0; + + case KEY_KERN_OPT: + return fuse_opt_add_opt(&mo->kernel_opts, arg); + + case KEY_FUSERMOUNT_OPT: + return fuse_opt_add_opt(&mo->fusermount_opts, arg); + + case KEY_SUBTYPE_OPT: + return fuse_opt_add_opt(&mo->subtype_opt, arg); + + case KEY_MTAB_OPT: + return fuse_opt_add_opt(&mo->mtab_opts, arg); + + case KEY_HELP: + mount_help(); + mo->ishelp = 1; + break; + + case KEY_VERSION: + mount_version(); + mo->ishelp = 1; + break; + } + return 1; } /* return value: - * >= 0 => fd - * -1 => error + * >= 0 => fd + * -1 => error */ static int receive_fd(int fd) { - struct msghdr msg; - struct iovec iov; - char buf[1]; - int rv; - size_t ccmsg[CMSG_SPACE(sizeof(int)) / sizeof(size_t)]; - struct cmsghdr *cmsg; - - iov.iov_base = buf; - iov.iov_len = 1; - - msg.msg_name = 0; - msg.msg_namelen = 0; - msg.msg_iov = &iov; - msg.msg_iovlen = 1; - /* old BSD implementations should use msg_accrights instead of - * msg_control; the interface is different. */ - msg.msg_control = ccmsg; - msg.msg_controllen = sizeof(ccmsg); - - while(((rv = recvmsg(fd, &msg, 0)) == -1) && errno == EINTR); - if (rv == -1) { - perror("recvmsg"); - return -1; - } - if(!rv) { - /* EOF */ - return -1; - } - - cmsg = CMSG_FIRSTHDR(&msg); - if (!cmsg->cmsg_type == SCM_RIGHTS) { - fprintf(stderr, "got control message of unknown type %d\n", - cmsg->cmsg_type); - return -1; - } - return *(int*)CMSG_DATA(cmsg); + struct msghdr msg; + struct iovec iov; + char buf[1]; + int rv; + size_t ccmsg[CMSG_SPACE(sizeof(int)) / sizeof(size_t)]; + struct cmsghdr *cmsg; + + iov.iov_base = buf; + iov.iov_len = 1; + + msg.msg_name = 0; + msg.msg_namelen = 0; + msg.msg_iov = &iov; + msg.msg_iovlen = 1; + /* old BSD implementations should use msg_accrights instead of + * msg_control; the interface is different. */ + msg.msg_control = ccmsg; + msg.msg_controllen = sizeof(ccmsg); + + while(((rv = recvmsg(fd, &msg, 0)) == -1) && errno == EINTR); + if (rv == -1) { + perror("recvmsg"); + return -1; + } + if(!rv) { + /* EOF */ + return -1; + } + + cmsg = CMSG_FIRSTHDR(&msg); + if (!cmsg->cmsg_type == SCM_RIGHTS) { + fprintf(stderr, "got control message of unknown type %d\n", + cmsg->cmsg_type); + return -1; + } + return *(int*)CMSG_DATA(cmsg); } void fuse_kern_unmount(const char *mountpoint, int fd) { - int res; - int pid; - - if (!mountpoint) - return; - - if (fd != -1) { - struct pollfd pfd; - - pfd.fd = fd; - pfd.events = 0; - res = poll(&pfd, 1, 0); - /* If file poll returns POLLERR on the device file descriptor, - then the filesystem is already unmounted */ - if (res == 1 && (pfd.revents & POLLERR)) - return; - - /* Need to close file descriptor, otherwise synchronous umount - would recurse into filesystem, and deadlock */ - close(fd); - } - - if (geteuid() == 0) { - fuse_mnt_umount("fuse", mountpoint, 1); - return; - } - - res = umount2(mountpoint, 2); - if (res == 0) - return; - - pid = fork(); - if(pid == -1) - return; - - if(pid == 0) { - const char *argv[] = - { FUSERMOUNT_PROG, "-u", "-q", "-z", "--", mountpoint, NULL }; - - exec_fusermount(argv); - _exit(1); - } - waitpid(pid, NULL, 0); + int res; + int pid; + + if (!mountpoint) + return; + + if (fd != -1) { + struct pollfd pfd; + + pfd.fd = fd; + pfd.events = 0; + res = poll(&pfd, 1, 0); + /* If file poll returns POLLERR on the device file descriptor, + then the filesystem is already unmounted */ + if (res == 1 && (pfd.revents & POLLERR)) + return; + + /* Need to close file descriptor, otherwise synchronous umount + would recurse into filesystem, and deadlock */ + close(fd); + } + + if (geteuid() == 0) { + fuse_mnt_umount("fuse", mountpoint, 1); + return; + } + + res = umount2(mountpoint, 2); + if (res == 0) + return; + + pid = fork(); + if(pid == -1) + return; + + if(pid == 0) { + const char *argv[] = { FUSERMOUNT_PROG, "-u", "-q", "-z", + "--", mountpoint, NULL }; + + exec_fusermount(argv); + _exit(1); + } + waitpid(pid, NULL, 0); } void fuse_unmount_compat22(const char *mountpoint) { - fuse_kern_unmount(mountpoint, -1); + fuse_kern_unmount(mountpoint, -1); } static int fuse_mount_fusermount(const char *mountpoint, const char *opts, - int quiet) + int quiet) { - int fds[2], pid; - int res; - int rv; - - if (!mountpoint) { - fprintf(stderr, "fuse: missing mountpoint\n"); - return -1; - } - - res = socketpair(PF_UNIX, SOCK_STREAM, 0, fds); - if(res == -1) { - perror("fuse: socketpair() failed"); - return -1; - } - - pid = fork(); - if(pid == -1) { - perror("fuse: fork() failed"); - close(fds[0]); - close(fds[1]); - return -1; - } - - if(pid == 0) { - char env[10]; - const char *argv[32]; - int a = 0; - - if (quiet) { - int fd = open("/dev/null", O_RDONLY); - dup2(fd, 1); - dup2(fd, 2); - } - - argv[a++] = FUSERMOUNT_PROG; - if (opts) { - argv[a++] = "-o"; - argv[a++] = opts; - } - argv[a++] = "--"; - argv[a++] = mountpoint; - argv[a++] = NULL; - - close(fds[1]); - fcntl(fds[0], F_SETFD, 0); - snprintf(env, sizeof(env), "%i", fds[0]); - setenv(FUSE_COMMFD_ENV, env, 1); - exec_fusermount(argv); - perror("fuse: failed to exec fusermount"); - _exit(1); - } - - close(fds[0]); - rv = receive_fd(fds[1]); - close(fds[1]); - waitpid(pid, NULL, 0); /* bury zombie */ - - return rv; + int fds[2], pid; + int res; + int rv; + + if (!mountpoint) { + fprintf(stderr, "fuse: missing mountpoint\n"); + return -1; + } + + res = socketpair(PF_UNIX, SOCK_STREAM, 0, fds); + if(res == -1) { + perror("fuse: socketpair() failed"); + return -1; + } + + pid = fork(); + if(pid == -1) { + perror("fuse: fork() failed"); + close(fds[0]); + close(fds[1]); + return -1; + } + + if(pid == 0) { + char env[10]; + const char *argv[32]; + int a = 0; + + if (quiet) { + int fd = open("/dev/null", O_RDONLY); + dup2(fd, 1); + dup2(fd, 2); + } + + argv[a++] = FUSERMOUNT_PROG; + if (opts) { + argv[a++] = "-o"; + argv[a++] = opts; + } + argv[a++] = "--"; + argv[a++] = mountpoint; + argv[a++] = NULL; + + close(fds[1]); + fcntl(fds[0], F_SETFD, 0); + snprintf(env, sizeof(env), "%i", fds[0]); + setenv(FUSE_COMMFD_ENV, env, 1); + exec_fusermount(argv); + perror("fuse: failed to exec fusermount"); + _exit(1); + } + + close(fds[0]); + rv = receive_fd(fds[1]); + close(fds[1]); + waitpid(pid, NULL, 0); /* bury zombie */ + + return rv; } int fuse_mount_compat22(const char *mountpoint, const char *opts) { - return fuse_mount_fusermount(mountpoint, opts, 0); + return fuse_mount_fusermount(mountpoint, opts, 0); } static int fuse_mount_sys(const char *mnt, struct mount_opts *mo, - const char *mnt_opts) + const char *mnt_opts) { - char tmp[128]; - const char *devname = "/dev/fuse"; - char *source = NULL; - char *type = NULL; - struct stat stbuf; - int fd; - int res; - - if (!mnt) { - fprintf(stderr, "fuse: missing mountpoint\n"); - return -1; - } - - res = lstat(mnt, &stbuf); - if (res == -1) { - fprintf(stderr ,"fuse: failed to access mountpoint %s: %s\n", - mnt, strerror(errno)); - return -1; - } - - if (!mo->nonempty) { - res = fuse_mnt_check_empty("fuse", mnt, stbuf.st_mode, stbuf.st_size); - if (res == -1) - return -1; - } - - fd = open(devname, O_RDWR); - if (fd == -1) { - if (errno == ENODEV || errno == ENOENT) - fprintf(stderr, - "fuse: device not found, try 'modprobe fuse' first\n"); - else - fprintf(stderr, "fuse: failed to open %s: %s\n", devname, - strerror(errno)); - return -1; - } - - snprintf(tmp, sizeof(tmp), "fd=%i,rootmode=%o,user_id=%i,group_id=%i", fd, - stbuf.st_mode & S_IFMT, getuid(), getgid()); - - res = fuse_opt_add_opt(&mo->kernel_opts, tmp); - if (res == -1) - goto out_close; - - source = malloc((mo->fsname ? strlen(mo->fsname) : 0) + - (mo->subtype ? strlen(mo->subtype) : 0) + - strlen(devname) + 32); - - type = malloc((mo->subtype ? strlen(mo->subtype) : 0) + 32); - if (!type || !source) { - fprintf(stderr, "fuse: failed to allocate memory\n"); - goto out_close; - } - - strcpy(type, mo->blkdev ? "fuseblk" : "fuse"); - if (mo->subtype) { - strcat(type, "."); - strcat(type, mo->subtype); - } - strcpy(source, - mo->fsname ? mo->fsname : (mo->subtype ? mo->subtype : devname)); - - res = mount(source, mnt, type, mo->flags, mo->kernel_opts); - if (res == -1 && errno == ENODEV && mo->subtype) { - /* Probably missing subtype support */ - strcpy(type, mo->blkdev ? "fuseblk" : "fuse"); - if (mo->fsname) { - if (!mo->blkdev) - sprintf(source, "%s#%s", mo->subtype, mo->fsname); - } else { - strcpy(source, type); - } - res = mount(source, mnt, type, mo->flags, mo->kernel_opts); - } - if (res == -1) { - /* - * Maybe kernel doesn't support unprivileged mounts, in this - * case try falling back to fusermount - */ - if (errno == EPERM) { - res = -2; - } else { - int errno_save = errno; - if (mo->blkdev && errno == ENODEV && !fuse_mnt_check_fuseblk()) - fprintf(stderr, "fuse: 'fuseblk' support missing\n"); - else - fprintf(stderr, "fuse: mount failed: %s\n", - strerror(errno_save)); - } - - goto out_close; - } - - if (geteuid() == 0) { - char *newmnt = fuse_mnt_resolve_path("fuse", mnt); - res = -1; - if (!newmnt) - goto out_umount; - - res = fuse_mnt_add_mount("fuse", source, newmnt, type, mnt_opts); - free(newmnt); - if (res == -1) - goto out_umount; - } - - return fd; - - out_umount: - umount2(mnt, 2); /* lazy umount */ - out_close: - free(type); - free(source); - close(fd); - return res; + char tmp[128]; + const char *devname = "/dev/fuse"; + char *source = NULL; + char *type = NULL; + struct stat stbuf; + int fd; + int res; + + if (!mnt) { + fprintf(stderr, "fuse: missing mountpoint\n"); + return -1; + } + + res = lstat(mnt, &stbuf); + if (res == -1) { + fprintf(stderr ,"fuse: failed to access mountpoint %s: %s\n", + mnt, strerror(errno)); + return -1; + } + + if (!mo->nonempty) { + res = fuse_mnt_check_empty("fuse", mnt, stbuf.st_mode, + stbuf.st_size); + if (res == -1) + return -1; + } + + fd = open(devname, O_RDWR); + if (fd == -1) { + if (errno == ENODEV || errno == ENOENT) + fprintf(stderr, "fuse: device not found, try 'modprobe fuse' first\n"); + else + fprintf(stderr, "fuse: failed to open %s: %s\n", + devname, strerror(errno)); + return -1; + } + + snprintf(tmp, sizeof(tmp), "fd=%i,rootmode=%o,user_id=%i,group_id=%i", + fd, stbuf.st_mode & S_IFMT, getuid(), getgid()); + + res = fuse_opt_add_opt(&mo->kernel_opts, tmp); + if (res == -1) + goto out_close; + + source = malloc((mo->fsname ? strlen(mo->fsname) : 0) + + (mo->subtype ? strlen(mo->subtype) : 0) + + strlen(devname) + 32); + + type = malloc((mo->subtype ? strlen(mo->subtype) : 0) + 32); + if (!type || !source) { + fprintf(stderr, "fuse: failed to allocate memory\n"); + goto out_close; + } + + strcpy(type, mo->blkdev ? "fuseblk" : "fuse"); + if (mo->subtype) { + strcat(type, "."); + strcat(type, mo->subtype); + } + strcpy(source, + mo->fsname ? mo->fsname : (mo->subtype ? mo->subtype : devname)); + + res = mount(source, mnt, type, mo->flags, mo->kernel_opts); + if (res == -1 && errno == ENODEV && mo->subtype) { + /* Probably missing subtype support */ + strcpy(type, mo->blkdev ? "fuseblk" : "fuse"); + if (mo->fsname) { + if (!mo->blkdev) + sprintf(source, "%s#%s", mo->subtype, + mo->fsname); + } else { + strcpy(source, type); + } + res = mount(source, mnt, type, mo->flags, mo->kernel_opts); + } + if (res == -1) { + /* + * Maybe kernel doesn't support unprivileged mounts, in this + * case try falling back to fusermount + */ + if (errno == EPERM) { + res = -2; + } else { + int errno_save = errno; + if (mo->blkdev && errno == ENODEV && + !fuse_mnt_check_fuseblk()) + fprintf(stderr, + "fuse: 'fuseblk' support missing\n"); + else + fprintf(stderr, "fuse: mount failed: %s\n", + strerror(errno_save)); + } + + goto out_close; + } + + if (geteuid() == 0) { + char *newmnt = fuse_mnt_resolve_path("fuse", mnt); + res = -1; + if (!newmnt) + goto out_umount; + + res = fuse_mnt_add_mount("fuse", source, newmnt, type, + mnt_opts); + free(newmnt); + if (res == -1) + goto out_umount; + } + + return fd; + +out_umount: + umount2(mnt, 2); /* lazy umount */ +out_close: + free(type); + free(source); + close(fd); + return res; } static int get_mnt_flag_opts(char **mnt_optsp, int flags) { - int i; + int i; - if (!(flags & MS_RDONLY) && fuse_opt_add_opt(mnt_optsp, "rw") == -1) - return -1; + if (!(flags & MS_RDONLY) && fuse_opt_add_opt(mnt_optsp, "rw") == -1) + return -1; - for (i = 0; mount_flags[i].opt != NULL; i++) { - if (mount_flags[i].on && (flags & mount_flags[i].flag) && - fuse_opt_add_opt(mnt_optsp, mount_flags[i].opt) == -1) - return -1; - } - return 0; + for (i = 0; mount_flags[i].opt != NULL; i++) { + if (mount_flags[i].on && (flags & mount_flags[i].flag) && + fuse_opt_add_opt(mnt_optsp, mount_flags[i].opt) == -1) + return -1; + } + return 0; } int fuse_kern_mount(const char *mountpoint, struct fuse_args *args) { - struct mount_opts mo; - int res = -1; - char *mnt_opts = NULL; - - memset(&mo, 0, sizeof(mo)); - mo.flags = MS_NOSUID | MS_NODEV; - - if (args && - fuse_opt_parse(args, &mo, fuse_mount_opts, fuse_mount_opt_proc) == -1) - return -1; - - if (mo.allow_other && mo.allow_root) { - fprintf(stderr, "fuse: 'allow_other' and 'allow_root' options are mutually exclusive\n"); - goto out; - } - res = 0; - if (mo.ishelp) - goto out; - - res = -1; - if (get_mnt_flag_opts(&mnt_opts, mo.flags) == -1) - goto out; - if (mo.kernel_opts && fuse_opt_add_opt(&mnt_opts, mo.kernel_opts) == -1) - goto out; - if (mo.mtab_opts && fuse_opt_add_opt(&mnt_opts, mo.mtab_opts) == -1) - goto out; - - res = fuse_mount_sys(mountpoint, &mo, mnt_opts); - if (res == -2) { - if (mo.fusermount_opts && - fuse_opt_add_opt(&mnt_opts, mo.fusermount_opts) == -1) - goto out; - - if (mo.subtype) { - char *tmp_opts = NULL; - - res = -1; - if (fuse_opt_add_opt(&tmp_opts, mnt_opts) == -1 || - fuse_opt_add_opt(&tmp_opts, mo.subtype_opt) == -1) { - free(tmp_opts); - goto out; - } - - res = fuse_mount_fusermount(mountpoint, tmp_opts, 1); - free(tmp_opts); - if (res == -1) - res = fuse_mount_fusermount(mountpoint, mnt_opts, 0); - } else { - res = fuse_mount_fusermount(mountpoint, mnt_opts, 0); - } - } - out: - free(mnt_opts); - free(mo.fsname); - free(mo.subtype); - free(mo.fusermount_opts); - free(mo.subtype_opt); - free(mo.kernel_opts); - free(mo.mtab_opts); - return res; + struct mount_opts mo; + int res = -1; + char *mnt_opts = NULL; + + memset(&mo, 0, sizeof(mo)); + mo.flags = MS_NOSUID | MS_NODEV; + + if (args && + fuse_opt_parse(args, &mo, fuse_mount_opts, fuse_mount_opt_proc) == -1) + return -1; + + if (mo.allow_other && mo.allow_root) { + fprintf(stderr, "fuse: 'allow_other' and 'allow_root' options are mutually exclusive\n"); + goto out; + } + res = 0; + if (mo.ishelp) + goto out; + + res = -1; + if (get_mnt_flag_opts(&mnt_opts, mo.flags) == -1) + goto out; + if (mo.kernel_opts && fuse_opt_add_opt(&mnt_opts, mo.kernel_opts) == -1) + goto out; + if (mo.mtab_opts && fuse_opt_add_opt(&mnt_opts, mo.mtab_opts) == -1) + goto out; + + res = fuse_mount_sys(mountpoint, &mo, mnt_opts); + if (res == -2) { + if (mo.fusermount_opts && + fuse_opt_add_opt(&mnt_opts, mo.fusermount_opts) == -1) + goto out; + + if (mo.subtype) { + char *tmp_opts = NULL; + + res = -1; + if (fuse_opt_add_opt(&tmp_opts, mnt_opts) == -1 || + fuse_opt_add_opt(&tmp_opts, mo.subtype_opt) == -1) { + free(tmp_opts); + goto out; + } + + res = fuse_mount_fusermount(mountpoint, tmp_opts, 1); + free(tmp_opts); + if (res == -1) + res = fuse_mount_fusermount(mountpoint, + mnt_opts, 0); + } else { + res = fuse_mount_fusermount(mountpoint, mnt_opts, 0); + } + } +out: + free(mnt_opts); + free(mo.fsname); + free(mo.subtype); + free(mo.fusermount_opts); + free(mo.subtype_opt); + free(mo.kernel_opts); + free(mo.mtab_opts); + return res; } FUSE_SYMVER(".symver fuse_mount_compat22,fuse_mount@FUSE_2.2"); diff --git a/lib/mount_bsd.c b/lib/mount_bsd.c index 5197464..fb4f12a 100644 --- a/lib/mount_bsd.c +++ b/lib/mount_bsd.c @@ -1,9 +1,9 @@ /* - FUSE: Filesystem in Userspace - Copyright (C) 2005-2006 Csaba Henk + FUSE: Filesystem in Userspace + Copyright (C) 2005-2006 Csaba Henk - This program can be distributed under the terms of the GNU LGPLv2. - See the file COPYING.LIB. + This program can be distributed under the terms of the GNU LGPLv2. + See the file COPYING.LIB. */ #include "fuse_i.h" @@ -22,343 +22,349 @@ #include #include -#define FUSERMOUNT_PROG "mount_fusefs" -#define FUSE_DEV_TRUNK "/dev/fuse" +#define FUSERMOUNT_PROG "mount_fusefs" +#define FUSE_DEV_TRUNK "/dev/fuse" enum { - KEY_ALLOW_ROOT, - KEY_RO, - KEY_HELP, - KEY_VERSION, - KEY_KERN + KEY_ALLOW_ROOT, + KEY_RO, + KEY_HELP, + KEY_VERSION, + KEY_KERN }; struct mount_opts { - int allow_other; - int allow_root; - int ishelp; - char *kernel_opts; + int allow_other; + int allow_root; + int ishelp; + char *kernel_opts; }; static const struct fuse_opt fuse_mount_opts[] = { - { "allow_other", offsetof(struct mount_opts, allow_other), 1 }, - { "allow_root", offsetof(struct mount_opts, allow_root), 1 }, - FUSE_OPT_KEY("allow_root", KEY_ALLOW_ROOT), - FUSE_OPT_KEY("-r", KEY_RO), - FUSE_OPT_KEY("-h", KEY_HELP), - FUSE_OPT_KEY("--help", KEY_HELP), - FUSE_OPT_KEY("-V", KEY_VERSION), - FUSE_OPT_KEY("--version", KEY_VERSION), - /* standard FreeBSD mount options */ - FUSE_OPT_KEY("dev", KEY_KERN), - FUSE_OPT_KEY("async", KEY_KERN), - FUSE_OPT_KEY("atime", KEY_KERN), - FUSE_OPT_KEY("dev", KEY_KERN), - FUSE_OPT_KEY("exec", KEY_KERN), - FUSE_OPT_KEY("suid", KEY_KERN), - FUSE_OPT_KEY("symfollow", KEY_KERN), - FUSE_OPT_KEY("rdonly", KEY_KERN), - FUSE_OPT_KEY("sync", KEY_KERN), - FUSE_OPT_KEY("union", KEY_KERN), - FUSE_OPT_KEY("userquota", KEY_KERN), - FUSE_OPT_KEY("groupquota", KEY_KERN), - FUSE_OPT_KEY("clusterr", KEY_KERN), - FUSE_OPT_KEY("clusterw", KEY_KERN), - FUSE_OPT_KEY("suiddir", KEY_KERN), - FUSE_OPT_KEY("snapshot", KEY_KERN), - FUSE_OPT_KEY("multilabel", KEY_KERN), - FUSE_OPT_KEY("acls", KEY_KERN), - FUSE_OPT_KEY("force", KEY_KERN), - FUSE_OPT_KEY("update", KEY_KERN), - FUSE_OPT_KEY("ro", KEY_KERN), - FUSE_OPT_KEY("rw", KEY_KERN), - FUSE_OPT_KEY("auto", KEY_KERN), - /* options supported under both Linux and FBSD */ - FUSE_OPT_KEY("allow_other", KEY_KERN), - FUSE_OPT_KEY("default_permissions", KEY_KERN), - /* FBSD FUSE specific mount options */ - FUSE_OPT_KEY("private", KEY_KERN), - FUSE_OPT_KEY("neglect_shares", KEY_KERN), - FUSE_OPT_KEY("push_symlinks_in", KEY_KERN), - /* stock FBSD mountopt parsing routine lets anything be negated... */ - FUSE_OPT_KEY("nodev", KEY_KERN), - FUSE_OPT_KEY("noasync", KEY_KERN), - FUSE_OPT_KEY("noatime", KEY_KERN), - FUSE_OPT_KEY("nodev", KEY_KERN), - FUSE_OPT_KEY("noexec", KEY_KERN), - FUSE_OPT_KEY("nosuid", KEY_KERN), - FUSE_OPT_KEY("nosymfollow", KEY_KERN), - FUSE_OPT_KEY("nordonly", KEY_KERN), - FUSE_OPT_KEY("nosync", KEY_KERN), - FUSE_OPT_KEY("nounion", KEY_KERN), - FUSE_OPT_KEY("nouserquota", KEY_KERN), - FUSE_OPT_KEY("nogroupquota", KEY_KERN), - FUSE_OPT_KEY("noclusterr", KEY_KERN), - FUSE_OPT_KEY("noclusterw", KEY_KERN), - FUSE_OPT_KEY("nosuiddir", KEY_KERN), - FUSE_OPT_KEY("nosnapshot", KEY_KERN), - FUSE_OPT_KEY("nomultilabel", KEY_KERN), - FUSE_OPT_KEY("noacls", KEY_KERN), - FUSE_OPT_KEY("noforce", KEY_KERN), - FUSE_OPT_KEY("noupdate", KEY_KERN), - FUSE_OPT_KEY("noro", KEY_KERN), - FUSE_OPT_KEY("norw", KEY_KERN), - FUSE_OPT_KEY("noauto", KEY_KERN), - FUSE_OPT_KEY("noallow_other", KEY_KERN), - FUSE_OPT_KEY("nodefault_permissions", KEY_KERN), - FUSE_OPT_KEY("noprivate", KEY_KERN), - FUSE_OPT_KEY("noneglect_shares", KEY_KERN), - FUSE_OPT_KEY("nopush_symlinks_in", KEY_KERN), - /* Linux specific mount options, but let just the mount util handle them */ - FUSE_OPT_KEY("fsname=", KEY_KERN), - FUSE_OPT_KEY("nonempty", KEY_KERN), - FUSE_OPT_KEY("large_read", KEY_KERN), - FUSE_OPT_KEY("max_read=", KEY_KERN), - FUSE_OPT_END + { "allow_other", offsetof(struct mount_opts, allow_other), 1 }, + { "allow_root", offsetof(struct mount_opts, allow_root), 1 }, + FUSE_OPT_KEY("allow_root", KEY_ALLOW_ROOT), + FUSE_OPT_KEY("-r", KEY_RO), + FUSE_OPT_KEY("-h", KEY_HELP), + FUSE_OPT_KEY("--help", KEY_HELP), + FUSE_OPT_KEY("-V", KEY_VERSION), + FUSE_OPT_KEY("--version", KEY_VERSION), + /* standard FreeBSD mount options */ + FUSE_OPT_KEY("dev", KEY_KERN), + FUSE_OPT_KEY("async", KEY_KERN), + FUSE_OPT_KEY("atime", KEY_KERN), + FUSE_OPT_KEY("dev", KEY_KERN), + FUSE_OPT_KEY("exec", KEY_KERN), + FUSE_OPT_KEY("suid", KEY_KERN), + FUSE_OPT_KEY("symfollow", KEY_KERN), + FUSE_OPT_KEY("rdonly", KEY_KERN), + FUSE_OPT_KEY("sync", KEY_KERN), + FUSE_OPT_KEY("union", KEY_KERN), + FUSE_OPT_KEY("userquota", KEY_KERN), + FUSE_OPT_KEY("groupquota", KEY_KERN), + FUSE_OPT_KEY("clusterr", KEY_KERN), + FUSE_OPT_KEY("clusterw", KEY_KERN), + FUSE_OPT_KEY("suiddir", KEY_KERN), + FUSE_OPT_KEY("snapshot", KEY_KERN), + FUSE_OPT_KEY("multilabel", KEY_KERN), + FUSE_OPT_KEY("acls", KEY_KERN), + FUSE_OPT_KEY("force", KEY_KERN), + FUSE_OPT_KEY("update", KEY_KERN), + FUSE_OPT_KEY("ro", KEY_KERN), + FUSE_OPT_KEY("rw", KEY_KERN), + FUSE_OPT_KEY("auto", KEY_KERN), + /* options supported under both Linux and FBSD */ + FUSE_OPT_KEY("allow_other", KEY_KERN), + FUSE_OPT_KEY("default_permissions", KEY_KERN), + /* FBSD FUSE specific mount options */ + FUSE_OPT_KEY("private", KEY_KERN), + FUSE_OPT_KEY("neglect_shares", KEY_KERN), + FUSE_OPT_KEY("push_symlinks_in", KEY_KERN), + /* stock FBSD mountopt parsing routine lets anything be negated... */ + FUSE_OPT_KEY("nodev", KEY_KERN), + FUSE_OPT_KEY("noasync", KEY_KERN), + FUSE_OPT_KEY("noatime", KEY_KERN), + FUSE_OPT_KEY("nodev", KEY_KERN), + FUSE_OPT_KEY("noexec", KEY_KERN), + FUSE_OPT_KEY("nosuid", KEY_KERN), + FUSE_OPT_KEY("nosymfollow", KEY_KERN), + FUSE_OPT_KEY("nordonly", KEY_KERN), + FUSE_OPT_KEY("nosync", KEY_KERN), + FUSE_OPT_KEY("nounion", KEY_KERN), + FUSE_OPT_KEY("nouserquota", KEY_KERN), + FUSE_OPT_KEY("nogroupquota", KEY_KERN), + FUSE_OPT_KEY("noclusterr", KEY_KERN), + FUSE_OPT_KEY("noclusterw", KEY_KERN), + FUSE_OPT_KEY("nosuiddir", KEY_KERN), + FUSE_OPT_KEY("nosnapshot", KEY_KERN), + FUSE_OPT_KEY("nomultilabel", KEY_KERN), + FUSE_OPT_KEY("noacls", KEY_KERN), + FUSE_OPT_KEY("noforce", KEY_KERN), + FUSE_OPT_KEY("noupdate", KEY_KERN), + FUSE_OPT_KEY("noro", KEY_KERN), + FUSE_OPT_KEY("norw", KEY_KERN), + FUSE_OPT_KEY("noauto", KEY_KERN), + FUSE_OPT_KEY("noallow_other", KEY_KERN), + FUSE_OPT_KEY("nodefault_permissions", KEY_KERN), + FUSE_OPT_KEY("noprivate", KEY_KERN), + FUSE_OPT_KEY("noneglect_shares", KEY_KERN), + FUSE_OPT_KEY("nopush_symlinks_in", KEY_KERN), + /* + * Linux specific mount options, but let just the mount util + * handle them + */ + FUSE_OPT_KEY("fsname=", KEY_KERN), + FUSE_OPT_KEY("nonempty", KEY_KERN), + FUSE_OPT_KEY("large_read", KEY_KERN), + FUSE_OPT_KEY("max_read=", KEY_KERN), + FUSE_OPT_END }; static void mount_help(void) { - fprintf(stderr, - " -o allow_root allow access to root\n" - ); - system(FUSERMOUNT_PROG " --help"); - fputc('\n', stderr); + fprintf(stderr, + " -o allow_root allow access to root\n" + ); + system(FUSERMOUNT_PROG " --help"); + fputc('\n', stderr); } static void mount_version(void) { - system(FUSERMOUNT_PROG " --version"); + system(FUSERMOUNT_PROG " --version"); } static int fuse_mount_opt_proc(void *data, const char *arg, int key, - struct fuse_args *outargs) + struct fuse_args *outargs) { - struct mount_opts *mo = data; - - switch (key) { - case KEY_ALLOW_ROOT: - if (fuse_opt_add_opt(&mo->kernel_opts, "allow_other") == -1 || - fuse_opt_add_arg(outargs, "-oallow_root") == -1) - return -1; - return 0; - - case KEY_RO: - arg = "ro"; - /* fall through */ - - case KEY_KERN: - return fuse_opt_add_opt(&mo->kernel_opts, arg); - - case KEY_HELP: - mount_help(); - mo->ishelp = 1; - break; - - case KEY_VERSION: - mount_version(); - mo->ishelp = 1; - break; - } - return 1; + struct mount_opts *mo = data; + + switch (key) { + case KEY_ALLOW_ROOT: + if (fuse_opt_add_opt(&mo->kernel_opts, "allow_other") == -1 || + fuse_opt_add_arg(outargs, "-oallow_root") == -1) + return -1; + return 0; + + case KEY_RO: + arg = "ro"; + /* fall through */ + + case KEY_KERN: + return fuse_opt_add_opt(&mo->kernel_opts, arg); + + case KEY_HELP: + mount_help(); + mo->ishelp = 1; + break; + + case KEY_VERSION: + mount_version(); + mo->ishelp = 1; + break; + } + return 1; } void fuse_unmount_compat22(const char *mountpoint) { - char dev[128]; - char *ssc, *umount_cmd; - FILE *sf; - int rv; - char *seekscript = - "exec 2>/dev/null; " /* error message is annoying in help output */ - "/usr/bin/fstat " FUSE_DEV_TRUNK "* | " - "/usr/bin/awk 'BEGIN{ getline; if (! ($3 == \"PID\" && $10 == \"NAME\")) exit 1; }; " - " { if ($3 == %d) print $10; }' | " - "/usr/bin/sort | " - "/usr/bin/uniq | " - "/usr/bin/awk '{ i += 1; if (i > 1){ exit 1; }; printf; }; END{ if (i == 0) exit 1; }'"; - - (void) mountpoint; - - /* - * If we don't know the fd, we have to resort to the scripted solution -- - * iterating over the fd-s is unpractical, as we don't know how many of - * open files we have. (This could be looked up in procfs -- however, - * that's optional on FBSD; or read out from the kmem -- however, that's - * bound to privileges (in fact, that's what happens when we call the - * setgid kmem fstat(1) utility). - */ - asprintf(&ssc, seekscript, getpid()); - - errno = 0; - sf = popen(ssc, "r"); - if (! sf) - return; - - fgets(dev, sizeof(dev), sf); - rv = pclose(sf); - if (rv) - return; - - asprintf(&umount_cmd, "/sbin/umount %s", dev); - system(umount_cmd); + char dev[128]; + char *ssc, *umount_cmd; + FILE *sf; + int rv; + char *seekscript = + /* error message is annoying in help output */ + "exec 2>/dev/null; " + "/usr/bin/fstat " FUSE_DEV_TRUNK "* | " + "/usr/bin/awk 'BEGIN{ getline; if (! ($3 == \"PID\" && $10 == \"NAME\")) exit 1; }; " + " { if ($3 == %d) print $10; }' | " + "/usr/bin/sort | " + "/usr/bin/uniq | " + "/usr/bin/awk '{ i += 1; if (i > 1){ exit 1; }; printf; }; END{ if (i == 0) exit 1; }'"; + + (void) mountpoint; + + /* + * If we don't know the fd, we have to resort to the scripted + * solution -- iterating over the fd-s is unpractical, as we + * don't know how many of open files we have. (This could be + * looked up in procfs -- however, that's optional on FBSD; or + * read out from the kmem -- however, that's bound to + * privileges (in fact, that's what happens when we call the + * setgid kmem fstat(1) utility). + */ + asprintf(&ssc, seekscript, getpid()); + + errno = 0; + sf = popen(ssc, "r"); + if (! sf) + return; + + fgets(dev, sizeof(dev), sf); + rv = pclose(sf); + if (rv) + return; + + asprintf(&umount_cmd, "/sbin/umount %s", dev); + system(umount_cmd); } void fuse_kern_unmount(const char *mountpoint, int fd) { - char *ep, *umount_cmd, dev[128]; - struct stat sbuf; + char *ep, *umount_cmd, dev[128]; + struct stat sbuf; - (void)mountpoint; + (void)mountpoint; - if (fstat(fd, &sbuf) == -1) - return; + if (fstat(fd, &sbuf) == -1) + return; - devname_r(sbuf.st_rdev, S_IFCHR, dev, 128); + devname_r(sbuf.st_rdev, S_IFCHR, dev, 128); - if (strncmp(dev, "fuse", 4)) - return; + if (strncmp(dev, "fuse", 4)) + return; - strtol(dev + 4, &ep, 10); - if (*ep != '\0') - return; + strtol(dev + 4, &ep, 10); + if (*ep != '\0') + return; - asprintf(&umount_cmd, "/sbin/umount " _PATH_DEV "%s", dev); - system(umount_cmd); + asprintf(&umount_cmd, "/sbin/umount " _PATH_DEV "%s", dev); + system(umount_cmd); } /* Check if kernel is doing init in background */ static int init_backgrounded(void) { - int ibg, len; + int ibg, len; - len = sizeof(ibg); + len = sizeof(ibg); - if (sysctlbyname("vfs.fuse.init_backgrounded", &ibg, &len, NULL, 0)) - return 0; + if (sysctlbyname("vfs.fuse.init_backgrounded", &ibg, &len, NULL, 0)) + return 0; - return ibg; + return ibg; } static int fuse_mount_core(const char *mountpoint, const char *opts) { - const char *mountprog = FUSERMOUNT_PROG; - int fd; - char *fdnam, *dev; - int pid; + const char *mountprog = FUSERMOUNT_PROG; + int fd; + char *fdnam, *dev; + int pid; - fdnam = getenv("FUSE_DEV_FD"); + fdnam = getenv("FUSE_DEV_FD"); - if (fdnam) { - char *ep; + if (fdnam) { + char *ep; - fd = strtol(fdnam, &ep, 10); + fd = strtol(fdnam, &ep, 10); - if (*ep != '\0') { - fprintf(stderr, "invalid value given in FUSE_DEV_FD\n"); - return -1; - } + if (*ep != '\0') { + fprintf(stderr, "invalid value given in FUSE_DEV_FD\n"); + return -1; + } - if (fd < 0) - return -1; + if (fd < 0) + return -1; - goto mount; - } + goto mount; + } - dev = getenv("FUSE_DEV_NAME"); + dev = getenv("FUSE_DEV_NAME"); - if (! dev) - dev = FUSE_DEV_TRUNK; + if (! dev) + dev = FUSE_DEV_TRUNK; - if ((fd = open(dev, O_RDWR)) < 0) { - perror("fuse: failed to open fuse device"); - return -1; - } + if ((fd = open(dev, O_RDWR)) < 0) { + perror("fuse: failed to open fuse device"); + return -1; + } mount: - if (getenv("FUSE_NO_MOUNT") || ! mountpoint) - goto out; - - pid = fork(); - - if (pid == -1) { - perror("fuse: fork() failed"); - close(fd); - return -1; - } - - if (pid == 0) { - if (! init_backgrounded()) { - /* - * If init is not backgrounded, we have to call the mount util - * backgrounded, to avoid deadlock. - */ - - pid = fork(); - - if (pid == -1) { - perror("fuse: fork() failed"); - close(fd); - exit(1); - } - } - - if (pid == 0) { - const char *argv[32]; - int a = 0; - - if (! fdnam) - asprintf(&fdnam, "%d", fd); - - argv[a++] = mountprog; - if (opts) { - argv[a++] = "-o"; - argv[a++] = opts; - } - argv[a++] = fdnam; - argv[a++] = mountpoint; - argv[a++] = NULL; - execvp(mountprog, (char **) argv); - perror("fuse: failed to exec mount program"); - exit(1); - } - - exit(0); - } - - waitpid(pid, NULL, 0); + if (getenv("FUSE_NO_MOUNT") || ! mountpoint) + goto out; + + pid = fork(); + + if (pid == -1) { + perror("fuse: fork() failed"); + close(fd); + return -1; + } + + if (pid == 0) { + if (! init_backgrounded()) { + /* + * If init is not backgrounded, we have to + * call the mount util backgrounded, to avoid + * deadlock. + */ + + pid = fork(); + + if (pid == -1) { + perror("fuse: fork() failed"); + close(fd); + exit(1); + } + } + + if (pid == 0) { + const char *argv[32]; + int a = 0; + + if (! fdnam) + asprintf(&fdnam, "%d", fd); + + argv[a++] = mountprog; + if (opts) { + argv[a++] = "-o"; + argv[a++] = opts; + } + argv[a++] = fdnam; + argv[a++] = mountpoint; + argv[a++] = NULL; + execvp(mountprog, (char **) argv); + perror("fuse: failed to exec mount program"); + exit(1); + } + + exit(0); + } + + waitpid(pid, NULL, 0); out: - return fd; + return fd; } int fuse_kern_mount(const char *mountpoint, struct fuse_args *args) { - struct mount_opts mo; - int res = -1; - - memset(&mo, 0, sizeof(mo)); - /* mount util should not try to spawn the daemon */ - setenv("MOUNT_FUSEFS_SAFE", "1", 1); - /* to notify the mount util it's called from lib */ - setenv("MOUNT_FUSEFS_CALL_BY_LIB", "1", 1); - - if (args && - fuse_opt_parse(args, &mo, fuse_mount_opts, fuse_mount_opt_proc) == -1) - return -1; - - if (mo.allow_other && mo.allow_root) { - fprintf(stderr, "fuse: 'allow_other' and 'allow_root' options are mutually exclusive\n"); - goto out; - } - if (mo.ishelp) - return 0; - - res = fuse_mount_core(mountpoint, mo.kernel_opts); - out: - free(mo.kernel_opts); - return res; + struct mount_opts mo; + int res = -1; + + memset(&mo, 0, sizeof(mo)); + /* mount util should not try to spawn the daemon */ + setenv("MOUNT_FUSEFS_SAFE", "1", 1); + /* to notify the mount util it's called from lib */ + setenv("MOUNT_FUSEFS_CALL_BY_LIB", "1", 1); + + if (args && + fuse_opt_parse(args, &mo, fuse_mount_opts, fuse_mount_opt_proc) == -1) + return -1; + + if (mo.allow_other && mo.allow_root) { + fprintf(stderr, "fuse: 'allow_other' and 'allow_root' options are mutually exclusive\n"); + goto out; + } + if (mo.ishelp) + return 0; + + res = fuse_mount_core(mountpoint, mo.kernel_opts); +out: + free(mo.kernel_opts); + return res; } FUSE_SYMVER(".symver fuse_unmount_compat22,fuse_unmount@FUSE_2.2"); diff --git a/lib/mount_util.c b/lib/mount_util.c index 9ce431a..39a1e6f 100644 --- a/lib/mount_util.c +++ b/lib/mount_util.c @@ -1,9 +1,9 @@ /* - FUSE: Filesystem in Userspace - Copyright (C) 2001-2007 Miklos Szeredi + FUSE: Filesystem in Userspace + Copyright (C) 2001-2007 Miklos Szeredi - This program can be distributed under the terms of the GNU LGPLv2. - See the file COPYING.LIB. + This program can be distributed under the terms of the GNU LGPLv2. + See the file COPYING.LIB. */ #include "mount_util.h" @@ -21,220 +21,223 @@ static int mtab_needs_update(const char *mnt) { - struct stat stbuf; + struct stat stbuf; - /* If mtab is within new mount, don't touch it */ - if (strncmp(mnt, _PATH_MOUNTED, strlen(mnt)) == 0 && - _PATH_MOUNTED[strlen(mnt)] == '/') - return 0; + /* If mtab is within new mount, don't touch it */ + if (strncmp(mnt, _PATH_MOUNTED, strlen(mnt)) == 0 && + _PATH_MOUNTED[strlen(mnt)] == '/') + return 0; - if (lstat(_PATH_MOUNTED, &stbuf) != -1 && S_ISLNK(stbuf.st_mode)) - return 0; + if (lstat(_PATH_MOUNTED, &stbuf) != -1 && S_ISLNK(stbuf.st_mode)) + return 0; - return 1; + return 1; } int fuse_mnt_add_mount(const char *progname, const char *fsname, - const char *mnt, const char *type, const char *opts) + const char *mnt, const char *type, const char *opts) { - int res; - int status; - - if (!mtab_needs_update(mnt)) - return 0; - - res = fork(); - if (res == -1) { - fprintf(stderr, "%s: fork: %s\n", progname, strerror(errno)); - return -1; - } - if (res == 0) { - char templ[] = "/tmp/fusermountXXXXXX"; - char *tmp; - - setuid(geteuid()); - - /* - * hide in a directory, where mount isn't able to resolve - * fsname as a valid path - */ - tmp = mkdtemp(templ); - if (!tmp) { - fprintf(stderr, "%s: failed to create temporary directory\n", - progname); - exit(1); - } - if (chdir(tmp)) { - fprintf(stderr, "%s: failed to chdir to %s: %s\n", - progname, tmp, strerror(errno)); - exit(1); - } - rmdir(tmp); - execl("/bin/mount", "/bin/mount", "-i", "-f", "-t", type, "-o", opts, - fsname, mnt, NULL); - fprintf(stderr, "%s: failed to execute /bin/mount: %s\n", progname, - strerror(errno)); - exit(1); - } - res = waitpid(res, &status, 0); - if (res == -1) { - fprintf(stderr, "%s: waitpid: %s\n", progname, strerror(errno)); - return -1; - } - if (status != 0) - return -1; - - return 0; + int res; + int status; + + if (!mtab_needs_update(mnt)) + return 0; + + res = fork(); + if (res == -1) { + fprintf(stderr, "%s: fork: %s\n", progname, strerror(errno)); + return -1; + } + if (res == 0) { + char templ[] = "/tmp/fusermountXXXXXX"; + char *tmp; + + setuid(geteuid()); + + /* + * hide in a directory, where mount isn't able to resolve + * fsname as a valid path + */ + tmp = mkdtemp(templ); + if (!tmp) { + fprintf(stderr, + "%s: failed to create temporary directory\n", + progname); + exit(1); + } + if (chdir(tmp)) { + fprintf(stderr, "%s: failed to chdir to %s: %s\n", + progname, tmp, strerror(errno)); + exit(1); + } + rmdir(tmp); + execl("/bin/mount", "/bin/mount", "-i", "-f", "-t", type, + "-o", opts, fsname, mnt, NULL); + fprintf(stderr, "%s: failed to execute /bin/mount: %s\n", + progname, strerror(errno)); + exit(1); + } + res = waitpid(res, &status, 0); + if (res == -1) { + fprintf(stderr, "%s: waitpid: %s\n", progname, strerror(errno)); + return -1; + } + if (status != 0) + return -1; + + return 0; } int fuse_mnt_umount(const char *progname, const char *mnt, int lazy) { - int res; - int status; - - if (!mtab_needs_update(mnt)) { - res = umount2(mnt, lazy ? 2 : 0); - if (res == -1) - fprintf(stderr, "%s: failed to unmount %s: %s\n", progname, - mnt, strerror(errno)); - return res; - } - - res = fork(); - if (res == -1) { - fprintf(stderr, "%s: fork: %s\n", progname, strerror(errno)); - return -1; - } - if (res == 0) { - setuid(geteuid()); - execl("/bin/umount", "/bin/umount", "-i", mnt, lazy ? "-l" : NULL, - NULL); - fprintf(stderr, "%s: failed to execute /bin/umount: %s\n", progname, - strerror(errno)); - exit(1); - } - res = waitpid(res, &status, 0); - if (res == -1) { - fprintf(stderr, "%s: waitpid: %s\n", progname, strerror(errno)); - return -1; - } - if (status != 0) - return -1; - - return 0; + int res; + int status; + + if (!mtab_needs_update(mnt)) { + res = umount2(mnt, lazy ? 2 : 0); + if (res == -1) + fprintf(stderr, "%s: failed to unmount %s: %s\n", + progname, mnt, strerror(errno)); + return res; + } + + res = fork(); + if (res == -1) { + fprintf(stderr, "%s: fork: %s\n", progname, strerror(errno)); + return -1; + } + if (res == 0) { + setuid(geteuid()); + execl("/bin/umount", "/bin/umount", "-i", mnt, + lazy ? "-l" : NULL, NULL); + fprintf(stderr, "%s: failed to execute /bin/umount: %s\n", + progname, strerror(errno)); + exit(1); + } + res = waitpid(res, &status, 0); + if (res == -1) { + fprintf(stderr, "%s: waitpid: %s\n", progname, strerror(errno)); + return -1; + } + if (status != 0) + return -1; + + return 0; } char *fuse_mnt_resolve_path(const char *progname, const char *orig) { - char buf[PATH_MAX]; - char *copy; - char *dst; - char *end; - char *lastcomp; - const char *toresolv; - - if (!orig[0]) { - fprintf(stderr, "%s: invalid mountpoint '%s'\n", progname, orig); - return NULL; - } - - copy = strdup(orig); - if (copy == NULL) { - fprintf(stderr, "%s: failed to allocate memory\n", progname); - return NULL; - } - - toresolv = copy; - lastcomp = NULL; - for (end = copy + strlen(copy) - 1; end > copy && *end == '/'; end --); - if (end[0] != '/') { - char *tmp; - end[1] = '\0'; - tmp = strrchr(copy, '/'); - if (tmp == NULL) { - lastcomp = copy; - toresolv = "."; - } else { - lastcomp = tmp + 1; - if (tmp == copy) - toresolv = "/"; - } - if (strcmp(lastcomp, ".") == 0 || strcmp(lastcomp, "..") == 0) { - lastcomp = NULL; - toresolv = copy; - } - else if (tmp) - tmp[0] = '\0'; - } - if (realpath(toresolv, buf) == NULL) { - fprintf(stderr, "%s: bad mount point %s: %s\n", progname, orig, - strerror(errno)); - free(copy); - return NULL; - } - if (lastcomp == NULL) - dst = strdup(buf); - else { - dst = (char *) malloc(strlen(buf) + 1 + strlen(lastcomp) + 1); - if (dst) { - unsigned buflen = strlen(buf); - if (buflen && buf[buflen-1] == '/') - sprintf(dst, "%s%s", buf, lastcomp); - else - sprintf(dst, "%s/%s", buf, lastcomp); - } - } - free(copy); - if (dst == NULL) - fprintf(stderr, "%s: failed to allocate memory\n", progname); - return dst; + char buf[PATH_MAX]; + char *copy; + char *dst; + char *end; + char *lastcomp; + const char *toresolv; + + if (!orig[0]) { + fprintf(stderr, "%s: invalid mountpoint '%s'\n", progname, + orig); + return NULL; + } + + copy = strdup(orig); + if (copy == NULL) { + fprintf(stderr, "%s: failed to allocate memory\n", progname); + return NULL; + } + + toresolv = copy; + lastcomp = NULL; + for (end = copy + strlen(copy) - 1; end > copy && *end == '/'; end --); + if (end[0] != '/') { + char *tmp; + end[1] = '\0'; + tmp = strrchr(copy, '/'); + if (tmp == NULL) { + lastcomp = copy; + toresolv = "."; + } else { + lastcomp = tmp + 1; + if (tmp == copy) + toresolv = "/"; + } + if (strcmp(lastcomp, ".") == 0 || strcmp(lastcomp, "..") == 0) { + lastcomp = NULL; + toresolv = copy; + } + else if (tmp) + tmp[0] = '\0'; + } + if (realpath(toresolv, buf) == NULL) { + fprintf(stderr, "%s: bad mount point %s: %s\n", progname, orig, + strerror(errno)); + free(copy); + return NULL; + } + if (lastcomp == NULL) + dst = strdup(buf); + else { + dst = (char *) malloc(strlen(buf) + 1 + strlen(lastcomp) + 1); + if (dst) { + unsigned buflen = strlen(buf); + if (buflen && buf[buflen-1] == '/') + sprintf(dst, "%s%s", buf, lastcomp); + else + sprintf(dst, "%s/%s", buf, lastcomp); + } + } + free(copy); + if (dst == NULL) + fprintf(stderr, "%s: failed to allocate memory\n", progname); + return dst; } int fuse_mnt_check_empty(const char *progname, const char *mnt, - mode_t rootmode, off_t rootsize) + mode_t rootmode, off_t rootsize) { - int isempty = 1; - - if (S_ISDIR(rootmode)) { - struct dirent *ent; - DIR *dp = opendir(mnt); - if (dp == NULL) { - fprintf(stderr, "%s: failed to open mountpoint for reading: %s\n", - progname, strerror(errno)); - return -1; - } - while ((ent = readdir(dp)) != NULL) { - if (strcmp(ent->d_name, ".") != 0 && - strcmp(ent->d_name, "..") != 0) { - isempty = 0; - break; - } - } - closedir(dp); - } else if (rootsize) - isempty = 0; - - if (!isempty) { - fprintf(stderr, "%s: mountpoint is not empty\n", progname); - fprintf(stderr, "%s: if you are sure this is safe, use the 'nonempty' mount option\n", progname); - return -1; - } - return 0; + int isempty = 1; + + if (S_ISDIR(rootmode)) { + struct dirent *ent; + DIR *dp = opendir(mnt); + if (dp == NULL) { + fprintf(stderr, + "%s: failed to open mountpoint for reading: %s\n", + progname, strerror(errno)); + return -1; + } + while ((ent = readdir(dp)) != NULL) { + if (strcmp(ent->d_name, ".") != 0 && + strcmp(ent->d_name, "..") != 0) { + isempty = 0; + break; + } + } + closedir(dp); + } else if (rootsize) + isempty = 0; + + if (!isempty) { + fprintf(stderr, "%s: mountpoint is not empty\n", progname); + fprintf(stderr, "%s: if you are sure this is safe, use the 'nonempty' mount option\n", progname); + return -1; + } + return 0; } int fuse_mnt_check_fuseblk(void) { - char buf[256]; - FILE *f = fopen("/proc/filesystems", "r"); - if (!f) - return 1; - - while (fgets(buf, sizeof(buf), f)) - if (strstr(buf, "fuseblk\n")) { - fclose(f); - return 1; - } - - fclose(f); - return 0; + char buf[256]; + FILE *f = fopen("/proc/filesystems", "r"); + if (!f) + return 1; + + while (fgets(buf, sizeof(buf), f)) + if (strstr(buf, "fuseblk\n")) { + fclose(f); + return 1; + } + + fclose(f); + return 0; } diff --git a/lib/mount_util.h b/lib/mount_util.h index 29de2be..cf54d9d 100644 --- a/lib/mount_util.h +++ b/lib/mount_util.h @@ -1,17 +1,17 @@ /* - FUSE: Filesystem in Userspace - Copyright (C) 2001-2007 Miklos Szeredi + FUSE: Filesystem in Userspace + Copyright (C) 2001-2007 Miklos Szeredi - This program can be distributed under the terms of the GNU LGPLv2. - See the file COPYING.LIB. + This program can be distributed under the terms of the GNU LGPLv2. + See the file COPYING.LIB. */ #include int fuse_mnt_add_mount(const char *progname, const char *fsname, - const char *mnt, const char *type, const char *opts); + const char *mnt, const char *type, const char *opts); int fuse_mnt_umount(const char *progname, const char *mnt, int lazy); char *fuse_mnt_resolve_path(const char *progname, const char *orig); int fuse_mnt_check_empty(const char *progname, const char *mnt, - mode_t rootmode, off_t rootsize); + mode_t rootmode, off_t rootsize); int fuse_mnt_check_fuseblk(void); diff --git a/lib/ulockmgr.c b/lib/ulockmgr.c index e38fdc5..6703cd0 100644 --- a/lib/ulockmgr.c +++ b/lib/ulockmgr.c @@ -1,9 +1,9 @@ /* - libulockmgr: Userspace Lock Manager Library - Copyright (C) 2006 Miklos Szeredi + libulockmgr: Userspace Lock Manager Library + Copyright (C) 2006 Miklos Szeredi - This program can be distributed under the terms of the GNU LGPLv2. - See the file COPYING.LIB + This program can be distributed under the terms of the GNU LGPLv2. + See the file COPYING.LIB */ /* #define DEBUG 1 */ @@ -22,28 +22,28 @@ #include struct message { - unsigned intr : 1; - unsigned nofd : 1; - pthread_t thr; - int cmd; - int fd; - struct flock lock; - int error; + unsigned intr : 1; + unsigned nofd : 1; + pthread_t thr; + int cmd; + int fd; + struct flock lock; + int error; }; struct fd_store { - struct fd_store *next; - int fd; - int inuse; + struct fd_store *next; + int fd; + int inuse; }; struct owner { - struct owner *next; - struct owner *prev; - struct fd_store *fds; - void *id; - size_t id_len; - int cfd; + struct owner *next; + struct owner *prev; + struct fd_store *fds; + void *id; + size_t id_len; + int cfd; }; static pthread_mutex_t ulockmgr_lock; @@ -54,19 +54,19 @@ static struct owner owner_list = { .next = &owner_list, .prev = &owner_list }; static void list_del_owner(struct owner *owner) { - struct owner *prev = owner->prev; - struct owner *next = owner->next; - prev->next = next; - next->prev = prev; + struct owner *prev = owner->prev; + struct owner *next = owner->next; + prev->next = next; + next->prev = prev; } static void list_add_owner(struct owner *owner, struct owner *next) { - struct owner *prev = next->prev; - owner->next = next; - owner->prev = prev; - prev->next = owner; - next->prev = owner; + struct owner *prev = next->prev; + owner->next = next; + owner->prev = prev; + prev->next = owner; + next->prev = owner; } /* @@ -74,365 +74,367 @@ static void list_add_owner(struct owner *owner, struct owner *next) * on AF_UNIX, SOCK_STREAM sockets, that could cause it to return * zero, even if data was available. Retrying the recv will return * the data in this case. -*/ + */ static int do_recv(int sock, void *buf, size_t len, int flags) { - int res = recv(sock, buf, len, flags); - if (res == 0) - res = recv(sock, buf, len, flags); + int res = recv(sock, buf, len, flags); + if (res == 0) + res = recv(sock, buf, len, flags); - return res; + return res; } static int ulockmgr_send_message(int sock, void *buf, size_t buflen, - int *fdp, int numfds) + int *fdp, int numfds) { - struct msghdr msg; - struct cmsghdr *p_cmsg; - struct iovec vec; - size_t cmsgbuf[CMSG_SPACE(sizeof(int) * MAX_SEND_FDS) / sizeof(size_t)]; - int res; - - assert(numfds <= MAX_SEND_FDS); - msg.msg_control = cmsgbuf; - msg.msg_controllen = sizeof(cmsgbuf); - p_cmsg = CMSG_FIRSTHDR(&msg); - p_cmsg->cmsg_level = SOL_SOCKET; - p_cmsg->cmsg_type = SCM_RIGHTS; - p_cmsg->cmsg_len = CMSG_LEN(sizeof(int) * numfds); - memcpy(CMSG_DATA(p_cmsg), fdp, sizeof(int) * numfds); - msg.msg_controllen = p_cmsg->cmsg_len; - msg.msg_name = NULL; - msg.msg_namelen = 0; - msg.msg_iov = &vec; - msg.msg_iovlen = 1; - msg.msg_flags = 0; - vec.iov_base = buf; - vec.iov_len = buflen; - res = sendmsg(sock, &msg, MSG_NOSIGNAL); - if (res == -1) { - perror("libulockmgr: sendmsg"); - return -1; - } - if ((size_t) res != buflen) { - fprintf(stderr, "libulockmgr: sendmsg short\n"); - return -1; - } - return 0; + struct msghdr msg; + struct cmsghdr *p_cmsg; + struct iovec vec; + size_t cmsgbuf[CMSG_SPACE(sizeof(int) * MAX_SEND_FDS) / sizeof(size_t)]; + int res; + + assert(numfds <= MAX_SEND_FDS); + msg.msg_control = cmsgbuf; + msg.msg_controllen = sizeof(cmsgbuf); + p_cmsg = CMSG_FIRSTHDR(&msg); + p_cmsg->cmsg_level = SOL_SOCKET; + p_cmsg->cmsg_type = SCM_RIGHTS; + p_cmsg->cmsg_len = CMSG_LEN(sizeof(int) * numfds); + memcpy(CMSG_DATA(p_cmsg), fdp, sizeof(int) * numfds); + msg.msg_controllen = p_cmsg->cmsg_len; + msg.msg_name = NULL; + msg.msg_namelen = 0; + msg.msg_iov = &vec; + msg.msg_iovlen = 1; + msg.msg_flags = 0; + vec.iov_base = buf; + vec.iov_len = buflen; + res = sendmsg(sock, &msg, MSG_NOSIGNAL); + if (res == -1) { + perror("libulockmgr: sendmsg"); + return -1; + } + if ((size_t) res != buflen) { + fprintf(stderr, "libulockmgr: sendmsg short\n"); + return -1; + } + return 0; } static int ulockmgr_start_daemon(void) { - int sv[2]; - int res; - char tmp[64]; - - res = socketpair(AF_UNIX, SOCK_STREAM, 0, sv); - if (res == -1) { - perror("libulockmgr: socketpair"); - return -1; - } - snprintf(tmp, sizeof(tmp), "exec ulockmgr_server %i", sv[0]); - res = system(tmp); - close(sv[0]); - if (res == -1 || !WIFEXITED(res) || WEXITSTATUS(res) != 0) { - close(sv[1]); - return -1; - } - ulockmgr_cfd = sv[1]; - return 0; + int sv[2]; + int res; + char tmp[64]; + + res = socketpair(AF_UNIX, SOCK_STREAM, 0, sv); + if (res == -1) { + perror("libulockmgr: socketpair"); + return -1; + } + snprintf(tmp, sizeof(tmp), "exec ulockmgr_server %i", sv[0]); + res = system(tmp); + close(sv[0]); + if (res == -1 || !WIFEXITED(res) || WEXITSTATUS(res) != 0) { + close(sv[1]); + return -1; + } + ulockmgr_cfd = sv[1]; + return 0; } static struct owner *ulockmgr_new_owner(const void *id, size_t id_len) { - int sv[2]; - int res; - char c = 'm'; - struct owner *o; - - if (ulockmgr_cfd == -1 && ulockmgr_start_daemon() == -1) - return NULL; - - o = calloc(1, sizeof(struct owner) + id_len); - if (!o) { - fprintf(stderr, "libulockmgr: failed to allocate memory\n"); - return NULL; - } - o->id = o + 1; - o->id_len = id_len; - res = socketpair(AF_UNIX, SOCK_STREAM, 0, sv); - if (res == -1) { - perror("libulockmgr: socketpair"); - goto out_free; - } - res = ulockmgr_send_message(ulockmgr_cfd, &c, sizeof(c), &sv[0], 1); - close(sv[0]); - if (res == -1) { - close(ulockmgr_cfd); - ulockmgr_cfd = -1; - goto out_close; - } - - o->cfd = sv[1]; - memcpy(o->id, id, id_len); - list_add_owner(o, &owner_list); - - return o; - - out_close: - close(sv[1]); - out_free: - free(o); - return NULL; + int sv[2]; + int res; + char c = 'm'; + struct owner *o; + + if (ulockmgr_cfd == -1 && ulockmgr_start_daemon() == -1) + return NULL; + + o = calloc(1, sizeof(struct owner) + id_len); + if (!o) { + fprintf(stderr, "libulockmgr: failed to allocate memory\n"); + return NULL; + } + o->id = o + 1; + o->id_len = id_len; + res = socketpair(AF_UNIX, SOCK_STREAM, 0, sv); + if (res == -1) { + perror("libulockmgr: socketpair"); + goto out_free; + } + res = ulockmgr_send_message(ulockmgr_cfd, &c, sizeof(c), &sv[0], 1); + close(sv[0]); + if (res == -1) { + close(ulockmgr_cfd); + ulockmgr_cfd = -1; + goto out_close; + } + + o->cfd = sv[1]; + memcpy(o->id, id, id_len); + list_add_owner(o, &owner_list); + + return o; + +out_close: + close(sv[1]); +out_free: + free(o); + return NULL; } static int ulockmgr_send_request(struct message *msg, const void *id, - size_t id_len) + size_t id_len) { - int sv[2]; - int cfd; - struct owner *o; - struct fd_store *f = NULL; - struct fd_store *newf = NULL; - struct fd_store **fp; - int fd = msg->fd; - int cmd = msg->cmd; - int res; - int unlockall = (cmd == F_SETLK && msg->lock.l_type == F_UNLCK && - msg->lock.l_start == 0 && msg->lock.l_len == 0); - - for (o = owner_list.next; o != &owner_list; o = o->next) - if (o->id_len == id_len && memcmp(o->id, id, id_len) == 0) - break; - - if (o == &owner_list) - o = NULL; - - if (!o && cmd != F_GETLK && msg->lock.l_type != F_UNLCK) - o = ulockmgr_new_owner(id, id_len); - - if (!o) { - if (cmd == F_GETLK) { - res = fcntl(msg->fd, F_GETLK, &msg->lock); - return (res == -1) ? -errno : 0; - } else if (msg->lock.l_type == F_UNLCK) - return 0; - else - return -ENOLCK; - } - - if (unlockall) - msg->nofd = 1; - else { - for (fp = &o->fds; *fp; fp = &(*fp)->next) { - f = *fp; - if (f->fd == fd) { - msg->nofd = 1; - break; - } - } - } - - if (!msg->nofd) { - newf = f = calloc(1, sizeof(struct fd_store)); - if (!f) { - fprintf(stderr, "libulockmgr: failed to allocate memory\n"); - return -ENOLCK; - } - } - - res = socketpair(AF_UNIX, SOCK_STREAM, 0, sv); - if (res == -1) { - perror("libulockmgr: socketpair"); - free(newf); - return -ENOLCK; - } - - cfd = sv[1]; - sv[1] = msg->fd; - res = ulockmgr_send_message(o->cfd, msg, sizeof(struct message), sv, - msg->nofd ? 1 : 2); - close(sv[0]); - if (res == -1) { - free(newf); - close(cfd); - return -EIO; - } - - if (newf) { - newf->fd = msg->fd; - newf->next = o->fds; - o->fds = newf; - } - if (f) - f->inuse++; - - res = do_recv(cfd, msg, sizeof(struct message), MSG_WAITALL); - if (res == -1) { - perror("libulockmgr: recv"); - msg->error = EIO; - } else if (res != sizeof(struct message)) { - fprintf(stderr, "libulockmgr: recv short\n"); - msg->error = EIO; - } else if (cmd == F_SETLKW && msg->error == EAGAIN) { - pthread_mutex_unlock(&ulockmgr_lock); - while (1) { - sigset_t old; - sigset_t unblock; - int errno_save; - - sigemptyset(&unblock); - sigaddset(&unblock, SIGUSR1); - pthread_sigmask(SIG_UNBLOCK, &unblock, &old); - res = do_recv(cfd, msg, sizeof(struct message), MSG_WAITALL); - errno_save = errno; - pthread_sigmask(SIG_SETMASK, &old, NULL); - if (res == sizeof(struct message)) - break; - else if (res >= 0) { - fprintf(stderr, "libulockmgr: recv short\n"); - msg->error = EIO; - break; - } else if (errno_save != EINTR) { - errno = errno_save; - perror("libulockmgr: recv"); - msg->error = EIO; - break; - } - msg->intr = 1; - res = send(o->cfd, msg, sizeof(struct message), MSG_NOSIGNAL); - if (res == -1) { - perror("libulockmgr: send"); - msg->error = EIO; - break; - } - if (res != sizeof(struct message)) { - fprintf(stderr, "libulockmgr: send short\n"); - msg->error = EIO; - break; - } - } - pthread_mutex_lock(&ulockmgr_lock); - - } - if (f) - f->inuse--; - close(cfd); - if (unlockall) { - for (fp = &o->fds; *fp;) { - f = *fp; - if (f->fd == fd && !f->inuse) { - *fp = f->next; - free(f); - } else - fp = &f->next; - } - if (!o->fds) { - list_del_owner(o); - close(o->cfd); - free(o); - } - /* Force OK on unlock-all, since it _will_ succeed once the - owner is deleted */ - msg->error = 0; - } - - return -msg->error; + int sv[2]; + int cfd; + struct owner *o; + struct fd_store *f = NULL; + struct fd_store *newf = NULL; + struct fd_store **fp; + int fd = msg->fd; + int cmd = msg->cmd; + int res; + int unlockall = (cmd == F_SETLK && msg->lock.l_type == F_UNLCK && + msg->lock.l_start == 0 && msg->lock.l_len == 0); + + for (o = owner_list.next; o != &owner_list; o = o->next) + if (o->id_len == id_len && memcmp(o->id, id, id_len) == 0) + break; + + if (o == &owner_list) + o = NULL; + + if (!o && cmd != F_GETLK && msg->lock.l_type != F_UNLCK) + o = ulockmgr_new_owner(id, id_len); + + if (!o) { + if (cmd == F_GETLK) { + res = fcntl(msg->fd, F_GETLK, &msg->lock); + return (res == -1) ? -errno : 0; + } else if (msg->lock.l_type == F_UNLCK) + return 0; + else + return -ENOLCK; + } + + if (unlockall) + msg->nofd = 1; + else { + for (fp = &o->fds; *fp; fp = &(*fp)->next) { + f = *fp; + if (f->fd == fd) { + msg->nofd = 1; + break; + } + } + } + + if (!msg->nofd) { + newf = f = calloc(1, sizeof(struct fd_store)); + if (!f) { + fprintf(stderr, "libulockmgr: failed to allocate memory\n"); + return -ENOLCK; + } + } + + res = socketpair(AF_UNIX, SOCK_STREAM, 0, sv); + if (res == -1) { + perror("libulockmgr: socketpair"); + free(newf); + return -ENOLCK; + } + + cfd = sv[1]; + sv[1] = msg->fd; + res = ulockmgr_send_message(o->cfd, msg, sizeof(struct message), sv, + msg->nofd ? 1 : 2); + close(sv[0]); + if (res == -1) { + free(newf); + close(cfd); + return -EIO; + } + + if (newf) { + newf->fd = msg->fd; + newf->next = o->fds; + o->fds = newf; + } + if (f) + f->inuse++; + + res = do_recv(cfd, msg, sizeof(struct message), MSG_WAITALL); + if (res == -1) { + perror("libulockmgr: recv"); + msg->error = EIO; + } else if (res != sizeof(struct message)) { + fprintf(stderr, "libulockmgr: recv short\n"); + msg->error = EIO; + } else if (cmd == F_SETLKW && msg->error == EAGAIN) { + pthread_mutex_unlock(&ulockmgr_lock); + while (1) { + sigset_t old; + sigset_t unblock; + int errno_save; + + sigemptyset(&unblock); + sigaddset(&unblock, SIGUSR1); + pthread_sigmask(SIG_UNBLOCK, &unblock, &old); + res = do_recv(cfd, msg, sizeof(struct message), + MSG_WAITALL); + errno_save = errno; + pthread_sigmask(SIG_SETMASK, &old, NULL); + if (res == sizeof(struct message)) + break; + else if (res >= 0) { + fprintf(stderr, "libulockmgr: recv short\n"); + msg->error = EIO; + break; + } else if (errno_save != EINTR) { + errno = errno_save; + perror("libulockmgr: recv"); + msg->error = EIO; + break; + } + msg->intr = 1; + res = send(o->cfd, msg, sizeof(struct message), + MSG_NOSIGNAL); + if (res == -1) { + perror("libulockmgr: send"); + msg->error = EIO; + break; + } + if (res != sizeof(struct message)) { + fprintf(stderr, "libulockmgr: send short\n"); + msg->error = EIO; + break; + } + } + pthread_mutex_lock(&ulockmgr_lock); + + } + if (f) + f->inuse--; + close(cfd); + if (unlockall) { + for (fp = &o->fds; *fp;) { + f = *fp; + if (f->fd == fd && !f->inuse) { + *fp = f->next; + free(f); + } else + fp = &f->next; + } + if (!o->fds) { + list_del_owner(o); + close(o->cfd); + free(o); + } + /* Force OK on unlock-all, since it _will_ succeed once the + owner is deleted */ + msg->error = 0; + } + + return -msg->error; } #ifdef DEBUG static uint32_t owner_hash(const unsigned char *id, size_t id_len) { - uint32_t h = 0; - size_t i; - for (i = 0; i < id_len; i++) - h = ((h << 8) | (h >> 24)) ^ id[i]; + uint32_t h = 0; + size_t i; + for (i = 0; i < id_len; i++) + h = ((h << 8) | (h >> 24)) ^ id[i]; - return h; + return h; } #endif static int ulockmgr_canonicalize(int fd, struct flock *lock) { - off_t offset; - if (lock->l_whence == SEEK_CUR) { - offset = lseek(fd, 0, SEEK_CUR); - if (offset == (off_t) -1) - return -errno; - } else if (lock->l_whence == SEEK_END) { - struct stat stbuf; - int res = fstat(fd, &stbuf); - if (res == -1) - return -errno; - - offset = stbuf.st_size; - } else - offset = 0; - - lock->l_whence = SEEK_SET; - lock->l_start += offset; - - if (lock->l_start < 0) - return -EINVAL; - - if (lock->l_len < 0) { - lock->l_start += lock->l_len; - if (lock->l_start < 0) - return -EINVAL; - lock->l_len = -lock->l_len; - } - if (lock->l_len && lock->l_start + lock->l_len - 1 < 0) - return -EINVAL; - - return 0; + off_t offset; + if (lock->l_whence == SEEK_CUR) { + offset = lseek(fd, 0, SEEK_CUR); + if (offset == (off_t) -1) + return -errno; + } else if (lock->l_whence == SEEK_END) { + struct stat stbuf; + int res = fstat(fd, &stbuf); + if (res == -1) + return -errno; + + offset = stbuf.st_size; + } else + offset = 0; + + lock->l_whence = SEEK_SET; + lock->l_start += offset; + + if (lock->l_start < 0) + return -EINVAL; + + if (lock->l_len < 0) { + lock->l_start += lock->l_len; + if (lock->l_start < 0) + return -EINVAL; + lock->l_len = -lock->l_len; + } + if (lock->l_len && lock->l_start + lock->l_len - 1 < 0) + return -EINVAL; + + return 0; } int ulockmgr_op(int fd, int cmd, struct flock *lock, const void *owner, - size_t owner_len) + size_t owner_len) { - int err; - struct message msg; - sigset_t old; - sigset_t block; + int err; + struct message msg; + sigset_t old; + sigset_t block; - if (cmd != F_GETLK && cmd != F_SETLK && cmd != F_SETLKW) - return -EINVAL; + if (cmd != F_GETLK && cmd != F_SETLK && cmd != F_SETLKW) + return -EINVAL; - if (lock->l_whence != SEEK_SET && lock->l_whence != SEEK_CUR && - lock->l_whence != SEEK_END) - return -EINVAL; + if (lock->l_whence != SEEK_SET && lock->l_whence != SEEK_CUR && + lock->l_whence != SEEK_END) + return -EINVAL; #ifdef DEBUG - fprintf(stderr, "libulockmgr: %i %i %i %lli %lli own: 0x%08x\n", - cmd, lock->l_type, lock->l_whence, lock->l_start, lock->l_len, - owner_hash(owner, owner_len)); + fprintf(stderr, "libulockmgr: %i %i %i %lli %lli own: 0x%08x\n", + cmd, lock->l_type, lock->l_whence, lock->l_start, lock->l_len, + owner_hash(owner, owner_len)); #endif - /* Unlock should never block anyway */ - if (cmd == F_SETLKW && lock->l_type == F_UNLCK) - cmd = F_SETLK; - - memset(&msg, 0, sizeof(struct message)); - msg.cmd = cmd; - msg.fd = fd; - msg.lock = *lock; - err = ulockmgr_canonicalize(fd, &msg.lock); - if (err) - return err; - - sigemptyset(&block); - sigaddset(&block, SIGUSR1); - pthread_sigmask(SIG_BLOCK, &block, &old); - pthread_mutex_lock(&ulockmgr_lock); - err = ulockmgr_send_request(&msg, owner, owner_len); - pthread_mutex_unlock(&ulockmgr_lock); - pthread_sigmask(SIG_SETMASK, &old, NULL); - if (!err && cmd == F_GETLK) { - if (msg.lock.l_type == F_UNLCK) - lock->l_type = F_UNLCK; - else - *lock = msg.lock; - } - - return err; + /* Unlock should never block anyway */ + if (cmd == F_SETLKW && lock->l_type == F_UNLCK) + cmd = F_SETLK; + + memset(&msg, 0, sizeof(struct message)); + msg.cmd = cmd; + msg.fd = fd; + msg.lock = *lock; + err = ulockmgr_canonicalize(fd, &msg.lock); + if (err) + return err; + + sigemptyset(&block); + sigaddset(&block, SIGUSR1); + pthread_sigmask(SIG_BLOCK, &block, &old); + pthread_mutex_lock(&ulockmgr_lock); + err = ulockmgr_send_request(&msg, owner, owner_len); + pthread_mutex_unlock(&ulockmgr_lock); + pthread_sigmask(SIG_SETMASK, &old, NULL); + if (!err && cmd == F_GETLK) { + if (msg.lock.l_type == F_UNLCK) + lock->l_type = F_UNLCK; + else + *lock = msg.lock; + } + + return err; } diff --git a/test/stracedecode.c b/test/stracedecode.c index 7908f43..27b883c 100644 --- a/test/stracedecode.c +++ b/test/stracedecode.c @@ -3,195 +3,195 @@ #include "fuse_kernel.h" static struct { - const char *name; + const char *name; } fuse_ll_ops[] = { - [FUSE_LOOKUP] = { "LOOKUP" }, - [FUSE_FORGET] = { "FORGET" }, - [FUSE_GETATTR] = { "GETATTR" }, - [FUSE_SETATTR] = { "SETATTR" }, - [FUSE_READLINK] = { "READLINK" }, - [FUSE_SYMLINK] = { "SYMLINK" }, - [FUSE_MKNOD] = { "MKNOD" }, - [FUSE_MKDIR] = { "MKDIR" }, - [FUSE_UNLINK] = { "UNLINK" }, - [FUSE_RMDIR] = { "RMDIR" }, - [FUSE_RENAME] = { "RENAME" }, - [FUSE_LINK] = { "LINK" }, - [FUSE_OPEN] = { "OPEN" }, - [FUSE_READ] = { "READ" }, - [FUSE_WRITE] = { "WRITE" }, - [FUSE_STATFS] = { "STATFS" }, - [FUSE_RELEASE] = { "RELEASE" }, - [FUSE_FSYNC] = { "FSYNC" }, - [FUSE_SETXATTR] = { "SETXATTR" }, - [FUSE_GETXATTR] = { "GETXATTR" }, - [FUSE_LISTXATTR] = { "LISTXATTR" }, - [FUSE_REMOVEXATTR] = { "REMOVEXATTR" }, - [FUSE_FLUSH] = { "FLUSH" }, - [FUSE_INIT] = { "INIT" }, - [FUSE_OPENDIR] = { "OPENDIR" }, - [FUSE_READDIR] = { "READDIR" }, - [FUSE_RELEASEDIR] = { "RELEASEDIR" }, - [FUSE_FSYNCDIR] = { "FSYNCDIR" }, - [FUSE_GETLK] = { "GETLK" }, - [FUSE_SETLK] = { "SETLK" }, - [FUSE_SETLKW] = { "SETLKW" }, - [FUSE_ACCESS] = { "ACCESS" }, - [FUSE_CREATE] = { "CREATE" }, - [FUSE_INTERRUPT] = { "INTERRUPT" }, - [FUSE_BMAP] = { "BMAP" }, - [FUSE_DESTROY] = { "DESTROY" }, + [FUSE_LOOKUP] = { "LOOKUP" }, + [FUSE_FORGET] = { "FORGET" }, + [FUSE_GETATTR] = { "GETATTR" }, + [FUSE_SETATTR] = { "SETATTR" }, + [FUSE_READLINK] = { "READLINK" }, + [FUSE_SYMLINK] = { "SYMLINK" }, + [FUSE_MKNOD] = { "MKNOD" }, + [FUSE_MKDIR] = { "MKDIR" }, + [FUSE_UNLINK] = { "UNLINK" }, + [FUSE_RMDIR] = { "RMDIR" }, + [FUSE_RENAME] = { "RENAME" }, + [FUSE_LINK] = { "LINK" }, + [FUSE_OPEN] = { "OPEN" }, + [FUSE_READ] = { "READ" }, + [FUSE_WRITE] = { "WRITE" }, + [FUSE_STATFS] = { "STATFS" }, + [FUSE_RELEASE] = { "RELEASE" }, + [FUSE_FSYNC] = { "FSYNC" }, + [FUSE_SETXATTR] = { "SETXATTR" }, + [FUSE_GETXATTR] = { "GETXATTR" }, + [FUSE_LISTXATTR] = { "LISTXATTR" }, + [FUSE_REMOVEXATTR] = { "REMOVEXATTR" }, + [FUSE_FLUSH] = { "FLUSH" }, + [FUSE_INIT] = { "INIT" }, + [FUSE_OPENDIR] = { "OPENDIR" }, + [FUSE_READDIR] = { "READDIR" }, + [FUSE_RELEASEDIR] = { "RELEASEDIR" }, + [FUSE_FSYNCDIR] = { "FSYNCDIR" }, + [FUSE_GETLK] = { "GETLK" }, + [FUSE_SETLK] = { "SETLK" }, + [FUSE_SETLKW] = { "SETLKW" }, + [FUSE_ACCESS] = { "ACCESS" }, + [FUSE_CREATE] = { "CREATE" }, + [FUSE_INTERRUPT] = { "INTERRUPT" }, + [FUSE_BMAP] = { "BMAP" }, + [FUSE_DESTROY] = { "DESTROY" }, }; #define FUSE_MAXOP (sizeof(fuse_ll_ops) / sizeof(fuse_ll_ops[0])) static const char *opname(enum fuse_opcode opcode) { - if (opcode >= FUSE_MAXOP || !fuse_ll_ops[opcode].name) - return "???"; - else - return fuse_ll_ops[opcode].name; + if (opcode >= FUSE_MAXOP || !fuse_ll_ops[opcode].name) + return "???"; + else + return fuse_ll_ops[opcode].name; } static void process_buf(int dir, char *buf, int len) { - static unsigned long long prevuniq = -1; - static int prevopcode; - - if (!dir) { - struct fuse_in_header *in = (struct fuse_in_header *) buf; - buf += sizeof(struct fuse_in_header); - - printf("unique: %llu, opcode: %s (%i), nodeid: %lu, len: %i, insize: %i\n", - (unsigned long long) in->unique, - opname((enum fuse_opcode) in->opcode), in->opcode, - (unsigned long) in->nodeid, in->len, len); - - switch (in->opcode) { - case FUSE_READ: { - struct fuse_read_in *arg = (struct fuse_read_in *) buf; - printf("-READ fh:%llu off:%llu siz:%u rfl:%u own:%llu fl:%u\n", - arg->fh, arg->offset, arg->size, arg->read_flags, - arg->lock_owner, arg->flags); - break; - } - case FUSE_WRITE: { - struct fuse_write_in *arg = (struct fuse_write_in *) buf; - printf("-WRITE fh:%llu off:%llu siz:%u wfl:%u own:%llu fl:%u\n", - arg->fh, arg->offset, arg->size, arg->write_flags, - arg->lock_owner, arg->flags); - break; - } - } - prevuniq = in->unique; - prevopcode = in->opcode; - } else { - struct fuse_out_header *out = (struct fuse_out_header *) buf; - buf += sizeof(struct fuse_out_header); - - printf(" unique: %llu, error: %i (%s), len: %i, outsize: %i\n", - (unsigned long long) out->unique, out->error, - strerror(-out->error), out->len, len); - - if (out->unique == prevuniq) { - switch (prevopcode) { - case FUSE_GETATTR: { - struct fuse_attr_out *arg = (struct fuse_attr_out *) buf; - printf("+ATTR v:%llu.%09u i:%llu s:%llu b:%llu\n", - arg->attr_valid, arg->attr_valid_nsec, - arg->attr.ino, arg->attr.size, arg->attr.blocks); - break; - } - case FUSE_LOOKUP: { - struct fuse_entry_out *arg = (struct fuse_entry_out *) buf; - printf("+ENTRY nodeid:%llu v:%llu.%09u i:%llu s:%llu b:%llu\n", - arg->nodeid, arg->attr_valid, arg->attr_valid_nsec, - arg->attr.ino, arg->attr.size, arg->attr.blocks); - break; - } - } - } - } + static unsigned long long prevuniq = -1; + static int prevopcode; + + if (!dir) { + struct fuse_in_header *in = (struct fuse_in_header *) buf; + buf += sizeof(struct fuse_in_header); + + printf("unique: %llu, opcode: %s (%i), nodeid: %lu, len: %i, insize: %i\n", + (unsigned long long) in->unique, + opname((enum fuse_opcode) in->opcode), in->opcode, + (unsigned long) in->nodeid, in->len, len); + + switch (in->opcode) { + case FUSE_READ: { + struct fuse_read_in *arg = (struct fuse_read_in *) buf; + printf("-READ fh:%llu off:%llu siz:%u rfl:%u own:%llu fl:%u\n", + arg->fh, arg->offset, arg->size, arg->read_flags, + arg->lock_owner, arg->flags); + break; + } + case FUSE_WRITE: { + struct fuse_write_in *arg = (struct fuse_write_in *) buf; + printf("-WRITE fh:%llu off:%llu siz:%u wfl:%u own:%llu fl:%u\n", + arg->fh, arg->offset, arg->size, arg->write_flags, + arg->lock_owner, arg->flags); + break; + } + } + prevuniq = in->unique; + prevopcode = in->opcode; + } else { + struct fuse_out_header *out = (struct fuse_out_header *) buf; + buf += sizeof(struct fuse_out_header); + + printf(" unique: %llu, error: %i (%s), len: %i, outsize: %i\n", + (unsigned long long) out->unique, out->error, + strerror(-out->error), out->len, len); + + if (out->unique == prevuniq) { + switch (prevopcode) { + case FUSE_GETATTR: { + struct fuse_attr_out *arg = (struct fuse_attr_out *) buf; + printf("+ATTR v:%llu.%09u i:%llu s:%llu b:%llu\n", + arg->attr_valid, arg->attr_valid_nsec, + arg->attr.ino, arg->attr.size, arg->attr.blocks); + break; + } + case FUSE_LOOKUP: { + struct fuse_entry_out *arg = (struct fuse_entry_out *) buf; + printf("+ENTRY nodeid:%llu v:%llu.%09u i:%llu s:%llu b:%llu\n", + arg->nodeid, arg->attr_valid, arg->attr_valid_nsec, + arg->attr.ino, arg->attr.size, arg->attr.blocks); + break; + } + } + } + } } int main(void) { - FILE *in = stdin; - while (1) { - int dir; - int res; - char buf[1048576]; - unsigned len = 0; - - memset(buf, 0, sizeof(buf)); - while (1) { - char str[32]; - - res = fscanf(in, "%30s", str); - if (res != 1 && feof(in)) - return 0; - - if (res == 0) - continue; - - if (strncmp(str, "read(", 5) == 0) { - dir = 0; - break; - } else if (strncmp(str, "writev(", 7) == 0) { - dir = 1; - break; - } - } - - while (1) { - int c = getc(in); - if (c == '"') { - while (1) { - int val; - - c = getc(in); - if (c == EOF) { - fprintf(stderr, "eof in string\n"); - break; - } - if (c == '\n') { - fprintf(stderr, "eol in string\n"); - break; - } - if (c == '"') - break; - if (c != '\\') { - val = c; - } else { - c = getc(in); - switch (c) { - case 'n': val = '\n'; break; - case 'r': val = '\r'; break; - case 't': val = '\t'; break; - case '"': val = '"'; break; - case '\\': val = '\\'; break; - case 'x': - res = scanf("%x", &val); - if (res != 1) { - fprintf(stderr, "parse error\n"); - continue; - } - break; - default: - fprintf(stderr, "unknown sequence: '\\%c'\n", c); - continue; - } - } - buf[len++] = val; - } - } - if (c == '\n') - break; - } - process_buf(dir, buf, len); - memset(buf, 0, len); - len = 0; - } + FILE *in = stdin; + while (1) { + int dir; + int res; + char buf[1048576]; + unsigned len = 0; + + memset(buf, 0, sizeof(buf)); + while (1) { + char str[32]; + + res = fscanf(in, "%30s", str); + if (res != 1 && feof(in)) + return 0; + + if (res == 0) + continue; + + if (strncmp(str, "read(", 5) == 0) { + dir = 0; + break; + } else if (strncmp(str, "writev(", 7) == 0) { + dir = 1; + break; + } + } + + while (1) { + int c = getc(in); + if (c == '"') { + while (1) { + int val; + + c = getc(in); + if (c == EOF) { + fprintf(stderr, "eof in string\n"); + break; + } + if (c == '\n') { + fprintf(stderr, "eol in string\n"); + break; + } + if (c == '"') + break; + if (c != '\\') { + val = c; + } else { + c = getc(in); + switch (c) { + case 'n': val = '\n'; break; + case 'r': val = '\r'; break; + case 't': val = '\t'; break; + case '"': val = '"'; break; + case '\\': val = '\\'; break; + case 'x': + res = scanf("%x", &val); + if (res != 1) { + fprintf(stderr, "parse error\n"); + continue; + } + break; + default: + fprintf(stderr, "unknown sequence: '\\%c'\n", c); + continue; + } + } + buf[len++] = val; + } + } + if (c == '\n') + break; + } + process_buf(dir, buf, len); + memset(buf, 0, len); + len = 0; + } } diff --git a/test/test.c b/test/test.c index f9aa823..a2ce3cd 100644 --- a/test/test.c +++ b/test/test.c @@ -27,37 +27,37 @@ static int testdata2len = sizeof(testdata2) - 1; static void test_perror(const char *func, const char *msg) { - fprintf(stderr, "[%s] %s() - %s: %s\n", testname, func, msg, - strerror(errno)); + fprintf(stderr, "[%s] %s() - %s: %s\n", testname, func, msg, + strerror(errno)); } static void test_error(const char *func, const char *msg, ...) - __attribute__ ((format (printf, 2, 3))); + __attribute__ ((format (printf, 2, 3))); static void start_test(const char *fmt, ...) - __attribute__ ((format (printf, 1, 2))); + __attribute__ ((format (printf, 1, 2))); static void test_error(const char *func, const char *msg, ...) { - va_list ap; - fprintf(stderr, "[%s] %s() - ", testname, func); - va_start(ap, msg); - vfprintf(stderr, msg, ap); - va_end(ap); - fprintf(stderr, "\n"); + va_list ap; + fprintf(stderr, "[%s] %s() - ", testname, func); + va_start(ap, msg); + vfprintf(stderr, msg, ap); + va_end(ap); + fprintf(stderr, "\n"); } static void success(void) { - fprintf(stderr, "[%s] OK\n", testname); + fprintf(stderr, "[%s] OK\n", testname); } static void start_test(const char *fmt, ...) { - va_list ap; - va_start(ap, fmt); - vsprintf(testname, fmt, ap); - va_end(ap); + va_list ap; + va_start(ap, fmt); + vsprintf(testname, fmt, ap); + va_end(ap); } #define PERROR(msg) test_perror(__FUNCTION__, msg) @@ -65,1271 +65,1287 @@ static void start_test(const char *fmt, ...) static int check_size(const char *path, int len) { - struct stat stbuf; - int res = stat(path, &stbuf); - if (res == -1) { - PERROR("stat"); - return -1; - } - if (stbuf.st_size != len) { - ERROR("length %u instead of %u", (int) stbuf.st_size, (int) len); - return -1; - } - return 0; + struct stat stbuf; + int res = stat(path, &stbuf); + if (res == -1) { + PERROR("stat"); + return -1; + } + if (stbuf.st_size != len) { + ERROR("length %u instead of %u", (int) stbuf.st_size, + (int) len); + return -1; + } + return 0; } static int fcheck_size(int fd, int len) { - struct stat stbuf; - int res = fstat(fd, &stbuf); - if (res == -1) { - PERROR("fstat"); - return -1; - } - if (stbuf.st_size != len) { - ERROR("length %u instead of %u", (int) stbuf.st_size, (int) len); - return -1; - } - return 0; + struct stat stbuf; + int res = fstat(fd, &stbuf); + if (res == -1) { + PERROR("fstat"); + return -1; + } + if (stbuf.st_size != len) { + ERROR("length %u instead of %u", (int) stbuf.st_size, + (int) len); + return -1; + } + return 0; } static int check_type(const char *path, mode_t type) { - struct stat stbuf; - int res = lstat(path, &stbuf); - if (res == -1) { - PERROR("lstat"); - return -1; - } - if ((stbuf.st_mode & S_IFMT) != type) { - ERROR("type 0%o instead of 0%o", stbuf.st_mode & S_IFMT, type); - return -1; - } - return 0; + struct stat stbuf; + int res = lstat(path, &stbuf); + if (res == -1) { + PERROR("lstat"); + return -1; + } + if ((stbuf.st_mode & S_IFMT) != type) { + ERROR("type 0%o instead of 0%o", stbuf.st_mode & S_IFMT, type); + return -1; + } + return 0; } static int fcheck_type(int fd, mode_t type) { - struct stat stbuf; - int res = fstat(fd, &stbuf); - if (res == -1) { - PERROR("fstat"); - return -1; - } - if ((stbuf.st_mode & S_IFMT) != type) { - ERROR("type 0%o instead of 0%o", stbuf.st_mode & S_IFMT, type); - return -1; - } - return 0; + struct stat stbuf; + int res = fstat(fd, &stbuf); + if (res == -1) { + PERROR("fstat"); + return -1; + } + if ((stbuf.st_mode & S_IFMT) != type) { + ERROR("type 0%o instead of 0%o", stbuf.st_mode & S_IFMT, type); + return -1; + } + return 0; } static int check_mode(const char *path, mode_t mode) { - struct stat stbuf; - int res = lstat(path, &stbuf); - if (res == -1) { - PERROR("lstat"); - return -1; - } - if ((stbuf.st_mode & 07777) != mode) { - ERROR("mode 0%o instead of 0%o", stbuf.st_mode & 07777, mode); - return -1; - } - return 0; + struct stat stbuf; + int res = lstat(path, &stbuf); + if (res == -1) { + PERROR("lstat"); + return -1; + } + if ((stbuf.st_mode & 07777) != mode) { + ERROR("mode 0%o instead of 0%o", stbuf.st_mode & 07777, mode); + return -1; + } + return 0; } static int fcheck_mode(int fd, mode_t mode) { - struct stat stbuf; - int res = fstat(fd, &stbuf); - if (res == -1) { - PERROR("fstat"); - return -1; - } - if ((stbuf.st_mode & 07777) != mode) { - ERROR("mode 0%o instead of 0%o", stbuf.st_mode & 07777, mode); - return -1; - } - return 0; + struct stat stbuf; + int res = fstat(fd, &stbuf); + if (res == -1) { + PERROR("fstat"); + return -1; + } + if ((stbuf.st_mode & 07777) != mode) { + ERROR("mode 0%o instead of 0%o", stbuf.st_mode & 07777, mode); + return -1; + } + return 0; } static int check_times(const char *path, time_t atime, time_t mtime) { - int err = 0; - struct stat stbuf; - int res = lstat(path, &stbuf); - if (res == -1) { - PERROR("lstat"); - return -1; - } - if (stbuf.st_atime != atime) { - ERROR("atime %li instead of %li", stbuf.st_atime, atime); - err--; - } - if (stbuf.st_mtime != mtime) { - ERROR("mtime %li instead of %li", stbuf.st_mtime, mtime); - err--; - } - if (err) - return -1; - - return 0; + int err = 0; + struct stat stbuf; + int res = lstat(path, &stbuf); + if (res == -1) { + PERROR("lstat"); + return -1; + } + if (stbuf.st_atime != atime) { + ERROR("atime %li instead of %li", stbuf.st_atime, atime); + err--; + } + if (stbuf.st_mtime != mtime) { + ERROR("mtime %li instead of %li", stbuf.st_mtime, mtime); + err--; + } + if (err) + return -1; + + return 0; } static int fcheck_times(int fd, time_t atime, time_t mtime) { - int err = 0; - struct stat stbuf; - int res = fstat(fd, &stbuf); - if (res == -1) { - PERROR("fstat"); - return -1; - } - if (stbuf.st_atime != atime) { - ERROR("atime %li instead of %li", stbuf.st_atime, atime); - err--; - } - if (stbuf.st_mtime != mtime) { - ERROR("mtime %li instead of %li", stbuf.st_mtime, mtime); - err--; - } - if (err) - return -1; - - return 0; + int err = 0; + struct stat stbuf; + int res = fstat(fd, &stbuf); + if (res == -1) { + PERROR("fstat"); + return -1; + } + if (stbuf.st_atime != atime) { + ERROR("atime %li instead of %li", stbuf.st_atime, atime); + err--; + } + if (stbuf.st_mtime != mtime) { + ERROR("mtime %li instead of %li", stbuf.st_mtime, mtime); + err--; + } + if (err) + return -1; + + return 0; } static int check_nlink(const char *path, nlink_t nlink) { - struct stat stbuf; - int res = lstat(path, &stbuf); - if (res == -1) { - PERROR("lstat"); - return -1; - } - if (stbuf.st_nlink != nlink) { - ERROR("nlink %li instead of %li", (long) stbuf.st_nlink, (long) nlink); - return -1; - } - return 0; + struct stat stbuf; + int res = lstat(path, &stbuf); + if (res == -1) { + PERROR("lstat"); + return -1; + } + if (stbuf.st_nlink != nlink) { + ERROR("nlink %li instead of %li", (long) stbuf.st_nlink, + (long) nlink); + return -1; + } + return 0; } static int fcheck_nlink(int fd, nlink_t nlink) { - struct stat stbuf; - int res = fstat(fd, &stbuf); - if (res == -1) { - PERROR("fstat"); - return -1; - } - if (stbuf.st_nlink != nlink) { - ERROR("nlink %li instead of %li", (long) stbuf.st_nlink, (long) nlink); - return -1; - } - return 0; + struct stat stbuf; + int res = fstat(fd, &stbuf); + if (res == -1) { + PERROR("fstat"); + return -1; + } + if (stbuf.st_nlink != nlink) { + ERROR("nlink %li instead of %li", (long) stbuf.st_nlink, + (long) nlink); + return -1; + } + return 0; } static int check_nonexist(const char *path) { - struct stat stbuf; - int res = lstat(path, &stbuf); - if (res == 0) { - ERROR("file should not exist"); - return -1; - } - if (errno != ENOENT) { - ERROR("file should not exist: %s", strerror(errno)); - return -1; - } - return 0; + struct stat stbuf; + int res = lstat(path, &stbuf); + if (res == 0) { + ERROR("file should not exist"); + return -1; + } + if (errno != ENOENT) { + ERROR("file should not exist: %s", strerror(errno)); + return -1; + } + return 0; } static int check_buffer(const char *buf, const char *data, unsigned len) { - if (memcmp(buf, data, len) != 0) { - ERROR("data mismatch"); - return -1; - } - return 0; + if (memcmp(buf, data, len) != 0) { + ERROR("data mismatch"); + return -1; + } + return 0; } static int check_data(const char *path, const char *data, int offset, - unsigned len) + unsigned len) { - char buf[4096]; - int res; - int fd = open(path, O_RDONLY); - if (fd == -1) { - PERROR("open"); - return -1; - } - if (lseek(fd, offset, SEEK_SET) == (off_t) -1) { - PERROR("lseek"); - close(fd); - return -1; - } - while (len) { - int rdlen = len < sizeof(buf) ? len : sizeof(buf); - res = read(fd, buf, rdlen); - if (res == -1) { - PERROR("read"); - close(fd); - return -1; - } - if (res != rdlen) { - ERROR("short read: %u instead of %u", res, rdlen); - close(fd); - return -1; - } - if (check_buffer(buf, data, rdlen) != 0) { - close(fd); - return -1; - } - data += rdlen; - len -= rdlen; - } - res = close(fd); - if (res == -1) { - PERROR("close"); - return -1; - } - return 0; + char buf[4096]; + int res; + int fd = open(path, O_RDONLY); + if (fd == -1) { + PERROR("open"); + return -1; + } + if (lseek(fd, offset, SEEK_SET) == (off_t) -1) { + PERROR("lseek"); + close(fd); + return -1; + } + while (len) { + int rdlen = len < sizeof(buf) ? len : sizeof(buf); + res = read(fd, buf, rdlen); + if (res == -1) { + PERROR("read"); + close(fd); + return -1; + } + if (res != rdlen) { + ERROR("short read: %u instead of %u", res, rdlen); + close(fd); + return -1; + } + if (check_buffer(buf, data, rdlen) != 0) { + close(fd); + return -1; + } + data += rdlen; + len -= rdlen; + } + res = close(fd); + if (res == -1) { + PERROR("close"); + return -1; + } + return 0; } static int fcheck_data(int fd, const char *data, int offset, - unsigned len) + unsigned len) { - char buf[4096]; - int res; - if (lseek(fd, offset, SEEK_SET) == (off_t) -1) { - PERROR("lseek"); - return -1; - } - while (len) { - int rdlen = len < sizeof(buf) ? len : sizeof(buf); - res = read(fd, buf, rdlen); - if (res == -1) { - PERROR("read"); - return -1; - } - if (res != rdlen) { - ERROR("short read: %u instead of %u", res, rdlen); - return -1; - } - if (check_buffer(buf, data, rdlen) != 0) { - return -1; - } - data += rdlen; - len -= rdlen; - } - return 0; + char buf[4096]; + int res; + if (lseek(fd, offset, SEEK_SET) == (off_t) -1) { + PERROR("lseek"); + return -1; + } + while (len) { + int rdlen = len < sizeof(buf) ? len : sizeof(buf); + res = read(fd, buf, rdlen); + if (res == -1) { + PERROR("read"); + return -1; + } + if (res != rdlen) { + ERROR("short read: %u instead of %u", res, rdlen); + return -1; + } + if (check_buffer(buf, data, rdlen) != 0) { + return -1; + } + data += rdlen; + len -= rdlen; + } + return 0; } static int check_dir_contents(const char *path, const char **contents) { - int i; - int res; - int err = 0; - int found[MAX_ENTRIES]; - const char *cont[MAX_ENTRIES]; - DIR *dp; - - for (i = 0; contents[i]; i++) { - assert(i < MAX_ENTRIES - 3); - found[i] = 0; - cont[i] = contents[i]; - } - found[i] = 0; - cont[i++] = "."; - found[i] = 0; - cont[i++] = ".."; - cont[i] = NULL; - - dp = opendir(path); - if (dp == NULL) { - PERROR("opendir"); - return -1; - } - memset(found, 0, sizeof(found)); - while(1) { - struct dirent *de; - errno = 0; - de = readdir(dp); - if (de == NULL) { - if (errno) { - PERROR("readdir"); - closedir(dp); - return -1; - } - break; - } - for (i = 0; cont[i] != NULL; i++) { - assert(i < MAX_ENTRIES); - if (strcmp(cont[i], de->d_name) == 0) { - if (found[i]) { - ERROR("duplicate entry <%s>", de->d_name); - err--; - } else - found[i] = 1; - break; - } - } - if (!cont[i]) { - ERROR("unexpected entry <%s>", de->d_name); - err --; - } - } - for (i = 0; cont[i] != NULL; i++) { - if (!found[i]) { - ERROR("missing entry <%s>", cont[i]); - err--; - } - } - res = closedir(dp); - if (res == -1) { - PERROR("closedir"); - return -1; - } - if (err) - return -1; - - return 0; + int i; + int res; + int err = 0; + int found[MAX_ENTRIES]; + const char *cont[MAX_ENTRIES]; + DIR *dp; + + for (i = 0; contents[i]; i++) { + assert(i < MAX_ENTRIES - 3); + found[i] = 0; + cont[i] = contents[i]; + } + found[i] = 0; + cont[i++] = "."; + found[i] = 0; + cont[i++] = ".."; + cont[i] = NULL; + + dp = opendir(path); + if (dp == NULL) { + PERROR("opendir"); + return -1; + } + memset(found, 0, sizeof(found)); + while(1) { + struct dirent *de; + errno = 0; + de = readdir(dp); + if (de == NULL) { + if (errno) { + PERROR("readdir"); + closedir(dp); + return -1; + } + break; + } + for (i = 0; cont[i] != NULL; i++) { + assert(i < MAX_ENTRIES); + if (strcmp(cont[i], de->d_name) == 0) { + if (found[i]) { + ERROR("duplicate entry <%s>", + de->d_name); + err--; + } else + found[i] = 1; + break; + } + } + if (!cont[i]) { + ERROR("unexpected entry <%s>", de->d_name); + err --; + } + } + for (i = 0; cont[i] != NULL; i++) { + if (!found[i]) { + ERROR("missing entry <%s>", cont[i]); + err--; + } + } + res = closedir(dp); + if (res == -1) { + PERROR("closedir"); + return -1; + } + if (err) + return -1; + + return 0; } static int create_file(const char *path, const char *data, int len) { - int res; - int fd; - - unlink(path); - fd = creat(path, 0644); - if (fd == -1) { - PERROR("creat"); - return -1; - } - if (len) { - res = write(fd, data, len); - if (res == -1) { - PERROR("write"); - close(fd); - return -1; - } - if (res != len) { - ERROR("write is short: %u instead of %u", res, len); - close(fd); - return -1; - } - } - res = close(fd); - if (res == -1) { - PERROR("close"); - return -1; - } - res = check_type(path, S_IFREG); - if (res == -1) - return -1; - res = check_mode(path, 0644); - if (res == -1) - return -1; - res = check_nlink(path, 1); - if (res == -1) - return -1; - res = check_size(path, len); - if (res == -1) - return -1; - - if (len) { - res = check_data(path, data, 0, len); - if (res == -1) - return -1; - } - - return 0; + int res; + int fd; + + unlink(path); + fd = creat(path, 0644); + if (fd == -1) { + PERROR("creat"); + return -1; + } + if (len) { + res = write(fd, data, len); + if (res == -1) { + PERROR("write"); + close(fd); + return -1; + } + if (res != len) { + ERROR("write is short: %u instead of %u", res, len); + close(fd); + return -1; + } + } + res = close(fd); + if (res == -1) { + PERROR("close"); + return -1; + } + res = check_type(path, S_IFREG); + if (res == -1) + return -1; + res = check_mode(path, 0644); + if (res == -1) + return -1; + res = check_nlink(path, 1); + if (res == -1) + return -1; + res = check_size(path, len); + if (res == -1) + return -1; + + if (len) { + res = check_data(path, data, 0, len); + if (res == -1) + return -1; + } + + return 0; } static int cleanup_dir(const char *path, const char **dir_files, int quiet) { - int i; - int err = 0; - - for (i = 0; dir_files[i]; i++) { - int res; - char fpath[1024]; - sprintf(fpath, "%s/%s", path, dir_files[i]); - res = unlink(fpath); - if (res == -1 && !quiet) { - PERROR("unlink"); - err --; - } - } - if (err) - return -1; - - return 0; + int i; + int err = 0; + + for (i = 0; dir_files[i]; i++) { + int res; + char fpath[1024]; + sprintf(fpath, "%s/%s", path, dir_files[i]); + res = unlink(fpath); + if (res == -1 && !quiet) { + PERROR("unlink"); + err --; + } + } + if (err) + return -1; + + return 0; } static int create_dir(const char *path, const char **dir_files) { - int res; - int i; - - rmdir(path); - res = mkdir(path, 0755); - if (res == -1) { - PERROR("mkdir"); - return -1; - } - res = check_type(path, S_IFDIR); - if (res == -1) - return -1; - res = check_mode(path, 0755); - if (res == -1) - return -1; - - for (i = 0; dir_files[i]; i++) { - char fpath[1024]; - sprintf(fpath, "%s/%s", path, dir_files[i]); - res = create_file(fpath, "", 0); - if (res == -1) { - cleanup_dir(path, dir_files, 1); - return -1; - } - } - res = check_dir_contents(path, dir_files); - if (res == -1) { - cleanup_dir(path, dir_files, 1); - return -1; - } - - return 0; + int res; + int i; + + rmdir(path); + res = mkdir(path, 0755); + if (res == -1) { + PERROR("mkdir"); + return -1; + } + res = check_type(path, S_IFDIR); + if (res == -1) + return -1; + res = check_mode(path, 0755); + if (res == -1) + return -1; + + for (i = 0; dir_files[i]; i++) { + char fpath[1024]; + sprintf(fpath, "%s/%s", path, dir_files[i]); + res = create_file(fpath, "", 0); + if (res == -1) { + cleanup_dir(path, dir_files, 1); + return -1; + } + } + res = check_dir_contents(path, dir_files); + if (res == -1) { + cleanup_dir(path, dir_files, 1); + return -1; + } + + return 0; } static int test_truncate(int len) { - const char *data = testdata; - int datalen = testdatalen; - int res; - - start_test("truncate(%u)", (int) len); - res = create_file(testfile, data, datalen); - if (res == -1) - return -1; - - res = truncate(testfile, len); - if (res == -1) { - PERROR("truncate"); - return -1; - } - res = check_size(testfile, len); - if (res == -1) - return -1; - - if (len > 0) { - if (len <= datalen) { - res = check_data(testfile, data, 0, len); - if (res == -1) - return -1; - } else { - res = check_data(testfile, data, 0, datalen); - if (res == -1) - return -1; - res = check_data(testfile, zerodata, datalen, len - datalen); - if (res == -1) - return -1; - } - } - res = unlink(testfile); - if (res == -1) { - PERROR("unlink"); - return -1; - } - res = check_nonexist(testfile); - if (res == -1) - return -1; - - success(); - return 0; + const char *data = testdata; + int datalen = testdatalen; + int res; + + start_test("truncate(%u)", (int) len); + res = create_file(testfile, data, datalen); + if (res == -1) + return -1; + + res = truncate(testfile, len); + if (res == -1) { + PERROR("truncate"); + return -1; + } + res = check_size(testfile, len); + if (res == -1) + return -1; + + if (len > 0) { + if (len <= datalen) { + res = check_data(testfile, data, 0, len); + if (res == -1) + return -1; + } else { + res = check_data(testfile, data, 0, datalen); + if (res == -1) + return -1; + res = check_data(testfile, zerodata, datalen, + len - datalen); + if (res == -1) + return -1; + } + } + res = unlink(testfile); + if (res == -1) { + PERROR("unlink"); + return -1; + } + res = check_nonexist(testfile); + if (res == -1) + return -1; + + success(); + return 0; } static int test_ftruncate(int len, int mode) { - const char *data = testdata; - int datalen = testdatalen; - int res; - int fd; - - start_test("ftruncate(%u) mode: 0%03o", len, mode); - res = create_file(testfile, data, datalen); - if (res == -1) - return -1; - - fd = open(testfile, O_WRONLY); - if (fd == -1) { - PERROR("open"); - return -1; - } - - res = fchmod(fd, mode); - if (res == -1) { - PERROR("fchmod"); - close(fd); - return -1; - } - res = check_mode(testfile, mode); - if (res == -1) { - close(fd); - return -1; - } - res = ftruncate(fd, len); - if (res == -1) { - PERROR("ftruncate"); - close(fd); - return -1; - } - close(fd); - res = check_size(testfile, len); - if (res == -1) - return -1; - - if (len > 0) { - if (len <= datalen) { - res = check_data(testfile, data, 0, len); - if (res == -1) - return -1; - } else { - res = check_data(testfile, data, 0, datalen); - if (res == -1) - return -1; - res = check_data(testfile, zerodata, datalen, len - datalen); - if (res == -1) - return -1; - } - } - res = unlink(testfile); - if (res == -1) { - PERROR("unlink"); - return -1; - } - res = check_nonexist(testfile); - if (res == -1) - return -1; - - success(); - return 0; + const char *data = testdata; + int datalen = testdatalen; + int res; + int fd; + + start_test("ftruncate(%u) mode: 0%03o", len, mode); + res = create_file(testfile, data, datalen); + if (res == -1) + return -1; + + fd = open(testfile, O_WRONLY); + if (fd == -1) { + PERROR("open"); + return -1; + } + + res = fchmod(fd, mode); + if (res == -1) { + PERROR("fchmod"); + close(fd); + return -1; + } + res = check_mode(testfile, mode); + if (res == -1) { + close(fd); + return -1; + } + res = ftruncate(fd, len); + if (res == -1) { + PERROR("ftruncate"); + close(fd); + return -1; + } + close(fd); + res = check_size(testfile, len); + if (res == -1) + return -1; + + if (len > 0) { + if (len <= datalen) { + res = check_data(testfile, data, 0, len); + if (res == -1) + return -1; + } else { + res = check_data(testfile, data, 0, datalen); + if (res == -1) + return -1; + res = check_data(testfile, zerodata, datalen, + len - datalen); + if (res == -1) + return -1; + } + } + res = unlink(testfile); + if (res == -1) { + PERROR("unlink"); + return -1; + } + res = check_nonexist(testfile); + if (res == -1) + return -1; + + success(); + return 0; } static int test_utime(void) { - struct utimbuf utm; - time_t atime = 987631200; - time_t mtime = 123116400; - int res; - - start_test("utime"); - res = create_file(testfile, NULL, 0); - if (res == -1) - return -1; - - utm.actime = atime; - utm.modtime = mtime; - res = utime(testfile, &utm); - if (res == -1) { - PERROR("utime"); - return -1; - } - res = check_times(testfile, atime, mtime); - if (res == -1) { - return -1; - } - res = unlink(testfile); - if (res == -1) { - PERROR("unlink"); - return -1; - } - res = check_nonexist(testfile); - if (res == -1) - return -1; - - success(); - return 0; + struct utimbuf utm; + time_t atime = 987631200; + time_t mtime = 123116400; + int res; + + start_test("utime"); + res = create_file(testfile, NULL, 0); + if (res == -1) + return -1; + + utm.actime = atime; + utm.modtime = mtime; + res = utime(testfile, &utm); + if (res == -1) { + PERROR("utime"); + return -1; + } + res = check_times(testfile, atime, mtime); + if (res == -1) { + return -1; + } + res = unlink(testfile); + if (res == -1) { + PERROR("unlink"); + return -1; + } + res = check_nonexist(testfile); + if (res == -1) + return -1; + + success(); + return 0; } static int test_create(void) { - const char *data = testdata; - int datalen = testdatalen; - int err = 0; - int res; - int fd; - - start_test("create"); - unlink(testfile); - fd = creat(testfile, 0644); - if (fd == -1) { - PERROR("creat"); - return -1; - } - res = write(fd, data, datalen); - if (res == -1) { - PERROR("write"); - close(fd); - return -1; - } - if (res != datalen) { - ERROR("write is short: %u instead of %u", res, datalen); - close(fd); - return -1; - } - res = close(fd); - if (res == -1) { - PERROR("close"); - return -1; - } - res = check_type(testfile, S_IFREG); - if (res == -1) - return -1; - err += check_mode(testfile, 0644); - err += check_nlink(testfile, 1); - err += check_size(testfile, datalen); - err += check_data(testfile, data, 0, datalen); - res = unlink(testfile); - if (res == -1) { - PERROR("unlink"); - return -1; - } - res = check_nonexist(testfile); - if (res == -1) - return -1; - if (err) - return -1; - - success(); - return 0; + const char *data = testdata; + int datalen = testdatalen; + int err = 0; + int res; + int fd; + + start_test("create"); + unlink(testfile); + fd = creat(testfile, 0644); + if (fd == -1) { + PERROR("creat"); + return -1; + } + res = write(fd, data, datalen); + if (res == -1) { + PERROR("write"); + close(fd); + return -1; + } + if (res != datalen) { + ERROR("write is short: %u instead of %u", res, datalen); + close(fd); + return -1; + } + res = close(fd); + if (res == -1) { + PERROR("close"); + return -1; + } + res = check_type(testfile, S_IFREG); + if (res == -1) + return -1; + err += check_mode(testfile, 0644); + err += check_nlink(testfile, 1); + err += check_size(testfile, datalen); + err += check_data(testfile, data, 0, datalen); + res = unlink(testfile); + if (res == -1) { + PERROR("unlink"); + return -1; + } + res = check_nonexist(testfile); + if (res == -1) + return -1; + if (err) + return -1; + + success(); + return 0; } static int test_create_unlink(void) { - const char *data = testdata; - int datalen = testdatalen; - int err = 0; - int res; - int fd; - - start_test("create+unlink"); - unlink(testfile); - fd = open(testfile, O_CREAT | O_RDWR | O_TRUNC, 0644); - if (fd == -1) { - PERROR("creat"); - return -1; - } - res = unlink(testfile); - if (res == -1) { - PERROR("unlink"); - close(fd); - return -1; - } - res = check_nonexist(testfile); - if (res == -1) - return -1; - res = write(fd, data, datalen); - if (res == -1) { - PERROR("write"); - close(fd); - return -1; - } - if (res != datalen) { - ERROR("write is short: %u instead of %u", res, datalen); - close(fd); - return -1; - } - err += fcheck_type(fd, S_IFREG); - err += fcheck_mode(fd, 0644); - err += fcheck_nlink(fd, 0); - err += fcheck_size(fd, datalen); - err += fcheck_data(fd, data, 0, datalen); - res = close(fd); - if (res == -1) { - PERROR("close"); - err--; - } - if (err) - return -1; - - success(); - return 0; + const char *data = testdata; + int datalen = testdatalen; + int err = 0; + int res; + int fd; + + start_test("create+unlink"); + unlink(testfile); + fd = open(testfile, O_CREAT | O_RDWR | O_TRUNC, 0644); + if (fd == -1) { + PERROR("creat"); + return -1; + } + res = unlink(testfile); + if (res == -1) { + PERROR("unlink"); + close(fd); + return -1; + } + res = check_nonexist(testfile); + if (res == -1) + return -1; + res = write(fd, data, datalen); + if (res == -1) { + PERROR("write"); + close(fd); + return -1; + } + if (res != datalen) { + ERROR("write is short: %u instead of %u", res, datalen); + close(fd); + return -1; + } + err += fcheck_type(fd, S_IFREG); + err += fcheck_mode(fd, 0644); + err += fcheck_nlink(fd, 0); + err += fcheck_size(fd, datalen); + err += fcheck_data(fd, data, 0, datalen); + res = close(fd); + if (res == -1) { + PERROR("close"); + err--; + } + if (err) + return -1; + + success(); + return 0; } static int test_mknod(void) { - int err = 0; - int res; - - start_test("mknod"); - unlink(testfile); - res = mknod(testfile, 0644, 0); - if (res == -1) { - PERROR("mknod"); - return -1; - } - res = check_type(testfile, S_IFREG); - if (res == -1) - return -1; - err += check_mode(testfile, 0644); - err += check_nlink(testfile, 1); - err += check_size(testfile, 0); - res = unlink(testfile); - if (res == -1) { - PERROR("unlink"); - return -1; - } - res = check_nonexist(testfile); - if (res == -1) - return -1; - if (err) - return -1; - - success(); - return 0; + int err = 0; + int res; + + start_test("mknod"); + unlink(testfile); + res = mknod(testfile, 0644, 0); + if (res == -1) { + PERROR("mknod"); + return -1; + } + res = check_type(testfile, S_IFREG); + if (res == -1) + return -1; + err += check_mode(testfile, 0644); + err += check_nlink(testfile, 1); + err += check_size(testfile, 0); + res = unlink(testfile); + if (res == -1) { + PERROR("unlink"); + return -1; + } + res = check_nonexist(testfile); + if (res == -1) + return -1; + if (err) + return -1; + + success(); + return 0; } #define test_open(exist, flags, mode) do_test_open(exist, flags, #flags, mode) static int do_test_open(int exist, int flags, const char *flags_str, int mode) { - char buf[4096]; - const char *data = testdata; - int datalen = testdatalen; - unsigned currlen = 0; - int err = 0; - int res; - int fd; - off_t off; - - start_test("open(%s, %s, 0%03o)", exist ? "+" : "-", flags_str, mode); - unlink(testfile); - if (exist) { - res = create_file(testfile, testdata2, testdata2len); - if (res == -1) - return -1; - - currlen = testdata2len; - } - - fd = open(testfile, flags, mode); - if ((flags & O_CREAT) && (flags & O_EXCL) && exist) { - if (fd != -1) { - ERROR("open should have failed"); - close(fd); - return -1; - } else if (errno == EEXIST) - goto succ; - } - if (!(flags & O_CREAT) && !exist) { - if (fd != -1) { - ERROR("open should have failed"); - close(fd); - return -1; - } else if (errno == ENOENT) - goto succ; - } - if (fd == -1) { - PERROR("open"); - return -1; - } - - if (flags & O_TRUNC) - currlen = 0; - - err += check_type(testfile, S_IFREG); - if (exist) - err += check_mode(testfile, 0644); - else - err += check_mode(testfile, mode); - err += check_nlink(testfile, 1); - err += check_size(testfile, currlen); - if (exist && !(flags & O_TRUNC) && (mode & 0400)) - err += check_data(testfile, testdata2, 0, testdata2len); - - res = write(fd, data, datalen); - if ((flags & O_ACCMODE) != O_RDONLY) { - if (res == -1) { - PERROR("write"); - err --; - } else if (res != datalen) { - ERROR("write is short: %u instead of %u", res, datalen); - err --; - } else { - if (datalen > (int) currlen) - currlen = datalen; - - err += check_size(testfile, currlen); - - if (mode & 0400) { - err += check_data(testfile, data, 0, datalen); - if (exist && !(flags & O_TRUNC) && testdata2len > datalen) - err += check_data(testfile, testdata2 + datalen, datalen, - testdata2len - datalen); - } - } - } else { - if (res != -1) { - ERROR("write should have failed"); - err --; - } else if (errno != EBADF) { - PERROR("write"); - err --; - } - } - off = lseek(fd, SEEK_SET, 0); - if (off == (off_t) -1) { - PERROR("lseek"); - err--; - } else if (off != 0) { - ERROR("offset should have returned 0"); - err --; - } - res = read(fd, buf, sizeof(buf)); - if ((flags & O_ACCMODE) != O_WRONLY) { - if (res == -1) { - PERROR("read"); - err--; - } else { - int readsize = currlen < sizeof(buf) ? currlen : sizeof(buf); - if (res != readsize) { - ERROR("read is short: %i instead of %u", res, readsize); - err--; - } else { - if ((flags & O_ACCMODE) != O_RDONLY) { - err += check_buffer(buf, data, datalen); - if (exist && !(flags & O_TRUNC) && testdata2len > datalen) - err += check_buffer(buf + datalen, testdata2 + datalen, - testdata2len - datalen); - } else if (exist) - err += check_buffer(buf, testdata2, testdata2len); - } - } - } else { - if (res != -1) { - ERROR("read should have failed"); - err --; - } else if (errno != EBADF) { - PERROR("read"); - err --; - } - } - - res = close(fd); - if (res == -1) { - PERROR("close"); - return -1; - } - res = unlink(testfile); - if (res == -1) { - PERROR("unlink"); - return -1; - } - res = check_nonexist(testfile); - if (res == -1) - return -1; - if (err) - return -1; - - succ: - success(); - return 0; + char buf[4096]; + const char *data = testdata; + int datalen = testdatalen; + unsigned currlen = 0; + int err = 0; + int res; + int fd; + off_t off; + + start_test("open(%s, %s, 0%03o)", exist ? "+" : "-", flags_str, mode); + unlink(testfile); + if (exist) { + res = create_file(testfile, testdata2, testdata2len); + if (res == -1) + return -1; + + currlen = testdata2len; + } + + fd = open(testfile, flags, mode); + if ((flags & O_CREAT) && (flags & O_EXCL) && exist) { + if (fd != -1) { + ERROR("open should have failed"); + close(fd); + return -1; + } else if (errno == EEXIST) + goto succ; + } + if (!(flags & O_CREAT) && !exist) { + if (fd != -1) { + ERROR("open should have failed"); + close(fd); + return -1; + } else if (errno == ENOENT) + goto succ; + } + if (fd == -1) { + PERROR("open"); + return -1; + } + + if (flags & O_TRUNC) + currlen = 0; + + err += check_type(testfile, S_IFREG); + if (exist) + err += check_mode(testfile, 0644); + else + err += check_mode(testfile, mode); + err += check_nlink(testfile, 1); + err += check_size(testfile, currlen); + if (exist && !(flags & O_TRUNC) && (mode & 0400)) + err += check_data(testfile, testdata2, 0, testdata2len); + + res = write(fd, data, datalen); + if ((flags & O_ACCMODE) != O_RDONLY) { + if (res == -1) { + PERROR("write"); + err --; + } else if (res != datalen) { + ERROR("write is short: %u instead of %u", res, datalen); + err --; + } else { + if (datalen > (int) currlen) + currlen = datalen; + + err += check_size(testfile, currlen); + + if (mode & 0400) { + err += check_data(testfile, data, 0, datalen); + if (exist && !(flags & O_TRUNC) && + testdata2len > datalen) + err += check_data(testfile, + testdata2 + datalen, + datalen, + testdata2len - datalen); + } + } + } else { + if (res != -1) { + ERROR("write should have failed"); + err --; + } else if (errno != EBADF) { + PERROR("write"); + err --; + } + } + off = lseek(fd, SEEK_SET, 0); + if (off == (off_t) -1) { + PERROR("lseek"); + err--; + } else if (off != 0) { + ERROR("offset should have returned 0"); + err --; + } + res = read(fd, buf, sizeof(buf)); + if ((flags & O_ACCMODE) != O_WRONLY) { + if (res == -1) { + PERROR("read"); + err--; + } else { + int readsize = + currlen < sizeof(buf) ? currlen : sizeof(buf); + if (res != readsize) { + ERROR("read is short: %i instead of %u", + res, readsize); + err--; + } else { + if ((flags & O_ACCMODE) != O_RDONLY) { + err += check_buffer(buf, data, datalen); + if (exist && !(flags & O_TRUNC) && + testdata2len > datalen) + err += check_buffer(buf + datalen, + testdata2 + datalen, + testdata2len - datalen); + } else if (exist) + err += check_buffer(buf, testdata2, + testdata2len); + } + } + } else { + if (res != -1) { + ERROR("read should have failed"); + err --; + } else if (errno != EBADF) { + PERROR("read"); + err --; + } + } + + res = close(fd); + if (res == -1) { + PERROR("close"); + return -1; + } + res = unlink(testfile); + if (res == -1) { + PERROR("unlink"); + return -1; + } + res = check_nonexist(testfile); + if (res == -1) + return -1; + if (err) + return -1; + +succ: + success(); + return 0; } -#define test_open_acc(flags, mode, err) do_test_open_acc(flags, #flags, mode, err) +#define test_open_acc(flags, mode, err) \ + do_test_open_acc(flags, #flags, mode, err) static int do_test_open_acc(int flags, const char *flags_str, int mode, int err) { - const char *data = testdata; - int datalen = testdatalen; - int res; - int fd; - - start_test("open_acc(%s) mode: 0%03o error: '%s'", flags_str, mode, - strerror(err)); - unlink(testfile); - res = create_file(testfile, data, datalen); - if (res == -1) - return -1; - - res = chmod(testfile, mode); - if (res == -1) { - PERROR("chmod"); - return -1; - } - - res = check_mode(testfile, mode); - if (res == -1) - return -1; - - fd = open(testfile, flags); - if (fd == -1) { - if (err != errno) { - PERROR("open"); - return -1; - } - } else { - if (err) { - ERROR("open should have failed"); - close(fd); - return -1; - } - close(fd); - } - success(); - return 0; + const char *data = testdata; + int datalen = testdatalen; + int res; + int fd; + + start_test("open_acc(%s) mode: 0%03o error: '%s'", flags_str, mode, + strerror(err)); + unlink(testfile); + res = create_file(testfile, data, datalen); + if (res == -1) + return -1; + + res = chmod(testfile, mode); + if (res == -1) { + PERROR("chmod"); + return -1; + } + + res = check_mode(testfile, mode); + if (res == -1) + return -1; + + fd = open(testfile, flags); + if (fd == -1) { + if (err != errno) { + PERROR("open"); + return -1; + } + } else { + if (err) { + ERROR("open should have failed"); + close(fd); + return -1; + } + close(fd); + } + success(); + return 0; } static int test_symlink(void) { - char buf[1024]; - const char *data = testdata; - int datalen = testdatalen; - int linklen = strlen(testfile); - int err = 0; - int res; - - start_test("symlink"); - res = create_file(testfile, data, datalen); - if (res == -1) - return -1; - - unlink(testfile2); - res = symlink(testfile, testfile2); - if (res == -1) { - PERROR("symlink"); - return -1; - } - res = check_type(testfile2, S_IFLNK); - if (res == -1) - return -1; - err += check_mode(testfile2, 0777); - err += check_nlink(testfile2, 1); - res = readlink(testfile2, buf, sizeof(buf)); - if (res == -1) { - PERROR("readlink"); - err--; - } - if (res != linklen) { - ERROR("short readlink: %u instead of %u", res, linklen); - err--; - } - if (memcmp(buf, testfile, linklen) != 0) { - ERROR("link mismatch"); - err--; - } - err += check_size(testfile2, datalen); - err += check_data(testfile2, data, 0, datalen); - res = unlink(testfile2); - if (res == -1) { - PERROR("unlink"); - return -1; - } - res = check_nonexist(testfile2); - if (res == -1) - return -1; - if (err) - return -1; - - success(); - return 0; + char buf[1024]; + const char *data = testdata; + int datalen = testdatalen; + int linklen = strlen(testfile); + int err = 0; + int res; + + start_test("symlink"); + res = create_file(testfile, data, datalen); + if (res == -1) + return -1; + + unlink(testfile2); + res = symlink(testfile, testfile2); + if (res == -1) { + PERROR("symlink"); + return -1; + } + res = check_type(testfile2, S_IFLNK); + if (res == -1) + return -1; + err += check_mode(testfile2, 0777); + err += check_nlink(testfile2, 1); + res = readlink(testfile2, buf, sizeof(buf)); + if (res == -1) { + PERROR("readlink"); + err--; + } + if (res != linklen) { + ERROR("short readlink: %u instead of %u", res, linklen); + err--; + } + if (memcmp(buf, testfile, linklen) != 0) { + ERROR("link mismatch"); + err--; + } + err += check_size(testfile2, datalen); + err += check_data(testfile2, data, 0, datalen); + res = unlink(testfile2); + if (res == -1) { + PERROR("unlink"); + return -1; + } + res = check_nonexist(testfile2); + if (res == -1) + return -1; + if (err) + return -1; + + success(); + return 0; } static int test_link(void) { - const char *data = testdata; - int datalen = testdatalen; - int err = 0; - int res; - - start_test("link"); - res = create_file(testfile, data, datalen); - if (res == -1) - return -1; - - unlink(testfile2); - res = link(testfile, testfile2); - if (res == -1) { - PERROR("link"); - return -1; - } - res = check_type(testfile2, S_IFREG); - if (res == -1) - return -1; - err += check_mode(testfile2, 0644); - err += check_nlink(testfile2, 2); - err += check_size(testfile2, datalen); - err += check_data(testfile2, data, 0, datalen); - res = unlink(testfile); - if (res == -1) { - PERROR("unlink"); - return -1; - } - res = check_nonexist(testfile); - if (res == -1) - return -1; - - err += check_nlink(testfile2, 1); - res = unlink(testfile2); - if (res == -1) { - PERROR("unlink"); - return -1; - } - res = check_nonexist(testfile2); - if (res == -1) - return -1; - if (err) - return -1; - - success(); - return 0; + const char *data = testdata; + int datalen = testdatalen; + int err = 0; + int res; + + start_test("link"); + res = create_file(testfile, data, datalen); + if (res == -1) + return -1; + + unlink(testfile2); + res = link(testfile, testfile2); + if (res == -1) { + PERROR("link"); + return -1; + } + res = check_type(testfile2, S_IFREG); + if (res == -1) + return -1; + err += check_mode(testfile2, 0644); + err += check_nlink(testfile2, 2); + err += check_size(testfile2, datalen); + err += check_data(testfile2, data, 0, datalen); + res = unlink(testfile); + if (res == -1) { + PERROR("unlink"); + return -1; + } + res = check_nonexist(testfile); + if (res == -1) + return -1; + + err += check_nlink(testfile2, 1); + res = unlink(testfile2); + if (res == -1) { + PERROR("unlink"); + return -1; + } + res = check_nonexist(testfile2); + if (res == -1) + return -1; + if (err) + return -1; + + success(); + return 0; } static int test_rename_file(void) { - const char *data = testdata; - int datalen = testdatalen; - int err = 0; - int res; - - start_test("rename file"); - res = create_file(testfile, data, datalen); - if (res == -1) - return -1; - - unlink(testfile2); - res = rename(testfile, testfile2); - if (res == -1) { - PERROR("rename"); - return -1; - } - res = check_nonexist(testfile); - if (res == -1) - return -1; - res = check_type(testfile2, S_IFREG); - if (res == -1) - return -1; - err += check_mode(testfile2, 0644); - err += check_nlink(testfile2, 1); - err += check_size(testfile2, datalen); - err += check_data(testfile2, data, 0, datalen); - res = unlink(testfile2); - if (res == -1) { - PERROR("unlink"); - return -1; - } - res = check_nonexist(testfile2); - if (res == -1) - return -1; - if (err) - return -1; - - success(); - return 0; + const char *data = testdata; + int datalen = testdatalen; + int err = 0; + int res; + + start_test("rename file"); + res = create_file(testfile, data, datalen); + if (res == -1) + return -1; + + unlink(testfile2); + res = rename(testfile, testfile2); + if (res == -1) { + PERROR("rename"); + return -1; + } + res = check_nonexist(testfile); + if (res == -1) + return -1; + res = check_type(testfile2, S_IFREG); + if (res == -1) + return -1; + err += check_mode(testfile2, 0644); + err += check_nlink(testfile2, 1); + err += check_size(testfile2, datalen); + err += check_data(testfile2, data, 0, datalen); + res = unlink(testfile2); + if (res == -1) { + PERROR("unlink"); + return -1; + } + res = check_nonexist(testfile2); + if (res == -1) + return -1; + if (err) + return -1; + + success(); + return 0; } static int test_rename_dir(void) { - int err = 0; - int res; - - start_test("rename dir"); - res = create_dir(testdir, testdir_files); - if (res == -1) - return -1; - - rmdir(testdir2); - res = rename(testdir, testdir2); - if (res == -1) { - PERROR("rename"); - cleanup_dir(testdir, testdir_files, 1); - return -1; - } - res = check_nonexist(testdir); - if (res == -1) { - cleanup_dir(testdir, testdir_files, 1); - return -1; - } - res = check_type(testdir2, S_IFDIR); - if (res == -1) { - cleanup_dir(testdir2, testdir_files, 1); - return -1; - } - err += check_mode(testdir2, 0755); - err += check_dir_contents(testdir2, testdir_files); - err += cleanup_dir(testdir2, testdir_files, 0); - res = rmdir(testdir2); - if (res == -1) { - PERROR("rmdir"); - return -1; - } - res = check_nonexist(testdir2); - if (res == -1) - return -1; - if (err) - return -1; - - success(); - return 0; + int err = 0; + int res; + + start_test("rename dir"); + res = create_dir(testdir, testdir_files); + if (res == -1) + return -1; + + rmdir(testdir2); + res = rename(testdir, testdir2); + if (res == -1) { + PERROR("rename"); + cleanup_dir(testdir, testdir_files, 1); + return -1; + } + res = check_nonexist(testdir); + if (res == -1) { + cleanup_dir(testdir, testdir_files, 1); + return -1; + } + res = check_type(testdir2, S_IFDIR); + if (res == -1) { + cleanup_dir(testdir2, testdir_files, 1); + return -1; + } + err += check_mode(testdir2, 0755); + err += check_dir_contents(testdir2, testdir_files); + err += cleanup_dir(testdir2, testdir_files, 0); + res = rmdir(testdir2); + if (res == -1) { + PERROR("rmdir"); + return -1; + } + res = check_nonexist(testdir2); + if (res == -1) + return -1; + if (err) + return -1; + + success(); + return 0; } static int test_mkfifo(void) { - int res; - int err = 0; - - start_test("mkfifo"); - unlink(testfile); - res = mkfifo(testfile, 0644); - if (res == -1) { - PERROR("mkfifo"); - return -1; - } - res = check_type(testfile, S_IFIFO); - if (res == -1) - return -1; - err += check_mode(testfile, 0644); - err += check_nlink(testfile, 1); - res = unlink(testfile); - if (res == -1) { - PERROR("unlink"); - return -1; - } - res = check_nonexist(testfile); - if (res == -1) - return -1; - if (err) - return -1; - - success(); - return 0; + int res; + int err = 0; + + start_test("mkfifo"); + unlink(testfile); + res = mkfifo(testfile, 0644); + if (res == -1) { + PERROR("mkfifo"); + return -1; + } + res = check_type(testfile, S_IFIFO); + if (res == -1) + return -1; + err += check_mode(testfile, 0644); + err += check_nlink(testfile, 1); + res = unlink(testfile); + if (res == -1) { + PERROR("unlink"); + return -1; + } + res = check_nonexist(testfile); + if (res == -1) + return -1; + if (err) + return -1; + + success(); + return 0; } static int test_mkdir(void) { - int res; - int err = 0; - const char *dir_contents[] = {NULL}; - - start_test("mkdir"); - rmdir(testdir); - res = mkdir(testdir, 0755); - if (res == -1) { - PERROR("mkdir"); - return -1; - } - res = check_type(testdir, S_IFDIR); - if (res == -1) - return -1; - err += check_mode(testdir, 0755); - err += check_nlink(testdir, 2); - err += check_dir_contents(testdir, dir_contents); - res = rmdir(testdir); - if (res == -1) { - PERROR("rmdir"); - return -1; - } - res = check_nonexist(testdir); - if (res == -1) - return -1; - if (err) - return -1; - - success(); - return 0; + int res; + int err = 0; + const char *dir_contents[] = {NULL}; + + start_test("mkdir"); + rmdir(testdir); + res = mkdir(testdir, 0755); + if (res == -1) { + PERROR("mkdir"); + return -1; + } + res = check_type(testdir, S_IFDIR); + if (res == -1) + return -1; + err += check_mode(testdir, 0755); + err += check_nlink(testdir, 2); + err += check_dir_contents(testdir, dir_contents); + res = rmdir(testdir); + if (res == -1) { + PERROR("rmdir"); + return -1; + } + res = check_nonexist(testdir); + if (res == -1) + return -1; + if (err) + return -1; + + success(); + return 0; } int main(int argc, char *argv[]) { - const char *basepath; - int err = 0; - - umask(0); - if (argc != 2) { - fprintf(stderr, "usage: %s testdir\n", argv[0]); - return 1; - } - basepath = argv[1]; - assert(strlen(basepath) < 512); - if (basepath[0] != '/') { - fprintf(stderr, "testdir must be an absolute path\n"); - return 1; - } - - sprintf(testfile, "%s/testfile", basepath); - sprintf(testfile2, "%s/testfile2", basepath); - sprintf(testdir, "%s/testdir", basepath); - sprintf(testdir2, "%s/testdir2", basepath); - err += test_create(); - err += test_create_unlink(); - err += test_mknod(); - err += test_symlink(); - err += test_link(); - err += test_mkfifo(); - err += test_mkdir(); - err += test_rename_file(); - err += test_rename_dir(); - err += test_utime(); - err += test_truncate(0); - err += test_truncate(testdatalen / 2); - err += test_truncate(testdatalen); - err += test_truncate(testdatalen + 100); - err += test_ftruncate(0, 0600); - err += test_ftruncate(testdatalen / 2, 0600); - err += test_ftruncate(testdatalen, 0600); - err += test_ftruncate(testdatalen + 100, 0600); - err += test_ftruncate(0, 0400); - err += test_ftruncate(0, 0200); - err += test_ftruncate(0, 0000); - err += test_open(0, O_RDONLY, 0); - err += test_open(1, O_RDONLY, 0); - err += test_open(1, O_RDWR, 0); - err += test_open(1, O_WRONLY, 0); - err += test_open(0, O_RDWR | O_CREAT, 0600); - err += test_open(1, O_RDWR | O_CREAT, 0600); - err += test_open(0, O_RDWR | O_CREAT | O_TRUNC, 0600); - err += test_open(1, O_RDWR | O_CREAT | O_TRUNC, 0600); - err += test_open(0, O_RDONLY | O_CREAT, 0600); - err += test_open(0, O_RDONLY | O_CREAT, 0400); - err += test_open(0, O_RDONLY | O_CREAT, 0200); - err += test_open(0, O_RDONLY | O_CREAT, 0000); - err += test_open(0, O_WRONLY | O_CREAT, 0600); - err += test_open(0, O_WRONLY | O_CREAT, 0400); - err += test_open(0, O_WRONLY | O_CREAT, 0200); - err += test_open(0, O_WRONLY | O_CREAT, 0000); - err += test_open(0, O_RDWR | O_CREAT, 0400); - err += test_open(0, O_RDWR | O_CREAT, 0200); - err += test_open(0, O_RDWR | O_CREAT, 0000); - err += test_open(0, O_RDWR | O_CREAT | O_EXCL, 0600); - err += test_open(1, O_RDWR | O_CREAT | O_EXCL, 0600); - err += test_open(0, O_RDWR | O_CREAT | O_EXCL, 0000); - err += test_open(1, O_RDWR | O_CREAT | O_EXCL, 0000); - err += test_open_acc(O_RDONLY, 0600, 0); - err += test_open_acc(O_WRONLY, 0600, 0); - err += test_open_acc(O_RDWR, 0600, 0); - err += test_open_acc(O_RDONLY, 0400, 0); - err += test_open_acc(O_RDONLY | O_TRUNC, 0400, EACCES); - err += test_open_acc(O_WRONLY, 0400, EACCES); - err += test_open_acc(O_RDWR, 0400, EACCES); - err += test_open_acc(O_RDONLY, 0200, EACCES); - err += test_open_acc(O_WRONLY, 0200, 0); - err += test_open_acc(O_RDWR, 0200, EACCES); - err += test_open_acc(O_RDONLY, 0000, EACCES); - err += test_open_acc(O_WRONLY, 0000, EACCES); - err += test_open_acc(O_RDWR, 0000, EACCES); - - unlink(testfile); - unlink(testfile2); - rmdir(testdir); - rmdir(testdir2); - - if (err) { - fprintf(stderr, "%i tests failed\n", -err); - return 1; - } - - return 0; + const char *basepath; + int err = 0; + + umask(0); + if (argc != 2) { + fprintf(stderr, "usage: %s testdir\n", argv[0]); + return 1; + } + basepath = argv[1]; + assert(strlen(basepath) < 512); + if (basepath[0] != '/') { + fprintf(stderr, "testdir must be an absolute path\n"); + return 1; + } + + sprintf(testfile, "%s/testfile", basepath); + sprintf(testfile2, "%s/testfile2", basepath); + sprintf(testdir, "%s/testdir", basepath); + sprintf(testdir2, "%s/testdir2", basepath); + err += test_create(); + err += test_create_unlink(); + err += test_mknod(); + err += test_symlink(); + err += test_link(); + err += test_mkfifo(); + err += test_mkdir(); + err += test_rename_file(); + err += test_rename_dir(); + err += test_utime(); + err += test_truncate(0); + err += test_truncate(testdatalen / 2); + err += test_truncate(testdatalen); + err += test_truncate(testdatalen + 100); + err += test_ftruncate(0, 0600); + err += test_ftruncate(testdatalen / 2, 0600); + err += test_ftruncate(testdatalen, 0600); + err += test_ftruncate(testdatalen + 100, 0600); + err += test_ftruncate(0, 0400); + err += test_ftruncate(0, 0200); + err += test_ftruncate(0, 0000); + err += test_open(0, O_RDONLY, 0); + err += test_open(1, O_RDONLY, 0); + err += test_open(1, O_RDWR, 0); + err += test_open(1, O_WRONLY, 0); + err += test_open(0, O_RDWR | O_CREAT, 0600); + err += test_open(1, O_RDWR | O_CREAT, 0600); + err += test_open(0, O_RDWR | O_CREAT | O_TRUNC, 0600); + err += test_open(1, O_RDWR | O_CREAT | O_TRUNC, 0600); + err += test_open(0, O_RDONLY | O_CREAT, 0600); + err += test_open(0, O_RDONLY | O_CREAT, 0400); + err += test_open(0, O_RDONLY | O_CREAT, 0200); + err += test_open(0, O_RDONLY | O_CREAT, 0000); + err += test_open(0, O_WRONLY | O_CREAT, 0600); + err += test_open(0, O_WRONLY | O_CREAT, 0400); + err += test_open(0, O_WRONLY | O_CREAT, 0200); + err += test_open(0, O_WRONLY | O_CREAT, 0000); + err += test_open(0, O_RDWR | O_CREAT, 0400); + err += test_open(0, O_RDWR | O_CREAT, 0200); + err += test_open(0, O_RDWR | O_CREAT, 0000); + err += test_open(0, O_RDWR | O_CREAT | O_EXCL, 0600); + err += test_open(1, O_RDWR | O_CREAT | O_EXCL, 0600); + err += test_open(0, O_RDWR | O_CREAT | O_EXCL, 0000); + err += test_open(1, O_RDWR | O_CREAT | O_EXCL, 0000); + err += test_open_acc(O_RDONLY, 0600, 0); + err += test_open_acc(O_WRONLY, 0600, 0); + err += test_open_acc(O_RDWR, 0600, 0); + err += test_open_acc(O_RDONLY, 0400, 0); + err += test_open_acc(O_RDONLY | O_TRUNC, 0400, EACCES); + err += test_open_acc(O_WRONLY, 0400, EACCES); + err += test_open_acc(O_RDWR, 0400, EACCES); + err += test_open_acc(O_RDONLY, 0200, EACCES); + err += test_open_acc(O_WRONLY, 0200, 0); + err += test_open_acc(O_RDWR, 0200, EACCES); + err += test_open_acc(O_RDONLY, 0000, EACCES); + err += test_open_acc(O_WRONLY, 0000, EACCES); + err += test_open_acc(O_RDWR, 0000, EACCES); + + unlink(testfile); + unlink(testfile2); + rmdir(testdir); + rmdir(testdir2); + + if (err) { + fprintf(stderr, "%i tests failed\n", -err); + return 1; + } + + return 0; } diff --git a/util/fusermount.c b/util/fusermount.c index 716caff..e3c98c5 100644 --- a/util/fusermount.c +++ b/util/fusermount.c @@ -1,9 +1,9 @@ /* - FUSE: Filesystem in Userspace - Copyright (C) 2001-2007 Miklos Szeredi + 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. + This program can be distributed under the terms of the GNU GPL. + See the file COPYING. */ /* This program does the mounting and unmounting of FUSE filesystems */ @@ -27,7 +27,7 @@ #include #include -#define FUSE_COMMFD_ENV "_FUSE_COMMFD" +#define FUSE_COMMFD_ENV "_FUSE_COMMFD" #define FUSE_DEV_OLD "/proc/fs/fuse/dev" #define FUSE_DEV_NEW "/dev/fuse" @@ -45,13 +45,13 @@ static int mount_max = 1000; static const char *get_user_name(void) { - struct passwd *pw = getpwuid(getuid()); - if (pw != NULL && pw->pw_name != NULL) - return pw->pw_name; - else { - fprintf(stderr, "%s: could not determine username\n", progname); - return NULL; - } + struct passwd *pw = getpwuid(getuid()); + if (pw != NULL && pw->pw_name != NULL) + return pw->pw_name; + else { + fprintf(stderr, "%s: could not determine username\n", progname); + return NULL; + } } static uid_t oldfsuid; @@ -59,868 +59,897 @@ static gid_t oldfsgid; static void drop_privs(void) { - if (getuid() != 0) { - oldfsuid = setfsuid(getuid()); - oldfsgid = setfsgid(getgid()); - } + if (getuid() != 0) { + oldfsuid = setfsuid(getuid()); + oldfsgid = setfsgid(getgid()); + } } static void restore_privs(void) { - if (getuid() != 0) { - setfsuid(oldfsuid); - setfsgid(oldfsgid); - } + if (getuid() != 0) { + setfsuid(oldfsuid); + setfsgid(oldfsgid); + } } #ifndef IGNORE_MTAB static int add_mount(const char *source, const char *mnt, const char *type, - const char *opts) + const char *opts) { - return fuse_mnt_add_mount(progname, source, mnt, type, opts); + return fuse_mnt_add_mount(progname, source, mnt, type, opts); } static int unmount_fuse(const char *mnt, int quiet, int lazy) { - if (getuid() != 0) { - struct mntent *entp; - FILE *fp; - const char *user = NULL; - char uidstr[32]; - unsigned uidlen = 0; - int found; - const char *mtab = _PATH_MOUNTED; - - user = get_user_name(); - if (user == NULL) - return -1; - - fp = setmntent(mtab, "r"); - if (fp == NULL) { - fprintf(stderr, "%s: failed to open %s: %s\n", progname, mtab, - strerror(errno)); - return -1; - } - - uidlen = sprintf(uidstr, "%u", getuid()); - - found = 0; - while ((entp = getmntent(fp)) != NULL) { - if (!found && strcmp(entp->mnt_dir, mnt) == 0 && - (strcmp(entp->mnt_type, "fuse") == 0 || - strcmp(entp->mnt_type, "fuseblk") == 0 || - strncmp(entp->mnt_type, "fuse.", 5) == 0 || - strncmp(entp->mnt_type, "fuseblk.", 8) == 0)) { - char *p = strstr(entp->mnt_opts, "user="); - if (p && (p == entp->mnt_opts || *(p-1) == ',') && - strcmp(p + 5, user) == 0) { - found = 1; - break; - } - /* /etc/mtab is a link pointing to /proc/mounts: */ - else if ((p = strstr(entp->mnt_opts, "user_id=")) && - (p == entp->mnt_opts || *(p-1) == ',') && - strncmp(p + 8, uidstr, uidlen) == 0 && - (*(p+8+uidlen) == ',' || *(p+8+uidlen) == '\0')) { - found = 1; - break; - } - } - } - endmntent(fp); - - if (!found) { - if (!quiet) - fprintf(stderr, "%s: entry for %s not found in %s\n", progname, - mnt, mtab); - return -1; - } - } - - return fuse_mnt_umount(progname, mnt, lazy); + if (getuid() != 0) { + struct mntent *entp; + FILE *fp; + const char *user = NULL; + char uidstr[32]; + unsigned uidlen = 0; + int found; + const char *mtab = _PATH_MOUNTED; + + user = get_user_name(); + if (user == NULL) + return -1; + + fp = setmntent(mtab, "r"); + if (fp == NULL) { + fprintf(stderr, + "%s: failed to open %s: %s\n", progname, mtab, + strerror(errno)); + return -1; + } + + uidlen = sprintf(uidstr, "%u", getuid()); + + found = 0; + while ((entp = getmntent(fp)) != NULL) { + if (!found && strcmp(entp->mnt_dir, mnt) == 0 && + (strcmp(entp->mnt_type, "fuse") == 0 || + strcmp(entp->mnt_type, "fuseblk") == 0 || + strncmp(entp->mnt_type, "fuse.", 5) == 0 || + strncmp(entp->mnt_type, "fuseblk.", 8) == 0)) { + char *p = strstr(entp->mnt_opts, "user="); + if (p && + (p == entp->mnt_opts || *(p-1) == ',') && + strcmp(p + 5, user) == 0) { + found = 1; + break; + } + /* /etc/mtab is a link pointing to + /proc/mounts: */ + else if ((p = + strstr(entp->mnt_opts, "user_id=")) && + (p == entp->mnt_opts || + *(p-1) == ',') && + strncmp(p + 8, uidstr, uidlen) == 0 && + (*(p+8+uidlen) == ',' || + *(p+8+uidlen) == '\0')) { + found = 1; + break; + } + } + } + endmntent(fp); + + if (!found) { + if (!quiet) + fprintf(stderr, + "%s: entry for %s not found in %s\n", + progname, mnt, mtab); + return -1; + } + } + + return fuse_mnt_umount(progname, mnt, lazy); } static int count_fuse_fs(void) { - struct mntent *entp; - int count = 0; - const char *mtab = _PATH_MOUNTED; - FILE *fp = setmntent(mtab, "r"); - if (fp == NULL) { - fprintf(stderr, "%s: failed to open %s: %s\n", progname, mtab, - strerror(errno)); - return -1; - } - while ((entp = getmntent(fp)) != NULL) { - if (strcmp(entp->mnt_type, "fuse") == 0 || - strncmp(entp->mnt_type, "fuse.", 5) == 0) - count ++; - } - endmntent(fp); - return count; + struct mntent *entp; + int count = 0; + const char *mtab = _PATH_MOUNTED; + FILE *fp = setmntent(mtab, "r"); + if (fp == NULL) { + fprintf(stderr, "%s: failed to open %s: %s\n", progname, mtab, + strerror(errno)); + return -1; + } + while ((entp = getmntent(fp)) != NULL) { + if (strcmp(entp->mnt_type, "fuse") == 0 || + strncmp(entp->mnt_type, "fuse.", 5) == 0) + count ++; + } + endmntent(fp); + return count; } #else /* IGNORE_MTAB */ static int count_fuse_fs() { - return 0; + return 0; } static int add_mount(const char *source, const char *mnt, const char *type, - const char *opts) + const char *opts) { - (void) source; - (void) mnt; - (void) type; - (void) opts; - return 0; + (void) source; + (void) mnt; + (void) type; + (void) opts; + return 0; } static int unmount_fuse(const char *mnt, int quiet, int lazy) { - return fuse_mnt_umount(progname, mnt, lazy); + return fuse_mnt_umount(progname, mnt, lazy); } #endif /* IGNORE_MTAB */ static void strip_line(char *line) { - char *s = strchr(line, '#'); - if (s != NULL) - s[0] = '\0'; - for (s = line + strlen(line) - 1; s >= line && isspace((unsigned char) *s); s--); - s[1] = '\0'; - for (s = line; isspace((unsigned char) *s); s++); - if (s != line) - memmove(line, s, strlen(s)+1); + char *s = strchr(line, '#'); + if (s != NULL) + s[0] = '\0'; + for (s = line + strlen(line) - 1; + s >= line && isspace((unsigned char) *s); s--); + s[1] = '\0'; + for (s = line; isspace((unsigned char) *s); s++); + if (s != line) + memmove(line, s, strlen(s)+1); } static void parse_line(char *line, int linenum) { - int tmp; - if (strcmp(line, "user_allow_other") == 0) - user_allow_other = 1; - else if (sscanf(line, "mount_max = %i", &tmp) == 1) - mount_max = tmp; - else if(line[0]) - fprintf(stderr, "%s: unknown parameter in %s at line %i: '%s'\n", - progname, FUSE_CONF, linenum, line); + int tmp; + if (strcmp(line, "user_allow_other") == 0) + user_allow_other = 1; + else if (sscanf(line, "mount_max = %i", &tmp) == 1) + mount_max = tmp; + else if(line[0]) + fprintf(stderr, + "%s: unknown parameter in %s at line %i: '%s'\n", + progname, FUSE_CONF, linenum, line); } static void read_conf(void) { - FILE *fp = fopen(FUSE_CONF, "r"); - if (fp != NULL) { - int linenum = 1; - char line[256]; - int isnewline = 1; - while (fgets(line, sizeof(line), fp) != NULL) { - if (isnewline) { - if (line[strlen(line)-1] == '\n') { - strip_line(line); - parse_line(line, linenum); - } else { - fprintf(stderr, "%s: reading %s: line %i too long\n", - progname, FUSE_CONF, linenum); - isnewline = 0; - } - } else if(line[strlen(line)-1] == '\n') - isnewline = 1; - if (isnewline) - linenum ++; - } - fclose(fp); - } else if (errno != ENOENT) { - fprintf(stderr, "%s: failed to open %s: %s\n", progname, FUSE_CONF, - strerror(errno)); - } + FILE *fp = fopen(FUSE_CONF, "r"); + if (fp != NULL) { + int linenum = 1; + char line[256]; + int isnewline = 1; + while (fgets(line, sizeof(line), fp) != NULL) { + if (isnewline) { + if (line[strlen(line)-1] == '\n') { + strip_line(line); + parse_line(line, linenum); + } else { + fprintf(stderr, "%s: reading %s: line %i too long\n", + progname, FUSE_CONF, linenum); + isnewline = 0; + } + } else if(line[strlen(line)-1] == '\n') + isnewline = 1; + if (isnewline) + linenum ++; + } + fclose(fp); + } else if (errno != ENOENT) { + fprintf(stderr, "%s: failed to open %s: %s\n", + progname, FUSE_CONF, strerror(errno)); + } } static int begins_with(const char *s, const char *beg) { - if (strncmp(s, beg, strlen(beg)) == 0) - return 1; - else - return 0; + if (strncmp(s, beg, strlen(beg)) == 0) + return 1; + else + return 0; } struct mount_flags { - const char *opt; - unsigned long flag; - int on; - int safe; + const char *opt; + unsigned long flag; + int on; + int safe; }; static struct mount_flags mount_flags[] = { - {"rw", MS_RDONLY, 0, 1}, - {"ro", MS_RDONLY, 1, 1}, - {"suid", MS_NOSUID, 0, 0}, - {"nosuid", MS_NOSUID, 1, 1}, - {"dev", MS_NODEV, 0, 0}, - {"nodev", MS_NODEV, 1, 1}, - {"exec", MS_NOEXEC, 0, 1}, - {"noexec", MS_NOEXEC, 1, 1}, - {"async", MS_SYNCHRONOUS, 0, 1}, - {"sync", MS_SYNCHRONOUS, 1, 1}, - {"atime", MS_NOATIME, 0, 1}, - {"noatime", MS_NOATIME, 1, 1}, - {"dirsync", MS_DIRSYNC, 1, 1}, - {NULL, 0, 0, 0} + {"rw", MS_RDONLY, 0, 1}, + {"ro", MS_RDONLY, 1, 1}, + {"suid", MS_NOSUID, 0, 0}, + {"nosuid", MS_NOSUID, 1, 1}, + {"dev", MS_NODEV, 0, 0}, + {"nodev", MS_NODEV, 1, 1}, + {"exec", MS_NOEXEC, 0, 1}, + {"noexec", MS_NOEXEC, 1, 1}, + {"async", MS_SYNCHRONOUS, 0, 1}, + {"sync", MS_SYNCHRONOUS, 1, 1}, + {"atime", MS_NOATIME, 0, 1}, + {"noatime", MS_NOATIME, 1, 1}, + {"dirsync", MS_DIRSYNC, 1, 1}, + {NULL, 0, 0, 0} }; static int find_mount_flag(const char *s, unsigned len, int *on, int *flag) { - int i; - - for (i = 0; mount_flags[i].opt != NULL; i++) { - const char *opt = mount_flags[i].opt; - if (strlen(opt) == len && strncmp(opt, s, len) == 0) { - *on = mount_flags[i].on; - *flag = mount_flags[i].flag; - if (!mount_flags[i].safe && getuid() != 0) { - *flag = 0; - fprintf(stderr, "%s: unsafe option %s ignored\n", - progname, opt); - } - return 1; - } - } - return 0; + int i; + + for (i = 0; mount_flags[i].opt != NULL; i++) { + const char *opt = mount_flags[i].opt; + if (strlen(opt) == len && strncmp(opt, s, len) == 0) { + *on = mount_flags[i].on; + *flag = mount_flags[i].flag; + if (!mount_flags[i].safe && getuid() != 0) { + *flag = 0; + fprintf(stderr, + "%s: unsafe option %s ignored\n", + progname, opt); + } + return 1; + } + } + return 0; } static int add_option(char **optsp, const char *opt, unsigned expand) { - char *newopts; - if (*optsp == NULL) - newopts = strdup(opt); - else { - unsigned oldsize = strlen(*optsp); - unsigned newsize = oldsize + 1 + strlen(opt) + expand + 1; - newopts = (char *) realloc(*optsp, newsize); - if (newopts) - sprintf(newopts + oldsize, ",%s", opt); - } - if (newopts == NULL) { - fprintf(stderr, "%s: failed to allocate memory\n", progname); - return -1; - } - *optsp = newopts; - return 0; + char *newopts; + if (*optsp == NULL) + newopts = strdup(opt); + else { + unsigned oldsize = strlen(*optsp); + unsigned newsize = oldsize + 1 + strlen(opt) + expand + 1; + newopts = (char *) realloc(*optsp, newsize); + if (newopts) + sprintf(newopts + oldsize, ",%s", opt); + } + if (newopts == NULL) { + fprintf(stderr, "%s: failed to allocate memory\n", progname); + return -1; + } + *optsp = newopts; + return 0; } static int get_mnt_opts(int flags, char *opts, char **mnt_optsp) { - int i; - int l; - - if (!(flags & MS_RDONLY) && add_option(mnt_optsp, "rw", 0) == -1) - return -1; - - for (i = 0; mount_flags[i].opt != NULL; i++) { - if (mount_flags[i].on && (flags & mount_flags[i].flag) && - add_option(mnt_optsp, mount_flags[i].opt, 0) == -1) - return -1; - } - - if (add_option(mnt_optsp, opts, 0) == -1) - return -1; - /* remove comma from end of opts*/ - l = strlen(*mnt_optsp); - if ((*mnt_optsp)[l-1] == ',') - (*mnt_optsp)[l-1] = '\0'; - if (getuid() != 0) { - const char *user = get_user_name(); - if (user == NULL) - return -1; - - if (add_option(mnt_optsp, "user=", strlen(user)) == -1) - return -1; - strcat(*mnt_optsp, user); - } - return 0; + int i; + int l; + + if (!(flags & MS_RDONLY) && add_option(mnt_optsp, "rw", 0) == -1) + return -1; + + for (i = 0; mount_flags[i].opt != NULL; i++) { + if (mount_flags[i].on && (flags & mount_flags[i].flag) && + add_option(mnt_optsp, mount_flags[i].opt, 0) == -1) + return -1; + } + + if (add_option(mnt_optsp, opts, 0) == -1) + return -1; + /* remove comma from end of opts*/ + l = strlen(*mnt_optsp); + if ((*mnt_optsp)[l-1] == ',') + (*mnt_optsp)[l-1] = '\0'; + if (getuid() != 0) { + const char *user = get_user_name(); + if (user == NULL) + return -1; + + if (add_option(mnt_optsp, "user=", strlen(user)) == -1) + return -1; + strcat(*mnt_optsp, user); + } + return 0; } static int opt_eq(const char *s, unsigned len, const char *opt) { - if(strlen(opt) == len && strncmp(s, opt, len) == 0) - return 1; - else - return 0; + if(strlen(opt) == len && strncmp(s, opt, len) == 0) + return 1; + else + return 0; } static int get_string_opt(const char *s, unsigned len, const char *opt, - char **val) + char **val) { - unsigned opt_len = strlen(opt); - - if (*val) - free(*val); - *val = (char *) malloc(len - opt_len + 1); - if (!*val) { - fprintf(stderr, "%s: failed to allocate memory\n", progname); - return 0; - } - - memcpy(*val, s + opt_len, len - opt_len); - (*val)[len - opt_len] = '\0'; - return 1; + unsigned opt_len = strlen(opt); + + if (*val) + free(*val); + *val = (char *) malloc(len - opt_len + 1); + if (!*val) { + fprintf(stderr, "%s: failed to allocate memory\n", progname); + return 0; + } + + memcpy(*val, s + opt_len, len - opt_len); + (*val)[len - opt_len] = '\0'; + return 1; } static int do_mount(const char *mnt, char **typep, mode_t rootmode, - int fd, const char *opts, const char *dev, char **sourcep, - char **mnt_optsp, off_t rootsize) + int fd, const char *opts, const char *dev, char **sourcep, + char **mnt_optsp, off_t rootsize) { - int res; - int flags = MS_NOSUID | MS_NODEV; - char *optbuf; - char *mnt_opts = NULL; - const char *s; - char *d; - char *fsname = NULL; - char *subtype = NULL; - char *source = NULL; - char *type = NULL; - int check_empty = 1; - int blkdev = 0; - - optbuf = (char *) malloc(strlen(opts) + 128); - if (!optbuf) { - fprintf(stderr, "%s: failed to allocate memory\n", progname); - return -1; - } - - for (s = opts, d = optbuf; *s;) { - unsigned len; - const char *fsname_str = "fsname="; - const char *subtype_str = "subtype="; - for (len = 0; s[len] && s[len] != ','; len++); - if (begins_with(s, fsname_str)) { - if (!get_string_opt(s, len, fsname_str, &fsname)) - goto err; - } else if (begins_with(s, subtype_str)) { - if (!get_string_opt(s, len, subtype_str, &subtype)) - goto err; - } else if (opt_eq(s, len, "blkdev")) { - if (getuid() != 0) { - fprintf(stderr, "%s: option blkdev is privileged\n", progname); - goto err; - } - blkdev = 1; - } else if (opt_eq(s, len, "nonempty")) { - check_empty = 0; - } else if (!begins_with(s, "fd=") && - !begins_with(s, "rootmode=") && - !begins_with(s, "user_id=") && - !begins_with(s, "group_id=")) { - int on; - int flag; - int skip_option = 0; - if (opt_eq(s, len, "large_read")) { - struct utsname utsname; - unsigned kmaj, kmin; - res = uname(&utsname); - if (res == 0 && - sscanf(utsname.release, "%u.%u", &kmaj, &kmin) == 2 && - (kmaj > 2 || (kmaj == 2 && kmin > 4))) { - fprintf(stderr, "%s: note: 'large_read' mount option is deprecated for %i.%i kernels\n", progname, kmaj, kmin); - skip_option = 1; - } - } - if (getuid() != 0 && !user_allow_other && - (opt_eq(s, len, "allow_other") || - opt_eq(s, len, "allow_root"))) { - fprintf(stderr, "%s: option %.*s only allowed if 'user_allow_other' is set in /etc/fuse.conf\n", progname, len, s); - goto err; - } - if (!skip_option) { - if (find_mount_flag(s, len, &on, &flag)) { - if (on) - flags |= flag; - else - flags &= ~flag; - } else { - memcpy(d, s, len); - d += len; - *d++ = ','; - } - } - } - s += len; - if (*s) - s++; - } - *d = '\0'; - res = get_mnt_opts(flags, optbuf, &mnt_opts); - if (res == -1) - goto err; - - sprintf(d, "fd=%i,rootmode=%o,user_id=%i,group_id=%i", - fd, rootmode, getuid(), getgid()); - - if (check_empty && - fuse_mnt_check_empty(progname, mnt, rootmode, rootsize) == -1) - goto err; - - source = malloc((fsname ? strlen(fsname) : 0) + - (subtype ? strlen(subtype) : 0) + strlen(dev) + 32); - - type = malloc((subtype ? strlen(subtype) : 0) + 32); - if (!type || !source) { - fprintf(stderr, "%s: failed to allocate memory\n", progname); - goto err; - } - - if (subtype) - sprintf(type, "%s.%s", blkdev ? "fuseblk" : "fuse", subtype); - else - strcpy(type, blkdev ? "fuseblk" : "fuse"); - - if (fsname) - strcpy(source, fsname); - else - strcpy(source, subtype ? subtype : dev); - - res = mount(source, mnt, type, flags, optbuf); - if (res == -1 && errno == ENODEV && subtype) { - /* Probably missing subtype support */ - strcpy(type, blkdev ? "fuseblk" : "fuse"); - if (fsname) { - if (!blkdev) - sprintf(source, "%s#%s", subtype, fsname); - } else { - strcpy(source, type); - } - - res = mount(source, mnt, type, flags, optbuf); - } - if (res == -1 && errno == EINVAL) { - /* It could be an old version not supporting group_id */ - sprintf(d, "fd=%i,rootmode=%o,user_id=%i", fd, rootmode, getuid()); - res = mount(source, mnt, type, flags, optbuf); - } - if (res == -1) { - int errno_save = errno; - if (blkdev && errno == ENODEV && !fuse_mnt_check_fuseblk()) - fprintf(stderr, "%s: 'fuseblk' support missing\n", progname); - else - fprintf(stderr, "%s: mount failed: %s\n", progname, strerror(errno_save)); - goto err; - } else { - *sourcep = source; - *typep = type; - *mnt_optsp = mnt_opts; - } - free(optbuf); - - return res; - - err: - free(fsname); - free(subtype); - free(source); - free(type); - free(mnt_opts); - free(optbuf); - return -1; + int res; + int flags = MS_NOSUID | MS_NODEV; + char *optbuf; + char *mnt_opts = NULL; + const char *s; + char *d; + char *fsname = NULL; + char *subtype = NULL; + char *source = NULL; + char *type = NULL; + int check_empty = 1; + int blkdev = 0; + + optbuf = (char *) malloc(strlen(opts) + 128); + if (!optbuf) { + fprintf(stderr, "%s: failed to allocate memory\n", progname); + return -1; + } + + for (s = opts, d = optbuf; *s;) { + unsigned len; + const char *fsname_str = "fsname="; + const char *subtype_str = "subtype="; + for (len = 0; s[len] && s[len] != ','; len++); + if (begins_with(s, fsname_str)) { + if (!get_string_opt(s, len, fsname_str, &fsname)) + goto err; + } else if (begins_with(s, subtype_str)) { + if (!get_string_opt(s, len, subtype_str, &subtype)) + goto err; + } else if (opt_eq(s, len, "blkdev")) { + if (getuid() != 0) { + fprintf(stderr, + "%s: option blkdev is privileged\n", + progname); + goto err; + } + blkdev = 1; + } else if (opt_eq(s, len, "nonempty")) { + check_empty = 0; + } else if (!begins_with(s, "fd=") && + !begins_with(s, "rootmode=") && + !begins_with(s, "user_id=") && + !begins_with(s, "group_id=")) { + int on; + int flag; + int skip_option = 0; + if (opt_eq(s, len, "large_read")) { + struct utsname utsname; + unsigned kmaj, kmin; + res = uname(&utsname); + if (res == 0 && + sscanf(utsname.release, "%u.%u", + &kmaj, &kmin) == 2 && + (kmaj > 2 || (kmaj == 2 && kmin > 4))) { + fprintf(stderr, "%s: note: 'large_read' mount option is deprecated for %i.%i kernels\n", progname, kmaj, kmin); + skip_option = 1; + } + } + if (getuid() != 0 && !user_allow_other && + (opt_eq(s, len, "allow_other") || + opt_eq(s, len, "allow_root"))) { + fprintf(stderr, "%s: option %.*s only allowed if 'user_allow_other' is set in /etc/fuse.conf\n", progname, len, s); + goto err; + } + if (!skip_option) { + if (find_mount_flag(s, len, &on, &flag)) { + if (on) + flags |= flag; + else + flags &= ~flag; + } else { + memcpy(d, s, len); + d += len; + *d++ = ','; + } + } + } + s += len; + if (*s) + s++; + } + *d = '\0'; + res = get_mnt_opts(flags, optbuf, &mnt_opts); + if (res == -1) + goto err; + + sprintf(d, "fd=%i,rootmode=%o,user_id=%i,group_id=%i", + fd, rootmode, getuid(), getgid()); + + if (check_empty && + fuse_mnt_check_empty(progname, mnt, rootmode, rootsize) == -1) + goto err; + + source = malloc((fsname ? strlen(fsname) : 0) + + (subtype ? strlen(subtype) : 0) + strlen(dev) + 32); + + type = malloc((subtype ? strlen(subtype) : 0) + 32); + if (!type || !source) { + fprintf(stderr, "%s: failed to allocate memory\n", progname); + goto err; + } + + if (subtype) + sprintf(type, "%s.%s", blkdev ? "fuseblk" : "fuse", subtype); + else + strcpy(type, blkdev ? "fuseblk" : "fuse"); + + if (fsname) + strcpy(source, fsname); + else + strcpy(source, subtype ? subtype : dev); + + res = mount(source, mnt, type, flags, optbuf); + if (res == -1 && errno == ENODEV && subtype) { + /* Probably missing subtype support */ + strcpy(type, blkdev ? "fuseblk" : "fuse"); + if (fsname) { + if (!blkdev) + sprintf(source, "%s#%s", subtype, fsname); + } else { + strcpy(source, type); + } + + res = mount(source, mnt, type, flags, optbuf); + } + if (res == -1 && errno == EINVAL) { + /* It could be an old version not supporting group_id */ + sprintf(d, "fd=%i,rootmode=%o,user_id=%i", + fd, rootmode, getuid()); + res = mount(source, mnt, type, flags, optbuf); + } + if (res == -1) { + int errno_save = errno; + if (blkdev && errno == ENODEV && !fuse_mnt_check_fuseblk()) + fprintf(stderr, "%s: 'fuseblk' support missing\n", + progname); + else + fprintf(stderr, "%s: mount failed: %s\n", progname, + strerror(errno_save)); + goto err; + } else { + *sourcep = source; + *typep = type; + *mnt_optsp = mnt_opts; + } + free(optbuf); + + return res; + +err: + free(fsname); + free(subtype); + free(source); + free(type); + free(mnt_opts); + free(optbuf); + return -1; } static int check_version(const char *dev) { - int res; - int majorver; - int minorver; - const char *version_file; - FILE *vf; - - if (strcmp(dev, FUSE_DEV_OLD) != 0) - return 0; - - version_file = FUSE_VERSION_FILE_OLD; - vf = fopen(version_file, "r"); - if (vf == NULL) { - fprintf(stderr, "%s: kernel interface too old\n", progname); - return -1; - } - res = fscanf(vf, "%i.%i", &majorver, &minorver); - fclose(vf); - if (res != 2) { - fprintf(stderr, "%s: error reading %s\n", progname, version_file); - return -1; - } - if (majorver < 3) { - fprintf(stderr, "%s: kernel interface too old\n", progname); - return -1; - } - return 0; + int res; + int majorver; + int minorver; + const char *version_file; + FILE *vf; + + if (strcmp(dev, FUSE_DEV_OLD) != 0) + return 0; + + version_file = FUSE_VERSION_FILE_OLD; + vf = fopen(version_file, "r"); + if (vf == NULL) { + fprintf(stderr, "%s: kernel interface too old\n", progname); + return -1; + } + res = fscanf(vf, "%i.%i", &majorver, &minorver); + fclose(vf); + if (res != 2) { + fprintf(stderr, "%s: error reading %s\n", progname, + version_file); + return -1; + } + if (majorver < 3) { + fprintf(stderr, "%s: kernel interface too old\n", progname); + return -1; + } + return 0; } static int check_perm(const char **mntp, struct stat *stbuf, int *currdir_fd, - int *mountpoint_fd) + int *mountpoint_fd) { - int res; - const char *mnt = *mntp; - const char *origmnt = mnt; - - res = lstat(mnt, stbuf); - if (res == -1) { - fprintf(stderr, "%s: failed to access mountpoint %s: %s\n", - progname, mnt, strerror(errno)); - return -1; - } - - /* No permission checking is done for root */ - if (getuid() == 0) - return 0; - - if (S_ISDIR(stbuf->st_mode)) { - *currdir_fd = open(".", O_RDONLY); - if (*currdir_fd == -1) { - fprintf(stderr, "%s: failed to open current directory: %s\n", - progname, strerror(errno)); - return -1; - } - res = chdir(mnt); - if (res == -1) { - fprintf(stderr, "%s: failed to chdir to mountpoint: %s\n", - progname, strerror(errno)); - return -1; - } - mnt = *mntp = "."; - res = lstat(mnt, stbuf); - if (res == -1) { - fprintf(stderr, "%s: failed to access mountpoint %s: %s\n", - progname, origmnt, strerror(errno)); - return -1; - } - - if ((stbuf->st_mode & S_ISVTX) && stbuf->st_uid != getuid()) { - fprintf(stderr, "%s: mountpoint %s not owned by user\n", - progname, origmnt); - return -1; - } - - res = access(mnt, W_OK); - if (res == -1) { - fprintf(stderr, "%s: user has no write access to mountpoint %s\n", - progname, origmnt); - return -1; - } - } else if (S_ISREG(stbuf->st_mode)) { - static char procfile[256]; - *mountpoint_fd = open(mnt, O_WRONLY); - if (*mountpoint_fd == -1) { - fprintf(stderr, "%s: failed to open %s: %s\n", progname, mnt, - strerror(errno)); - return -1; - } - res = fstat(*mountpoint_fd, stbuf); - if (res == -1) { - fprintf(stderr, "%s: failed to access mountpoint %s: %s\n", - progname, mnt, strerror(errno)); - return -1; - } - if (!S_ISREG(stbuf->st_mode)) { - fprintf(stderr, "%s: mountpoint %s is no longer a regular file\n", - progname, mnt); - return -1; - } - - sprintf(procfile, "/proc/self/fd/%i", *mountpoint_fd); - *mntp = procfile; - } else { - fprintf(stderr, - "%s: mountpoint %s is not a directory or a regular file\n", - progname, mnt); - return -1; - } - - - return 0; + int res; + const char *mnt = *mntp; + const char *origmnt = mnt; + + res = lstat(mnt, stbuf); + if (res == -1) { + fprintf(stderr, "%s: failed to access mountpoint %s: %s\n", + progname, mnt, strerror(errno)); + return -1; + } + + /* No permission checking is done for root */ + if (getuid() == 0) + return 0; + + if (S_ISDIR(stbuf->st_mode)) { + *currdir_fd = open(".", O_RDONLY); + if (*currdir_fd == -1) { + fprintf(stderr, + "%s: failed to open current directory: %s\n", + progname, strerror(errno)); + return -1; + } + res = chdir(mnt); + if (res == -1) { + fprintf(stderr, + "%s: failed to chdir to mountpoint: %s\n", + progname, strerror(errno)); + return -1; + } + mnt = *mntp = "."; + res = lstat(mnt, stbuf); + if (res == -1) { + fprintf(stderr, + "%s: failed to access mountpoint %s: %s\n", + progname, origmnt, strerror(errno)); + return -1; + } + + if ((stbuf->st_mode & S_ISVTX) && stbuf->st_uid != getuid()) { + fprintf(stderr, "%s: mountpoint %s not owned by user\n", + progname, origmnt); + return -1; + } + + res = access(mnt, W_OK); + if (res == -1) { + fprintf(stderr, "%s: user has no write access to mountpoint %s\n", + progname, origmnt); + return -1; + } + } else if (S_ISREG(stbuf->st_mode)) { + static char procfile[256]; + *mountpoint_fd = open(mnt, O_WRONLY); + if (*mountpoint_fd == -1) { + fprintf(stderr, "%s: failed to open %s: %s\n", + progname, mnt, strerror(errno)); + return -1; + } + res = fstat(*mountpoint_fd, stbuf); + if (res == -1) { + fprintf(stderr, + "%s: failed to access mountpoint %s: %s\n", + progname, mnt, strerror(errno)); + return -1; + } + if (!S_ISREG(stbuf->st_mode)) { + fprintf(stderr, + "%s: mountpoint %s is no longer a regular file\n", + progname, mnt); + return -1; + } + + sprintf(procfile, "/proc/self/fd/%i", *mountpoint_fd); + *mntp = procfile; + } else { + fprintf(stderr, + "%s: mountpoint %s is not a directory or a regular file\n", + progname, mnt); + return -1; + } + + + return 0; } static int try_open(const char *dev, char **devp, int silent) { - int fd = open(dev, O_RDWR); - if (fd != -1) { - *devp = strdup(dev); - if (*devp == NULL) { - fprintf(stderr, "%s: failed to allocate memory\n", progname); - close(fd); - fd = -1; - } - } else if (errno == ENODEV || - errno == ENOENT) /* check for ENOENT too, for the udev case */ - return -2; - else if (!silent) { - fprintf(stderr, "%s: failed to open %s: %s\n", progname, dev, - strerror(errno)); - } - return fd; + int fd = open(dev, O_RDWR); + if (fd != -1) { + *devp = strdup(dev); + if (*devp == NULL) { + fprintf(stderr, "%s: failed to allocate memory\n", + progname); + close(fd); + fd = -1; + } + } else if (errno == ENODEV || + errno == ENOENT)/* check for ENOENT too, for the udev case */ + return -2; + else if (!silent) { + fprintf(stderr, "%s: failed to open %s: %s\n", progname, dev, + strerror(errno)); + } + return fd; } static int try_open_fuse_device(char **devp) { - int fd; - int err; + int fd; + int err; - drop_privs(); - fd = try_open(FUSE_DEV_NEW, devp, 0); - restore_privs(); - if (fd >= 0) - return fd; + drop_privs(); + fd = try_open(FUSE_DEV_NEW, devp, 0); + restore_privs(); + if (fd >= 0) + return fd; - err = fd; - fd = try_open(FUSE_DEV_OLD, devp, 1); - if (fd >= 0) - return fd; + err = fd; + fd = try_open(FUSE_DEV_OLD, devp, 1); + if (fd >= 0) + return fd; - return err; + return err; } static int open_fuse_device(char **devp) { - int fd = try_open_fuse_device(devp); - if (fd >= -1) - return fd; + int fd = try_open_fuse_device(devp); + if (fd >= -1) + return fd; - fprintf(stderr, "%s: fuse device not found, try 'modprobe fuse' first\n", - progname); + fprintf(stderr, + "%s: fuse device not found, try 'modprobe fuse' first\n", + progname); - return -1; + return -1; } static int mount_fuse(const char *mnt, const char *opts) { - int res; - int fd; - char *dev; - struct stat stbuf; - char *type = NULL; - char *source = NULL; - char *mnt_opts = NULL; - const char *real_mnt = mnt; - int currdir_fd = -1; - int mountpoint_fd = -1; - - fd = open_fuse_device(&dev); - if (fd == -1) - return -1; - - drop_privs(); - read_conf(); - - if (getuid() != 0 && mount_max != -1) { - int mount_count = count_fuse_fs(); - if (mount_count >= mount_max) { - fprintf(stderr, "%s: too many FUSE filesystems mounted; mount_max=N can be set in /etc/fuse.conf\n", progname); - close(fd); - return -1; - } - } - - res = check_version(dev); - if (res != -1) { - res = check_perm(&real_mnt, &stbuf, &currdir_fd, &mountpoint_fd); - restore_privs(); - if (res != -1) - res = do_mount(real_mnt, &type, stbuf.st_mode & S_IFMT, fd, opts, - dev, &source, &mnt_opts, stbuf.st_size); - } else - restore_privs(); - - if (currdir_fd != -1) { - fchdir(currdir_fd); - close(currdir_fd); - } - if (mountpoint_fd != -1) - close(mountpoint_fd); - - if (res == -1) { - close(fd); - return -1; - } - - if (geteuid() == 0) { - res = add_mount(source, mnt, type, mnt_opts); - if (res == -1) { - umount2(mnt, 2); /* lazy umount */ - close(fd); - return -1; - } - } - - free(source); - free(type); - free(mnt_opts); - free(dev); - - return fd; + int res; + int fd; + char *dev; + struct stat stbuf; + char *type = NULL; + char *source = NULL; + char *mnt_opts = NULL; + const char *real_mnt = mnt; + int currdir_fd = -1; + int mountpoint_fd = -1; + + fd = open_fuse_device(&dev); + if (fd == -1) + return -1; + + drop_privs(); + read_conf(); + + if (getuid() != 0 && mount_max != -1) { + int mount_count = count_fuse_fs(); + if (mount_count >= mount_max) { + fprintf(stderr, "%s: too many FUSE filesystems mounted; mount_max=N can be set in /etc/fuse.conf\n", progname); + close(fd); + return -1; + } + } + + res = check_version(dev); + if (res != -1) { + res = check_perm(&real_mnt, &stbuf, &currdir_fd, + &mountpoint_fd); + restore_privs(); + if (res != -1) + res = do_mount(real_mnt, &type, stbuf.st_mode & S_IFMT, + fd, opts, dev, &source, &mnt_opts, + stbuf.st_size); + } else + restore_privs(); + + if (currdir_fd != -1) { + fchdir(currdir_fd); + close(currdir_fd); + } + if (mountpoint_fd != -1) + close(mountpoint_fd); + + if (res == -1) { + close(fd); + return -1; + } + + if (geteuid() == 0) { + res = add_mount(source, mnt, type, mnt_opts); + if (res == -1) { + umount2(mnt, 2); /* lazy umount */ + close(fd); + return -1; + } + } + + free(source); + free(type); + free(mnt_opts); + free(dev); + + return fd; } static int send_fd(int sock_fd, int fd) { - int retval; - struct msghdr msg; - struct cmsghdr *p_cmsg; - struct iovec vec; - size_t cmsgbuf[CMSG_SPACE(sizeof(fd)) / sizeof(size_t)]; - int *p_fds; - char sendchar = 0; - - msg.msg_control = cmsgbuf; - msg.msg_controllen = sizeof(cmsgbuf); - p_cmsg = CMSG_FIRSTHDR(&msg); - p_cmsg->cmsg_level = SOL_SOCKET; - p_cmsg->cmsg_type = SCM_RIGHTS; - p_cmsg->cmsg_len = CMSG_LEN(sizeof(fd)); - p_fds = (int *) CMSG_DATA(p_cmsg); - *p_fds = fd; - msg.msg_controllen = p_cmsg->cmsg_len; - msg.msg_name = NULL; - msg.msg_namelen = 0; - msg.msg_iov = &vec; - msg.msg_iovlen = 1; - msg.msg_flags = 0; - /* "To pass file descriptors or credentials you need to send/read at - * least one byte" (man 7 unix) */ - vec.iov_base = &sendchar; - vec.iov_len = sizeof(sendchar); - while ((retval = sendmsg(sock_fd, &msg, 0)) == -1 && errno == EINTR); - if (retval != 1) { - perror("sending file descriptor"); - return -1; - } - return 0; + int retval; + struct msghdr msg; + struct cmsghdr *p_cmsg; + struct iovec vec; + size_t cmsgbuf[CMSG_SPACE(sizeof(fd)) / sizeof(size_t)]; + int *p_fds; + char sendchar = 0; + + msg.msg_control = cmsgbuf; + msg.msg_controllen = sizeof(cmsgbuf); + p_cmsg = CMSG_FIRSTHDR(&msg); + p_cmsg->cmsg_level = SOL_SOCKET; + p_cmsg->cmsg_type = SCM_RIGHTS; + p_cmsg->cmsg_len = CMSG_LEN(sizeof(fd)); + p_fds = (int *) CMSG_DATA(p_cmsg); + *p_fds = fd; + msg.msg_controllen = p_cmsg->cmsg_len; + msg.msg_name = NULL; + msg.msg_namelen = 0; + msg.msg_iov = &vec; + msg.msg_iovlen = 1; + msg.msg_flags = 0; + /* "To pass file descriptors or credentials you need to send/read at + * least one byte" (man 7 unix) */ + vec.iov_base = &sendchar; + vec.iov_len = sizeof(sendchar); + while ((retval = sendmsg(sock_fd, &msg, 0)) == -1 && errno == EINTR); + if (retval != 1) { + perror("sending file descriptor"); + return -1; + } + return 0; } static void usage(void) { - fprintf(stderr, - "%s: [options] mountpoint\n" - "Options:\n" - " -h print help\n" - " -V print version\n" - " -o opt[,opt...] mount options\n" - " -u unmount\n" - " -q quiet\n" - " -z lazy unmount\n", - progname); - exit(1); + fprintf(stderr, + "%s: [options] mountpoint\n" + "Options:\n" + " -h print help\n" + " -V print version\n" + " -o opt[,opt...] mount options\n" + " -u unmount\n" + " -q quiet\n" + " -z lazy unmount\n", + progname); + exit(1); } static void show_version(void) { - printf("fusermount version: %s\n", PACKAGE_VERSION); - exit(0); + printf("fusermount version: %s\n", PACKAGE_VERSION); + exit(0); } int main(int argc, char *argv[]) { - int ch; - int fd; - int res; - char *origmnt; - char *mnt; - static int unmount = 0; - static int lazy = 0; - static int quiet = 0; - char *commfd; - int cfd; - const char *opts = ""; - - static const struct option long_opts[] = { - {"unmount", no_argument, NULL, 'u'}, - {"lazy", no_argument, NULL, 'z'}, - {"quiet", no_argument, NULL, 'q'}, - {"help", no_argument, NULL, 'h'}, - {"version", no_argument, NULL, 'V'}, - {0, 0, 0, 0}}; - - progname = strdup(argv[0]); - if (progname == NULL) { - fprintf(stderr, "%s: failed to allocate memory\n", argv[0]); - exit(1); - } - - while ((ch = getopt_long(argc, argv, "hVo:uzq", long_opts, NULL)) != -1) { - switch (ch) { - case 'h': - usage(); - break; - - case 'V': - show_version(); - break; - - case 'o': - opts = optarg; - break; - - case 'u': - unmount = 1; - break; - - case 'z': - lazy = 1; - break; - - case 'q': - quiet = 1; - break; - - default: - exit(1); - } - } - - if (lazy && !unmount) { - fprintf(stderr, "%s: -z can only be used with -u\n", progname); - exit(1); - } - - if (optind >= argc) { - fprintf(stderr, "%s: missing mountpoint argument\n", progname); - exit(1); - } - - origmnt = argv[optind]; - - drop_privs(); - mnt = fuse_mnt_resolve_path(progname, origmnt); - restore_privs(); - if (mnt == NULL) - exit(1); - - umask(033); - if (unmount) { - if (geteuid() == 0) - res = unmount_fuse(mnt, quiet, lazy); - else { - res = umount2(mnt, lazy ? 2 : 0); - if (res == -1 && !quiet) - fprintf(stderr, "%s: failed to unmount %s: %s\n", progname, - mnt, strerror(errno)); - } - if (res == -1) - exit(1); - return 0; - } - - commfd = getenv(FUSE_COMMFD_ENV); - if (commfd == NULL) { - fprintf(stderr, "%s: old style mounting not supported\n", progname); - exit(1); - } - - fd = mount_fuse(mnt, opts); - if (fd == -1) - exit(1); - - cfd = atoi(commfd); - res = send_fd(cfd, fd); - if (res == -1) - exit(1); - - return 0; + int ch; + int fd; + int res; + char *origmnt; + char *mnt; + static int unmount = 0; + static int lazy = 0; + static int quiet = 0; + char *commfd; + int cfd; + const char *opts = ""; + + static const struct option long_opts[] = { + {"unmount", no_argument, NULL, 'u'}, + {"lazy", no_argument, NULL, 'z'}, + {"quiet", no_argument, NULL, 'q'}, + {"help", no_argument, NULL, 'h'}, + {"version", no_argument, NULL, 'V'}, + {0, 0, 0, 0}}; + + progname = strdup(argv[0]); + if (progname == NULL) { + fprintf(stderr, "%s: failed to allocate memory\n", argv[0]); + exit(1); + } + + while ((ch = getopt_long(argc, argv, "hVo:uzq", long_opts, + NULL)) != -1) { + switch (ch) { + case 'h': + usage(); + break; + + case 'V': + show_version(); + break; + + case 'o': + opts = optarg; + break; + + case 'u': + unmount = 1; + break; + + case 'z': + lazy = 1; + break; + + case 'q': + quiet = 1; + break; + + default: + exit(1); + } + } + + if (lazy && !unmount) { + fprintf(stderr, "%s: -z can only be used with -u\n", progname); + exit(1); + } + + if (optind >= argc) { + fprintf(stderr, "%s: missing mountpoint argument\n", progname); + exit(1); + } + + origmnt = argv[optind]; + + drop_privs(); + mnt = fuse_mnt_resolve_path(progname, origmnt); + restore_privs(); + if (mnt == NULL) + exit(1); + + umask(033); + if (unmount) { + if (geteuid() == 0) + res = unmount_fuse(mnt, quiet, lazy); + else { + res = umount2(mnt, lazy ? 2 : 0); + if (res == -1 && !quiet) + fprintf(stderr, + "%s: failed to unmount %s: %s\n", + progname, mnt, strerror(errno)); + } + if (res == -1) + exit(1); + return 0; + } + + commfd = getenv(FUSE_COMMFD_ENV); + if (commfd == NULL) { + fprintf(stderr, "%s: old style mounting not supported\n", + progname); + exit(1); + } + + fd = mount_fuse(mnt, opts); + if (fd == -1) + exit(1); + + cfd = atoi(commfd); + res = send_fd(cfd, fd); + if (res == -1) + exit(1); + + return 0; } diff --git a/util/mount.fuse.c b/util/mount.fuse.c index 4cc0394..7bd0e83 100644 --- a/util/mount.fuse.c +++ b/util/mount.fuse.c @@ -1,3 +1,11 @@ +/* + 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. +*/ + #include #include #include @@ -8,184 +16,193 @@ static char *progname; static char *xstrdup(const char *s) { - char *t = strdup(s); - if (!t) { - fprintf(stderr, "%s: failed to allocate memory\n", progname); - exit(1); - } - return t; + char *t = strdup(s); + if (!t) { + fprintf(stderr, "%s: failed to allocate memory\n", progname); + exit(1); + } + return t; } static void *xrealloc(void *oldptr, size_t size) { - void *ptr = realloc(oldptr, size); - if (!ptr) { - fprintf(stderr, "%s: failed to allocate memory\n", progname); - exit(1); - } - return ptr; + void *ptr = realloc(oldptr, size); + if (!ptr) { + fprintf(stderr, "%s: failed to allocate memory\n", progname); + exit(1); + } + return ptr; } static void add_arg(char **cmdp, const char *opt) { - size_t optlen = strlen(opt); - size_t cmdlen = *cmdp ? strlen(*cmdp) : 0; - char *cmd = xrealloc(*cmdp, cmdlen + optlen * 4 + 4); - char *s; - s = cmd + cmdlen; - if (*cmdp) - *s++ = ' '; - - *s++ = '\''; - for (; *opt; opt++) { - if (*opt == '\'') { - *s++ = '\''; - *s++ = '\\'; - *s++ = '\''; - *s++ = '\''; - } else - *s++ = *opt; - } - *s++ = '\''; - *s = '\0'; - *cmdp = cmd; + size_t optlen = strlen(opt); + size_t cmdlen = *cmdp ? strlen(*cmdp) : 0; + char *cmd = xrealloc(*cmdp, cmdlen + optlen * 4 + 4); + char *s; + s = cmd + cmdlen; + if (*cmdp) + *s++ = ' '; + + *s++ = '\''; + for (; *opt; opt++) { + if (*opt == '\'') { + *s++ = '\''; + *s++ = '\\'; + *s++ = '\''; + *s++ = '\''; + } else + *s++ = *opt; + } + *s++ = '\''; + *s = '\0'; + *cmdp = cmd; } int main(int argc, char *argv[]) { - char *type = NULL; - char *source; - const char *mountpoint; - char *basename; - char *options = NULL; - char *command = NULL; - char *setuid = NULL; - int i; - - progname = argv[0]; - basename = strrchr(argv[0], '/'); - if (basename) - basename++; - else - basename = argv[0]; - - if (strncmp(basename, "mount.fuse.", 11) == 0) - type = basename + 11; - if (strncmp(basename, "mount.fuseblk.", 14) == 0) - type = basename + 14; - - if (type && !type[0]) - type = NULL; - - if (argc < 3) { - fprintf(stderr, "usage: %s %s destination [-t type] [-o opt[,opts...]]\n", - progname, type ? "source" : "type#[source]"); - exit(1); - } - - source = argv[1]; - if (!source[0]) - source = NULL; - - mountpoint = argv[2]; - - for (i = 3; i < argc; i++) { - if (strcmp(argv[i], "-v") == 0) { - continue; - } else if (strcmp(argv[i], "-t") == 0) { - i++; - - if (i == argc) { - fprintf(stderr, - "%s: missing argument to option '-t'\n", progname); - exit(1); - } - type = argv[i]; - if (strncmp(type, "fuse.", 5) == 0) - type += 5; - else if (strncmp(type, "fuseblk.", 8) == 0) - type += 8; - - if (!type[0]) { - fprintf(stderr, - "%s: empty type given as argument to option '-t'\n", - progname); - exit(1); - } - } else if (strcmp(argv[i], "-o") == 0) { - char *opts; - char *opt; - i++; - if (i == argc) - break; - - opts = xstrdup(argv[i]); - opt = strtok(opts, ","); - while (opt) { - int j; - int ignore = 0; - const char *ignore_opts[] = { "", "user", "nouser", "users", - "auto", "noauto", "_netdev", - NULL}; - if (strncmp(opt, "setuid=", 7) == 0) { - setuid = xstrdup(opt + 7); - ignore = 1; - } - for (j = 0; ignore_opts[j]; j++) - if (strcmp(opt, ignore_opts[j]) == 0) - ignore = 1; - - if (!ignore) { - int oldlen = options ? strlen(options) : 0; - options = xrealloc(options, oldlen + 1 + strlen(opt) + 1); - if (!oldlen) - strcpy(options, opt); - else { - strcat(options, ","); - strcat(options, opt); - } - } - opt = strtok(NULL, ","); - } - } - } - - if (!type) { - type = xstrdup(source); - source = strchr(type, '#'); - if (source) - *source++ = '\0'; - - if (!type[0]) { - fprintf(stderr, "%s: empty filesystem type\n", progname); - exit(1); - } - } - - add_arg(&command, type); - if (source) - add_arg(&command, source); - add_arg(&command, mountpoint); - if (options) { - add_arg(&command, "-o"); - add_arg(&command, options); - } - - if (setuid && setuid[0]) { - char *sucommand = command; - command = NULL; - add_arg(&command, "su"); - add_arg(&command, "-"); - add_arg(&command, setuid); - add_arg(&command, "-c"); - add_arg(&command, sucommand); - } else if (!getenv("HOME")) { - /* Hack to make filesystems work in the boot environment */ - setenv("HOME", "/root", 0); - } - - execl("/bin/sh", "/bin/sh", "-c", command, NULL); - fprintf(stderr, "%s: failed to execute /bin/sh: %s\n", progname, - strerror(errno)); - return 1; + char *type = NULL; + char *source; + const char *mountpoint; + char *basename; + char *options = NULL; + char *command = NULL; + char *setuid = NULL; + int i; + + progname = argv[0]; + basename = strrchr(argv[0], '/'); + if (basename) + basename++; + else + basename = argv[0]; + + if (strncmp(basename, "mount.fuse.", 11) == 0) + type = basename + 11; + if (strncmp(basename, "mount.fuseblk.", 14) == 0) + type = basename + 14; + + if (type && !type[0]) + type = NULL; + + if (argc < 3) { + fprintf(stderr, + "usage: %s %s destination [-t type] [-o opt[,opts...]]\n", + progname, type ? "source" : "type#[source]"); + exit(1); + } + + source = argv[1]; + if (!source[0]) + source = NULL; + + mountpoint = argv[2]; + + for (i = 3; i < argc; i++) { + if (strcmp(argv[i], "-v") == 0) { + continue; + } else if (strcmp(argv[i], "-t") == 0) { + i++; + + if (i == argc) { + fprintf(stderr, + "%s: missing argument to option '-t'\n", + progname); + exit(1); + } + type = argv[i]; + if (strncmp(type, "fuse.", 5) == 0) + type += 5; + else if (strncmp(type, "fuseblk.", 8) == 0) + type += 8; + + if (!type[0]) { + fprintf(stderr, + "%s: empty type given as argument to option '-t'\n", + progname); + exit(1); + } + } else if (strcmp(argv[i], "-o") == 0) { + char *opts; + char *opt; + i++; + if (i == argc) + break; + + opts = xstrdup(argv[i]); + opt = strtok(opts, ","); + while (opt) { + int j; + int ignore = 0; + const char *ignore_opts[] = { "", + "user", + "nouser", + "users", + "auto", + "noauto", + "_netdev", + NULL}; + if (strncmp(opt, "setuid=", 7) == 0) { + setuid = xstrdup(opt + 7); + ignore = 1; + } + for (j = 0; ignore_opts[j]; j++) + if (strcmp(opt, ignore_opts[j]) == 0) + ignore = 1; + + if (!ignore) { + int oldlen = + options ? strlen(options) : 0; + options = xrealloc(options, oldlen + 1 + strlen(opt) + 1); + if (!oldlen) + strcpy(options, opt); + else { + strcat(options, ","); + strcat(options, opt); + } + } + opt = strtok(NULL, ","); + } + } + } + + if (!type) { + type = xstrdup(source); + source = strchr(type, '#'); + if (source) + *source++ = '\0'; + + if (!type[0]) { + fprintf(stderr, "%s: empty filesystem type\n", + progname); + exit(1); + } + } + + add_arg(&command, type); + if (source) + add_arg(&command, source); + add_arg(&command, mountpoint); + if (options) { + add_arg(&command, "-o"); + add_arg(&command, options); + } + + if (setuid && setuid[0]) { + char *sucommand = command; + command = NULL; + add_arg(&command, "su"); + add_arg(&command, "-"); + add_arg(&command, setuid); + add_arg(&command, "-c"); + add_arg(&command, sucommand); + } else if (!getenv("HOME")) { + /* Hack to make filesystems work in the boot environment */ + setenv("HOME", "/root", 0); + } + + execl("/bin/sh", "/bin/sh", "-c", command, NULL); + fprintf(stderr, "%s: failed to execute /bin/sh: %s\n", progname, + strerror(errno)); + return 1; } diff --git a/util/ulockmgr_server.c b/util/ulockmgr_server.c index 4f831b0..8ffdfef 100644 --- a/util/ulockmgr_server.c +++ b/util/ulockmgr_server.c @@ -1,9 +1,9 @@ /* - ulockmgr_server: Userspace Lock Manager Server - Copyright (C) 2006 Miklos Szeredi + ulockmgr_server: Userspace Lock Manager Server + Copyright (C) 2006 Miklos Szeredi - This program can be distributed under the terms of the GNU GPL. - See the file COPYING. + This program can be distributed under the terms of the GNU GPL. + See the file COPYING. */ /* #define DEBUG 1 */ @@ -23,381 +23,388 @@ #include struct message { - unsigned intr : 1; - unsigned nofd : 1; - pthread_t thr; - int cmd; - int fd; - struct flock lock; - int error; + unsigned intr : 1; + unsigned nofd : 1; + pthread_t thr; + int cmd; + int fd; + struct flock lock; + int error; }; struct fd_store { - struct fd_store *next; - int fd; - int origfd; - int inuse; + struct fd_store *next; + int fd; + int origfd; + int inuse; }; struct owner { - struct fd_store *fds; - pthread_mutex_t lock; + struct fd_store *fds; + pthread_mutex_t lock; }; struct req_data { - struct owner *o; - int cfd; - struct fd_store *f; - struct message msg; + struct owner *o; + int cfd; + struct fd_store *f; + struct message msg; }; #define MAX_SEND_FDS 2 static int receive_message(int sock, void *buf, size_t buflen, int *fdp, - int *numfds) + int *numfds) { - struct msghdr msg; - struct iovec iov; - size_t ccmsg[CMSG_SPACE(sizeof(int) * MAX_SEND_FDS) / sizeof(size_t)]; - struct cmsghdr *cmsg; - int res; - int i; - - assert(*numfds <= MAX_SEND_FDS); - iov.iov_base = buf; - iov.iov_len = buflen; - - memset(&msg, 0, sizeof(msg)); - memset(ccmsg, -1, sizeof(ccmsg)); - msg.msg_iov = &iov; - msg.msg_iovlen = 1; - msg.msg_control = ccmsg; - msg.msg_controllen = sizeof(ccmsg); - - res = recvmsg(sock, &msg, MSG_WAITALL); - if (!res) { - /* retry on zero return, see do_recv() in ulockmgr.c */ - res = recvmsg(sock, &msg, MSG_WAITALL); - if (!res) - return 0; - } - if (res == -1) { - perror("ulockmgr_server: recvmsg"); - return -1; - } - if ((size_t) res != buflen) { - fprintf(stderr, "ulockmgr_server: short message received\n"); - return -1; - } - - cmsg = CMSG_FIRSTHDR(&msg); - if (cmsg) { - if (!cmsg->cmsg_type == SCM_RIGHTS) { - fprintf(stderr, "ulockmgr_server: unknown control message %d\n", - cmsg->cmsg_type); - return -1; - } - memcpy(fdp, CMSG_DATA(cmsg), sizeof(int) * *numfds); - if (msg.msg_flags & MSG_CTRUNC) { - fprintf(stderr, "ulockmgr_server: control message truncated\n"); - for (i = 0; i < *numfds; i++) - close(fdp[i]); - *numfds = 0; - } - } else { - if (msg.msg_flags & MSG_CTRUNC) { - fprintf(stderr, "ulockmgr_server: control message truncated(*)\n"); - - /* There's a bug in the Linux kernel, that if not all file - descriptors were allocated, then the cmsg header is not - filled in */ - cmsg = (struct cmsghdr *) ccmsg; - memcpy(fdp, CMSG_DATA(cmsg), sizeof(int) * *numfds); - for (i = 0; i < *numfds; i++) - close(fdp[i]); - } - *numfds = 0; - } - return res; + struct msghdr msg; + struct iovec iov; + size_t ccmsg[CMSG_SPACE(sizeof(int) * MAX_SEND_FDS) / sizeof(size_t)]; + struct cmsghdr *cmsg; + int res; + int i; + + assert(*numfds <= MAX_SEND_FDS); + iov.iov_base = buf; + iov.iov_len = buflen; + + memset(&msg, 0, sizeof(msg)); + memset(ccmsg, -1, sizeof(ccmsg)); + msg.msg_iov = &iov; + msg.msg_iovlen = 1; + msg.msg_control = ccmsg; + msg.msg_controllen = sizeof(ccmsg); + + res = recvmsg(sock, &msg, MSG_WAITALL); + if (!res) { + /* retry on zero return, see do_recv() in ulockmgr.c */ + res = recvmsg(sock, &msg, MSG_WAITALL); + if (!res) + return 0; + } + if (res == -1) { + perror("ulockmgr_server: recvmsg"); + return -1; + } + if ((size_t) res != buflen) { + fprintf(stderr, "ulockmgr_server: short message received\n"); + return -1; + } + + cmsg = CMSG_FIRSTHDR(&msg); + if (cmsg) { + if (!cmsg->cmsg_type == SCM_RIGHTS) { + fprintf(stderr, + "ulockmgr_server: unknown control message %d\n", + cmsg->cmsg_type); + return -1; + } + memcpy(fdp, CMSG_DATA(cmsg), sizeof(int) * *numfds); + if (msg.msg_flags & MSG_CTRUNC) { + fprintf(stderr, + "ulockmgr_server: control message truncated\n"); + for (i = 0; i < *numfds; i++) + close(fdp[i]); + *numfds = 0; + } + } else { + if (msg.msg_flags & MSG_CTRUNC) { + fprintf(stderr, + "ulockmgr_server: control message truncated(*)\n"); + + /* There's a bug in the Linux kernel, that if + not all file descriptors were allocated, + then the cmsg header is not filled in */ + cmsg = (struct cmsghdr *) ccmsg; + memcpy(fdp, CMSG_DATA(cmsg), sizeof(int) * *numfds); + for (i = 0; i < *numfds; i++) + close(fdp[i]); + } + *numfds = 0; + } + return res; } static int closefrom(int minfd) { - DIR *dir = opendir("/proc/self/fd"); - if (dir) { - int dfd = dirfd(dir); - struct dirent *ent; - while ((ent = readdir(dir))) { - char *end; - int fd = strtol(ent->d_name, &end, 10); - if (ent->d_name[0] && !end[0] && fd >= minfd && fd != dfd) - close(fd); - } - closedir(dir); - } - return 0; + DIR *dir = opendir("/proc/self/fd"); + if (dir) { + int dfd = dirfd(dir); + struct dirent *ent; + while ((ent = readdir(dir))) { + char *end; + int fd = strtol(ent->d_name, &end, 10); + if (ent->d_name[0] && !end[0] && fd >= minfd && + fd != dfd) + close(fd); + } + closedir(dir); + } + return 0; } static void send_reply(int cfd, struct message *msg) { - int res = send(cfd, msg, sizeof(struct message), MSG_NOSIGNAL); - if (res == -1) - perror("ulockmgr_server: sending reply"); + int res = send(cfd, msg, sizeof(struct message), MSG_NOSIGNAL); + if (res == -1) + perror("ulockmgr_server: sending reply"); #ifdef DEBUG - fprintf(stderr, "ulockmgr_server: error: %i\n", msg->error); + fprintf(stderr, "ulockmgr_server: error: %i\n", msg->error); #endif } static void *process_request(void *d_) { - struct req_data *d = d_; - int res; - - assert(d->msg.cmd == F_SETLKW); - res = fcntl(d->f->fd, F_SETLK, &d->msg.lock); - if (res == -1 && errno == EAGAIN) { - d->msg.error = EAGAIN; - d->msg.thr = pthread_self(); - send_reply(d->cfd, &d->msg); - res = fcntl(d->f->fd, F_SETLKW, &d->msg.lock); - } - d->msg.error = (res == -1) ? errno : 0; - pthread_mutex_lock(&d->o->lock); - d->f->inuse--; - pthread_mutex_unlock(&d->o->lock); - send_reply(d->cfd, &d->msg); - close(d->cfd); - free(d); - - return NULL; + struct req_data *d = d_; + int res; + + assert(d->msg.cmd == F_SETLKW); + res = fcntl(d->f->fd, F_SETLK, &d->msg.lock); + if (res == -1 && errno == EAGAIN) { + d->msg.error = EAGAIN; + d->msg.thr = pthread_self(); + send_reply(d->cfd, &d->msg); + res = fcntl(d->f->fd, F_SETLKW, &d->msg.lock); + } + d->msg.error = (res == -1) ? errno : 0; + pthread_mutex_lock(&d->o->lock); + d->f->inuse--; + pthread_mutex_unlock(&d->o->lock); + send_reply(d->cfd, &d->msg); + close(d->cfd); + free(d); + + return NULL; } static void process_message(struct owner *o, struct message *msg, int cfd, - int fd) + int fd) { - struct fd_store *f = NULL; - struct fd_store *newf = NULL; - struct fd_store **fp; - struct req_data *d; - pthread_t tid; - int res; + struct fd_store *f = NULL; + struct fd_store *newf = NULL; + struct fd_store **fp; + struct req_data *d; + pthread_t tid; + int res; #ifdef DEBUG - fprintf(stderr, "ulockmgr_server: %i %i %i %lli %lli\n", - msg->cmd, msg->lock.l_type, msg->lock.l_whence, msg->lock.l_start, - msg->lock.l_len); + fprintf(stderr, "ulockmgr_server: %i %i %i %lli %lli\n", + msg->cmd, msg->lock.l_type, msg->lock.l_whence, + msg->lock.l_start, msg->lock.l_len); #endif - if (msg->cmd == F_SETLK && msg->lock.l_type == F_UNLCK && - msg->lock.l_start == 0 && msg->lock.l_len == 0) { - for (fp = &o->fds; *fp;) { - f = *fp; - if (f->origfd == msg->fd && !f->inuse) { - close(f->fd); - *fp = f->next; - free(f); - } else - fp = &f->next; - } - if (!msg->nofd) - close(fd); - - msg->error = 0; - send_reply(cfd, msg); - close(cfd); - return; - } - - if (msg->nofd) { - for (fp = &o->fds; *fp; fp = &(*fp)->next) { - f = *fp; - if (f->origfd == msg->fd) - break; - } - if (!*fp) { - fprintf(stderr, "ulockmgr_server: fd %i not found\n", msg->fd); - msg->error = EIO; - send_reply(cfd, msg); - close(cfd); - return; - } - } else { - newf = f = malloc(sizeof(struct fd_store)); - if (!f) { - msg->error = ENOLCK; - send_reply(cfd, msg); - close(cfd); - return; - } - - f->fd = fd; - f->origfd = msg->fd; - f->inuse = 0; - } - - if (msg->cmd == F_GETLK || msg->cmd == F_SETLK || - msg->lock.l_type == F_UNLCK) { - res = fcntl(f->fd, msg->cmd, &msg->lock); - msg->error = (res == -1) ? errno : 0; - send_reply(cfd, msg); - close(cfd); - if (newf) { - newf->next = o->fds; - o->fds = newf; - } - return; - } - - d = malloc(sizeof(struct req_data)); - if (!d) { - msg->error = ENOLCK; - send_reply(cfd, msg); - close(cfd); - free(newf); - return; - } - - f->inuse++; - d->o = o; - d->cfd = cfd; - d->f = f; - d->msg = *msg; - res = pthread_create(&tid, NULL, process_request, d); - if (res) { - msg->error = ENOLCK; - send_reply(cfd, msg); - close(cfd); - free(d); - f->inuse--; - free(newf); - return; - } - - if (newf) { - newf->next = o->fds; - o->fds = newf; - } - pthread_detach(tid); + if (msg->cmd == F_SETLK && msg->lock.l_type == F_UNLCK && + msg->lock.l_start == 0 && msg->lock.l_len == 0) { + for (fp = &o->fds; *fp;) { + f = *fp; + if (f->origfd == msg->fd && !f->inuse) { + close(f->fd); + *fp = f->next; + free(f); + } else + fp = &f->next; + } + if (!msg->nofd) + close(fd); + + msg->error = 0; + send_reply(cfd, msg); + close(cfd); + return; + } + + if (msg->nofd) { + for (fp = &o->fds; *fp; fp = &(*fp)->next) { + f = *fp; + if (f->origfd == msg->fd) + break; + } + if (!*fp) { + fprintf(stderr, "ulockmgr_server: fd %i not found\n", + msg->fd); + msg->error = EIO; + send_reply(cfd, msg); + close(cfd); + return; + } + } else { + newf = f = malloc(sizeof(struct fd_store)); + if (!f) { + msg->error = ENOLCK; + send_reply(cfd, msg); + close(cfd); + return; + } + + f->fd = fd; + f->origfd = msg->fd; + f->inuse = 0; + } + + if (msg->cmd == F_GETLK || msg->cmd == F_SETLK || + msg->lock.l_type == F_UNLCK) { + res = fcntl(f->fd, msg->cmd, &msg->lock); + msg->error = (res == -1) ? errno : 0; + send_reply(cfd, msg); + close(cfd); + if (newf) { + newf->next = o->fds; + o->fds = newf; + } + return; + } + + d = malloc(sizeof(struct req_data)); + if (!d) { + msg->error = ENOLCK; + send_reply(cfd, msg); + close(cfd); + free(newf); + return; + } + + f->inuse++; + d->o = o; + d->cfd = cfd; + d->f = f; + d->msg = *msg; + res = pthread_create(&tid, NULL, process_request, d); + if (res) { + msg->error = ENOLCK; + send_reply(cfd, msg); + close(cfd); + free(d); + f->inuse--; + free(newf); + return; + } + + if (newf) { + newf->next = o->fds; + o->fds = newf; + } + pthread_detach(tid); } static void sigusr1_handler(int sig) { - (void) sig; - /* Nothing to do */ + (void) sig; + /* Nothing to do */ } static void process_owner(int cfd) { - struct owner o; - struct sigaction sa; - - memset(&sa, 0, sizeof(struct sigaction)); - sa.sa_handler = sigusr1_handler; - sigemptyset(&sa.sa_mask); - - if (sigaction(SIGUSR1, &sa, NULL) == -1) { - perror("ulockmgr_server: cannot set sigusr1 signal handler"); - exit(1); - } - - memset(&o, 0, sizeof(struct owner)); - pthread_mutex_init(&o.lock, NULL); - while (1) { - struct message msg; - int rfds[2]; - int res; - int numfds = 2; - - res = receive_message(cfd, &msg, sizeof(msg), rfds, &numfds); - if (!res) - break; - if (res == -1) - exit(1); - - if (msg.intr) { - if (numfds != 0) - fprintf(stderr, "ulockmgr_server: too many fds for intr\n"); - pthread_kill(msg.thr, SIGUSR1); - } else { - if (numfds != 2) - continue; - - pthread_mutex_lock(&o.lock); - process_message(&o, &msg, rfds[0], rfds[1]); - pthread_mutex_unlock(&o.lock); - } - } - if (o.fds) - fprintf(stderr, "ulockmgr_server: open file descriptors on exit\n"); + struct owner o; + struct sigaction sa; + + memset(&sa, 0, sizeof(struct sigaction)); + sa.sa_handler = sigusr1_handler; + sigemptyset(&sa.sa_mask); + + if (sigaction(SIGUSR1, &sa, NULL) == -1) { + perror("ulockmgr_server: cannot set sigusr1 signal handler"); + exit(1); + } + + memset(&o, 0, sizeof(struct owner)); + pthread_mutex_init(&o.lock, NULL); + while (1) { + struct message msg; + int rfds[2]; + int res; + int numfds = 2; + + res = receive_message(cfd, &msg, sizeof(msg), rfds, &numfds); + if (!res) + break; + if (res == -1) + exit(1); + + if (msg.intr) { + if (numfds != 0) + fprintf(stderr, + "ulockmgr_server: too many fds for intr\n"); + pthread_kill(msg.thr, SIGUSR1); + } else { + if (numfds != 2) + continue; + + pthread_mutex_lock(&o.lock); + process_message(&o, &msg, rfds[0], rfds[1]); + pthread_mutex_unlock(&o.lock); + } + } + if (o.fds) + fprintf(stderr, + "ulockmgr_server: open file descriptors on exit\n"); } int main(int argc, char *argv[]) { - int nullfd; - char *end; - int cfd; - sigset_t empty; - - if (argc != 2 || !argv[1][0]) - goto out_inval; - - cfd = strtol(argv[1], &end, 10); - if (*end) - goto out_inval; - - if (daemon(0, 1) == -1) { - perror("ulockmgr_server: daemon"); - exit(1); - } - - sigemptyset(&empty); - sigprocmask(SIG_SETMASK, &empty, NULL); - - if (dup2(cfd, 4) == -1) { - perror("ulockmgr_server: dup2"); - exit(1); - } - cfd = 4; - nullfd = open("/dev/null", O_RDWR); - dup2(nullfd, 0); - dup2(nullfd, 1); - close(3); - closefrom(5); - while (1) { - char c; - int sock; - int pid; - int numfds = 1; - int res = receive_message(cfd, &c, sizeof(c), &sock, &numfds); - if (!res) - break; - if (res == -1) - exit(1); - assert(numfds == 1); - - pid = fork(); - if (pid == -1) { - perror("ulockmgr_server: fork"); - close(sock); - continue; - } - if (pid == 0) { - close(cfd); - pid = fork(); - if (pid == -1) { - perror("ulockmgr_server: fork"); - _exit(1); - } - if (pid == 0) - process_owner(sock); - _exit(0); - } - waitpid(pid, NULL, 0); - close(sock); - } - return 0; - - out_inval: - fprintf(stderr, "%s should be started by libulockmgr\n", argv[0]); - return 1; + int nullfd; + char *end; + int cfd; + sigset_t empty; + + if (argc != 2 || !argv[1][0]) + goto out_inval; + + cfd = strtol(argv[1], &end, 10); + if (*end) + goto out_inval; + + if (daemon(0, 1) == -1) { + perror("ulockmgr_server: daemon"); + exit(1); + } + + sigemptyset(&empty); + sigprocmask(SIG_SETMASK, &empty, NULL); + + if (dup2(cfd, 4) == -1) { + perror("ulockmgr_server: dup2"); + exit(1); + } + cfd = 4; + nullfd = open("/dev/null", O_RDWR); + dup2(nullfd, 0); + dup2(nullfd, 1); + close(3); + closefrom(5); + while (1) { + char c; + int sock; + int pid; + int numfds = 1; + int res = receive_message(cfd, &c, sizeof(c), &sock, &numfds); + if (!res) + break; + if (res == -1) + exit(1); + assert(numfds == 1); + + pid = fork(); + if (pid == -1) { + perror("ulockmgr_server: fork"); + close(sock); + continue; + } + if (pid == 0) { + close(cfd); + pid = fork(); + if (pid == -1) { + perror("ulockmgr_server: fork"); + _exit(1); + } + if (pid == 0) + process_owner(sock); + _exit(0); + } + waitpid(pid, NULL, 0); + close(sock); + } + return 0; + +out_inval: + fprintf(stderr, "%s should be started by libulockmgr\n", argv[0]); + return 1; } -- cgit v1.2.3