summaryrefslogtreecommitdiff
path: root/src/unionfs.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/unionfs.c')
-rw-r--r--src/unionfs.c337
1 files changed, 186 insertions, 151 deletions
diff --git a/src/unionfs.c b/src/unionfs.c
index 0d08721..26e3b98 100644
--- a/src/unionfs.c
+++ b/src/unionfs.c
@@ -16,6 +16,7 @@
#endif
#include <fuse.h>
+#include <fuse/fuse_common.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
@@ -27,13 +28,14 @@
#include <errno.h>
#include <sys/types.h>
#include <sys/time.h>
+#include <inttypes.h>
#ifdef linux
#include <sys/vfs.h>
#else
#include <sys/statvfs.h>
#endif
-#ifdef HAVE_SETXATTR
+#ifdef HAVE_XATTR
#include <sys/xattr.h>
#endif
@@ -48,52 +50,59 @@
#include "rmdir.h"
#include "readdir.h"
#include "cow.h"
+#include "string.h"
+#include "usyslog.h"
static struct fuse_opt unionfs_opts[] = {
+ FUSE_OPT_KEY("chroot=%s,", KEY_CHROOT),
+ FUSE_OPT_KEY("cow", KEY_COW),
+ FUSE_OPT_KEY("-d", KEY_DEBUG),
+ FUSE_OPT_KEY("debug_file=%s", KEY_DEBUG_FILE),
+ FUSE_OPT_KEY("dirs=%s", KEY_DIRS),
FUSE_OPT_KEY("--help", KEY_HELP),
- FUSE_OPT_KEY("--version", KEY_VERSION),
FUSE_OPT_KEY("-h", KEY_HELP),
- FUSE_OPT_KEY("-V", KEY_VERSION),
- FUSE_OPT_KEY("dirs=%s", KEY_DIRS),
- FUSE_OPT_KEY("stats", KEY_STATS),
- FUSE_OPT_KEY("cow", KEY_COW),
+ FUSE_OPT_KEY("hide_meta_dir", KEY_HIDE_METADIR),
+ FUSE_OPT_KEY("hide_meta_files", KEY_HIDE_META_FILES),
+ FUSE_OPT_KEY("max_files=%s", KEY_MAX_FILES),
FUSE_OPT_KEY("noinitgroups", KEY_NOINITGROUPS),
+ FUSE_OPT_KEY("relaxed_permissions", KEY_RELAXED_PERMISSIONS),
FUSE_OPT_KEY("statfs_omit_ro", KEY_STATFS_OMIT_RO),
- FUSE_OPT_KEY("chroot=%s,", KEY_CHROOT),
- FUSE_OPT_KEY("max_files=%s", KEY_MAX_FILES),
+ FUSE_OPT_KEY("stats", KEY_STATS),
+ FUSE_OPT_KEY("--version", KEY_VERSION),
+ FUSE_OPT_KEY("-V", KEY_VERSION),
FUSE_OPT_END
};
static int unionfs_chmod(const char *path, mode_t mode) {
- DBG_IN();
+ DBG("%s\n", path);
int i = find_rw_branch_cow(path);
- if (i == -1) return -errno;
+ if (i == -1) RETURN(-errno);
char p[PATHLEN_MAX];
- snprintf(p, PATHLEN_MAX, "%s%s", uopt.branches[i].path, path);
+ if (BUILD_PATH(p, uopt.branches[i].path, path)) RETURN(-ENAMETOOLONG);
int res = chmod(p, mode);
- if (res == -1) return -errno;
+ if (res == -1) RETURN(-errno);
- return 0;
+ RETURN(0);
}
static int unionfs_chown(const char *path, uid_t uid, gid_t gid) {
- DBG_IN();
+ DBG("%s\n", path);
int i = find_rw_branch_cow(path);
- if (i == -1) return -errno;
+ if (i == -1) RETURN(-errno);
char p[PATHLEN_MAX];
- snprintf(p, PATHLEN_MAX, "%s%s", uopt.branches[i].path, path);
+ if (BUILD_PATH(p, uopt.branches[i].path, path)) RETURN(-ENAMETOOLONG);
int res = lchown(p, uid, gid);
- if (res == -1) return -errno;
+ if (res == -1) RETURN(-errno);
- return 0;
+ RETURN(0);
}
/**
@@ -101,20 +110,20 @@ static int unionfs_chown(const char *path, uid_t uid, gid_t gid) {
* libfuse will call this to create regular files
*/
static int unionfs_create(const char *path, mode_t mode, struct fuse_file_info *fi) {
- DBG_IN();
+ DBG("%s\n", path);
int i = find_rw_branch_cutlast(path);
- if (i == -1) return -errno;
+ if (i == -1) RETURN(-errno);
char p[PATHLEN_MAX];
- snprintf(p, PATHLEN_MAX, "%s%s", uopt.branches[i].path, path);
+ if (BUILD_PATH(p, uopt.branches[i].path, path)) RETURN(-ENAMETOOLONG);
// NOTE: We should do:
// Create the file with mode=0 first, otherwise we might create
// a file as root + x-bit + suid bit set, which might be used for
// security racing!
int res = open(p, fi->flags, 0);
- if (res == -1) return -errno;
+ if (res == -1) RETURN(-errno);
set_owner(p); // no error check, since creating the file succeeded
@@ -124,7 +133,8 @@ static int unionfs_create(const char *path, mode_t mode, struct fuse_file_info *
fi->fh = res;
remove_hidden(path, i);
- return 0;
+ DBG("fd = %" PRIx64 "\n", fi->fh);
+ RETURN(0);
}
@@ -134,32 +144,32 @@ static int unionfs_create(const char *path, mode_t mode, struct fuse_file_info *
* which flush the data/metadata on close()
*/
static int unionfs_flush(const char *path, struct fuse_file_info *fi) {
- DBG_IN();
+ DBG("fd = %"PRIx64"\n", fi->fh);
- if (uopt.stats_enabled && strcmp(path, STATS_FILENAME) == 0) return 0;
+ if (uopt.stats_enabled && strcmp(path, STATS_FILENAME) == 0) RETURN(0);
int fd = dup(fi->fh);
if (fd == -1) {
// What to do now?
- if (fsync(fi->fh) == -1) return -EIO;
+ if (fsync(fi->fh) == -1) RETURN(-EIO);
- return -errno;
+ RETURN(-errno);
}
int res = close(fd);
- if (res == -1) return -errno;
+ if (res == -1) RETURN(-errno);
- return 0;
+ RETURN(0);
}
/**
* Just a stub. This method is optional and can safely be left unimplemented
*/
static int unionfs_fsync(const char *path, int isdatasync, struct fuse_file_info *fi) {
- DBG_IN();
+ DBG("fd = %"PRIx64"\n", fi->fh);
- if (uopt.stats_enabled && strcmp(path, STATS_FILENAME) == 0) return 0;
+ if (uopt.stats_enabled && strcmp(path, STATS_FILENAME) == 0) RETURN(0);
int res;
if (isdatasync) {
@@ -172,30 +182,30 @@ static int unionfs_fsync(const char *path, int isdatasync, struct fuse_file_info
res = fsync(fi->fh);
}
- if (res == -1) return -errno;
+ if (res == -1) RETURN(-errno);
- return 0;
+ RETURN(0);
}
static int unionfs_getattr(const char *path, struct stat *stbuf) {
- DBG_IN();
+ DBG("%s\n", path);
if (uopt.stats_enabled && strcmp(path, STATS_FILENAME) == 0) {
memset(stbuf, 0, sizeof(stbuf));
stbuf->st_mode = S_IFREG | 0444;
stbuf->st_nlink = 1;
stbuf->st_size = STATS_SIZE;
- return 0;
+ RETURN(0);
}
-
+
int i = find_rorw_branch(path);
- if (i == -1) return -errno;
+ if (i == -1) RETURN(-errno);
char p[PATHLEN_MAX];
- snprintf(p, PATHLEN_MAX, "%s%s", uopt.branches[i].path, path);
+ if (BUILD_PATH(p, uopt.branches[i].path, path)) RETURN(-ENAMETOOLONG);
int res = lstat(p, stbuf);
- if (res == -1) return -errno;
+ if (res == -1) RETURN(-errno);
/* This is a workaround for broken gnu find implementations. Actually,
* n_links is not defined at all for directories by posix. However, it
@@ -206,7 +216,7 @@ static int unionfs_getattr(const char *path, struct stat *stbuf) {
*/
if (S_ISDIR(stbuf->st_mode)) stbuf->st_nlink = 1;
- return 0;
+ RETURN(0);
}
/**
@@ -222,7 +232,7 @@ static void * unionfs_init(struct fuse_conn_info *conn) {
if (uopt.chroot) {
int res = chroot(uopt.chroot);
if (res) {
- usyslog("Chdir to %s failed: %s ! Aborting!\n",
+ USYSLOG(LOG_WARNING, "Chdir to %s failed: %s ! Aborting!\n",
uopt.chroot, strerror(errno));
exit(1);
}
@@ -231,27 +241,28 @@ static void * unionfs_init(struct fuse_conn_info *conn) {
}
static int unionfs_link(const char *from, const char *to) {
- DBG_IN();
+ DBG("from %s to %s\n", from, to);
// hardlinks do not work across different filesystems so we need a copy of from first
int i = find_rw_branch_cow(from);
- if (i == -1) return -errno;
+ if (i == -1) RETURN(-errno);
- // FIXME, we actually MUST COW to i
- int j = find_rw_branch_cutlast(to);
- if (j == -1) return -errno;
+ int j = __find_rw_branch_cutlast(to, i);
+ if (j == -1) RETURN(-errno);
+
+ DBG("from branch: %d to branch: %d\n", i, j);
char f[PATHLEN_MAX], t[PATHLEN_MAX];
- snprintf(f, PATHLEN_MAX, "%s%s", uopt.branches[i].path, from);
- snprintf(t, PATHLEN_MAX, "%s%s", uopt.branches[j].path, to);
+ if (BUILD_PATH(f, uopt.branches[i].path, from)) RETURN(-ENAMETOOLONG);
+ if (BUILD_PATH(t, uopt.branches[j].path, to)) RETURN(-ENAMETOOLONG);
int res = link(f, t);
- if (res == -1) return -errno;
+ if (res == -1) RETURN(-errno);
// no need for set_owner(), since owner and permissions are copied over by link()
remove_hidden(to, i); // remove hide file (if any)
- return 0;
+ RETURN(0);
}
/**
@@ -261,32 +272,32 @@ static int unionfs_link(const char *from, const char *to) {
* make already hidden sub-branches visible again.
*/
static int unionfs_mkdir(const char *path, mode_t mode) {
- DBG_IN();
+ DBG("%s\n", path);
int i = find_rw_branch_cutlast(path);
- if (i == -1) return -errno;
+ if (i == -1) RETURN(-errno);
char p[PATHLEN_MAX];
- snprintf(p, PATHLEN_MAX, "%s%s", uopt.branches[i].path, path);
+ if (BUILD_PATH(p, uopt.branches[i].path, path)) RETURN(-ENAMETOOLONG);
int res = mkdir(p, 0);
- if (res == -1) return -errno;
+ if (res == -1) RETURN(-errno);
set_owner(p); // no error check, since creating the file succeeded
// NOW, that the file has the proper owner we may set the requested mode
chmod(p, mode);
- return 0;
+ RETURN(0);
}
static int unionfs_mknod(const char *path, mode_t mode, dev_t rdev) {
- DBG_IN();
+ DBG("%s\n", path);
int i = find_rw_branch_cutlast(path);
- if (i == -1) return -errno;
+ if (i == -1) RETURN(-errno);
char p[PATHLEN_MAX];
- snprintf(p, PATHLEN_MAX, "%s%s", uopt.branches[i].path, path);
+ if (BUILD_PATH(p, uopt.branches[i].path, path)) RETURN(-ENAMETOOLONG);
int file_type = mode & S_IFMT;
int file_perm = mode & (S_PROT_MASK);
@@ -298,15 +309,15 @@ static int unionfs_mknod(const char *path, mode_t mode, dev_t rdev) {
// since we now have the unionfs_create() method
// So can we remove it?
- usyslog (LOG_INFO, "deprecated mknod workaround, tell the unionfs-fuse authors if you see this!\n");
+ USYSLOG (LOG_INFO, "deprecated mknod workaround, tell the unionfs-fuse authors if you see this!\n");
res = creat(p, 0);
- if (res > 0 && close(res) == -1) usyslog(LOG_WARNING, "Warning, cannot close file\n");
+ if (res > 0 && close(res) == -1) USYSLOG(LOG_WARNING, "Warning, cannot close file\n");
} else {
res = mknod(p, file_type, rdev);
}
- if (res == -1) return -errno;
+ if (res == -1) RETURN(-errno);
set_owner(p); // no error check, since creating the file succeeded
// NOW, that the file has the proper owner we may set the requested mode
@@ -314,19 +325,19 @@ static int unionfs_mknod(const char *path, mode_t mode, dev_t rdev) {
remove_hidden(path, i);
- return 0;
+ RETURN(0);
}
static int unionfs_open(const char *path, struct fuse_file_info *fi) {
- DBG_IN();
+ DBG("%s\n", path);
if (uopt.stats_enabled && strcmp(path, STATS_FILENAME) == 0) {
if ((fi->flags & 3) == O_RDONLY) {
// This makes exec() fail
//fi->direct_io = 1;
- return 0;
+ RETURN(0);
}
- return -EACCES;
+ RETURN(-EACCES);
}
int i;
@@ -336,13 +347,13 @@ static int unionfs_open(const char *path, struct fuse_file_info *fi) {
i = find_rorw_branch(path);
}
- if (i == -1) return -errno;
+ if (i == -1) RETURN(-errno);
char p[PATHLEN_MAX];
- snprintf(p, PATHLEN_MAX, "%s%s", uopt.branches[i].path, path);
+ if (BUILD_PATH(p, uopt.branches[i].path, path)) RETURN(-ENAMETOOLONG);
int fd = open(p, fi->flags);
- if (fd == -1) return -errno;
+ if (fd == -1) RETURN(-errno);
if (fi->flags & (O_WRONLY | O_RDWR)) {
// There might have been a hide file, but since we successfully
@@ -354,11 +365,12 @@ static int unionfs_open(const char *path, struct fuse_file_info *fi) {
//fi->direct_io = 1;
fi->fh = (unsigned long)fd;
- return 0;
+ DBG("fd = %"PRIx64"\n", fi->fh);
+ RETURN(0);
}
static int unionfs_read(const char *path, char *buf, size_t size, off_t offset, struct fuse_file_info *fi) {
- DBG_IN();
+ DBG("fd = %"PRIx64"\n", fi->fh);
if (uopt.stats_enabled && strcmp(path, STATS_FILENAME) == 0) {
char out[STATS_SIZE] = "";
@@ -377,40 +389,40 @@ static int unionfs_read(const char *path, char *buf, size_t size, off_t offset,
int res = pread(fi->fh, buf, size, offset);
- if (res == -1) return -errno;
+ if (res == -1) RETURN(-errno);
if (uopt.stats_enabled) stats_add_read(&stats, size);
- return res;
+ RETURN(res);
}
static int unionfs_readlink(const char *path, char *buf, size_t size) {
- DBG_IN();
+ DBG("%s\n", path);
int i = find_rorw_branch(path);
- if (i == -1) return -errno;
+ if (i == -1) RETURN(-errno);
char p[PATHLEN_MAX];
- snprintf(p, PATHLEN_MAX, "%s%s", uopt.branches[i].path, path);
+ if (BUILD_PATH(p, uopt.branches[i].path, path)) RETURN(-ENAMETOOLONG);
int res = readlink(p, buf, size - 1);
- if (res == -1) return -errno;
+ if (res == -1) RETURN(-errno);
buf[res] = '\0';
- return 0;
+ RETURN(0);
}
static int unionfs_release(const char *path, struct fuse_file_info *fi) {
- DBG_IN();
+ DBG("fd = %"PRIx64"\n", fi->fh);
- if (uopt.stats_enabled && strcmp(path, STATS_FILENAME) == 0) return 0;
+ if (uopt.stats_enabled && strcmp(path, STATS_FILENAME) == 0) RETURN(0);
int res = close(fi->fh);
- if (res == -1) return -errno;
+ if (res == -1) RETURN(-errno);
- return 0;
+ RETURN(0);
}
/**
@@ -419,34 +431,34 @@ static int unionfs_release(const char *path, struct fuse_file_info *fi) {
* all files to the renamed directory on the read-write branch.
*/
static int unionfs_rename(const char *from, const char *to) {
- DBG_IN();
+ DBG("from %s to %s\n", from, to);
bool is_dir = false; // is 'from' a file or directory
int j = find_rw_branch_cutlast(to);
- if (j == -1) return -errno;
+ if (j == -1) RETURN(-errno);
int i = find_rorw_branch(from);
- if (i == -1) return -errno;
+ if (i == -1) RETURN(-errno);
if (!uopt.branches[i].rw) {
i = find_rw_branch_cow(from);
- if (i == -1) return -errno;
+ if (i == -1) RETURN(-errno);
}
if (i != j) {
- usyslog(LOG_ERR, "%s: from and to are on different writable branches %d vs %d, which"
+ USYSLOG(LOG_ERR, "%s: from and to are on different writable branches %d vs %d, which"
"is not supported yet.\n", __func__, i, j);
- return -EXDEV;
+ RETURN(-EXDEV);
}
char f[PATHLEN_MAX], t[PATHLEN_MAX];
- snprintf(f, PATHLEN_MAX, "%s%s", uopt.branches[i].path, from);
- snprintf(t, PATHLEN_MAX, "%s%s", uopt.branches[i].path, to);
+ if (BUILD_PATH(f, uopt.branches[i].path, from)) RETURN(-ENAMETOOLONG);
+ if (BUILD_PATH(t, uopt.branches[i].path, to)) RETURN(-ENAMETOOLONG);
filetype_t ftype = path_is_dir(f);
if (ftype == NOT_EXISTING)
- return -ENOENT;
+ RETURN(-ENOENT);
else if (ftype == IS_DIR)
is_dir = true;
@@ -458,7 +470,7 @@ static int unionfs_rename(const char *from, const char *to) {
res = hide_dir(from, i);
else
res = hide_file(from, i);
- if (res) return -errno;
+ if (res) RETURN(-errno);
}
res = rename(f, t);
@@ -468,14 +480,14 @@ static int unionfs_rename(const char *from, const char *to) {
// if from was on a read-only branch we copied it, but now rename failed so we need to delete it
if (!uopt.branches[i].rw) {
if (unlink(f))
- usyslog(LOG_ERR, "%s: cow of %s succeeded, but rename() failed and now "
+ USYSLOG(LOG_ERR, "%s: cow of %s succeeded, but rename() failed and now "
"also unlink() failed\n", __func__, from);
if (remove_hidden(from, i))
- usyslog(LOG_ERR, "%s: cow of %s succeeded, but rename() failed and now "
+ USYSLOG(LOG_ERR, "%s: cow of %s succeeded, but rename() failed and now "
"also removing the whiteout failed\n", __func__, from);
}
- return -err;
+ RETURN(-err);
}
if (uopt.branches[i].rw) {
@@ -489,7 +501,7 @@ static int unionfs_rename(const char *from, const char *to) {
}
remove_hidden(to, i); // remove hide file (if any)
- return 0;
+ RETURN(0);
}
/**
@@ -508,7 +520,7 @@ static int statvfs_local(const char *path, struct statvfs *stbuf) {
*/
struct statfs stfs;
int res = statfs(path, &stfs);
- if (res == -1) return res;
+ if (res == -1) RETURN(res);
memset(stbuf, 0, sizeof(*stbuf));
stbuf->f_bsize = stfs.f_bsize;
@@ -532,9 +544,9 @@ static int statvfs_local(const char *path, struct statvfs *stbuf) {
stbuf->f_flag = 0;
stbuf->f_namemax = stfs.f_namelen;
- return 0;
+ RETURN(0);
#else
- return statvfs(path, stbuf);
+ RETURN(statvfs(path, stbuf));
#endif
}
@@ -549,7 +561,7 @@ static int statvfs_local(const char *path, struct statvfs *stbuf) {
static int unionfs_statfs(const char *path, struct statvfs *stbuf) {
(void)path;
- DBG_IN();
+ DBG("%s\n", path);
int first = 1;
@@ -610,139 +622,139 @@ static int unionfs_statfs(const char *path, struct statvfs *stbuf) {
}
}
- return 0;
+ RETURN(0);
}
static int unionfs_symlink(const char *from, const char *to) {
- DBG_IN();
+ DBG("from %s to %s\n", from, to);
int i = find_rw_branch_cutlast(to);
- if (i == -1) return -errno;
+ if (i == -1) RETURN(-errno);
char t[PATHLEN_MAX];
- snprintf(t, PATHLEN_MAX, "%s%s", uopt.branches[i].path, to);
+ if (BUILD_PATH(t, uopt.branches[i].path, to)) RETURN(-ENAMETOOLONG);
int res = symlink(from, t);
- if (res == -1) return -errno;
+ if (res == -1) RETURN(-errno);
set_owner(t); // no error check, since creating the file succeeded
remove_hidden(to, i); // remove hide file (if any)
- return 0;
+ RETURN(0);
}
static int unionfs_truncate(const char *path, off_t size) {
- DBG_IN();
+ DBG("%s\n", path);
int i = find_rw_branch_cow(path);
- if (i == -1) return -errno;
+ if (i == -1) RETURN(-errno);
char p[PATHLEN_MAX];
- snprintf(p, PATHLEN_MAX, "%s%s", uopt.branches[i].path, path);
+ if (BUILD_PATH(p, uopt.branches[i].path, path)) RETURN(-ENAMETOOLONG);
int res = truncate(p, size);
- if (res == -1) return -errno;
+ if (res == -1) RETURN(-errno);
- return 0;
+ RETURN(0);
}
static int unionfs_utimens(const char *path, const struct timespec ts[2]) {
- DBG_IN();
+ DBG("%s\n", path);
- if (uopt.stats_enabled && strcmp(path, STATS_FILENAME) == 0) return 0;
+ if (uopt.stats_enabled && strcmp(path, STATS_FILENAME) == 0) RETURN(0);
int i = find_rw_branch_cow(path);
- if (i == -1) return -errno;
+ if (i == -1) RETURN(-errno);
char p[PATHLEN_MAX];
- snprintf(p, PATHLEN_MAX, "%s%s", uopt.branches[i].path, path);
+ if (BUILD_PATH(p, uopt.branches[i].path, path)) RETURN(-ENAMETOOLONG);
int res = utimensat(0, p, ts, AT_SYMLINK_NOFOLLOW);
- if (res == -1) return -errno;
+ if (res == -1) RETURN(-errno);
- return 0;
+ RETURN(0);
}
static int unionfs_write(const char *path, const char *buf, size_t size, off_t offset, struct fuse_file_info *fi) {
(void)path;
- DBG_IN();
+ DBG("fd = %"PRIx64"\n", fi->fh);
int res = pwrite(fi->fh, buf, size, offset);
- if (res == -1) return -errno;
+ if (res == -1) RETURN(-errno);
if (uopt.stats_enabled) stats_add_written(&stats, size);
- return res;
+ RETURN(res);
}
-#ifdef HAVE_SETXATTR
+#ifdef HAVE_XATTR
static int unionfs_getxattr(const char *path, const char *name, char *value, size_t size) {
- DBG_IN();
+ DBG("%s\n", path);
int i = find_rorw_branch(path);
- if (i == -1) return -errno;
+ if (i == -1) RETURN(-errno);
char p[PATHLEN_MAX];
- snprintf(p, PATHLEN_MAX, "%s%s", uopt.branches[i].path, path);
+ if (BUILD_PATH(p, uopt.branches[i].path, path)) RETURN(-ENAMETOOLONG);
int res = lgetxattr(p, name, value, size);
- if (res == -1) return -errno;
+ if (res == -1) RETURN(-errno);
- return res;
+ RETURN(res);
}
static int unionfs_listxattr(const char *path, char *list, size_t size) {
- DBG_IN();
+ DBG("%s\n", path);
int i = find_rorw_branch(path);
- if (i == -1) return -errno;
+ if (i == -1) RETURN(-errno);
char p[PATHLEN_MAX];
- snprintf(p, PATHLEN_MAX, "%s%s", uopt.branches[i].path, path);
+ if (BUILD_PATH(p, uopt.branches[i].path, path)) RETURN(-ENAMETOOLONG);
int res = llistxattr(p, list, size);
- if (res == -1) return -errno;
+ if (res == -1) RETURN(-errno);
- return res;
+ RETURN(res);
}
static int unionfs_removexattr(const char *path, const char *name) {
- DBG_IN();
+ DBG("%s\n", path);
int i = find_rw_branch_cow(path);
- if (i == -1) return -errno;
+ if (i == -1) RETURN(-errno);
char p[PATHLEN_MAX];
- snprintf(p, PATHLEN_MAX, "%s%s", uopt.branches[i].path, path);
+ if (BUILD_PATH(p, uopt.branches[i].path, path)) RETURN(-ENAMETOOLONG);
int res = lremovexattr(p, name);
- if (res == -1) return -errno;
+ if (res == -1) RETURN(-errno);
- return res;
+ RETURN(res);
}
static int unionfs_setxattr(const char *path, const char *name, const char *value, size_t size, int flags) {
- DBG_IN();
+ DBG("%s\n", path);
int i = find_rw_branch_cow(path);
- if (i == -1) return -errno;
+ if (i == -1) RETURN(-errno);
char p[PATHLEN_MAX];
- snprintf(p, PATHLEN_MAX, "%s%s", uopt.branches[i].path, path);
+ if (BUILD_PATH(p, uopt.branches[i].path, path)) RETURN(-ENAMETOOLONG);
int res = lsetxattr(p, name, value, size, flags);
- if (res == -1) return -errno;
+ if (res == -1) RETURN(-errno);
- return res;
+ RETURN(res);
}
-#endif // HAVE_SETXATTR
+#endif // HAVE_XATTR
static struct fuse_operations unionfs_oper = {
.chmod = unionfs_chmod,
@@ -768,7 +780,7 @@ static struct fuse_operations unionfs_oper = {
.unlink = unionfs_unlink,
.utimens = unionfs_utimens,
.write = unionfs_write,
-#ifdef HAVE_SETXATTR
+#ifdef HAVE_XATTR
.getxattr = unionfs_getxattr,
.listxattr = unionfs_listxattr,
.removexattr = unionfs_removexattr,
@@ -779,17 +791,17 @@ static struct fuse_operations unionfs_oper = {
int main(int argc, char *argv[]) {
struct fuse_args args = FUSE_ARGS_INIT(argc, argv);
- int res = debug_init();
- if (res != 0) return res;
-
+ init_syslog();
uopt_init();
- if (fuse_opt_parse(&args, NULL, unionfs_opts, unionfs_opt_proc) == -1) return 1;
+ if (fuse_opt_parse(&args, NULL, unionfs_opts, unionfs_opt_proc) == -1) RETURN(1);
+
+ if (uopt.debug) debug_init();
if (!uopt.doexit) {
if (uopt.nbranches == 0) {
printf("You need to specify at least one branch!\n");
- return 1;
+ RETURN(1);
}
if (uopt.stats_enabled) stats_init(&stats);
@@ -797,13 +809,36 @@ int main(int argc, char *argv[]) {
// enable fuse permission checks, we need to set this, even we we are
// not root, since we don't have our own access() function
- if (fuse_opt_add_arg(&args, "-odefault_permissions")) {
- fprintf(stderr, "Severe failure, can't enable permssion checks, aborting!\n");
+ int uid = getuid();
+ int gid = getgid();
+ bool default_permissions = true;
+
+ if (uid != 0 && gid != 0 && uopt.relaxed_permissions) {
+ default_permissions = false;
+ } else if (uopt.relaxed_permissions) {
+ // protec the user of a very critical security issue
+ fprintf(stderr, "Relaxed permissions disallowed for root!\n");
exit(1);
}
+
+ if (default_permissions) {
+ if (fuse_opt_add_arg(&args, "-odefault_permissions")) {
+ fprintf(stderr, "Severe failure, can't enable permssion checks, aborting!\n");
+ exit(1);
+ }
+ }
unionfs_post_opts();
+#ifdef FUSE_CAP_BIG_WRITES
+ /* libfuse > 0.8 supports large IO, also for reads, to increase performance
+ * We support any IO sizes, so lets enable that option */
+ if (fuse_opt_add_arg(&args, "-obig_writes")) {
+ fprintf(stderr, "Failed to enable big writes!\n");
+ exit(1);
+ }
+#endif
+
umask(0);
- res = fuse_main(args.argc, args.argv, &unionfs_oper, NULL);
- return uopt.doexit ? uopt.retval : res;
+ int res = fuse_main(args.argc, args.argv, &unionfs_oper, NULL);
+ RETURN(uopt.doexit ? uopt.retval : res);
}