diff options
author | Stefan Siegl <stesie@brokenpipe.de> | 2006-04-13 22:52:47 +0000 |
---|---|---|
committer | Stefan Siegl <stesie@brokenpipe.de> | 2006-04-13 22:52:47 +0000 |
commit | 5147e9e1b0e63b00b4fb7a04720da591a5f6c024 (patch) | |
tree | adc11c0bff93d1fe5eb2bccc467ee044886fc1af | |
parent | c2552b393a785f7ba9872215695ff3a22cbdfd5f (diff) |
pulled in headers from fuse 2.5.3 and added examples. fuse_ops variable renamed to fuse_ops_compat22 (to make room for 2.5 api functions).
-rw-r--r-- | configure.ac | 5 | ||||
-rw-r--r-- | example-23/Makefile.am | 2 | ||||
-rw-r--r-- | example-24/Makefile.am | 2 | ||||
-rw-r--r-- | example-25/.cvsignore | 8 | ||||
-rw-r--r-- | example-25/Makefile.am | 12 | ||||
-rw-r--r-- | example-25/fusexmp.c | 373 | ||||
-rw-r--r-- | example-25/fusexmp_fh.c | 418 | ||||
-rw-r--r-- | example-25/hello.c | 94 | ||||
-rw-r--r-- | example-25/hello_ll.c | 177 | ||||
-rw-r--r-- | example-25/null.c | 88 | ||||
-rw-r--r-- | include/fuse.h | 234 | ||||
-rw-r--r-- | include/fuse_common.h | 117 | ||||
-rw-r--r-- | include/fuse_compat.h | 64 | ||||
-rw-r--r-- | include/fuse_opt.h | 227 | ||||
-rw-r--r-- | src/fuse_i.h | 20 | ||||
-rw-r--r-- | src/main.c | 51 | ||||
-rw-r--r-- | src/netfs.c | 90 | ||||
-rw-r--r-- | src/netnode.c | 7 |
18 files changed, 1832 insertions, 157 deletions
diff --git a/configure.ac b/configure.ac index 90a2fa81b..1f1676004 100644 --- a/configure.ac +++ b/configure.ac @@ -5,7 +5,7 @@ AC_PREREQ(2.59) AC_INIT(libfuse, 0.1, hurdextras-hackers@nongnu.org) -AC_REVISION($Revision: 1.8 $) +AC_REVISION($Revision: 1.9 $) AC_CONFIG_SRCDIR(src/main.c) AM_CONFIG_HEADER(config.h) @@ -44,5 +44,6 @@ AC_CONFIG_FILES([fuse.pc Makefile] [example/Makefile example-22/Makefile example-23/Makefile - example-24/Makefile]) + example-24/Makefile + example-25/Makefile]) AC_OUTPUT diff --git a/example-23/Makefile.am b/example-23/Makefile.am index 44f1bfe50..849cebd6e 100644 --- a/example-23/Makefile.am +++ b/example-23/Makefile.am @@ -8,4 +8,4 @@ null_SOURCES = null.c hello_SOURCES = hello.c LDADD = ../src/libfuse.la -AM_CPPFLAGS = -DFUSE_USE_VERSION=23 -I$(top_srcdir) -I$(top_srcdir)/include +AM_CPPFLAGS = -DFUSE_USE_VERSION=22 -I$(top_srcdir) -I$(top_srcdir)/include diff --git a/example-24/Makefile.am b/example-24/Makefile.am index 8a875b8df..15284f816 100644 --- a/example-24/Makefile.am +++ b/example-24/Makefile.am @@ -9,4 +9,4 @@ null_SOURCES = null.c hello_SOURCES = hello.c LDADD = ../src/libfuse.la -AM_CPPFLAGS = -DFUSE_USE_VERSION=23 -I$(top_srcdir) -I$(top_srcdir)/include +AM_CPPFLAGS = -DFUSE_USE_VERSION=22 -I$(top_srcdir) -I$(top_srcdir)/include diff --git a/example-25/.cvsignore b/example-25/.cvsignore new file mode 100644 index 000000000..80eb82bdb --- /dev/null +++ b/example-25/.cvsignore @@ -0,0 +1,8 @@ +Makefile.in +Makefile +.deps +fusexmp +fusexmp_fh +null +hello +.libs diff --git a/example-25/Makefile.am b/example-25/Makefile.am new file mode 100644 index 000000000..0ed939a32 --- /dev/null +++ b/example-25/Makefile.am @@ -0,0 +1,12 @@ +## Process this file with automake to produce Makefile.in + +noinst_PROGRAMS = fusexmp fusexmp_fh null hello +# low-level api not supported: hello_ll + +fusexmp_SOURCES = fusexmp.c +fusexmp_fh_SOURCES = fusexmp_fh.c +null_SOURCES = null.c +hello_SOURCES = hello.c + +LDADD = ../src/libfuse.la +AM_CPPFLAGS = -DFUSE_USE_VERSION=25 -I$(top_srcdir) -I$(top_srcdir)/include diff --git a/example-25/fusexmp.c b/example-25/fusexmp.c new file mode 100644 index 000000000..172dc883f --- /dev/null +++ b/example-25/fusexmp.c @@ -0,0 +1,373 @@ +/* + FUSE: Filesystem in Userspace + Copyright (C) 2001-2006 Miklos Szeredi <miklos@szeredi.hu> + + This program can be distributed under the terms of the GNU GPL. + See the file COPYING. +*/ + +#include <config.h> + +#ifdef linux +/* For pread()/pwrite() */ +#define _XOPEN_SOURCE 500 +#endif + +#include <fuse.h> +#include <stdio.h> +#include <string.h> +#include <unistd.h> +#include <fcntl.h> +#include <dirent.h> +#include <errno.h> +#ifdef HAVE_SETXATTR +#include <sys/xattr.h> +#endif + +static int xmp_getattr(const char *path, struct stat *stbuf) +{ + int res; + + res = lstat(path, stbuf); + if (res == -1) + return -errno; + + return 0; +} + +static int xmp_access(const char *path, int mask) +{ + int res; + + res = access(path, mask); + if (res == -1) + return -errno; + + return 0; +} + +static int xmp_readlink(const char *path, char *buf, size_t size) +{ + int res; + + res = readlink(path, buf, size - 1); + if (res == -1) + return -errno; + + buf[res] = '\0'; + return 0; +} + + +static int xmp_readdir(const char *path, void *buf, fuse_fill_dir_t filler, + off_t offset, struct fuse_file_info *fi) +{ + 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; +} + +static int xmp_mkdir(const char *path, mode_t mode) +{ + int res; + + res = mkdir(path, mode); + if (res == -1) + return -errno; + + return 0; +} + +static int xmp_unlink(const char *path) +{ + int res; + + res = unlink(path); + if (res == -1) + return -errno; + + return 0; +} + +static int xmp_rmdir(const char *path) +{ + int res; + + res = rmdir(path); + if (res == -1) + return -errno; + + return 0; +} + +static int xmp_symlink(const char *from, const char *to) +{ + int res; + + res = symlink(from, to); + if (res == -1) + return -errno; + + return 0; +} + +static int xmp_rename(const char *from, const char *to) +{ + int res; + + res = rename(from, to); + if (res == -1) + return -errno; + + return 0; +} + +static int xmp_link(const char *from, const char *to) +{ + int res; + + res = link(from, to); + if (res == -1) + return -errno; + + return 0; +} + +static int xmp_chmod(const char *path, mode_t mode) +{ + int res; + + res = chmod(path, mode); + if (res == -1) + return -errno; + + return 0; +} + +static int xmp_chown(const char *path, uid_t uid, gid_t gid) +{ + int res; + + res = lchown(path, uid, gid); + if (res == -1) + return -errno; + + return 0; +} + +static int xmp_truncate(const char *path, off_t size) +{ + int res; + + res = truncate(path, size); + if (res == -1) + return -errno; + + return 0; +} + +static int xmp_utime(const char *path, struct utimbuf *buf) +{ + int res; + + res = utime(path, buf); + if (res == -1) + return -errno; + + return 0; +} + + +static int xmp_open(const char *path, struct fuse_file_info *fi) +{ + int res; + + res = open(path, fi->flags); + if (res == -1) + return -errno; + + close(res); + return 0; +} + +static int xmp_read(const char *path, char *buf, size_t size, off_t offset, + struct fuse_file_info *fi) +{ + int fd; + int res; + + (void) fi; + fd = open(path, O_RDONLY); + if (fd == -1) + return -errno; + + res = pread(fd, buf, size, offset); + if (res == -1) + res = -errno; + + close(fd); + return res; +} + +static int xmp_write(const char *path, const char *buf, size_t size, + off_t offset, struct fuse_file_info *fi) +{ + int fd; + int res; + + (void) fi; + fd = open(path, O_WRONLY); + if (fd == -1) + return -errno; + + res = pwrite(fd, buf, size, offset); + if (res == -1) + res = -errno; + + close(fd); + return res; +} + +static int xmp_statfs(const char *path, struct statvfs *stbuf) +{ + int res; + + res = statvfs(path, stbuf); + if (res == -1) + return -errno; + + return 0; +} + +static int xmp_release(const char *path, struct fuse_file_info *fi) +{ + /* Just a stub. This method is optional and can safely be left + unimplemented */ + + (void) path; + (void) fi; + return 0; +} + +static int xmp_fsync(const char *path, int isdatasync, + struct fuse_file_info *fi) +{ + /* Just a stub. This method is optional and can safely be left + unimplemented */ + + (void) path; + (void) isdatasync; + (void) fi; + return 0; +} + +#ifdef HAVE_SETXATTR +/* xattr operations are optional and can safely be left unimplemented */ +static int xmp_setxattr(const char *path, const char *name, const char *value, + size_t size, int flags) +{ + int res = lsetxattr(path, name, value, size, flags); + if (res == -1) + return -errno; + return 0; +} + +static int xmp_getxattr(const char *path, const char *name, char *value, + size_t size) +{ + int res = lgetxattr(path, name, value, size); + if (res == -1) + return -errno; + return res; +} + +static int xmp_listxattr(const char *path, char *list, size_t size) +{ + int res = llistxattr(path, list, size); + if (res == -1) + return -errno; + return res; +} + +static int xmp_removexattr(const char *path, const char *name) +{ + int res = lremovexattr(path, name); + if (res == -1) + return -errno; + return 0; +} +#endif /* HAVE_SETXATTR */ + +static struct fuse_operations xmp_oper = { + .getattr = xmp_getattr, + .access = xmp_access, + .readlink = xmp_readlink, + .readdir = xmp_readdir, + .mknod = xmp_mknod, + .mkdir = xmp_mkdir, + .symlink = xmp_symlink, + .unlink = xmp_unlink, + .rmdir = xmp_rmdir, + .rename = xmp_rename, + .link = xmp_link, + .chmod = xmp_chmod, + .chown = xmp_chown, + .truncate = xmp_truncate, + .utime = xmp_utime, + .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, +#endif +}; + +int main(int argc, char *argv[]) +{ + umask(0); + return fuse_main(argc, argv, &xmp_oper); +} diff --git a/example-25/fusexmp_fh.c b/example-25/fusexmp_fh.c new file mode 100644 index 000000000..3ff6c9dc5 --- /dev/null +++ b/example-25/fusexmp_fh.c @@ -0,0 +1,418 @@ +/* + FUSE: Filesystem in Userspace + Copyright (C) 2001-2006 Miklos Szeredi <miklos@szeredi.hu> + + This program can be distributed under the terms of the GNU GPL. + See the file COPYING. +*/ + +#include <config.h> + +#define _GNU_SOURCE + +#include <fuse.h> +#include <stdio.h> +#include <string.h> +#include <unistd.h> +#include <fcntl.h> +#include <dirent.h> +#include <errno.h> +#ifdef HAVE_SETXATTR +#include <sys/xattr.h> +#endif + +static int xmp_getattr(const char *path, struct stat *stbuf) +{ + int res; + + res = lstat(path, stbuf); + if (res == -1) + return -errno; + + return 0; +} + +static int xmp_fgetattr(const char *path, struct stat *stbuf, + struct fuse_file_info *fi) +{ + int res; + + (void) path; + + res = fstat(fi->fh, stbuf); + if (res == -1) + return -errno; + + return 0; +} + +static int xmp_access(const char *path, int mask) +{ + int res; + + res = access(path, mask); + if (res == -1) + return -errno; + + return 0; +} + +static int xmp_readlink(const char *path, char *buf, size_t size) +{ + int res; + + res = readlink(path, buf, size - 1); + if (res == -1) + return -errno; + + buf[res] = '\0'; + return 0; +} + +static int xmp_opendir(const char *path, struct fuse_file_info *fi) +{ + DIR *dp = opendir(path); + if (dp == NULL) + return -errno; + + fi->fh = (unsigned long) dp; + return 0; +} + +static inline DIR *get_dirp(struct fuse_file_info *fi) +{ + 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) +{ + 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; + } + + 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; +} + +static int xmp_mknod(const char *path, mode_t mode, dev_t rdev) +{ + int res; + + if (S_ISFIFO(mode)) + res = mkfifo(path, mode); + else + res = mknod(path, mode, rdev); + if (res == -1) + return -errno; + + return 0; +} + +static int xmp_mkdir(const char *path, mode_t mode) +{ + int res; + + res = mkdir(path, mode); + if (res == -1) + return -errno; + + return 0; +} + +static int xmp_unlink(const char *path) +{ + int res; + + res = unlink(path); + if (res == -1) + return -errno; + + return 0; +} + +static int xmp_rmdir(const char *path) +{ + int res; + + res = rmdir(path); + if (res == -1) + return -errno; + + return 0; +} + +static int xmp_symlink(const char *from, const char *to) +{ + int res; + + res = symlink(from, to); + if (res == -1) + return -errno; + + return 0; +} + +static int xmp_rename(const char *from, const char *to) +{ + int res; + + res = rename(from, to); + if (res == -1) + return -errno; + + return 0; +} + +static int xmp_link(const char *from, const char *to) +{ + int res; + + res = link(from, to); + if (res == -1) + return -errno; + + return 0; +} + +static int xmp_chmod(const char *path, mode_t mode) +{ + int res; + + res = chmod(path, mode); + if (res == -1) + return -errno; + + return 0; +} + +static int xmp_chown(const char *path, uid_t uid, gid_t gid) +{ + int res; + + res = lchown(path, uid, gid); + if (res == -1) + return -errno; + + return 0; +} + +static int xmp_truncate(const char *path, off_t size) +{ + int res; + + res = truncate(path, size); + if (res == -1) + return -errno; + + return 0; +} + +static int xmp_ftruncate(const char *path, off_t size, + struct fuse_file_info *fi) +{ + int res; + + (void) path; + + res = ftruncate(fi->fh, size); + if (res == -1) + return -errno; + + return 0; +} + +static int xmp_utime(const char *path, struct utimbuf *buf) +{ + int res; + + res = utime(path, buf); + if (res == -1) + return -errno; + + return 0; +} + +static int xmp_create(const char *path, mode_t mode, struct fuse_file_info *fi) +{ + int fd; + + fd = open(path, fi->flags, mode); + if (fd == -1) + return -errno; + + fi->fh = fd; + return 0; +} + +static int xmp_open(const char *path, struct fuse_file_info *fi) +{ + int fd; + + fd = open(path, fi->flags); + if (fd == -1) + return -errno; + + fi->fh = fd; + return 0; +} + +static int xmp_read(const char *path, char *buf, size_t size, off_t offset, + struct fuse_file_info *fi) +{ + int res; + + (void) path; + res = pread(fi->fh, buf, size, offset); + if (res == -1) + res = -errno; + + return res; +} + +static int xmp_write(const char *path, const char *buf, size_t size, + off_t offset, struct fuse_file_info *fi) +{ + int res; + + (void) path; + res = pwrite(fi->fh, buf, size, offset); + if (res == -1) + res = -errno; + + return res; +} + +static int xmp_statfs(const char *path, struct statvfs *stbuf) +{ + int res; + + res = statvfs(path, stbuf); + if (res == -1) + return -errno; + + return 0; +} + +static int xmp_release(const char *path, struct fuse_file_info *fi) +{ + (void) path; + close(fi->fh); + + return 0; +} + +static int xmp_fsync(const char *path, int isdatasync, + struct fuse_file_info *fi) +{ + int res; + (void) path; + +#ifndef HAVE_FDATASYNC + (void) isdatasync; +#else + if (isdatasync) + res = fdatasync(fi->fh); + else +#endif + res = fsync(fi->fh); + if (res == -1) + return -errno; + + return 0; +} + +#ifdef HAVE_SETXATTR +/* xattr operations are optional and can safely be left unimplemented */ +static int xmp_setxattr(const char *path, const char *name, const char *value, + size_t size, int flags) +{ + int res = lsetxattr(path, name, value, size, flags); + if (res == -1) + return -errno; + return 0; +} + +static int xmp_getxattr(const char *path, const char *name, char *value, + size_t size) +{ + int res = lgetxattr(path, name, value, size); + if (res == -1) + return -errno; + return res; +} + +static int xmp_listxattr(const char *path, char *list, size_t size) +{ + int res = llistxattr(path, list, size); + if (res == -1) + return -errno; + return res; +} + +static int xmp_removexattr(const char *path, const char *name) +{ + int res = lremovexattr(path, name); + if (res == -1) + return -errno; + return 0; +} +#endif /* HAVE_SETXATTR */ + +static struct fuse_operations xmp_oper = { + .getattr = xmp_getattr, + .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, + .utime = xmp_utime, + .create = xmp_create, + .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, +#endif +}; + +int main(int argc, char *argv[]) +{ + umask(0); + return fuse_main(argc, argv, &xmp_oper); +} diff --git a/example-25/hello.c b/example-25/hello.c new file mode 100644 index 000000000..8ab718174 --- /dev/null +++ b/example-25/hello.c @@ -0,0 +1,94 @@ +/* + FUSE: Filesystem in Userspace + Copyright (C) 2001-2006 Miklos Szeredi <miklos@szeredi.hu> + + This program can be distributed under the terms of the GNU GPL. + See the file COPYING. +*/ + +#include <fuse.h> +#include <stdio.h> +#include <string.h> +#include <errno.h> +#include <fcntl.h> + +static const char *hello_str = "Hello World!\n"; +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; +} + +static int hello_readdir(const char *path, void *buf, fuse_fill_dir_t filler, + off_t offset, struct fuse_file_info *fi) +{ + (void) offset; + (void) fi; + + if(strcmp(path, "/") != 0) + return -ENOENT; + + filler(buf, ".", NULL, 0); + filler(buf, "..", NULL, 0); + filler(buf, hello_path + 1, NULL, 0); + + return 0; +} + +static int hello_open(const char *path, struct fuse_file_info *fi) +{ + if(strcmp(path, hello_path) != 0) + return -ENOENT; + + if((fi->flags & 3) != O_RDONLY) + return -EACCES; + + return 0; +} + +static int hello_read(const char *path, char *buf, size_t size, off_t offset, + 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; +} + +static struct fuse_operations hello_oper = { + .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); +} diff --git a/example-25/hello_ll.c b/example-25/hello_ll.c new file mode 100644 index 000000000..7682f4eaf --- /dev/null +++ b/example-25/hello_ll.c @@ -0,0 +1,177 @@ +/* + FUSE: Filesystem in Userspace + Copyright (C) 2001-2006 Miklos Szeredi <miklos@szeredi.hu> + + This program can be distributed under the terms of the GNU GPL. + See the file COPYING. +*/ + +#include <fuse_lowlevel.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <errno.h> +#include <fcntl.h> +#include <unistd.h> +#include <assert.h> + +static const char *hello_str = "Hello World!\n"; +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; +} + +static void hello_ll_getattr(fuse_req_t req, fuse_ino_t ino, + struct fuse_file_info *fi) +{ + struct stat stbuf; + + (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); +} + +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 dirbuf { + char *p; + size_t size; +}; + +static void dirbuf_add(struct dirbuf *b, const char *name, fuse_ino_t ino) +{ + struct stat stbuf; + size_t oldsize = b->size; + b->size += fuse_dirent_size(strlen(name)); + b->p = (char *) realloc(b->p, b->size); + memset(&stbuf, 0, sizeof(stbuf)); + stbuf.st_ino = ino; + fuse_add_dirent(b->p + 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) +{ + 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) +{ + (void) fi; + + if (ino != 1) + fuse_reply_err(req, ENOTDIR); + else { + struct dirbuf b; + + memset(&b, 0, sizeof(b)); + dirbuf_add(&b, ".", 1); + dirbuf_add(&b, "..", 1); + dirbuf_add(&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) +{ + 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) +{ + (void) fi; + + 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, +}; + +int main(int argc, char *argv[]) +{ + struct fuse_args args = FUSE_ARGS_INIT(argc, argv); + char *mountpoint; + int err = -1; + int fd; + + if (fuse_parse_cmdline(&args, &mountpoint, NULL, NULL) != -1 && + (fd = fuse_mount(mountpoint, &args)) != -1) { + 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) { + struct fuse_chan *ch = fuse_kern_chan_new(fd); + if (ch != NULL) { + fuse_session_add_chan(se, ch); + err = fuse_session_loop(se); + } + fuse_remove_signal_handlers(se); + } + fuse_session_destroy(se); + } + close(fd); + } + fuse_unmount(mountpoint); + fuse_opt_free_args(&args); + + return err ? 1 : 0; +} diff --git a/example-25/null.c b/example-25/null.c new file mode 100644 index 000000000..82e7c452d --- /dev/null +++ b/example-25/null.c @@ -0,0 +1,88 @@ +/* + FUSE: Filesystem in Userspace + Copyright (C) 2001-2006 Miklos Szeredi <miklos@szeredi.hu> + + This program can be distributed under the terms of the GNU GPL. + See the file COPYING. +*/ + +#include <fuse.h> +#include <string.h> +#include <unistd.h> +#include <time.h> +#include <errno.h> + +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; +} + +static int null_truncate(const char *path, off_t size) +{ + (void) size; + + if(strcmp(path, "/") != 0) + return -ENOENT; + + return 0; +} + +static int null_open(const char *path, struct fuse_file_info *fi) +{ + (void) fi; + + if(strcmp(path, "/") != 0) + return -ENOENT; + + return 0; +} + +static int null_read(const char *path, char *buf, size_t size, + off_t offset, struct fuse_file_info *fi) +{ + (void) buf; + (void) offset; + (void) fi; + + if(strcmp(path, "/") != 0) + return -ENOENT; + + return size; +} + +static int null_write(const char *path, const char *buf, size_t size, + off_t offset, struct fuse_file_info *fi) +{ + (void) buf; + (void) offset; + (void) fi; + + if(strcmp(path, "/") != 0) + return -ENOENT; + + return size; +} + +static struct fuse_operations null_oper = { + .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); +} diff --git a/include/fuse.h b/include/fuse.h index fb1c2d6df..eb41c75ec 100644 --- a/include/fuse.h +++ b/include/fuse.h @@ -1,6 +1,6 @@ /* FUSE: Filesystem in Userspace - Copyright (C) 2001-2005 Miklos Szeredi <miklos@szeredi.hu> + Copyright (C) 2001-2006 Miklos Szeredi <miklos@szeredi.hu> This program can be distributed under the terms of the GNU LGPL. See the file COPYING.LIB. @@ -12,28 +12,19 @@ /* This file defines the library interface of FUSE */ /* IMPORTANT: you should define FUSE_USE_VERSION before including this - header. To use the new API define it to 22 (recommended for any - new application), to use the old API define it to 21 (this is the - default), to use the even older 1.X API define it to 11. */ + header. To use the newest API define it to 25 (recommended for any + new application), to use the old API define it to 21 (default) or + 22, to use the even older 1.X API define it to 11. */ #ifndef FUSE_USE_VERSION #define FUSE_USE_VERSION 21 #endif -/** Major version of FUSE library interface */ -#define FUSE_MAJOR_VERSION 2 - -/** Minor version of FUSE library interface */ -#define FUSE_MINOR_VERSION 3 - -/* This interface uses 64 bit off_t */ -#if _FILE_OFFSET_BITS != 64 -#error Please add -D_FILE_OFFSET_BITS=64 to your compile flags! -#endif +#include "fuse_common.h" #include <sys/types.h> #include <sys/stat.h> -#include <sys/statfs.h> +#include <sys/statvfs.h> #include <utime.h> #ifdef __cplusplus @@ -47,6 +38,9 @@ extern "C" { /** Handle for a FUSE filesystem */ struct fuse; +/** Structure containing a raw command */ +struct fuse_cmd; + /** Function to add an entry in a readdir() operation * * @param buf the buffer passed to the readdir() operation @@ -56,27 +50,13 @@ struct fuse; * @return 1 if buffer is full, zero otherwise */ typedef int (*fuse_fill_dir_t) (void *buf, const char *name, - const struct stat *stat, 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); -/** Information about open files */ -struct fuse_file_info { - /** Open flags. Available in open() and release() */ - int flags; - - /** File handle. May be filled in by filesystem in open(). - Available in all other file operations */ - unsigned long fh; - - /** In case of a write operation indicates if this was caused by a - writepage */ - int writepage; -}; - /** * The file system operations: * @@ -86,10 +66,10 @@ struct fuse_file_info { * negated error value (-errno) directly. * * All methods are optional, but some are essential for a useful - * filesystem (e.g. getattr). Flush, release, fsync, opendir, - * releasedir, fsyncdir, init and destroy are special purpose - * methods, without which a full featured filesystem can still be - * implemented. + * filesystem (e.g. getattr). Open, flush, release, fsync, opendir, + * releasedir, fsyncdir, access, create, ftruncate, fgetattr, init and + * destroy are special purpose methods, without which a full featured + * filesystem can still be implemented. */ struct fuse_operations { /** Get file attributes. @@ -152,11 +132,13 @@ struct fuse_operations { /** File open operation * - * No creation, or trunctation flags (O_CREAT, O_EXCL, O_TRUNC) + * 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 arbitary filehandle in the fuse_file_info structure, + * 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 *); @@ -168,6 +150,8 @@ struct fuse_operations { * '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 *); @@ -176,15 +160,21 @@ struct fuse_operations { * 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 *); + /** Just a placeholder, don't set */ /** Get file system statistics * - * The 'f_type' and 'f_fsid' fields are ignored + * 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 statfs *); + int (*statfs) (const char *, struct statvfs *); /** Possibly flush cached data * @@ -203,6 +193,11 @@ struct fuse_operations { * 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 *); @@ -217,6 +212,8 @@ struct fuse_operations { * 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 *); @@ -224,6 +221,8 @@ struct fuse_operations { * * 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 *); @@ -239,10 +238,12 @@ struct fuse_operations { /** Remove extended attributes */ int (*removexattr) (const char *, const char *); - /** Open direcory + /** 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 *); @@ -264,17 +265,24 @@ struct fuse_operations { * 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 */ + /** 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 *); @@ -284,6 +292,8 @@ struct fuse_operations { * 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 */ void *(*init) (void); @@ -291,8 +301,65 @@ struct fuse_operations { * 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 *); }; /** Extra context that may be needed by some filesystems @@ -349,35 +416,16 @@ int fuse_main(int argc, char *argv[], const struct fuse_operations *op); * More detailed API * * ----------------------------------------------------------- */ -/* - * Create a FUSE mountpoint - * - * Returns a control file descriptor suitable for passing to - * fuse_new() - * - * @param mountpoint the mount point path - * @param opts a comma separated list of mount options. Can be NULL. - * @return the control file descriptor on success, -1 on failure - */ -int fuse_mount(const char *mountpoint, const char *opts); - -/* - * Umount a FUSE mountpoint - * - * @param mountpoint the mount point path - */ -void fuse_unmount(const char *mountpoint); - /** * Create a new FUSE filesystem. * * @param fd the control file descriptor - * @param opts mount options to be used by the library + * @param args argument vector * @param op the operations * @param op_size the size of the fuse_operations structure * @return the created FUSE handle */ -struct fuse *fuse_new(int fd, const char *opts, +struct fuse *fuse_new(int fd, struct fuse_args *args, const struct fuse_operations *op, size_t op_size); /** @@ -392,11 +440,11 @@ void fuse_destroy(struct fuse *f); /** * FUSE event loop. * - * Requests from the kernel are processed, and the apropriate + * Requests from the kernel are processed, and the appropriate * operations are called. * * @param f the FUSE handle - * @return 0 if no error occured, -1 otherwise + * @return 0 if no error occurred, -1 otherwise */ int fuse_loop(struct fuse *f); @@ -410,7 +458,7 @@ void fuse_exit(struct fuse *f); /** * FUSE event loop with multiple threads * - * Requests from the kernel are processed, and the apropriate + * Requests from the kernel are processed, and the appropriate * operations are called. Request are processed in parallel by * distributing them between multiple threads. * @@ -418,7 +466,7 @@ void fuse_exit(struct fuse *f); * the application. * * @param f the FUSE handle - * @return 0 if no error occured, -1 otherwise + * @return 0 if no error occurred, -1 otherwise */ int fuse_loop_mt(struct fuse *f); @@ -434,22 +482,13 @@ int fuse_loop_mt(struct fuse *f); struct fuse_context *fuse_get_context(void); /** - * Invalidate cached data of a file. - * - * Useful if the 'kernel_cache' mount option is given, since in that - * case the cache is not invalidated on file open. + * Obsolete, doesn't do anything * - * @return 0 on success or -errno on failure + * @return -EINVAL */ int fuse_invalidate(struct fuse *f, const char *path); -/** - * Check whether a mount option should be passed to the kernel or the - * library - * - * @param opt the option to check - * @return 1 if it is a library option, 0 otherwise - */ +/* Deprecated, don't use */ int fuse_is_lib_option(const char *opt); /** @@ -464,9 +503,6 @@ int fuse_main_real(int argc, char *argv[], const struct fuse_operations *op, * Advanced API for event handling, don't worry about this... * * ----------------------------------------------------------- */ -/** Structure containing a raw command */ -struct fuse_cmd; - /** Function type used to process commands */ typedef void (*fuse_processor_t)(struct fuse *, struct fuse_cmd *, void *); @@ -490,7 +526,7 @@ int fuse_loop_mt_proc(struct fuse *f, fuse_processor_t proc, void *data); /** Return the exited flag, which indicates if fuse_exit() has been called */ -int fuse_exited(struct fuse* f); +int fuse_exited(struct fuse *f); /** Set function which can be used to get the current context */ void fuse_set_getcontext_func(struct fuse_context *(*func)(void)); @@ -499,17 +535,27 @@ void fuse_set_getcontext_func(struct fuse_context *(*func)(void)); * Compatibility stuff * * ----------------------------------------------------------- */ -#if FUSE_USE_VERSION == 21 || FUSE_USE_VERSION == 11 +#ifndef __FreeBSD__ + +#if FUSE_USE_VERSION == 22 || FUSE_USE_VERSION == 21 || FUSE_USE_VERSION == 11 # include "fuse_compat.h" +# undef FUSE_MINOR_VERSION +# undef fuse_main +# if FUSE_USE_VERSION == 22 +# define FUSE_MINOR_VERSION 4 +# 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_operations fuse_operations_compat22 +# define fuse_file_info fuse_file_info_compat22 +# define fuse_mount fuse_mount_compat22 +# else # define fuse_dirfil_t fuse_dirfil_t_compat # define __fuse_read_cmd fuse_read_cmd # define __fuse_process_cmd fuse_process_cmd # define __fuse_loop_mt fuse_loop_mt_proc -# undef fuse_main -# undef FUSE_MINOR_VERSION -# undef FUSE_MAJOR_VERSION # if FUSE_USE_VERSION == 21 -# define FUSE_MAJOR_VERSION 2 # define FUSE_MINOR_VERSION 1 # define fuse_operations fuse_operations_compat2 # define fuse_main fuse_main_compat2 @@ -518,7 +564,10 @@ void fuse_set_getcontext_func(struct fuse_context *(*func)(void)); # define __fuse_teardown fuse_teardown # define __fuse_exited fuse_exited # define __fuse_set_getcontext_func fuse_set_getcontext_func +# define fuse_mount fuse_mount_compat22 # else +# warning Compatibility with API version 11 is deprecated +# undef FUSE_MAJOR_VERSION # define FUSE_MAJOR_VERSION 1 # define FUSE_MINOR_VERSION 1 # define fuse_statfs fuse_statfs_compat1 @@ -528,10 +577,19 @@ void fuse_set_getcontext_func(struct fuse_context *(*func)(void)); # define fuse_mount fuse_mount_compat1 # define FUSE_DEBUG FUSE_DEBUG_COMPAT1 # endif -#elif FUSE_USE_VERSION < 22 -# error Compatibility with API version other than 21 and 11 not supported +# endif +#elif FUSE_USE_VERSION < 25 +# error Compatibility with API version other than 21, 22 and 11 not supported #endif +#else /* __FreeBSD__ */ + +#if FUSE_USE_VERSION < 25 +# error On FreeBSD API version 25 or greater must be used +#endif + +#endif /* __FreeBSD__ */ + #ifdef __cplusplus } #endif diff --git a/include/fuse_common.h b/include/fuse_common.h new file mode 100644 index 000000000..0f35ea62b --- /dev/null +++ b/include/fuse_common.h @@ -0,0 +1,117 @@ +/* + FUSE: Filesystem in Userspace + Copyright (C) 2001-2006 Miklos Szeredi <miklos@szeredi.hu> + + This program can be distributed under the terms of the GNU LGPL. + See the file COPYING.LIB. +*/ + +#if !defined(_FUSE_H_) && !defined(_FUSE_LOWLEVEL_H_) +#error "Never include <fuse_common.h> directly; use <fuse.h> or <fuse_lowlevel.h instead." +#endif + +#ifndef _FUSE_COMMON_H_ +#define _FUSE_COMMON_H_ + +#include "fuse_opt.h" +#include <stdint.h> + +/** Major version of FUSE library interface */ +#define FUSE_MAJOR_VERSION 2 + +/** Minor version of FUSE library interface */ +#define FUSE_MINOR_VERSION 5 + +#define FUSE_MAKE_VERSION(maj, min) ((maj) * 10 + (min)) +#define FUSE_VERSION FUSE_MAKE_VERSION(FUSE_MAJOR_VERSION, FUSE_MINOR_VERSION) + +/* This interface uses 64 bit off_t */ +#if _FILE_OFFSET_BITS != 64 +#error Please add -D_FILE_OFFSET_BITS=64 to your compile flags! +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * Information about open files + * + * Changed in version 2.5 + */ +struct fuse_file_info { + /** Open flags. Available in open() and release() */ + int flags; + + /** 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; + + /** 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; + + /** Padding. Do not use*/ + unsigned int padding : 30; + + /** File handle. May be filled in by filesystem in open(). + Available in all other file operations */ + uint64_t fh; +}; + +/** + * Create a FUSE mountpoint + * + * Returns a control file descriptor suitable for passing to + * fuse_new() + * + * @param mountpoint the mount point path + * @param args argument vector + * @return the control file descriptor on success, -1 on failure + */ +int fuse_mount(const char *mountpoint, struct fuse_args *args); + +/** + * Umount a FUSE mountpoint + * + * @param mountpoint the mount point path + */ +void fuse_unmount(const char *mountpoint); + +/** + * Parse common options + * + * The following options are parsed: + * + * '-f' foreground + * '-d' '-odebug' foreground, but keep the debug option + * '-s' single threaded + * '-h' '--help' help + * '-ho' help without header + * '-ofsname=..' file system name, if not present, then set to the program + * name + * + * All parameters may be NULL + * + * @param args argument vector + * @param mountpoint the returned mountpoint, should be freed after use + * @param multithreaded set to 1 unless the '-s' option is present + * @param foreground set to 1 if one of the relevant options is present + * @return 0 on success, -1 on failure + */ +int fuse_parse_cmdline(struct fuse_args *args, char **mountpoint, + int *multithreaded, int *foreground); + + +#ifdef __cplusplus +} +#endif + +#endif /* _FUSE_COMMON_H_ */ diff --git a/include/fuse_compat.h b/include/fuse_compat.h index af7aecf7d..220ef0752 100644 --- a/include/fuse_compat.h +++ b/include/fuse_compat.h @@ -1,6 +1,6 @@ /* FUSE: Filesystem in Userspace - Copyright (C) 2001-2005 Miklos Szeredi <miklos@szeredi.hu> + Copyright (C) 2001-2006 Miklos Szeredi <miklos@szeredi.hu> This program can be distributed under the terms of the GNU LGPL. See the file COPYING.LIB. @@ -9,6 +9,68 @@ /* these definitions provide source compatibility to prior versions. Do not include this file directly! */ +#include <sys/statfs.h> + +struct fuse_file_info_compat22 { + int flags; + unsigned long fh; + int writepage; + unsigned int direct_io : 1; + unsigned int keep_cache : 1; +}; + +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_compat22 *); + int (*read) (const char *, char *, size_t, off_t, + struct fuse_file_info_compat22 *); + int (*write) (const char *, const char *, size_t, off_t, + struct fuse_file_info_compat22 *); + int (*statfs) (const char *, struct statfs *); + int (*flush) (const char *, struct fuse_file_info_compat22 *); + int (*release) (const char *, struct fuse_file_info_compat22 *); + int (*fsync) (const char *, int, struct fuse_file_info_compat22 *); + 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_compat22 *); + int (*readdir) (const char *, void *, fuse_fill_dir_t, off_t, + struct fuse_file_info_compat22 *); + int (*releasedir) (const char *, struct fuse_file_info_compat22 *); + int (*fsyncdir) (const char *, int, struct fuse_file_info_compat22 *); + 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); + +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); + +int fuse_main_real_compat22(int argc, char *argv[], + const struct fuse_operations_compat22 *op, + size_t op_size); + +int fuse_mount_compat22(const char *mountpoint, const char *opts); + 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 *); diff --git a/include/fuse_opt.h b/include/fuse_opt.h new file mode 100644 index 000000000..2988902f2 --- /dev/null +++ b/include/fuse_opt.h @@ -0,0 +1,227 @@ +/* + FUSE: Filesystem in Userspace + Copyright (C) 2001-2006 Miklos Szeredi <miklos@szeredi.hu> + + This program can be distributed under the terms of the GNU GPL. + See the file COPYING. +*/ + +#ifndef _FUSE_OPT_H_ +#define _FUSE_OPT_H_ + +/* This file defines the option parsing interface of FUSE */ + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * Option description + * + * This structure describes a single option, and and action associated + * with it, in case it matches. + * + * More than one such match may occur, in which case the action for + * each match is executed. + * + * There are three possible actions in case of a match: + * + * i) An integer (int or unsigned) variable determined by 'offset' is + * set to 'value' + * + * ii) The processing function is called, with 'value' as the key + * + * iii) An integer (any) or string (char *) variable determined by + * 'offset' is set to the value of an option parameter + * + * 'offset' should normally be either set to + * + * - 'offsetof(struct foo, member)' actions i) and iii) + * + * - -1 action ii) + * + * The 'offsetof()' macro is defined in the <stddef.h> header. + * + * The template determines which options match, and also have an + * effect on the action. Normally the action is either i) or ii), but + * if a format is present in the template, then action iii) is + * performed. + * + * The types of templates are: + * + * 1) "-x", "-foo", "--foo", "--foo-bar", etc. These match only + * themselves. Invalid values are "--" and anything beginning + * with "-o" + * + * 2) "foo", "foo-bar", etc. These match "-ofoo", "-ofoo-bar" or + * the relevant option in a comma separated option list + * + * 3) "bar=", "--foo=", etc. These are variations of 1) and 2) + * which have a parameter + * + * 4) "bar=%s", "--foo=%lu", etc. Same matching as above but perform + * action iii). + * + * 5) "-x ", etc. Matches either "-xparam" or "-x param" as + * two separate arguments + * + * 6) "-x %s", etc. Combination of 4) and 5) + * + * If the format is "%s", memory is allocated for the string unlike + * with scanf(). + */ +struct fuse_opt { + /** Matching template and optional parameter formatting */ + const char *templ; + + /** + * 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; +}; + +/** + * 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 + * template value + */ +#define FUSE_OPT_END { .templ = NULL } + +/** + * Argument list + */ +struct fuse_args { + /** Argument count */ + int argc; + + /** Argument vector. NULL terminated */ + char **argv; + + /** Is 'argv' allocated? */ + int allocated; +}; + +/** + * Initializer for 'struct fuse_args' + */ +#define FUSE_ARGS_INIT(argc, argv) { argc, argv, 0 } + +/** + * Key value passed to the processing function if an option did not + * match any template + */ +#define FUSE_OPT_KEY_OPT -1 + +/** + * Key value passed to the processing function for all non-options + * + * Non-options are the arguments beginning with a charater other than + * '-' or all arguments after the special '--' option + */ +#define FUSE_OPT_KEY_NONOPT -2 + +/** + * Processing function + * + * This function is called if + * - option did not match any 'struct fuse_opt' + * - argument is a non-option + * - option did match and offset was set to -1 + * + * The 'arg' parameter will always contain the whole argument or + * option including the parameter if exists. A two-argument option + * ("-x foo") is always converted to single arguemnt option of the + * form "-xfoo" before this function is called. + * + * Options of the form '-ofoo' are passed to this function without the + * '-o' prefix. + * + * The return value of this function determines whether this argument + * is to be inserted into the output argument vector, or discarded. + * + * @param data is the user data passed to the fuse_opt_parse() function + * @param arg is the whole argument or option + * @param key determines why the processing function was called + * @param outargs the current output argument list + * @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); + +/** + * Option parsing function + * + * If 'args' was returned from a previous call to fuse_opt_parse() or + * it was constructed from + * + * A NULL 'args' is equivalent to an empty argument vector + * + * A NULL 'opts' is equivalent to an 'opts' array containing a single + * end marker + * + * A NULL 'proc' is equivalent to a processing function always + * returning '1' + * + * @param args is the input and output argument list + * @param data is the user data + * @param opts is the option description array + * @param proc is the processing function + * @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); + +/** + * Add an option to a comma separated option list + * + * @param opts is a pointer to an option list, may point to a NULL value + * @param opt is the option to add + * @return -1 on allocation error, 0 on success + */ +int fuse_opt_add_opt(char **opts, const char *opt); + +/** + * Add an argument to a NULL terminated argument vector + * + * @param args is the structure containing the current argument list + * @param arg is the new argument to add + * @return -1 on allocation error, 0 on success + */ +int fuse_opt_add_arg(struct fuse_args *args, const char *arg); + +/** + * Free the contents of argument list + * + * The structure itself is not freed + * + * @param args is the structure containing the argument list + */ +void fuse_opt_free_args(struct fuse_args *args); + + +/** + * Check if an option matches + * + * @param opts is the option description array + * @param opt is the option to match + * @return 1 if a match is found, 0 if not + */ +int fuse_opt_match(const struct fuse_opt opts[], const char *opt); + +#ifdef __cplusplus +} +#endif + +#endif /* _FUSE_OPT_H_ */ diff --git a/src/fuse_i.h b/src/fuse_i.h index e6fd4e43e..81d46d405 100644 --- a/src/fuse_i.h +++ b/src/fuse_i.h @@ -17,7 +17,7 @@ #ifdef FUSE_USE_VERSION # include "fuse.h" #else -# define FUSE_USE_VERSION 23 +# define FUSE_USE_VERSION 25 # include "fuse.h" # include "fuse_compat.h" #endif @@ -30,13 +30,15 @@ __LINE__) /* pointer to the fuse_operations structure of this translator process */ -extern const struct fuse_operations *fuse_ops; -extern const struct fuse_operations_compat2 *fuse_ops_compat; +extern const struct fuse_operations_compat22 *fuse_ops_compat22; +extern const struct fuse_operations_compat2 *fuse_ops_compat2; -#define FUSE_OP_HAVE(a) ((fuse_ops) ? \ - (fuse_ops->a != NULL) : (fuse_ops_compat->a != NULL)) -#define FUSE_OP_CALL(a,b...) ((fuse_ops) ? \ - (fuse_ops->a(b)) : (fuse_ops_compat->a(b))) +#define FUSE_OP_HAVE(a) ((fuse_ops_compat22) ? \ + (fuse_ops_compat22->a != NULL) : \ + (fuse_ops_compat2->a != NULL)) +#define FUSE_OP_CALL(a,b...) ((fuse_ops_compat22) ? \ + (fuse_ops_compat22->a(b)) : \ + (fuse_ops_compat2->a(b))) /***************************************************************************** *** netnodes (in memory representation of libfuse's files or directories) *** @@ -53,7 +55,9 @@ struct netnode { /* information about the opened file */ - struct fuse_file_info info; + union { + struct fuse_file_info_compat22 compat22; + } info; /* pointer to our parent's netnode, if any */ struct netnode *parent; diff --git a/src/main.c b/src/main.c index 291c795b1..c2ca44d88 100644 --- a/src/main.c +++ b/src/main.c @@ -32,8 +32,8 @@ int netfs_maxsymlinks = 12; struct _libfuse_params libfuse_params = { 0 }; /* pointer to the fuse_operations structure of this translator process */ -const struct fuse_operations *fuse_ops = NULL; -const struct fuse_operations_compat2 *fuse_ops_compat = NULL; +const struct fuse_operations_compat22 *fuse_ops_compat22 = NULL; +const struct fuse_operations_compat2 *fuse_ops_compat2 = NULL; /* the port where to write out debug messages to, NULL to omit these */ FILE *debug_port = NULL; @@ -230,7 +230,7 @@ fuse_main_compat2(int argc, char *argv[], { fuse_parse_argv(argc, argv); - int fd = fuse_mount(NULL, NULL); + int fd = fuse_mount_compat22(NULL, NULL); return (libfuse_params.disable_mt ? fuse_loop : fuse_loop_mt) (fuse_new_compat2(fd, NULL, op)); } @@ -240,17 +240,25 @@ fuse_main_compat2(int argc, char *argv[], /* Main function of FUSE. * named fuse_main_real, since originial fuse.h defines a macro renaming it */ int -fuse_main_real(int argc, char *argv[], - const struct fuse_operations *op, size_t op_size) +fuse_main_real_compat22(int argc, char *argv[], + const struct fuse_operations_compat22 *op, + size_t op_size) { fuse_parse_argv(argc, argv); - int fd = fuse_mount(NULL, NULL); + int fd = fuse_mount_compat22(NULL, NULL); return (libfuse_params.disable_mt ? fuse_loop : fuse_loop_mt) - (fuse_new(fd, NULL, op, op_size)); + (fuse_new_compat22(fd, NULL, op, op_size)); } +int +fuse_main_real(int argc, char *argv[], const struct fuse_operations *op, + size_t op_size) +{ + assert(0); +} + /* Create a new FUSE filesystem, actually there's nothing for us to do * on the Hurd. @@ -267,7 +275,7 @@ fuse_new_compat2(int fd, const char *opts, if(fuse_parse_opts(opts)) return NULL; - fuse_ops_compat = op; + fuse_ops_compat2 = op; return (void *) FUSE_MAGIC; /* we don't have a fuse structure, sorry. */ } @@ -275,12 +283,23 @@ fuse_new_compat2(int fd, const char *opts, /* Create a new FUSE filesystem, actually there's nothing for us to do - * on the Hurd. + * on the Hurd. Hmm. */ struct fuse * -fuse_new(int fd, const char *opts, +fuse_new(int fd, struct fuse_args *args, const struct fuse_operations *op, size_t op_size) { + assert(0); +} + + +/* Create a new FUSE filesystem, actually there's nothing for us to do + * on the Hurd. + */ +struct fuse * +fuse_new_compat22(int fd, const char *opts, + const struct fuse_operations_compat22 *op, size_t op_size) +{ (void) op_size; /* FIXME, see what the real Fuse library does with * this argument */ @@ -290,18 +309,24 @@ fuse_new(int fd, const char *opts, if(fuse_parse_opts(opts)) return NULL; - fuse_ops = op; + fuse_ops_compat22 = op; return (void *) FUSE_MAGIC; /* we don't have a fuse structure, sorry. */ } - /* Create a new mountpoint for our fuse filesystem, i.e. do the netfs * initialization stuff ... */ int -fuse_mount(const char *mountpoint, const char *opts) +fuse_mount(const char *mountpoint, struct fuse_args *args) +{ + assert(0); +} + + +int +fuse_mount_compat22(const char *mountpoint, const char *opts) { (void) mountpoint; /* we don't care for the specified mountpoint, as * we need to be set up using settrans ... */ diff --git a/src/netfs.c b/src/netfs.c index 0fdb5c4a6..dd6ca32e2 100644 --- a/src/netfs.c +++ b/src/netfs.c @@ -369,8 +369,8 @@ netfs_check_open_permissions (struct iouser *user, struct node *node, * into memory. */ if(! err) { - node->nn->info.flags = flags; - if(flags & O_EXEC) node->nn->info.flags |= O_RDONLY; + node->nn->info.compat22.flags = flags; + if(flags & O_EXEC) node->nn->info.compat22.flags |= O_RDONLY; } out: @@ -510,10 +510,11 @@ netfs_attempt_sync (struct iouser *cred, struct node *node, int wait) goto out; } - if(fuse_ops) - err = -fuse_ops->fsync(node->nn->path, 0, &node->nn->info); + if(fuse_ops_compat22) + err = -fuse_ops_compat22->fsync(node->nn->path, 0, + &node->nn->info.compat22); else - err = -fuse_ops_compat->fsync(node->nn->path, 0); + err = -fuse_ops_compat2->fsync(node->nn->path, 0); if(! err) node->nn->may_need_sync = 0; @@ -1009,15 +1010,17 @@ error_t netfs_attempt_write (struct iouser *cred, struct node *node, goto out; } - node->nn->info.writepage = 0; /* cannot distinct on the Hurd :( */ + node->nn->info.compat22.writepage = 0; /* cannot distinct on the Hurd :( */ - if(fuse_ops && fuse_ops->open) - if((err = fuse_ops->open(node->nn->path, &node->nn->info))) + if(fuse_ops_compat22 && fuse_ops_compat22->open) + if((err = fuse_ops_compat22->open(node->nn->path, + &node->nn->info.compat22))) goto out; - int sz = fuse_ops ? - (fuse_ops->write(node->nn->path, data, *len, offset, &node->nn->info)) : - (fuse_ops_compat->write(node->nn->path, data, *len, offset)); + int sz = fuse_ops_compat22 ? + (fuse_ops_compat22->write(node->nn->path, data, *len, + offset, &node->nn->info.compat22)) : + (fuse_ops_compat2->write(node->nn->path, data, *len, offset)); /* FIXME: open, flush and release handling probably should be changed * completely, I mean, we probably should do fuse_ops->open in @@ -1026,11 +1029,12 @@ error_t netfs_attempt_write (struct iouser *cred, struct node *node, * * This way we wouldn't be able to report any errors back. */ - if(sz >= 0 && fuse_ops && fuse_ops->flush) - err = fuse_ops->flush(node->nn->path, &node->nn->info); + if(sz >= 0 && fuse_ops_compat22 && fuse_ops_compat22->flush) + err = fuse_ops_compat22->flush(node->nn->path, &node->nn->info.compat22); - if(fuse_ops && fuse_ops->open && fuse_ops->release) - fuse_ops->release(node->nn->path, &node->nn->info); + if(fuse_ops_compat22 && fuse_ops_compat22->open + && fuse_ops_compat22->release) + fuse_ops_compat22->release(node->nn->path, &node->nn->info.compat22); if(sz < 0) err = -sz; @@ -1108,13 +1112,15 @@ error_t netfs_attempt_read (struct iouser *cred, struct node *node, goto out; } - if(fuse_ops && fuse_ops->open) - if((err = fuse_ops->open(node->nn->path, &node->nn->info))) + if(fuse_ops_compat22 && fuse_ops_compat22->open) + if((err = fuse_ops_compat22->open(node->nn->path, + &node->nn->info.compat22))) goto out; - int sz = fuse_ops ? - (fuse_ops->read(node->nn->path, data, *len, offset, &node->nn->info)) : - (fuse_ops_compat->read(node->nn->path, data, *len, offset)); + int sz = fuse_ops_compat22 ? + (fuse_ops_compat22->read(node->nn->path, data, *len, + offset, &node->nn->info.compat22)) : + (fuse_ops_compat2->read(node->nn->path, data, *len, offset)); /* FIXME: open, flush and release handling probably should be changed * completely, I mean, we probably should do fuse_ops->open in @@ -1123,11 +1129,12 @@ error_t netfs_attempt_read (struct iouser *cred, struct node *node, * * This way we wouldn't be able to report any errors back. */ - if(sz >= 0 && fuse_ops && fuse_ops->flush) - err = fuse_ops->flush(node->nn->path, &node->nn->info); + if(sz >= 0 && fuse_ops_compat22 && fuse_ops_compat22->flush) + err = fuse_ops_compat22->flush(node->nn->path, &node->nn->info.compat22); - if(fuse_ops && fuse_ops->open && fuse_ops->release) - fuse_ops->release(node->nn->path, &node->nn->info); + if(fuse_ops_compat22 && fuse_ops_compat22->open + && fuse_ops_compat22->release) + fuse_ops_compat22->release(node->nn->path, &node->nn->info.compat22); if(sz < 0) err = -sz; @@ -1164,10 +1171,10 @@ fuse_get_inode(const char *name) { struct stat stat; - assert(fuse_ops); - assert(fuse_ops->getattr); + assert(fuse_ops_compat22); + assert(fuse_ops_compat22->getattr); - fuse_ops->getattr(name, &stat); + fuse_ops_compat22->getattr(name, &stat); return stat.st_ino; } @@ -1316,10 +1323,11 @@ get_dirents_getdir(struct node *dir, int first_entry, int num_entries, handle->parent = dir->nn; handle->hdrpos = (struct dirent*) *data; - if(fuse_ops) - fuse_ops->getdir(dir->nn->path, handle, get_dirents_getdir_helper); + if(fuse_ops_compat22) + fuse_ops_compat22->getdir(dir->nn->path, handle, + get_dirents_getdir_helper); else - fuse_ops_compat->getdir(dir->nn->path, handle, + fuse_ops_compat2->getdir(dir->nn->path, handle, get_dirents_getdir_helper_compat); @@ -1449,7 +1457,7 @@ get_dirents_readdir(struct node *dir, int first_entry, int num_entries, error_t err; FUNC_PROLOGUE_NODE("get_dirents_readdir", dir); - if(! (fuse_ops && fuse_ops->readdir)) + if(! (fuse_ops_compat22 && fuse_ops_compat22->readdir)) FUNC_RETURN(EOPNOTSUPP); fuse_dirh_t handle; @@ -1479,20 +1487,22 @@ get_dirents_readdir(struct node *dir, int first_entry, int num_entries, handle->parent = dir->nn; handle->hdrpos = (struct dirent*) *data; - if(fuse_ops->opendir - && (err = fuse_ops->opendir(dir->nn->path, &dir->nn->info))) + if(fuse_ops_compat22->opendir + && (err = fuse_ops_compat22->opendir(dir->nn->path, + &dir->nn->info.compat22))) goto out; - if((err = fuse_ops->readdir(dir->nn->path, handle, - get_dirents_readdir_helper, first_entry, - &dir->nn->info))) + if((err = fuse_ops_compat22->readdir(dir->nn->path, handle, + get_dirents_readdir_helper, + first_entry, &dir->nn->info.compat22))) { - fuse_ops->releasedir(dir->nn->path, &dir->nn->info); + fuse_ops_compat22->releasedir(dir->nn->path, &dir->nn->info.compat22); goto out; } - if(fuse_ops->releasedir - && (err = fuse_ops->releasedir(dir->nn->path, &dir->nn->info))) + if(fuse_ops_compat22->releasedir + && (err = fuse_ops_compat22->releasedir(dir->nn->path, + &dir->nn->info.compat22))) goto out; *data_len -= handle->size; /* subtract number of bytes left in the @@ -1526,7 +1536,7 @@ netfs_get_dirents (struct iouser *cred, struct node *dir, goto out; - if(fuse_ops && fuse_ops->readdir) + if(fuse_ops_compat22 && fuse_ops_compat22->readdir) err = get_dirents_readdir(dir, first_entry, num_entries, data, data_len, data_entries); diff --git a/src/netnode.c b/src/netnode.c index 9727097c1..dc9055262 100644 --- a/src/netnode.c +++ b/src/netnode.c @@ -152,9 +152,10 @@ fuse_sync_filesystem(void) { if(he->nn->may_need_sync) { - err = -(fuse_ops ? - fuse_ops->fsync(he->nn->path, 0, &he->nn->info) : - fuse_ops_compat->fsync(he->nn->path, 0)); + err = -(fuse_ops_compat22 ? + fuse_ops_compat22->fsync(he->nn->path, 0, + &he->nn->info.compat22) : + fuse_ops_compat2->fsync(he->nn->path, 0)); if(err) goto out; |