From: Miklos Szeredi Date: Sat, 4 Dec 2004 00:40:50 +0000 (+0000) Subject: backward compatibility X-Git-Tag: before_interruptible~6 X-Git-Url: http://git.maquefel.me/?a=commitdiff_plain;h=0b6a0adc4d44e5b9d0855e257091eec643f3a185;p=qemu-gpiodev%2Flibfuse.git backward compatibility --- diff --git a/ChangeLog b/ChangeLog index 5ec4bac..28bb9ce 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,12 @@ +2004-12-03 Miklos Szeredi + + * Add source compatibility to 2.1 and 1.1 APIs. To select betwen + versions simply define FUSE_USE_VERSION to 22, 21 or 11 before + including the fuse header + + * Add binary compatibility to 2.1 version of library with symbol + versioning + 2004-12-01 Miklos Szeredi * kernel: clean up writing functions diff --git a/configure.in b/configure.in index 315886d..adc9234 100644 --- a/configure.in +++ b/configure.in @@ -1,4 +1,4 @@ -AC_INIT(fuse, 3.0-pre0) +AC_INIT(fuse, 2.2-pre0) AM_INIT_AUTOMAKE AM_CONFIG_HEADER(include/config.h) @@ -14,7 +14,7 @@ if test -z "$mkdir_p"; then fi CFLAGS="-Wall -W -g -O2" -CPPFLAGS="$CPPFLAGS -D_FILE_OFFSET_BITS=64 -D_REENTRANT" +CPPFLAGS="$CPPFLAGS -D_FILE_OFFSET_BITS=64 -D_REENTRANT -DFUSE_USE_VERSION=22" AC_ARG_ENABLE(kernel-module, [ --enable-kernel-module Compile kernel module ]) diff --git a/include/Makefile.am b/include/Makefile.am index f6f1600..14ac9d9 100644 --- a/include/Makefile.am +++ b/include/Makefile.am @@ -1,7 +1,7 @@ ## Process this file with automake to produce Makefile.in fuseincludedir=$(includedir)/fuse -fuseinclude_HEADERS = fuse.h +fuseinclude_HEADERS = fuse.h fuse_compat.h noinst_HEADERS = fuse_kernel.h # remove fuse.h from old place to avoid collision with new one diff --git a/include/fuse.h b/include/fuse.h index 072ac22..3223155 100644 --- a/include/fuse.h +++ b/include/fuse.h @@ -11,11 +11,20 @@ /* 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, 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 3 +#define FUSE_MAJOR_VERSION 2 /** Minor version of FUSE library interface */ -#define FUSE_MINOR_VERSION 0 +#define FUSE_MINOR_VERSION 2 /* This interface uses 64 bit off_t */ #if _FILE_OFFSET_BITS != 64 @@ -174,12 +183,15 @@ struct fuse_context { * - registers the operations * - calls either the single-threaded or the multi-threaded event loop * + * Note: this is currently implemented as a macro. + * * @param argc the argument counter passed to the main() function * @param argv the argument vector passed to the main() function * @param op the file system operation * @return 0 on success, nonzero on failure */ -int fuse_main(int argc, char *argv[], const struct fuse_operations *op); +/* int fuse_main(int argc, char *argv[], const struct fuse_operations *op); */ +#define fuse_main(argc, argv, op) __fuse_main(argc, argv, op, sizeof(*(op))) /* ----------------------------------------------------------- * * More detailed API * @@ -210,10 +222,11 @@ void fuse_unmount(const char *mountpoint); * @param fd the control file descriptor * @param opts mount options to be used by the library * @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, - const struct fuse_operations *op); + const struct fuse_operations *op, size_t op_size); /** * Destroy the FUSE handle. @@ -287,6 +300,14 @@ int fuse_invalidate(struct fuse *f, const char *path); */ int fuse_is_lib_option(const char *opt); +/** + * The real main function + * + * Do not call this directly, use fuse_main() + */ +int __fuse_main(int argc, char *argv[], const struct fuse_operations *op, + size_t op_size); + /* ----------------------------------------------------------- * * Advanced API for event handling, don't worry about this... * * ----------------------------------------------------------- */ @@ -294,7 +315,7 @@ int fuse_is_lib_option(const char *opt); struct fuse_cmd; typedef void (*fuse_processor_t)(struct fuse *, struct fuse_cmd *, void *); struct fuse *__fuse_setup(int argc, char *argv[], - const struct fuse_operations *op, + const struct fuse_operations *op, size_t op_size, char **mountpoint, int *multithreaded, int *fd); void __fuse_teardown(struct fuse *fuse, int fd, char *mountpoint); struct fuse_cmd *__fuse_read_cmd(struct fuse *f); @@ -303,6 +324,38 @@ int __fuse_loop_mt(struct fuse *f, fuse_processor_t proc, void *data); int __fuse_exited(struct fuse* f); void __fuse_set_getcontext_func(struct fuse_context *(*func)(void)); +/* ----------------------------------------------------------- * + * Compatibility stuff * + * ----------------------------------------------------------- */ + +#if FUSE_USE_VERSION == 21 || FUSE_USE_VERSION == 11 +# include +# define fuse_dirfil_t _fuse_dirfil_t_compat +# 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 +# define fuse_new _fuse_new_compat2 +# define __fuse_setup _fuse_setup_compat2 +# else +# undef FUSE_MAJOR_VERSION +# define FUSE_MAJOR_VERSION 1 +# define FUSE_MINOR_VERSION 1 +# define fuse_statfs _fuse_statfs_compat1 +# define fuse_operations _fuse_operations_compat1 +# define fuse_main _fuse_main_compat1 +# define fuse_new _fuse_new_compat1 +# define fuse_mount _fuse_mount_compat1 +# define FUSE_DEBUG _FUSE_DEBUG_COMPAT1 +# endif +#elif FUSE_USE_VERSION != 22 +# error API version other than 22, 21 and 11 not supported +#endif + #ifdef __cplusplus } #endif diff --git a/include/fuse_compat.h b/include/fuse_compat.h new file mode 100644 index 0000000..7ec9a29 --- /dev/null +++ b/include/fuse_compat.h @@ -0,0 +1,85 @@ +/* + FUSE: Filesystem in Userspace + Copyright (C) 2001-2004 Miklos Szeredi + + This program can be distributed under the terms of the GNU LGPL. + See the file COPYING.LIB. +*/ + +/* these definitions provide source compatibility to prior versions. + Do not include this file directly! */ + +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 _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_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; +}; + +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); +}; + +#define _FUSE_DEBUG_COMPAT1 (1 << 1) + +int _fuse_mount_compat1(const char *mountpoint, const char *args[]); + +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); diff --git a/kernel/configure.ac b/kernel/configure.ac index f078427..f57a67c 100644 --- a/kernel/configure.ac +++ b/kernel/configure.ac @@ -1,4 +1,4 @@ -AC_INIT(fuse-kernel, 3.0-pre0) +AC_INIT(fuse-kernel, 2.2-pre0) AC_CONFIG_HEADERS([config.h]) AC_PROG_INSTALL diff --git a/lib/Makefile.am b/lib/Makefile.am index e370ef4..c9a2cd4 100644 --- a/lib/Makefile.am +++ b/lib/Makefile.am @@ -9,4 +9,5 @@ libfuse_la_SOURCES = \ mount.c \ fuse_i.h -libfuse_la_LDFLAGS = -lpthread -version-number 3:0:0 +libfuse_la_LDFLAGS = -lpthread -version-number 2:2:0 \ + -Wl,--version-script,fuse_versionscript diff --git a/lib/fuse.c b/lib/fuse.c index 100b50f..afc8c74 100644 --- a/lib/fuse.c +++ b/lib/fuse.c @@ -17,6 +17,7 @@ #include #include +#define FUSE_KERNEL_MINOR_VERSION_NEED 1 #define FUSE_VERSION_FILE_OLD "/proc/fs/fuse/version" #define FUSE_VERSION_FILE_NEW "/sys/fs/fuse/version" #define FUSE_DEV_OLD "/proc/fs/fuse/dev" @@ -1067,8 +1068,12 @@ static void do_open(struct fuse *f, struct fuse_in_header *in, path = get_path(f, in->nodeid); if (path != NULL) { res = -ENOSYS; - if (f->op.open) - res = f->op.open(path, &fi); + if (f->op.open.curr) { + if (!f->compat) + res = f->op.open.curr(path, &fi); + else + res = f->op.open.compat2(path, fi.flags); + } } if (res == 0) { int res2; @@ -1087,8 +1092,12 @@ static void do_open(struct fuse *f, struct fuse_in_header *in, res2 = __send_reply(f, in, res, &outarg, sizeof(outarg), 1); if(res2 == -ENOENT) { /* The open syscall was interrupted, so it must be cancelled */ - if(f->op.release) - f->op.release(path, &fi); + if(f->op.release.curr) { + if (!f->compat) + f->op.release.curr(path, &fi); + else + f->op.release.compat2(path, fi.flags); + } } else get_node(f, in->nodeid)->open_count ++; pthread_mutex_unlock(&f->lock); @@ -1146,8 +1155,12 @@ static void do_release(struct fuse *f, struct fuse_in_header *in, printf("RELEASE[%lu]\n", arg->fh); fflush(stdout); } - if (f->op.release) - f->op.release(path, &fi); + if (f->op.release.curr) { + if (!f->compat) + f->op.release.curr(path, &fi); + else + f->op.release.compat2(path, fi.flags); + } if(node->is_hidden && node->open_count == 0) /* can now clean up this hidden file */ @@ -1252,6 +1265,18 @@ static int default_statfs(struct statfs *buf) return 0; } +static void convert_statfs_compat(struct _fuse_statfs_compat1 *compatbuf, + struct statfs *statfs) +{ + statfs->f_bsize = compatbuf->block_size; + statfs->f_blocks = compatbuf->blocks; + statfs->f_bfree = compatbuf->blocks_free; + statfs->f_bavail = compatbuf->blocks_free; + statfs->f_files = compatbuf->files; + statfs->f_ffree = compatbuf->files_free; + statfs->f_namelen = compatbuf->namelen; +} + static void convert_statfs(struct statfs *statfs, struct fuse_kstatfs *kstatfs) { kstatfs->bsize = statfs->f_bsize; @@ -1270,8 +1295,17 @@ static void do_statfs(struct fuse *f, struct fuse_in_header *in) struct statfs buf; memset(&buf, 0, sizeof(struct statfs)); - if (f->op.statfs) - res = f->op.statfs("/", &buf); + if (f->op.statfs.curr) { + if (!f->compat || f->compat > 11) + res = f->op.statfs.curr("/", &buf); + else { + struct _fuse_statfs_compat1 compatbuf; + memset(&compatbuf, 0, sizeof(struct _fuse_statfs_compat1)); + res = f->op.statfs.compat1(&compatbuf); + if (res == 0) + convert_statfs_compat(&compatbuf, &buf); + } + } else res = default_statfs(&buf); @@ -1773,7 +1807,7 @@ static int check_version(struct fuse *f) FUSE_KERNEL_VERSION); return -1; } - if (f->minorver < FUSE_KERNEL_MINOR_VERSION) { + if (f->minorver < FUSE_KERNEL_MINOR_VERSION_NEED) { fprintf(stderr, "fuse: kernel interface too old: need >= %i.%i\n", FUSE_KERNEL_VERSION, FUSE_KERNEL_MINOR_VERSION); return -1; @@ -1818,11 +1852,18 @@ static int parse_lib_opts(struct fuse *f, const char *opts) return 0; } -struct fuse *fuse_new(int fd, const char *opts, const struct fuse_operations *op) +struct fuse *fuse_new_common(int fd, const char *opts, + const struct fuse_operations *op, + size_t op_size, int compat) { struct fuse *f; struct node *root; + if (sizeof(struct fuse_operations_i) < op_size) { + fprintf(stderr, "fuse: warning: library too old, some operations may not not work\n"); + op_size = sizeof(struct fuse_operations_i); + } + f = (struct fuse *) calloc(1, sizeof(struct fuse)); if (f == NULL) goto out; @@ -1862,7 +1903,8 @@ struct fuse *fuse_new(int fd, const char *opts, const struct fuse_operations *op #endif f->numworker = 0; f->numavail = 0; - f->op = *op; + memcpy(&f->op, op, op_size); + f->compat = compat; f->exited = 0; root = (struct node *) calloc(1, sizeof(struct node)); @@ -1895,6 +1937,29 @@ struct fuse *fuse_new(int fd, const char *opts, const struct fuse_operations *op return NULL; } +struct fuse *fuse_new(int fd, const char *opts, + const struct fuse_operations *op, size_t op_size) +{ + return fuse_new_common(fd, opts, op, op_size, 0); +} + +struct fuse *_fuse_new_compat2(int fd, const char *opts, + const struct _fuse_operations_compat2 *op) +{ + return fuse_new_common(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) +{ + char *opts = NULL; + if (flags & _FUSE_DEBUG_COMPAT1) + opts = "debug"; + return fuse_new_common(fd, opts, (struct fuse_operations *) op, + sizeof(struct _fuse_operations_compat1), 11); +} + void fuse_destroy(struct fuse *f) { size_t i; @@ -1923,3 +1988,5 @@ void fuse_destroy(struct fuse *f) pthread_mutex_destroy(&f->lock); free(f); } + +__asm__(".symver _fuse_new_compat2,fuse_new@"); diff --git a/lib/fuse_i.h b/lib/fuse_i.h index b9ea903..f88dda1 100644 --- a/lib/fuse_i.h +++ b/lib/fuse_i.h @@ -7,6 +7,7 @@ */ #include "fuse.h" +#include "fuse_compat.h" #include #include @@ -40,10 +41,50 @@ struct node { int is_hidden; }; +struct fuse_operations_i { + 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 *); + union { + int (*curr) (const char *, struct fuse_file_info *); + int (*compat2) (const char *, int); + } open; + 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 *); + union { + int (*curr) (const char *, struct statfs *); + int (*compat1) (struct _fuse_statfs_compat1 *); + } statfs; + int (*flush) (const char *, struct fuse_file_info *); + union { + int (*curr) (const char *, struct fuse_file_info *); + int (*compat2) (const char *, int); + } release; + 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 *); +}; + struct fuse { int flags; int fd; - struct fuse_operations op; + struct fuse_operations_i op; + int compat; struct node **name_table; size_t name_table_size; struct node **id_table; @@ -69,3 +110,7 @@ struct fuse_cmd { char *buf; size_t buflen; }; + +struct fuse *fuse_new_common(int fd, const char *opts, + const struct fuse_operations *op, + size_t op_size, int compat); diff --git a/lib/fuse_versionscript b/lib/fuse_versionscript new file mode 100644 index 0000000..175cf32 --- /dev/null +++ b/lib/fuse_versionscript @@ -0,0 +1,29 @@ +FUSE_2.2 { + global: + __fuse_exited; + __fuse_loop_mt; + __fuse_main; + __fuse_process_cmd; + __fuse_read_cmd; + __fuse_set_getcontext_func; + __fuse_setup; + __fuse_teardown; + _fuse_setup_compat2; + _fuse_main_compat1; + _fuse_main_compat2; + _fuse_mount_compat1; + _fuse_new_compat1; + _fuse_new_compat2; + fuse_destroy; + fuse_exit; + fuse_get_context; + fuse_invalidate; + fuse_is_lib_option; + fuse_loop; + fuse_loop_mt; + fuse_mount; + fuse_new; + fuse_unmount; + local: + *; +}; diff --git a/lib/helper.c b/lib/helper.c index b4d437f..50d43c1 100644 --- a/lib/helper.c +++ b/lib/helper.c @@ -6,7 +6,7 @@ See the file COPYING.LIB. */ -#include "fuse.h" +#include "fuse_i.h" #include #include @@ -249,16 +249,20 @@ static int fuse_parse_cmdline(int argc, const char *argv[], char **kernel_opts, } -struct fuse *__fuse_setup(int argc, char *argv[], - const struct fuse_operations *op, - char **mountpoint, int *multithreaded, int *fd) +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, + int compat) { struct fuse *fuse; int background; char *kernel_opts; char *lib_opts; int res; - + if (fuse_instance != NULL) { fprintf(stderr, "fuse: __fuse_setup() called twice\n"); return NULL; @@ -274,7 +278,7 @@ struct fuse *__fuse_setup(int argc, char *argv[], if (*fd == -1) goto err_free; - fuse = fuse_new(*fd, lib_opts, op); + fuse = fuse_new_common(*fd, lib_opts, op, op_size, compat); if (fuse == NULL) goto err_unmount; @@ -306,6 +310,25 @@ struct fuse *__fuse_setup(int argc, char *argv[], return NULL; } +struct fuse *__fuse_setup(int argc, char *argv[], + const struct fuse_operations *op, + size_t op_size, char **mountpoint, + int *multithreaded, int *fd) +{ + return fuse_setup_common(argc, argv, op, op_size, mountpoint, + multithreaded, fd, 0); +} + +struct fuse *_fuse_setup_compat2(int argc, char *argv[], + 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, 21); +} + void __fuse_teardown(struct fuse *fuse, int fd, char *mountpoint) { if (fuse_instance != fuse) @@ -319,8 +342,9 @@ void __fuse_teardown(struct fuse *fuse, int fd, char *mountpoint) free(mountpoint); } - -int fuse_main(int argc, char *argv[], const struct fuse_operations *op) +static int fuse_main_common(int argc, char *argv[], + const struct fuse_operations *op, size_t op_size, + int compat) { struct fuse *fuse; char *mountpoint; @@ -328,7 +352,8 @@ int fuse_main(int argc, char *argv[], const struct fuse_operations *op) int res; int fd; - fuse = __fuse_setup(argc, argv, op, &mountpoint, &multithreaded, &fd); + fuse = fuse_setup_common(argc, argv, op, op_size, &mountpoint, + &multithreaded, &fd, compat); if (fuse == NULL) return 1; @@ -344,3 +369,25 @@ int fuse_main(int argc, char *argv[], const struct fuse_operations *op) return 0; } +int __fuse_main(int argc, char *argv[],const struct fuse_operations *op, + size_t op_size) +{ + return fuse_main_common(argc, argv, op, op_size, 0); +} + +void _fuse_main_compat1(int argc, char *argv[], + const struct _fuse_operations_compat1 *op) +{ + fuse_main_common(argc, argv, (struct fuse_operations *) op, + sizeof(struct _fuse_operations_compat1), 11); +} + +int _fuse_main_compat2(int argc, char *argv[], + const struct _fuse_operations_compat2 *op) +{ + return fuse_main_common(argc, argv, (struct fuse_operations *) op, + sizeof(struct _fuse_operations_compat2), 21); +} + +__asm__(".symver _fuse_setup_compat2,__fuse_setup@"); +__asm__(".symver _fuse_main_compat2,fuse_main@"); diff --git a/lib/mount.c b/lib/mount.c index a84dbee..fd29020 100644 --- a/lib/mount.c +++ b/lib/mount.c @@ -7,6 +7,7 @@ */ #include "fuse.h" +#include "fuse_compat.h" #include #include @@ -124,3 +125,10 @@ int fuse_mount(const char *mountpoint, const char *opts) return rv; } + +int _fuse_mount_compat1(const char *mountpoint, const char *args[]) +{ + /* just ignore mount args for now */ + (void) args; + return fuse_mount(mountpoint, NULL); +}