mirror of
https://github.com/trapexit/mergerfs.git
synced 2024-11-29 12:03:59 +08:00
commit
401502579b
|
@ -12,12 +12,6 @@ else
|
||||||
mount_source = mount.c mount_util.c mount_util.h
|
mount_source = mount.c mount_util.c mount_util.h
|
||||||
endif
|
endif
|
||||||
|
|
||||||
if ICONV
|
|
||||||
iconv_source = modules/iconv.c
|
|
||||||
else
|
|
||||||
iconv_source =
|
|
||||||
endif
|
|
||||||
|
|
||||||
libfuse_la_SOURCES = \
|
libfuse_la_SOURCES = \
|
||||||
fuse.c \
|
fuse.c \
|
||||||
fuse_i.h \
|
fuse_i.h \
|
||||||
|
@ -32,9 +26,7 @@ libfuse_la_SOURCES = \
|
||||||
fuse_signals.c \
|
fuse_signals.c \
|
||||||
buffer.c \
|
buffer.c \
|
||||||
cuse_lowlevel.c \
|
cuse_lowlevel.c \
|
||||||
helper.c \
|
helper.c \
|
||||||
modules/subdir.c \
|
|
||||||
$(iconv_source) \
|
|
||||||
$(mount_source)
|
$(mount_source)
|
||||||
|
|
||||||
libfuse_la_LDFLAGS = -pthread @libfuse_libs@ -version-number 2:9:7 \
|
libfuse_la_LDFLAGS = -pthread @libfuse_libs@ -version-number 2:9:7 \
|
||||||
|
|
|
@ -75,13 +75,11 @@ struct fuse_config {
|
||||||
int intr;
|
int intr;
|
||||||
int intr_signal;
|
int intr_signal;
|
||||||
int help;
|
int help;
|
||||||
char *modules;
|
|
||||||
int threads;
|
int threads;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct fuse_fs {
|
struct fuse_fs {
|
||||||
struct fuse_operations op;
|
struct fuse_operations op;
|
||||||
struct fuse_module *m;
|
|
||||||
void *user_data;
|
void *user_data;
|
||||||
int compat;
|
int compat;
|
||||||
int debug;
|
int debug;
|
||||||
|
@ -222,104 +220,6 @@ struct fuse_context_i {
|
||||||
static pthread_key_t fuse_context_key;
|
static pthread_key_t fuse_context_key;
|
||||||
static pthread_mutex_t fuse_context_lock = PTHREAD_MUTEX_INITIALIZER;
|
static pthread_mutex_t fuse_context_lock = PTHREAD_MUTEX_INITIALIZER;
|
||||||
static int fuse_context_ref;
|
static int fuse_context_ref;
|
||||||
static struct fusemod_so *fuse_current_so;
|
|
||||||
static struct fuse_module *fuse_modules;
|
|
||||||
|
|
||||||
static int fuse_load_so_name(const char *soname)
|
|
||||||
{
|
|
||||||
struct fusemod_so *so;
|
|
||||||
|
|
||||||
so = calloc(1, sizeof(struct fusemod_so));
|
|
||||||
if (!so) {
|
|
||||||
fprintf(stderr, "fuse: memory allocation failed\n");
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
fuse_current_so = so;
|
|
||||||
so->handle = dlopen(soname, RTLD_NOW);
|
|
||||||
fuse_current_so = NULL;
|
|
||||||
if (!so->handle) {
|
|
||||||
fprintf(stderr, "fuse: %s\n", dlerror());
|
|
||||||
goto err;
|
|
||||||
}
|
|
||||||
if (!so->ctr) {
|
|
||||||
fprintf(stderr, "fuse: %s did not register any modules\n",
|
|
||||||
soname);
|
|
||||||
goto err;
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
err:
|
|
||||||
if (so->handle)
|
|
||||||
dlclose(so->handle);
|
|
||||||
free(so);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int fuse_load_so_module(const char *module)
|
|
||||||
{
|
|
||||||
int res;
|
|
||||||
char *soname = malloc(strlen(module) + 64);
|
|
||||||
if (!soname) {
|
|
||||||
fprintf(stderr, "fuse: memory allocation failed\n");
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
sprintf(soname, "libfusemod_%s.so", module);
|
|
||||||
res = fuse_load_so_name(soname);
|
|
||||||
free(soname);
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
|
|
||||||
static struct fuse_module *fuse_find_module(const char *module)
|
|
||||||
{
|
|
||||||
struct fuse_module *m;
|
|
||||||
for (m = fuse_modules; m; m = m->next) {
|
|
||||||
if (strcmp(module, m->name) == 0) {
|
|
||||||
m->ctr++;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return m;
|
|
||||||
}
|
|
||||||
|
|
||||||
static struct fuse_module *fuse_get_module(const char *module)
|
|
||||||
{
|
|
||||||
struct fuse_module *m;
|
|
||||||
|
|
||||||
pthread_mutex_lock(&fuse_context_lock);
|
|
||||||
m = fuse_find_module(module);
|
|
||||||
if (!m) {
|
|
||||||
int err = fuse_load_so_module(module);
|
|
||||||
if (!err)
|
|
||||||
m = fuse_find_module(module);
|
|
||||||
}
|
|
||||||
pthread_mutex_unlock(&fuse_context_lock);
|
|
||||||
return m;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void fuse_put_module(struct fuse_module *m)
|
|
||||||
{
|
|
||||||
pthread_mutex_lock(&fuse_context_lock);
|
|
||||||
assert(m->ctr > 0);
|
|
||||||
m->ctr--;
|
|
||||||
if (!m->ctr && m->so) {
|
|
||||||
struct fusemod_so *so = m->so;
|
|
||||||
assert(so->ctr > 0);
|
|
||||||
so->ctr--;
|
|
||||||
if (!so->ctr) {
|
|
||||||
struct fuse_module **mp;
|
|
||||||
for (mp = &fuse_modules; *mp;) {
|
|
||||||
if ((*mp)->so == so)
|
|
||||||
*mp = (*mp)->next;
|
|
||||||
else
|
|
||||||
mp = &(*mp)->next;
|
|
||||||
}
|
|
||||||
dlclose(so->handle);
|
|
||||||
free(so);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
pthread_mutex_unlock(&fuse_context_lock);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void init_list_head(struct list_head *list)
|
static void init_list_head(struct list_head *list)
|
||||||
{
|
{
|
||||||
|
@ -2612,8 +2512,6 @@ void fuse_fs_destroy(struct fuse_fs *fs)
|
||||||
fuse_get_context()->private_data = fs->user_data;
|
fuse_get_context()->private_data = fs->user_data;
|
||||||
if (fs->op.destroy)
|
if (fs->op.destroy)
|
||||||
fs->op.destroy(fs->user_data);
|
fs->op.destroy(fs->user_data);
|
||||||
if (fs->m)
|
|
||||||
fuse_put_module(fs->m);
|
|
||||||
free(fs);
|
free(fs);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -4399,7 +4297,6 @@ static const struct fuse_opt fuse_lib_opts[] = {
|
||||||
FUSE_LIB_OPT("nopath", nopath, 1),
|
FUSE_LIB_OPT("nopath", nopath, 1),
|
||||||
FUSE_LIB_OPT("intr", intr, 1),
|
FUSE_LIB_OPT("intr", intr, 1),
|
||||||
FUSE_LIB_OPT("intr_signal=%d", intr_signal, 0),
|
FUSE_LIB_OPT("intr_signal=%d", intr_signal, 0),
|
||||||
FUSE_LIB_OPT("modules=%s", modules, 0),
|
|
||||||
FUSE_LIB_OPT("threads=%d", threads, 0),
|
FUSE_LIB_OPT("threads=%d", threads, 0),
|
||||||
FUSE_OPT_END
|
FUSE_OPT_END
|
||||||
};
|
};
|
||||||
|
@ -4424,33 +4321,12 @@ static void fuse_lib_help(void)
|
||||||
" -o nopath don't supply path if not necessary\n"
|
" -o nopath don't supply path if not necessary\n"
|
||||||
" -o intr allow requests to be interrupted\n"
|
" -o intr allow requests to be interrupted\n"
|
||||||
" -o intr_signal=NUM signal to send on interrupt (%i)\n"
|
" -o intr_signal=NUM signal to send on interrupt (%i)\n"
|
||||||
" -o modules=M1[:M2...] names of modules to push onto filesystem stack\n"
|
|
||||||
" -o threads=NUM number of worker threads. 0 = autodetect.\n"
|
" -o threads=NUM number of worker threads. 0 = autodetect.\n"
|
||||||
" Negative values autodetect then divide by\n"
|
" Negative values autodetect then divide by\n"
|
||||||
" absolute value. default = 0\n"
|
" absolute value. default = 0\n"
|
||||||
"\n", FUSE_DEFAULT_INTR_SIGNAL);
|
"\n", FUSE_DEFAULT_INTR_SIGNAL);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void fuse_lib_help_modules(void)
|
|
||||||
{
|
|
||||||
struct fuse_module *m;
|
|
||||||
fprintf(stderr, "\nModule options:\n");
|
|
||||||
pthread_mutex_lock(&fuse_context_lock);
|
|
||||||
for (m = fuse_modules; m; m = m->next) {
|
|
||||||
struct fuse_fs *fs = NULL;
|
|
||||||
struct fuse_fs *newfs;
|
|
||||||
struct fuse_args args = FUSE_ARGS_INIT(0, NULL);
|
|
||||||
if (fuse_opt_add_arg(&args, "") != -1 &&
|
|
||||||
fuse_opt_add_arg(&args, "-h") != -1) {
|
|
||||||
fprintf(stderr, "\n[%s]\n", m->name);
|
|
||||||
newfs = m->factory(&args, &fs);
|
|
||||||
assert(newfs == NULL);
|
|
||||||
}
|
|
||||||
fuse_opt_free_args(&args);
|
|
||||||
}
|
|
||||||
pthread_mutex_unlock(&fuse_context_lock);
|
|
||||||
}
|
|
||||||
|
|
||||||
static int fuse_lib_opt_proc(void *data, const char *arg, int key,
|
static int fuse_lib_opt_proc(void *data, const char *arg, int key,
|
||||||
struct fuse_args *outargs)
|
struct fuse_args *outargs)
|
||||||
{
|
{
|
||||||
|
@ -4506,29 +4382,6 @@ static void fuse_restore_intr_signal(int signum)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static int fuse_push_module(struct fuse *f, const char *module,
|
|
||||||
struct fuse_args *args)
|
|
||||||
{
|
|
||||||
struct fuse_fs *fs[2] = { f->fs, NULL };
|
|
||||||
struct fuse_fs *newfs;
|
|
||||||
struct fuse_module *m = fuse_get_module(module);
|
|
||||||
|
|
||||||
if (!m)
|
|
||||||
return -1;
|
|
||||||
|
|
||||||
newfs = m->factory(args, fs);
|
|
||||||
if (!newfs) {
|
|
||||||
fuse_put_module(m);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
newfs->m = m;
|
|
||||||
f->fs = newfs;
|
|
||||||
f->nullpath_ok = newfs->op.flag_nullpath_ok && f->nullpath_ok;
|
|
||||||
f->conf.nopath = newfs->op.flag_nopath && f->conf.nopath;
|
|
||||||
f->utime_omit_ok = newfs->op.flag_utime_omit_ok && f->utime_omit_ok;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
struct fuse_fs *fuse_fs_new(const struct fuse_operations *op, size_t op_size,
|
struct fuse_fs *fuse_fs_new(const struct fuse_operations *op, size_t op_size,
|
||||||
void *user_data)
|
void *user_data)
|
||||||
{
|
{
|
||||||
|
@ -4643,21 +4496,6 @@ struct fuse *fuse_new_common(struct fuse_chan *ch, struct fuse_args *args,
|
||||||
fuse_lib_opt_proc) == -1)
|
fuse_lib_opt_proc) == -1)
|
||||||
goto out_free_fs;
|
goto out_free_fs;
|
||||||
|
|
||||||
if (f->conf.modules) {
|
|
||||||
char *module;
|
|
||||||
char *next;
|
|
||||||
|
|
||||||
for (module = f->conf.modules; module; module = next) {
|
|
||||||
char *p;
|
|
||||||
for (p = module; *p && *p != ':'; p++);
|
|
||||||
next = *p ? p + 1 : NULL;
|
|
||||||
*p = '\0';
|
|
||||||
if (module[0] &&
|
|
||||||
fuse_push_module(f, module, args) == -1)
|
|
||||||
goto out_free_fs;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!f->conf.ac_attr_timeout_set)
|
if (!f->conf.ac_attr_timeout_set)
|
||||||
f->conf.ac_attr_timeout = f->conf.attr_timeout;
|
f->conf.ac_attr_timeout = f->conf.attr_timeout;
|
||||||
|
|
||||||
|
@ -4676,8 +4514,6 @@ struct fuse *fuse_new_common(struct fuse_chan *ch, struct fuse_args *args,
|
||||||
|
|
||||||
f->se = fuse_lowlevel_new_common(args, &llop, sizeof(llop), f);
|
f->se = fuse_lowlevel_new_common(args, &llop, sizeof(llop), f);
|
||||||
if (f->se == NULL) {
|
if (f->se == NULL) {
|
||||||
if (f->conf.help)
|
|
||||||
fuse_lib_help_modules();
|
|
||||||
goto out_free_fs;
|
goto out_free_fs;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -4739,7 +4575,6 @@ out_free_fs:
|
||||||
called on the filesystem without init being called first */
|
called on the filesystem without init being called first */
|
||||||
fs->op.destroy = NULL;
|
fs->op.destroy = NULL;
|
||||||
fuse_fs_destroy(f->fs);
|
fuse_fs_destroy(f->fs);
|
||||||
free(f->conf.modules);
|
|
||||||
out_free:
|
out_free:
|
||||||
free(f);
|
free(f);
|
||||||
out_delete_context_key:
|
out_delete_context_key:
|
||||||
|
@ -4800,7 +4635,6 @@ void fuse_destroy(struct fuse *f)
|
||||||
free(f->name_table.array);
|
free(f->name_table.array);
|
||||||
pthread_mutex_destroy(&f->lock);
|
pthread_mutex_destroy(&f->lock);
|
||||||
fuse_session_destroy(f->se);
|
fuse_session_destroy(f->se);
|
||||||
free(f->conf.modules);
|
|
||||||
free(f);
|
free(f);
|
||||||
fuse_delete_context_key();
|
fuse_delete_context_key();
|
||||||
}
|
}
|
||||||
|
@ -4818,18 +4652,6 @@ static struct fuse *fuse_new_common_compat25(int fd, struct fuse_args *args,
|
||||||
return f;
|
return f;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* called with fuse_context_lock held or during initialization (before
|
|
||||||
main() has been called) */
|
|
||||||
void fuse_register_module(struct fuse_module *mod)
|
|
||||||
{
|
|
||||||
mod->ctr = 0;
|
|
||||||
mod->so = fuse_current_so;
|
|
||||||
if (mod->so)
|
|
||||||
mod->so->ctr++;
|
|
||||||
mod->next = fuse_modules;
|
|
||||||
fuse_modules = mod;
|
|
||||||
}
|
|
||||||
|
|
||||||
#if !defined(__FreeBSD__) && !defined(__NetBSD__)
|
#if !defined(__FreeBSD__) && !defined(__NetBSD__)
|
||||||
|
|
||||||
static struct fuse *fuse_new_common_compat(int fd, const char *opts,
|
static struct fuse *fuse_new_common_compat(int fd, const char *opts,
|
||||||
|
|
|
@ -1,739 +0,0 @@
|
||||||
/*
|
|
||||||
fuse iconv module: file name charset conversion
|
|
||||||
Copyright (C) 2007 Miklos Szeredi <miklos@szeredi.hu>
|
|
||||||
|
|
||||||
This program can be distributed under the terms of the GNU LGPLv2.
|
|
||||||
See the file COPYING.LIB
|
|
||||||
*/
|
|
||||||
|
|
||||||
#define FUSE_USE_VERSION 26
|
|
||||||
|
|
||||||
#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;
|
|
||||||
size_t newpathlen;
|
|
||||||
char *newpath;
|
|
||||||
size_t plen;
|
|
||||||
char *p;
|
|
||||||
size_t res;
|
|
||||||
int err;
|
|
||||||
|
|
||||||
if (path == NULL) {
|
|
||||||
*newpathp = NULL;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
pathlen = strlen(path);
|
|
||||||
newpathlen = pathlen * 4;
|
|
||||||
newpath = malloc(newpathlen + 1);
|
|
||||||
if (!newpath)
|
|
||||||
return -ENOMEM;
|
|
||||||
|
|
||||||
plen = newpathlen;
|
|
||||||
p = newpath;
|
|
||||||
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_buf(const char *path, struct fuse_bufvec **bufp,
|
|
||||||
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_buf(ic->next, newpath, bufp, size, offset, fi);
|
|
||||||
free(newpath);
|
|
||||||
}
|
|
||||||
return err;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int iconv_write_buf(const char *path, struct fuse_bufvec *buf,
|
|
||||||
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_buf(ic->next, newpath, buf, 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_flock(const char *path, struct fuse_file_info *fi, int op)
|
|
||||||
{
|
|
||||||
struct iconv *ic = iconv_get();
|
|
||||||
char *newpath;
|
|
||||||
int err = iconv_convpath(ic, path, &newpath, 0);
|
|
||||||
if (!err) {
|
|
||||||
err = fuse_fs_flock(ic->next, newpath, fi, op);
|
|
||||||
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 const 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_buf = iconv_read_buf,
|
|
||||||
.write_buf = iconv_write_buf,
|
|
||||||
.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,
|
|
||||||
.flock = iconv_flock,
|
|
||||||
.bmap = iconv_bmap,
|
|
||||||
|
|
||||||
.flag_nullpath_ok = 1,
|
|
||||||
.flag_nopath = 1,
|
|
||||||
};
|
|
||||||
|
|
||||||
static const 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);
|
|
||||||
if (old) {
|
|
||||||
setlocale(LC_CTYPE, old);
|
|
||||||
free(old);
|
|
||||||
}
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
FUSE_REGISTER_MODULE(iconv, iconv_new);
|
|
|
@ -1,697 +0,0 @@
|
||||||
/*
|
|
||||||
fuse subdir module: offset paths with a base directory
|
|
||||||
Copyright (C) 2007 Miklos Szeredi <miklos@szeredi.hu>
|
|
||||||
|
|
||||||
This program can be distributed under the terms of the GNU LGPLv2.
|
|
||||||
See the file COPYING.LIB
|
|
||||||
*/
|
|
||||||
|
|
||||||
#define FUSE_USE_VERSION 26
|
|
||||||
|
|
||||||
#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 int subdir_addpath(struct subdir *d, const char *path, char **newpathp)
|
|
||||||
{
|
|
||||||
char *newpath = NULL;
|
|
||||||
|
|
||||||
if (path != NULL) {
|
|
||||||
unsigned newlen = d->baselen + strlen(path);
|
|
||||||
|
|
||||||
newpath = malloc(newlen + 2);
|
|
||||||
if (!newpath)
|
|
||||||
return -ENOMEM;
|
|
||||||
|
|
||||||
if (path[0] == '/')
|
|
||||||
path++;
|
|
||||||
strcpy(newpath, d->base);
|
|
||||||
strcpy(newpath + d->baselen, path);
|
|
||||||
if (!newpath[0])
|
|
||||||
strcpy(newpath, ".");
|
|
||||||
}
|
|
||||||
*newpathp = newpath;
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int subdir_getattr(const char *path, struct stat *stbuf)
|
|
||||||
{
|
|
||||||
struct subdir *d = subdir_get();
|
|
||||||
char *newpath;
|
|
||||||
int err = subdir_addpath(d, path, &newpath);
|
|
||||||
if (!err) {
|
|
||||||
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;
|
|
||||||
int err = subdir_addpath(d, path, &newpath);
|
|
||||||
if (!err) {
|
|
||||||
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;
|
|
||||||
int err = subdir_addpath(d, path, &newpath);
|
|
||||||
if (!err) {
|
|
||||||
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 < (long) 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;
|
|
||||||
int err = subdir_addpath(d, path, &newpath);
|
|
||||||
if (!err) {
|
|
||||||
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;
|
|
||||||
int err = subdir_addpath(d, path, &newpath);
|
|
||||||
if (!err) {
|
|
||||||
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;
|
|
||||||
int err = subdir_addpath(d, path, &newpath);
|
|
||||||
if (!err) {
|
|
||||||
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;
|
|
||||||
int err = subdir_addpath(d, path, &newpath);
|
|
||||||
if (!err) {
|
|
||||||
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;
|
|
||||||
int err = subdir_addpath(d, path, &newpath);
|
|
||||||
if (!err) {
|
|
||||||
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;
|
|
||||||
int err = subdir_addpath(d, path, &newpath);
|
|
||||||
if (!err) {
|
|
||||||
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;
|
|
||||||
int err = subdir_addpath(d, path, &newpath);
|
|
||||||
if (!err) {
|
|
||||||
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;
|
|
||||||
int err = subdir_addpath(d, path, &newpath);
|
|
||||||
if (!err) {
|
|
||||||
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;
|
|
||||||
int err = subdir_addpath(d, path, &newpath);
|
|
||||||
if (!err) {
|
|
||||||
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;
|
|
||||||
char *newto;
|
|
||||||
int err = subdir_addpath(d, from, &newfrom);
|
|
||||||
if (!err) {
|
|
||||||
err = subdir_addpath(d, to, &newto);
|
|
||||||
if (!err) {
|
|
||||||
err = fuse_fs_rename(d->next, newfrom, newto);
|
|
||||||
free(newto);
|
|
||||||
}
|
|
||||||
free(newfrom);
|
|
||||||
}
|
|
||||||
return err;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int subdir_link(const char *from, const char *to)
|
|
||||||
{
|
|
||||||
struct subdir *d = subdir_get();
|
|
||||||
char *newfrom;
|
|
||||||
char *newto;
|
|
||||||
int err = subdir_addpath(d, from, &newfrom);
|
|
||||||
if (!err) {
|
|
||||||
err = subdir_addpath(d, to, &newto);
|
|
||||||
if (!err) {
|
|
||||||
err = fuse_fs_link(d->next, newfrom, newto);
|
|
||||||
free(newto);
|
|
||||||
}
|
|
||||||
free(newfrom);
|
|
||||||
}
|
|
||||||
return err;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int subdir_chmod(const char *path, mode_t mode)
|
|
||||||
{
|
|
||||||
struct subdir *d = subdir_get();
|
|
||||||
char *newpath;
|
|
||||||
int err = subdir_addpath(d, path, &newpath);
|
|
||||||
if (!err) {
|
|
||||||
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;
|
|
||||||
int err = subdir_addpath(d, path, &newpath);
|
|
||||||
if (!err) {
|
|
||||||
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;
|
|
||||||
int err = subdir_addpath(d, path, &newpath);
|
|
||||||
if (!err) {
|
|
||||||
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;
|
|
||||||
int err = subdir_addpath(d, path, &newpath);
|
|
||||||
if (!err) {
|
|
||||||
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;
|
|
||||||
int err = subdir_addpath(d, path, &newpath);
|
|
||||||
if (!err) {
|
|
||||||
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;
|
|
||||||
int err = subdir_addpath(d, path, &newpath);
|
|
||||||
if (!err) {
|
|
||||||
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;
|
|
||||||
int err = subdir_addpath(d, path, &newpath);
|
|
||||||
if (!err) {
|
|
||||||
err = fuse_fs_open(d->next, newpath, fi);
|
|
||||||
free(newpath);
|
|
||||||
}
|
|
||||||
return err;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int subdir_read_buf(const char *path, struct fuse_bufvec **bufp,
|
|
||||||
size_t size, off_t offset, struct fuse_file_info *fi)
|
|
||||||
{
|
|
||||||
struct subdir *d = subdir_get();
|
|
||||||
char *newpath;
|
|
||||||
int err = subdir_addpath(d, path, &newpath);
|
|
||||||
if (!err) {
|
|
||||||
err = fuse_fs_read_buf(d->next, newpath, bufp, size, offset, fi);
|
|
||||||
free(newpath);
|
|
||||||
}
|
|
||||||
return err;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int subdir_write_buf(const char *path, struct fuse_bufvec *buf,
|
|
||||||
off_t offset, struct fuse_file_info *fi)
|
|
||||||
{
|
|
||||||
struct subdir *d = subdir_get();
|
|
||||||
char *newpath;
|
|
||||||
int err = subdir_addpath(d, path, &newpath);
|
|
||||||
if (!err) {
|
|
||||||
err = fuse_fs_write_buf(d->next, newpath, buf, offset, fi);
|
|
||||||
free(newpath);
|
|
||||||
}
|
|
||||||
return err;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int subdir_statfs(const char *path, struct statvfs *stbuf)
|
|
||||||
{
|
|
||||||
struct subdir *d = subdir_get();
|
|
||||||
char *newpath;
|
|
||||||
int err = subdir_addpath(d, path, &newpath);
|
|
||||||
if (!err) {
|
|
||||||
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;
|
|
||||||
int err = subdir_addpath(d, path, &newpath);
|
|
||||||
if (!err) {
|
|
||||||
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;
|
|
||||||
int err = subdir_addpath(d, path, &newpath);
|
|
||||||
if (!err) {
|
|
||||||
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;
|
|
||||||
int err = subdir_addpath(d, path, &newpath);
|
|
||||||
if (!err) {
|
|
||||||
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;
|
|
||||||
int err = subdir_addpath(d, path, &newpath);
|
|
||||||
if (!err) {
|
|
||||||
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;
|
|
||||||
int err = subdir_addpath(d, path, &newpath);
|
|
||||||
if (!err) {
|
|
||||||
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;
|
|
||||||
int err = subdir_addpath(d, path, &newpath);
|
|
||||||
if (!err) {
|
|
||||||
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;
|
|
||||||
int err = subdir_addpath(d, path, &newpath);
|
|
||||||
if (!err) {
|
|
||||||
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;
|
|
||||||
int err = subdir_addpath(d, path, &newpath);
|
|
||||||
if (!err) {
|
|
||||||
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;
|
|
||||||
int err = subdir_addpath(d, path, &newpath);
|
|
||||||
if (!err) {
|
|
||||||
err = fuse_fs_lock(d->next, newpath, fi, cmd, lock);
|
|
||||||
free(newpath);
|
|
||||||
}
|
|
||||||
return err;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int subdir_flock(const char *path, struct fuse_file_info *fi, int op)
|
|
||||||
{
|
|
||||||
struct subdir *d = subdir_get();
|
|
||||||
char *newpath;
|
|
||||||
int err = subdir_addpath(d, path, &newpath);
|
|
||||||
if (!err) {
|
|
||||||
err = fuse_fs_flock(d->next, newpath, fi, op);
|
|
||||||
free(newpath);
|
|
||||||
}
|
|
||||||
return err;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int subdir_bmap(const char *path, size_t blocksize, uint64_t *idx)
|
|
||||||
{
|
|
||||||
struct subdir *d = subdir_get();
|
|
||||||
char *newpath;
|
|
||||||
int err = subdir_addpath(d, path, &newpath);
|
|
||||||
if (!err) {
|
|
||||||
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 const 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_buf = subdir_read_buf,
|
|
||||||
.write_buf = subdir_write_buf,
|
|
||||||
.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,
|
|
||||||
.flock = subdir_flock,
|
|
||||||
.bmap = subdir_bmap,
|
|
||||||
|
|
||||||
.flag_nullpath_ok = 1,
|
|
||||||
.flag_nopath = 1,
|
|
||||||
};
|
|
||||||
|
|
||||||
static const 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);
|
|
Loading…
Reference in New Issue
Block a user