? fuse_main.3.manlint
Index: debug.c
===================================================================
RCS file: /cvs/src/lib/libfuse/debug.c,v
retrieving revision 1.1
diff -u -p -r1.1 debug.c
--- debug.c	3 Jun 2013 16:00:50 -0000	1.1
+++ debug.c	21 Feb 2015 07:27:42 -0000
@@ -29,6 +29,7 @@ int ifuse_debug = -1;
 void
 ifuse_debug_init(void)
 {
+/*
 	char *dbg;
 
 	if (ifuse_debug < 0) {
@@ -36,5 +37,7 @@ ifuse_debug_init(void)
 		if (!dbg || sscanf(dbg, "%u", &ifuse_debug) != 1)
 			ifuse_debug = 0;
 	}
+*/
+	ifuse_debug = 1;
 }
 #endif
Index: fuse.c
===================================================================
RCS file: /cvs/src/lib/libfuse/fuse.c,v
retrieving revision 1.24
diff -u -p -r1.24 fuse.c
--- fuse.c	20 May 2014 13:32:22 -0000	1.24
+++ fuse.c	21 Feb 2015 07:27:42 -0000
@@ -33,13 +33,16 @@
 
 static struct fuse_session *sigse;
 static struct fuse_context *ictx = NULL;
-static int max_read = FUSEBUFMAXSIZE;
 
 enum {
 	KEY_HELP,
 	KEY_HELP_WITHOUT_HEADER,
 	KEY_VERSION,
 	KEY_MAXREAD,
+	KEY_FOREGROUND,
+	KEY_UID,
+	KEY_FSNAME,
+	KEY_DEBUG,
 	KEY_STUB
 };
 
@@ -49,17 +52,20 @@ static struct fuse_opt fuse_core_opts[] 
 	FUSE_OPT_KEY("-ho",			KEY_HELP_WITHOUT_HEADER),
 	FUSE_OPT_KEY("-V",			KEY_VERSION),
 	FUSE_OPT_KEY("--version",		KEY_VERSION),
-	FUSE_OPT_KEY("max_read=",		KEY_MAXREAD),
-	FUSE_OPT_KEY("debug",			KEY_STUB),
-	FUSE_OPT_KEY("-d",			KEY_STUB),
-	FUSE_OPT_KEY("-f",			KEY_STUB),
+	FUSE_OPT_KEY("max_read=%u",		KEY_MAXREAD),
+	FUSE_OPT_KEY("debug",			KEY_DEBUG),
+	FUSE_OPT_KEY("-d",			KEY_DEBUG),
+	FUSE_OPT_KEY("-f",			KEY_FOREGROUND),
 	FUSE_OPT_KEY("-s",			KEY_STUB),
 	FUSE_OPT_KEY("use_ino",			KEY_STUB),
 	FUSE_OPT_KEY("default_permissions",	KEY_STUB),
-	FUSE_OPT_KEY("fsname=",			KEY_STUB),
+	FUSE_OPT_KEY("fsname=%s",		KEY_FSNAME),
+	FUSE_OPT_KEY("uid=%u",			KEY_UID),
 	FUSE_OPT_END
 };
 
+static int ifuse_process_opt(void *, const char *, int,struct fuse_args *);
+
 int
 fuse_loop(struct fuse *fuse)
 {
@@ -149,11 +155,12 @@ fuse_loop(struct fuse *fuse)
 }
 
 struct fuse_chan *
-fuse_mount(const char *dir, unused struct fuse_args *args)
+fuse_mount(const char *dir, struct fuse_args *args)
 {
 	struct fusefs_args fargs;
 	struct fuse_chan *fc;
 	const char *errcause;
+	struct fuse_core_opt opt;
 
 	fc = calloc(1, sizeof(*fc));
 	if (fc == NULL)
@@ -168,8 +175,18 @@ fuse_mount(const char *dir, unused struc
 		goto bad;
 	}
 
+	/* configuration passed by clients */
+	bzero(&opt, sizeof(opt));
+	if (fuse_opt_parse(args, &opt, fuse_core_opts, ifuse_process_opt) == -1)
+		return (NULL);
+
 	fargs.fd = fc->fd;
-	fargs.max_read = max_read;
+
+	if (opt.max_read == 0)
+		fargs.max_read = FUSEBUFMAXSIZE;
+	else
+		fargs.max_read = opt.max_read;
+
 	if (mount(MOUNT_FUSEFS, fc->dir, 0, &fargs)) {
 		switch (errno) {
 		case EMFILE:
@@ -192,6 +209,8 @@ bad:
 		close(fc->fd);
 	free(fc->dir);
 	free(fc);
+	free(opt.mp);
+	free(opt.fsname);
 	return (NULL);
 }
 
@@ -230,12 +249,13 @@ fuse_loop_mt(unused struct fuse *fuse)
 }
 
 struct fuse *
-fuse_new(struct fuse_chan *fc, unused struct fuse_args *args,
+fuse_new(struct fuse_chan *fc, struct fuse_args *args,
     const struct fuse_operations *ops, unused size_t size,
-    unused void *userdata)
+    void *userdata)
 {
 	struct fuse *fuse;
 	struct fuse_vnode *root;
+	struct fuse_core_opt opt;
 
 	if ((fuse = calloc(1, sizeof(*fuse))) == NULL)
 		return (NULL);
@@ -248,6 +268,14 @@ fuse_new(struct fuse_chan *fc, unused st
 	fuse->se.args = fuse;
 	fuse->private_data = userdata;
 
+	/* configuration passed by clients */
+	bzero(&opt, sizeof(opt));
+	if (fuse_opt_parse(args, &opt, fuse_core_opts, ifuse_process_opt) == -1)
+		return (NULL);
+
+	fuse->conf.set_uid = opt.set_uid;
+	fuse->conf.uid = opt.uid;
+
 	if ((root = alloc_vn(fuse, "/", FUSE_ROOT_INO, 0)) == NULL) {
 		free(fuse);
 		return (NULL);
@@ -260,12 +288,17 @@ fuse_new(struct fuse_chan *fc, unused st
 		return (NULL);
 	}
 
+	free(opt.mp);
+	free(opt.fsname);
 	return (fuse);
 }
 
 int
-fuse_daemonize(unused int foreground)
+fuse_daemonize(int foreground)
 {
+	if (foreground)
+		return 0;
+
 #ifdef DEBUG
 	return (daemon(0,1));
 #else
@@ -368,7 +401,25 @@ ifuse_process_opt(void *data, const char
 				fprintf(stderr, "fuse: max_read %s\n", err);
 				return (-1);
 			}
-			max_read = res;
+			opt->max_read = res;
+			break;
+		case KEY_DEBUG:
+			ifuse_debug_init();
+			/* falls through */
+		case KEY_FOREGROUND:
+			opt->foreground = 1;
+			break;
+		case KEY_UID:
+			res = strtonum(arg, 0, UID_MAX, &err);
+			if (err) {
+				fprintf(stderr, "fuse: uid %s\n", err);
+				return (-1);
+			}
+			opt->set_uid = 1;
+			opt->uid = res;
+			break;
+		case KEY_FSNAME:
+			opt->fsname = strdup(arg);
 			break;
 		case FUSE_OPT_KEY_NONOPT:
 			if (opt->mp == NULL) {
@@ -406,13 +457,10 @@ ifuse_process_opt(void *data, const char
 }
 
 int
-fuse_parse_cmdline(struct fuse_args *args, char **mp, int *mt, unused int *fg)
+fuse_parse_cmdline(struct fuse_args *args, char **mp, int *mt, int *fg)
 {
 	struct fuse_core_opt opt;
 
-#ifdef DEBUG
-	ifuse_debug_init();
-#endif
 	bzero(&opt, sizeof(opt));
 	if (fuse_opt_parse(args, &opt, fuse_core_opts, ifuse_process_opt) == -1)
 		return (-1);
@@ -424,6 +472,10 @@ fuse_parse_cmdline(struct fuse_args *arg
 
 	*mp = strdup(opt.mp);
 	*mt = 0;
+	*fg = opt.foreground;
+
+	free(opt.mp);
+	free(opt.fsname);
 
 	return (0);
 }
@@ -465,7 +517,7 @@ fuse_setup(int argc, char **argv, const 
 	if (fuse_parse_cmdline(&args, mp, mt, &fg))
 		goto err;
 
-	fuse_daemonize(0);
+	fuse_daemonize(fg);
 
 	if ((fc = fuse_mount(*mp, NULL)) == NULL)
 		goto err;
@@ -477,8 +529,7 @@ fuse_setup(int argc, char **argv, const 
 
 	return (fuse);
 err:
-	if (*mp)
-		free(*mp);
+	free(*mp);
 	return (NULL);
 }
 
@@ -490,6 +541,9 @@ fuse_main(int argc, char **argv, const s
 	int mt;
 
 	fuse = fuse_setup(argc, argv, ops, sizeof(*ops), &mp, &mt, data);
+
+	free(mp);
+
 	if (!fuse)
 		return (-1);
 
Index: fuse_ops.c
===================================================================
RCS file: /cvs/src/lib/libfuse/fuse_ops.c,v
retrieving revision 1.24
diff -u -p -r1.24 fuse_ops.c
--- fuse_ops.c	5 Feb 2014 20:13:58 -0000	1.24
+++ fuse_ops.c	21 Feb 2015 07:27:44 -0000
@@ -180,8 +180,10 @@ ifuse_ops_open(struct fuse *f, struct fu
 	fbuf->fb_err = f->op.open(realname, &ffi);
 	free(realname);
 
-	if (!fbuf->fb_err)
+	if (!fbuf->fb_err) {
 		fbuf->fb_io_fd = ffi.fh;
+		vn->open++;
+	}
 
 	return (0);
 }
@@ -439,7 +441,17 @@ ifuse_ops_release(struct fuse *f, struct
 		fbuf->fb_err = -errno;
 		return (0);
 	}
+
 	fbuf->fb_err = f->op.release(realname, &ffi);
+	vn->open--;
+
+	if (vn->hidden && !vn->open) {
+		/* Ignore any errors. */
+		if (f->op.unlink)
+			f->op.unlink(realname);
+		remove_vnode_from_name_tree(f, vn);
+	}
+
 	free(realname);
 
 	return (0);
@@ -735,7 +747,7 @@ static int
 ifuse_ops_unlink(struct fuse *f, struct fusebuf *fbuf)
 {
 	struct fuse_vnode *vn;
-	char *realname;
+	char *realname = NULL;
 
 	CHECK_OPT(unlink);
 
@@ -753,7 +765,17 @@ ifuse_ops_unlink(struct fuse *f, struct 
 		return (0);
 	}
 
-	fbuf->fb_err = f->op.unlink(realname);
+	DPRINTF("open count %d\n", vn->open);
+	DPRINTF("hard_remove %d\n", f->conf.hard_remove);
+
+	if (!f->conf.hard_remove && vn->open && f->op.rename) {
+		fbuf->fb_err = hide(f, vn, realname);
+	} else {
+		fbuf->fb_err = f->op.unlink(realname);
+		if (!fbuf->fb_err)
+			remove_vnode_from_name_tree(f, vn);
+	}
+
 	free(realname);
 
 	return (0);
@@ -986,7 +1008,18 @@ ifuse_ops_rename(struct fuse *f, struct 
 		return (0);
 	}
 
+	DPRINTF("open count %d\n", vnt->open);
+	DPRINTF("hard_remove %d\n", f->conf.hard_remove);
+
+	/* If target exists and is open hide it first */
+	if (!f->conf.hard_remove && vnt->open) {
+		hide(f, vnt, realnamet);
+	}
+
 	fbuf->fb_err = f->op.rename(realnamef, realnamet);
+	if (!fbuf->fb_err)
+		remove_vnode_from_name_tree(f, vnf);
+
 	free(realnamef);
 	free(realnamet);
 
Index: fuse_opt.c
===================================================================
RCS file: /cvs/src/lib/libfuse/fuse_opt.c,v
retrieving revision 1.11
diff -u -p -r1.11 fuse_opt.c
--- fuse_opt.c	8 Oct 2014 04:50:10 -0000	1.11
+++ fuse_opt.c	21 Feb 2015 07:27:44 -0000
@@ -68,7 +68,7 @@ match_opt(const char *templ, const char 
 	const char *o, *t;
 	char *arg;
 
-	arg = strpbrk(templ, " =");
+	arg = strstr(templ, "=%");
 
 	/* verify template */
 	t = templ;
@@ -236,31 +236,33 @@ parse_opt(const struct fuse_opt *o, cons
 	}
 
 	for(; o->templ; o++) {
-		if ((keyval && strncmp(val, o->templ, idx) == 0) ||
-		    (!keyval && strcmp(val, o->templ) == 0)) {
+		if (match_opt(o->templ, val)) {
 			if (o->val == FUSE_OPT_KEY_DISCARD)
 				return (1);
-
 			if (FUSE_OPT_IS_OPT_KEY(o)) {
 				if (keyval)
 					ret = f(data, &val[idx], o->val, arg);
 				else
 					ret = f(data, val, o->val, arg);
-			}
 
-			if (ret == -1)
-				return (ret);
-			if (ret == 1)
-				fuse_opt_add_arg(arg, val);
-			found++;
+				if (ret == 1)
+					fuse_opt_add_arg(arg, val);
+			} else if (!keyval || !strchr(o->templ, '%')) {
+				*((int *)(data + o->off)) = o->val;
+			} else {
+				/* TODO parameterised templates */
+			}
+			found = 1;
 			break;
 		}
 	}
 
+/* This will still be useful for troubleshooting later.
 	if (!found) {
 		printf("fuse: unknown option %s\n", val);
 		return (-1);
 	}
+*/
 
 	return (ret);
 }
@@ -277,7 +279,8 @@ fuse_opt_parse(struct fuse_args *args, v
     const struct fuse_opt *opt, fuse_opt_proc_t f)
 {
 	struct fuse_args outargs;
-	const char *arg;
+	const char *arg, *ap;
+	char *optlist, *opt_free;
 	int ret = 0;
 	int i;
 
@@ -304,7 +307,16 @@ fuse_opt_parse(struct fuse_args *args, v
 			else
 				arg = args->argv[++i];
 
-			ret = parse_opt(opt, arg, data, f, &outargs);
+			optlist = strdup(arg);
+			if (optlist == NULL)
+				goto err;
+
+			opt_free = optlist;
+			while ((ap = strsep(&optlist, ",")) != NULL &&
+			       ret == 0)
+				ret = parse_opt(opt, ap, data, f, &outargs);
+
+			free(opt_free);
 
 			if (ret == -1)
 				goto err;
@@ -334,6 +346,9 @@ fuse_opt_insert_arg(struct fuse_args *ar
 	char *this_arg, *next_arg;
 	int i;
 
+#ifdef DEBUG
+	//ifuse_debug_init();
+#endif
 	if (name == NULL)
 		return (-1);
 
Index: fuse_private.h
===================================================================
RCS file: /cvs/src/lib/libfuse/fuse_private.h,v
retrieving revision 1.11
diff -u -p -r1.11 fuse_private.h
--- fuse_private.h	16 Jan 2015 16:48:51 -0000	1.11
+++ fuse_private.h	21 Feb 2015 07:27:44 -0000
@@ -33,6 +33,8 @@ struct fuse_args;
 struct fuse_vnode {
 	ino_t ino;
 	ino_t parent;
+	int   hidden;
+	int   open;
 
 	char path[NAME_MAX + 1];
 	struct fuse_dirhandle *fd;
@@ -68,10 +70,22 @@ struct fuse_config {
 	int			set_mode;
 	int			set_uid;
 	int			set_gid;
+	int			hard_remove;
 };
 
 struct fuse_core_opt {
-	char *mp;
+	char			*mp;
+	char			*fsname;
+	int			foreground;
+	int			max_read;
+	uid_t			uid;
+	gid_t			gid;
+	pid_t			pid;
+	mode_t			umask;
+	int			set_mode;
+	int			set_uid;
+	int			set_gid;
+	int			hard_remove;
 };
 
 struct fuse {
@@ -103,6 +117,7 @@ void			remove_vnode_from_name_tree(struc
     struct fuse_vnode *);
 int			set_vn(struct fuse *, struct fuse_vnode *);
 char			*build_realname(struct fuse *, ino_t);
+int hide(struct fuse *, struct fuse_vnode *, const char *);
 
 /* tree.c */
 #define tree_init(t)	SPLAY_INIT((t))
Index: fuse_subr.c
===================================================================
RCS file: /cvs/src/lib/libfuse/fuse_subr.c,v
retrieving revision 1.8
diff -u -p -r1.8 fuse_subr.c
--- fuse_subr.c	28 Apr 2014 13:08:34 -0000	1.8
+++ fuse_subr.c	21 Feb 2015 07:27:44 -0000
@@ -35,6 +35,8 @@ alloc_vn(struct fuse *f, const char *pat
 
 	vn->ino = ino;
 	vn->parent = parent;
+	vn->hidden = 0;
+	vn->open = 0;
 	if (strlcpy(vn->path, path, sizeof(vn->path)) >= sizeof(vn->path)) {
 		DPRINTF("%s: strlcpy name too long\n", __func__);
 		free(vn);
@@ -139,13 +141,13 @@ fail:
 	return (NULL);
 }
 
-char *
-build_realname(struct fuse *f, ino_t ino)
+static char *
+build_name(struct fuse *f, ino_t ino, const char *hidden_name)
 {
 	struct fuse_vnode *vn;
 	char *name = strdup("/");
 	char *tmp = NULL;
-	int firstshot = 0;
+	int not_first = 0;
 
 	vn = tree_get(&f->vnode_tree, ino);
 	if (!vn || !name) {
@@ -154,8 +156,10 @@ build_realname(struct fuse *f, ino_t ino
 	}
 
 	while (vn->parent != 0) {
-		if (firstshot++)
+		if (not_first++)
 			asprintf(&tmp, "/%s%s", vn->path, name);
+		else if (hidden_name != NULL)
+ 			asprintf(&tmp, "/%s", hidden_name);
 		else
 			asprintf(&tmp, "/%s", vn->path);
 
@@ -176,6 +180,45 @@ build_realname(struct fuse *f, ino_t ino
 	if (ino == (ino_t)0)
 		DPRINTF("%s: NULL ino\n", __func__);
 
-	DPRINTF("realname %s\n", name);
+	DPRINTF("%s %s\n", hidden_name == NULL ? "realname" : "hidden name",
+	    name);
+
 	return (name);
 }
+
+char *
+build_realname(struct fuse *f, ino_t ino)
+{
+	return build_name(f, ino, NULL);
+}
+
+int
+hide(struct fuse *f, struct fuse_vnode *vn, const char *realname)
+{
+	char *file_name;
+        char *hidename;
+        int ret;
+
+	if (vn->hidden)
+		return (0);
+
+        asprintf(&file_name, ".fuse_hidden%.10u", arc4random());
+        if (file_name == NULL)
+                return -errno;
+
+        hidename = build_name(f, vn->ino, file_name);
+        ret = f->op.rename(realname, hidename);
+
+        if (ret == 0) {
+                vn->hidden = 1;
+                remove_vnode_from_name_tree(f, vn);
+                strlcpy(vn->path, file_name, sizeof(vn->path));
+                DPRINTF("hidden %d\n", vn->hidden);
+        }
+
+        free(file_name);
+        free(hidename);
+
+        return (ret);
+}
+
