mirror of
https://github.com/openharmony/third_party_libfuse.git
synced 2026-07-19 21:43:34 -04:00
Add filesystem stacking support to high level API
This commit is contained in:
@@ -1,3 +1,13 @@
|
||||
2007-02-03 Miklos Szeredi <miklos@szeredi.hu>
|
||||
|
||||
* Add filesystem stacking support to high level API. Filesystem
|
||||
modules can be built into libfuse or loaded from shared object
|
||||
(.so) files
|
||||
|
||||
* Add 'subdir' and 'iconv' built in modules
|
||||
|
||||
* lib/fuse.c: Fix locking for the reply code in create and open
|
||||
|
||||
2007-02-02 Miklos Szeredi <miklos@szeredi.hu>
|
||||
|
||||
* kernel: make it compile on "strange" kernels which have emulated
|
||||
|
||||
+3
-2
@@ -1,4 +1,4 @@
|
||||
AC_INIT(fuse, 2.6.1)
|
||||
AC_INIT(fuse, 2.7.0-pre0)
|
||||
AC_CANONICAL_TARGET
|
||||
AM_INIT_AUTOMAKE
|
||||
AM_CONFIG_HEADER(include/config.h)
|
||||
@@ -62,8 +62,9 @@ AC_CHECK_FUNCS([fork setxattr fdatasync])
|
||||
AC_CHECK_MEMBERS([struct stat.st_atim])
|
||||
AC_CHECK_MEMBERS([struct stat.st_atimespec])
|
||||
|
||||
libfuse_libs=-pthread
|
||||
libfuse_libs="-pthread"
|
||||
LIBS=
|
||||
AC_SEARCH_LIBS(dlopen, [dl])
|
||||
AC_SEARCH_LIBS(clock_gettime, [rt])
|
||||
libfuse_libs="$libfuse_libs $LIBS"
|
||||
LIBS=
|
||||
|
||||
+2
-2
@@ -3,5 +3,5 @@
|
||||
AM_CPPFLAGS = -I$(top_srcdir)/include -D_FILE_OFFSET_BITS=64 -D_REENTRANT
|
||||
noinst_PROGRAMS = fusexmp fusexmp_fh null hello hello_ll
|
||||
|
||||
LDADD = ../lib/libfuse.la -lpthread
|
||||
fusexmp_fh_LDADD = ../lib/libfuse.la ../lib/libulockmgr.la -lpthread
|
||||
LDADD = ../lib/libfuse.la @libfuse_libs@
|
||||
fusexmp_fh_LDADD = ../lib/libfuse.la ../lib/libulockmgr.la @libfuse_libs@
|
||||
|
||||
@@ -572,6 +572,93 @@ int fuse_is_lib_option(const char *opt);
|
||||
int fuse_main_real(int argc, char *argv[], const struct fuse_operations *op,
|
||||
size_t op_size, void *user_data);
|
||||
|
||||
/*
|
||||
*
|
||||
*/
|
||||
|
||||
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);
|
||||
int fuse_fs_rename(struct fuse_fs *fs, const char *oldpath,
|
||||
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);
|
||||
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_open(struct fuse_fs *fs, const char *path,
|
||||
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);
|
||||
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);
|
||||
int fuse_fs_fsync(struct fuse_fs *fs, const char *path, int datasync,
|
||||
struct fuse_file_info *fi);
|
||||
int fuse_fs_flush(struct fuse_fs *fs, const char *path,
|
||||
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);
|
||||
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);
|
||||
int fuse_fs_fsyncdir(struct fuse_fs *fs, const char *path, int datasync,
|
||||
struct fuse_file_info *fi);
|
||||
int fuse_fs_releasedir(struct fuse_fs *fs, const char *path,
|
||||
struct fuse_file_info *fi);
|
||||
int fuse_fs_create(struct fuse_fs *fs, const char *path, mode_t mode,
|
||||
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);
|
||||
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);
|
||||
int fuse_fs_utimens(struct fuse_fs *fs, const char *path,
|
||||
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);
|
||||
int fuse_fs_mknod(struct fuse_fs *fs, const char *path, mode_t mode,
|
||||
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);
|
||||
int fuse_fs_getxattr(struct fuse_fs *fs, const char *path, const char *name,
|
||||
char *value, size_t size);
|
||||
int fuse_fs_listxattr(struct fuse_fs *fs, const char *path, char *list,
|
||||
size_t size);
|
||||
int fuse_fs_removexattr(struct fuse_fs *fs, const char *path,
|
||||
const char *name);
|
||||
int fuse_fs_bmap(struct fuse_fs *fs, const char *path, size_t blocksize,
|
||||
uint64_t *idx);
|
||||
void fuse_fs_init(struct fuse_fs *fs, struct fuse_conn_info *conn);
|
||||
void fuse_fs_destroy(struct fuse_fs *fs);
|
||||
|
||||
struct fuse_fs *fuse_fs_new(const struct fuse_operations *op, size_t op_size,
|
||||
void *user_data);
|
||||
|
||||
struct fuse_module {
|
||||
const char *name;
|
||||
struct fuse_fs *(*factory)(struct fuse_args *, struct fuse_fs *[]);
|
||||
struct fuse_module *next;
|
||||
struct fusemod_so *so;
|
||||
int ctr;
|
||||
};
|
||||
|
||||
void fuse_register_module(struct fuse_module *mod);
|
||||
#define FUSE_REGISTER_MODULE(name_, factory_) \
|
||||
static __attribute__((constructor)) void name_ ## _register(void) \
|
||||
{ \
|
||||
static struct fuse_module mod = { .name = #name_, .factory = factory_ }; \
|
||||
fuse_register_module(&mod); \
|
||||
}
|
||||
|
||||
|
||||
/* ----------------------------------------------------------- *
|
||||
* Advanced API for event handling, don't worry about this... *
|
||||
* ----------------------------------------------------------- */
|
||||
|
||||
@@ -20,7 +20,7 @@
|
||||
#define FUSE_MAJOR_VERSION 2
|
||||
|
||||
/** Minor version of FUSE library interface */
|
||||
#define FUSE_MINOR_VERSION 6
|
||||
#define FUSE_MINOR_VERSION 7
|
||||
|
||||
#define FUSE_MAKE_VERSION(maj, min) ((maj) * 10 + (min))
|
||||
#define FUSE_VERSION FUSE_MAKE_VERSION(FUSE_MAJOR_VERSION, FUSE_MINOR_VERSION)
|
||||
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
AC_INIT(fuse-kernel, 2.6.1)
|
||||
AC_INIT(fuse-kernel, 2.7.0-pre0)
|
||||
AC_CONFIG_HEADERS([config.h])
|
||||
|
||||
AC_PROG_INSTALL
|
||||
|
||||
+4
-2
@@ -24,12 +24,14 @@ libfuse_la_SOURCES = \
|
||||
fuse_session.c \
|
||||
fuse_signals.c \
|
||||
helper.c \
|
||||
modules/subdir.c \
|
||||
modules/iconv.c \
|
||||
$(mount_source)
|
||||
|
||||
libfuse_la_LDFLAGS = $(libfuse_libs) -version-number 2:6:1 \
|
||||
libfuse_la_LDFLAGS = @libfuse_libs@ -version-number 2:7:0 \
|
||||
-Wl,--version-script,$(srcdir)/fuse_versionscript
|
||||
|
||||
libulockmgr_la_SOURCES = ulockmgr.c
|
||||
libulockmgr_la_LDFLAGS = -version-number 1:0:0
|
||||
libulockmgr_la_LDFLAGS = -version-number 1:0:1
|
||||
|
||||
EXTRA_DIST = fuse_versionscript
|
||||
|
||||
+1173
-864
File diff suppressed because it is too large
Load Diff
+5
-9
@@ -75,11 +75,9 @@ static void convert_stat(const struct stat *stbuf, struct fuse_attr *attr)
|
||||
attr->atime = stbuf->st_atime;
|
||||
attr->mtime = stbuf->st_mtime;
|
||||
attr->ctime = stbuf->st_ctime;
|
||||
#ifdef FUSE_STAT_HAS_NANOSEC
|
||||
attr->atimensec = ST_ATIM(stbuf).tv_nsec;
|
||||
attr->mtimensec = ST_MTIM(stbuf).tv_nsec;
|
||||
attr->ctimensec = ST_CTIM(stbuf).tv_nsec;
|
||||
#endif
|
||||
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)
|
||||
@@ -90,10 +88,8 @@ static void convert_attr(const struct fuse_setattr_in *attr, struct stat *stbuf)
|
||||
stbuf->st_size = attr->size;
|
||||
stbuf->st_atime = attr->atime;
|
||||
stbuf->st_mtime = attr->mtime;
|
||||
#ifdef FUSE_STAT_HAS_NANOSEC
|
||||
ST_ATIM(stbuf).tv_nsec = attr->atimensec;
|
||||
ST_MTIM(stbuf).tv_nsec = attr->mtimensec;
|
||||
#endif
|
||||
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)
|
||||
|
||||
+16
-8
@@ -24,14 +24,22 @@ static inline void fuse_mutex_init(pthread_mutex_t *mut)
|
||||
|
||||
#ifdef HAVE_STRUCT_STAT_ST_ATIM
|
||||
/* Linux */
|
||||
#define ST_ATIM(stbuf) (stbuf)->st_atim
|
||||
#define ST_CTIM(stbuf) (stbuf)->st_ctim
|
||||
#define ST_MTIM(stbuf) (stbuf)->st_mtim
|
||||
#define FUSE_STAT_HAS_NANOSEC 1
|
||||
#define ST_ATIM_NSEC(stbuf) ((stbuf)->st_atim.tv_nsec)
|
||||
#define ST_CTIM_NSEC(stbuf) ((stbuf)->st_ctim.tv_nsec)
|
||||
#define ST_MTIM_NSEC(stbuf) ((stbuf)->st_mtim.tv_nsec)
|
||||
#define ST_ATIM_NSEC_SET(stbuf, val) (stbuf)->st_atim.tv_nsec = (val)
|
||||
#define ST_MTIM_NSEC_SET(stbuf, val) (stbuf)->st_mtim.tv_nsec = (val)
|
||||
#elif defined(HAVE_STRUCT_STAT_ST_ATIMESPEC)
|
||||
/* FreeBSD */
|
||||
#define ST_ATIM(stbuf) (stbuf)->st_atimespec
|
||||
#define ST_CTIM(stbuf) (stbuf)->st_ctimespec
|
||||
#define ST_MTIM(stbuf) (stbuf)->st_mtimespec
|
||||
#define FUSE_STAT_HAS_NANOSEC 1
|
||||
#define ST_ATIM(stbuf) ((stbuf)->st_atimespec.tv_nsec)
|
||||
#define ST_CTIM(stbuf) ((stbuf)->st_ctimespec.tv_nsec)
|
||||
#define ST_MTIM(stbuf) ((stbuf)->st_mtimespec.tv_nsec)
|
||||
#define ST_ATIM_NSEC_SET(stbuf, val) (stbuf)->st_atimespec.tv_nsec = (val)
|
||||
#define ST_MTIM_NSEC_SET(stbuf, val) (stbuf)->st_mtimespec.tv_nsec = (val)
|
||||
#else
|
||||
#define ST_ATIM_NSEC(stbuf) 0
|
||||
#define ST_CTIM_NSEC(stbuf) 0
|
||||
#define ST_MTIM_NSEC(stbuf) 0
|
||||
#define ST_ATIM_NSEC_SET(stbuf, val) do { } while (0)
|
||||
#define ST_MTIM_NSEC_SET(stbuf, val) do { } while (0)
|
||||
#endif
|
||||
|
||||
+44
-2
@@ -108,7 +108,49 @@ FUSE_2.6 {
|
||||
fuse_teardown_compat22;
|
||||
fuse_unmount;
|
||||
fuse_unmount_compat22;
|
||||
} FUSE_2.5;
|
||||
|
||||
FUSE_2.7 {
|
||||
global:
|
||||
fuse_fs_access;
|
||||
fuse_fs_bmap;
|
||||
fuse_fs_chmod;
|
||||
fuse_fs_chown;
|
||||
fuse_fs_create;
|
||||
fuse_fs_destroy;
|
||||
fuse_fs_fgetattr;
|
||||
fuse_fs_flush;
|
||||
fuse_fs_fsync;
|
||||
fuse_fs_fsyncdir;
|
||||
fuse_fs_ftruncate;
|
||||
fuse_fs_getattr;
|
||||
fuse_fs_getxattr;
|
||||
fuse_fs_init;
|
||||
fuse_fs_link;
|
||||
fuse_fs_listxattr;
|
||||
fuse_fs_lock;
|
||||
fuse_fs_mkdir;
|
||||
fuse_fs_mknod;
|
||||
fuse_fs_new;
|
||||
fuse_fs_open;
|
||||
fuse_fs_opendir;
|
||||
fuse_fs_read;
|
||||
fuse_fs_readdir;
|
||||
fuse_fs_readlink;
|
||||
fuse_fs_release;
|
||||
fuse_fs_releasedir;
|
||||
fuse_fs_removexattr;
|
||||
fuse_fs_rename;
|
||||
fuse_fs_rmdir;
|
||||
fuse_fs_setxattr;
|
||||
fuse_fs_statfs;
|
||||
fuse_fs_symlink;
|
||||
fuse_fs_truncate;
|
||||
fuse_fs_unlink;
|
||||
fuse_fs_utimens;
|
||||
fuse_fs_write;
|
||||
fuse_register_module;
|
||||
|
||||
local:
|
||||
*;
|
||||
} FUSE_2.5;
|
||||
*;
|
||||
} FUSE_2.6;
|
||||
|
||||
@@ -0,0 +1,701 @@
|
||||
#define FUSE_USE_VERSION 26
|
||||
#define _FILE_OFFSET_BITS 64
|
||||
|
||||
#include <fuse.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stddef.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
#include <iconv.h>
|
||||
#include <pthread.h>
|
||||
#include <locale.h>
|
||||
#include <langinfo.h>
|
||||
|
||||
struct iconv {
|
||||
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;
|
||||
};
|
||||
|
||||
static struct iconv *iconv_get(void)
|
||||
{
|
||||
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; /* FIXME after testing */
|
||||
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;
|
||||
}
|
||||
|
||||
static int iconv_fgetattr(const char *path, struct stat *stbuf,
|
||||
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;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
static int iconv_dir_fill(void *buf, const char *name,
|
||||
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;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
static int iconv_ftruncate(const char *path, off_t size,
|
||||
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;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
static int iconv_create(const char *path, mode_t mode,
|
||||
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;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
static int iconv_read(const char *path, char *buf, size_t size, 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_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)
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
static int iconv_fsync(const char *path, int isdatasync,
|
||||
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;
|
||||
}
|
||||
|
||||
static int iconv_fsyncdir(const char *path, int isdatasync,
|
||||
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;
|
||||
}
|
||||
|
||||
static int iconv_setxattr(const char *path, const char *name,
|
||||
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;
|
||||
}
|
||||
|
||||
static int iconv_getxattr(const char *path, const char *name, char *value,
|
||||
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;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
static int iconv_lock(const char *path, struct fuse_file_info *fi, int cmd,
|
||||
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;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
static void *iconv_init(struct fuse_conn_info *conn)
|
||||
{
|
||||
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);
|
||||
}
|
||||
|
||||
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,
|
||||
};
|
||||
|
||||
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
|
||||
};
|
||||
|
||||
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,
|
||||
" -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);
|
||||
}
|
||||
|
||||
static int iconv_opt_proc(void *data, const char *arg, int key,
|
||||
struct fuse_args *outargs)
|
||||
{
|
||||
(void) data; (void) arg; (void) outargs;
|
||||
|
||||
if (!key) {
|
||||
iconv_help();
|
||||
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;
|
||||
}
|
||||
|
||||
FUSE_REGISTER_MODULE(iconv, iconv_new);
|
||||
@@ -0,0 +1,655 @@
|
||||
#define FUSE_USE_VERSION 26
|
||||
#define _FILE_OFFSET_BITS 64
|
||||
|
||||
#include <fuse.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stddef.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
|
||||
struct subdir {
|
||||
char *base;
|
||||
size_t baselen;
|
||||
int rellinks;
|
||||
struct fuse_fs *next;
|
||||
};
|
||||
|
||||
static struct subdir *subdir_get(void)
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
static int subdir_fgetattr(const char *path, struct stat *stbuf,
|
||||
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;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
static int count_components(const char *p)
|
||||
{
|
||||
int 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));
|
||||
}
|
||||
|
||||
static void transform_symlink(struct subdir *d, const char *path,
|
||||
char *buf, size_t size)
|
||||
{
|
||||
const char *l = buf;
|
||||
size_t llen;
|
||||
char *s;
|
||||
int dotdots;
|
||||
int i;
|
||||
|
||||
if (l[0] != '/' || d->base[0] != '/')
|
||||
return;
|
||||
|
||||
strip_common(&l, &path);
|
||||
if (l - buf < d->baselen)
|
||||
return;
|
||||
|
||||
dotdots = count_components(path);
|
||||
if (!dotdots)
|
||||
return;
|
||||
dotdots--;
|
||||
|
||||
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';
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
static int subdir_readdir(const char *path, void *buf,
|
||||
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;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
static int subdir_ftruncate(const char *path, off_t size,
|
||||
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;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
static int subdir_read(const char *path, char *buf, size_t size, 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_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)
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
static int subdir_fsync(const char *path, int isdatasync,
|
||||
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;
|
||||
}
|
||||
|
||||
static int subdir_fsyncdir(const char *path, int isdatasync,
|
||||
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;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
static int subdir_getxattr(const char *path, const char *name, char *value,
|
||||
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;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
static int subdir_lock(const char *path, struct fuse_file_info *fi, int cmd,
|
||||
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;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
static void *subdir_init(struct fuse_conn_info *conn)
|
||||
{
|
||||
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);
|
||||
}
|
||||
|
||||
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,
|
||||
};
|
||||
|
||||
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
|
||||
};
|
||||
|
||||
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");
|
||||
}
|
||||
|
||||
static int subdir_opt_proc(void *data, const char *arg, int key,
|
||||
struct fuse_args *outargs)
|
||||
{
|
||||
(void) data; (void) arg; (void) outargs;
|
||||
|
||||
if (!key) {
|
||||
subdir_help();
|
||||
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;
|
||||
}
|
||||
|
||||
FUSE_REGISTER_MODULE(subdir, subdir_new);
|
||||
Reference in New Issue
Block a user