mirror of https://github.com/trapexit/mergerfs.git
trapexit
6 years ago
committed by
GitHub
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 1 additions and 1623 deletions
-
10libfuse/lib/Makefile.am
-
178libfuse/lib/fuse.c
-
739libfuse/lib/modules/iconv.c
-
697libfuse/lib/modules/subdir.c
@ -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); |
|
Write
Preview
Loading…
Cancel
Save
Reference in new issue