Package: fuse
Version: 2.7.4-1.1
Severity: normal
Tags: patch

Together with sshfs it fails to mount locations like:

lkajan,[EMAIL PROTECTED]:/home/groups/j/jb/jbio

because of the ',' in the name. Both sshfs and fuse need to be patched
to properly escape and unescape such locations.

-- System Information:
Debian Release: lenny/sid
  APT prefers testing
  APT policy: (500, 'testing'), (500, 'stable')
Architecture: i386 (i686)

Kernel: Linux 2.6.24-etchnhalf.1-686 (SMP w/2 CPU cores)
Locale: LANG=en_GB.UTF-8, LC_CTYPE=en_GB.UTF-8 (charmap=UTF-8)
Shell: /bin/sh linked to /bin/bash
diff -ur sshfs-fuse-2.1/sshfs.c good.sshfs-fuse-2.1/sshfs.c
--- sshfs-fuse-2.1/sshfs.c	2008-07-11 07:00:33.000000000 -0400
+++ good.sshfs-fuse-2.1/sshfs.c	2008-10-17 22:34:38.000000000 -0400
@@ -3091,12 +3091,39 @@
 	}
 }
 
+static char *escape_commas( const char * __s )
+{
+	char *__es = calloc( strlen(__s)*2+1, sizeof(char) );
+	const char *spos = __s;
+	char *espos = __es;
+
+	if( !__es ) {
+		fprintf(stderr, "sshfs: memory allocation failed\n");
+		abort();
+	}
+
+	while( *spos )
+	{
+		switch ( *spos ) {
+			case '\\':
+			case ',':
+				*espos = '\\';
+				++espos;
+			default:
+				*espos = *spos;
+				++espos; ++spos;
+		}
+	}
+	return __es;
+}
+
 int main(int argc, char *argv[])
 {
 	int res;
 	struct fuse_args args = FUSE_ARGS_INIT(argc, argv);
 	char *tmp;
 	char *fsname;
+	char *efsname = NULL;
 	char *base_path;
 	const char *sftp_server;
 	int libver;
@@ -3203,15 +3230,24 @@
 
 	if (fuse_is_lib_option("ac_attr_timeout="))
 		fuse_opt_insert_arg(&args, 1, "-oauto_cache,ac_attr_timeout=0");
+
 	tmp = g_strdup_printf("-omax_read=%u", sshfs.max_read);
 	fuse_opt_insert_arg(&args, 1, tmp);
+	g_free(tmp);
+
 	tmp = g_strdup_printf("-omax_write=%u", sshfs.max_write);
 	fuse_opt_insert_arg(&args, 1, tmp);
 	g_free(tmp);
+
 #if FUSE_VERSION >= 27
 	libver = fuse_version();
 	assert(libver >= 27);
-	tmp = g_strdup_printf("-osubtype=sshfs,fsname=%s", fsname);
+
+	// escape ',' in fsname
+	efsname = escape_commas( fsname );
+
+	tmp = g_strdup_printf("-osubtype=sshfs,fsname=%s", efsname);
+	free( efsname );
 #else
 	tmp = g_strdup_printf("-ofsname=sshfs#%s", fsname);
 #endif
diff -ur fuse-2.7.4/include/fuse_opt.h good.fuse-2.7.4/include/fuse_opt.h
--- fuse-2.7.4/include/fuse_opt.h	2008-02-19 14:51:23.000000000 -0500
+++ good.fuse-2.7.4/include/fuse_opt.h	2008-10-17 22:31:14.000000000 -0400
@@ -212,6 +212,14 @@
 int fuse_opt_add_opt(char **opts, const char *opt);
 
 /**
+ * Same as fuse_opt_add_opt except that '\\' and ',' are automatically escaped with '\\'.
+ *
+ */
+int fuse_opt_add_single_opt(char **opts, const char *opt);
+
+char *_nonesc_strchr(const char *__s, int __c, char **__ues, char **__escapes);
+
+/**
  * Add an argument to a NULL terminated argument vector
  *
  * @param args is the structure containing the current argument list
diff -ur fuse-2.7.4/lib/fuse_opt.c good.fuse-2.7.4/lib/fuse_opt.c
--- fuse-2.7.4/lib/fuse_opt.c	2008-02-19 14:51:26.000000000 -0500
+++ good.fuse-2.7.4/lib/fuse_opt.c	2008-10-17 22:38:33.000000000 -0400
@@ -109,9 +109,36 @@
 	return fuse_opt_add_arg(&ctx->outargs, arg);
 }
 
+static char *escape_commas( const char *__s )
+{
+	char *__es = calloc( strlen(__s)*2+1, sizeof(char) );
+	const char *spos = __s;
+	char *espos = __es;
+
+	if( !__es ) {
+		fprintf(stderr, "fuse: memory allocation failed\n");
+		return NULL;
+	}
+
+	while( *spos )
+	{
+		switch ( *spos ) {
+			case '\\':
+			case ',':
+				*espos = '\\';
+				++espos;
+			default:
+				*espos = *spos;
+				++espos; ++spos;
+		}
+	}
+	return __es;
+}
+
 int fuse_opt_add_opt(char **opts, const char *opt)
 {
 	char *newopts;
+
 	if (!*opts)
 		newopts = strdup(opt);
 	else {
@@ -129,9 +156,33 @@
 	return 0;
 }
 
+int fuse_opt_add_single_opt(char **opts, const char *opt)
+{
+	char *newopts;
+	char *eopt = escape_commas( opt );
+
+	if (!*opts)
+		newopts = strdup(eopt);
+	else {
+		unsigned oldlen = strlen(*opts);
+		newopts = realloc(*opts, oldlen + 1 + strlen(eopt) + 1);
+		if (newopts) {
+			newopts[oldlen] = ',';
+			strcpy(newopts + oldlen + 1, eopt);
+		}
+	}
+	free( eopt );
+
+	if (!newopts)
+		return alloc_failed();
+
+	*opts = newopts;
+	return 0;
+}
+
 static int add_opt(struct fuse_opt_context *ctx, const char *opt)
 {
-	return fuse_opt_add_opt(&ctx->opts, opt);
+	return fuse_opt_add_single_opt(&ctx->opts, opt);
 }
 
 static int call_proc(struct fuse_opt_context *ctx, const char *arg, int key,
@@ -272,19 +323,60 @@
 		return call_proc(ctx, arg, FUSE_OPT_KEY_OPT, iso);
 }
 
-static int process_real_option_group(struct fuse_opt_context *ctx, char *opts)
+char *_nonesc_strchr(const char *__s, int __c, char **__ues, char **__escapes)
+{
+	// find first non-escaped c
+	char *pos;
+	size_t s_len = strlen( __s );
+
+	*__escapes = calloc( s_len+1, sizeof(char) );
+	if (!*__escapes) {
+		fprintf(stderr, "fuse: memory allocation failed\n");
+		return NULL;
+	}
+	memset( *__escapes, ' ', sizeof(char) * s_len );
+	pos = *__ues = strdup(__s);
+	if (!*__ues) {
+		fprintf(stderr, "fuse: memory allocation failed\n");
+		return NULL;
+	}
+
+	while( ( pos = strchr(pos,'\\') ) ) {
+		*( *__escapes + ( pos - *__ues ) ) = '\\';
+		
+		memmove( pos, pos+1, strlen( pos ) * sizeof(char) ); // move the '\0' as well
+
+		++pos;
+	}
+
+	pos = *__ues;
+	while( ( pos = strchr(pos,',') ) && *( *__escapes + ( pos - *__ues ) ) == '\\' ) ++pos;
+
+	return pos;
+}
+
+static int process_real_option_group(struct fuse_opt_context *ctx, char *__ueopts, char *__es)
 {
 	char *sep;
+	int ptrdelta = 0;
 
 	do {
 		int res;
-		sep = strchr(opts, ',');
-		if (sep)
-			*sep = '\0';
-		res = process_gopt(ctx, opts, 1);
+		char *pos = __ueopts;
+		while( ( sep = strchr(pos, ',') ) && *( __es + ( sep - __ueopts ) ) == '\\' ) ++pos;
+
+		if (sep) {
+			ptrdelta = sep - __ueopts;
+
+			*( __es + ptrdelta ) = *sep = '\0';
+		}
+		res = process_gopt(ctx, __ueopts, 1);
 		if (res == -1)
 			return -1;
-		opts = sep + 1;
+		if( sep ) {
+			__ueopts = sep + 1;
+			__es = __es + ptrdelta + 1;
+		}
 	} while (sep);
 
 	return 0;
@@ -293,18 +385,18 @@
 static int process_option_group(struct fuse_opt_context *ctx, const char *opts)
 {
 	int res;
-	char *copy;
-	const char *sep = strchr(opts, ',');
+	const char *sep = NULL;
+	char *ueopts = NULL;
+	char *escapes = NULL;
+	
+	sep = _nonesc_strchr(opts, ',', &ueopts, &escapes);
+
 	if (!sep)
-		return process_gopt(ctx, opts, 1);
+		return process_gopt(ctx, ueopts, 1);
 
-	copy = strdup(opts);
-	if (!copy) {
-		fprintf(stderr, "fuse: memory allocation failed\n");
-		return -1;
-	}
-	res = process_real_option_group(ctx, copy);
-	free(copy);
+	res = process_real_option_group(ctx, ueopts, escapes);
+	free(escapes);
+	free(ueopts);
 	return res;
 }
 
diff -ur fuse-2.7.4/lib/mount.c good.fuse-2.7.4/lib/mount.c
--- fuse-2.7.4/lib/mount.c	2008-02-19 14:51:27.000000000 -0500
+++ good.fuse-2.7.4/lib/mount.c	2008-10-17 22:31:17.000000000 -0400
@@ -197,16 +197,16 @@
 		return 0;
 
 	case KEY_KERN_OPT:
-		return fuse_opt_add_opt(&mo->kernel_opts, arg);
+		return fuse_opt_add_single_opt(&mo->kernel_opts, arg);
 
 	case KEY_FUSERMOUNT_OPT:
-		return fuse_opt_add_opt(&mo->fusermount_opts, arg);
+		return fuse_opt_add_single_opt(&mo->fusermount_opts, arg);
 
 	case KEY_SUBTYPE_OPT:
-		return fuse_opt_add_opt(&mo->subtype_opt, arg);
+		return fuse_opt_add_single_opt(&mo->subtype_opt, arg);
 
 	case KEY_MTAB_OPT:
-		return fuse_opt_add_opt(&mo->mtab_opts, arg);
+		return fuse_opt_add_single_opt(&mo->mtab_opts, arg);
 
 	case KEY_HELP:
 		mount_help();
diff -ur fuse-2.7.4/util/fusermount.c good.fuse-2.7.4/util/fusermount.c
--- fuse-2.7.4/util/fusermount.c	2008-02-19 14:51:28.000000000 -0500
+++ good.fuse-2.7.4/util/fusermount.c	2008-10-17 22:31:17.000000000 -0400
@@ -10,6 +10,7 @@
 #include <config.h>
 
 #include "mount_util.h"
+#include "fuse_opt.h"
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
@@ -385,6 +386,7 @@
 	char *optbuf;
 	char *mnt_opts = NULL;
 	const char *s;
+	const char *t;
 	char *d;
 	char *fsname = NULL;
 	char *subtype = NULL;
@@ -392,6 +394,8 @@
 	char *type = NULL;
 	int check_empty = 1;
 	int blkdev = 0;
+	char *ueopts = NULL;
+	char *escapes = NULL;
 
 	optbuf = (char *) malloc(strlen(opts) + 128);
 	if (!optbuf) {
@@ -399,11 +403,13 @@
 		return -1;
 	}
 
-	for (s = opts, d = optbuf; *s;) {
+	_nonesc_strchr(opts, ',', &ueopts, &escapes);
+
+	for (s = ueopts, t = escapes, d = optbuf; *s && *t;) {
 		unsigned len;
 		const char *fsname_str = "fsname=";
 		const char *subtype_str = "subtype=";
-		for (len = 0; s[len] && s[len] != ','; len++);
+		for (len = 0; s[len] && ( s[len] != ',' || t[len] == '\\' ); len++);
 		if (begins_with(s, fsname_str)) {
 			if (!get_string_opt(s, len, fsname_str, &fsname))
 				goto err;
@@ -459,8 +465,12 @@
 			}
 		}
 		s += len;
-		if (*s)
-			s++;
+		t += len;
+
+		if (*s && *t) {
+			++s;
+			++t;
+		}
 	}
 	*d = '\0';
 	res = get_mnt_opts(flags, optbuf, &mnt_opts);
@@ -528,9 +538,14 @@
 	}
 	free(optbuf);
 
+	free(ueopts);
+	free(escapes);
+
 	return res;
 
 err:
+	free(ueopts);
+	free(escapes);
 	free(fsname);
 	free(subtype);
 	free(source);
diff -ur fuse-2.7.4/util/Makefile.am good.fuse-2.7.4/util/Makefile.am
--- fuse-2.7.4/util/Makefile.am	2008-02-19 14:51:28.000000000 -0500
+++ good.fuse-2.7.4/util/Makefile.am	2008-10-17 22:31:18.000000000 -0400
@@ -5,7 +5,7 @@
 noinst_PROGRAMS = mount.fuse
 
 fusermount_SOURCES = fusermount.c
-fusermount_LDADD = ../lib/mount_util.lo
+fusermount_LDADD = ../lib/mount_util.lo ../lib/fuse_opt.lo
 fusermount_CPPFLAGS = -I../lib
 mount_fuse_SOURCES = mount.fuse.c
 
diff -ur fuse-2.7.4/util/Makefile.in good.fuse-2.7.4/util/Makefile.in
--- fuse-2.7.4/util/Makefile.in	2008-07-25 14:19:24.000000000 -0400
+++ good.fuse-2.7.4/util/Makefile.in	2008-10-17 22:38:45.000000000 -0400
@@ -53,7 +53,7 @@
 PROGRAMS = $(bin_PROGRAMS) $(noinst_PROGRAMS)
 am_fusermount_OBJECTS = fusermount-fusermount.$(OBJEXT)
 fusermount_OBJECTS = $(am_fusermount_OBJECTS)
-fusermount_DEPENDENCIES = ../lib/mount_util.lo
+fusermount_DEPENDENCIES = ../lib/mount_util.lo ../lib/fuse_opt.lo
 am_mount_fuse_OBJECTS = mount.fuse.$(OBJEXT)
 mount_fuse_OBJECTS = $(am_mount_fuse_OBJECTS)
 mount_fuse_LDADD = $(LDADD)
@@ -197,7 +197,7 @@
 target_vendor = @target_vendor@
 AM_CPPFLAGS = -D_FILE_OFFSET_BITS=64 
 fusermount_SOURCES = fusermount.c
-fusermount_LDADD = ../lib/mount_util.lo
+fusermount_LDADD = ../lib/mount_util.lo ../lib/fuse_opt.lo
 fusermount_CPPFLAGS = -I../lib
 mount_fuse_SOURCES = mount.fuse.c
 ulockmgr_server_SOURCES = ulockmgr_server.c
@@ -541,7 +541,7 @@
 	$(INSTALL_PROGRAM) $(srcdir)/init_script $(DESTDIR)$(INIT_D_PATH)/fuse
 	@if test -x /usr/sbin/update-rc.d; then \
 		echo "/usr/sbin/update-rc.d fuse start 34 S . start 41 0 6 . || true"; \
-		/usr/sbin/update-rc.d fuse start 34 S . start 41 0 6 . || true; \
+	#	/usr/sbin/update-rc.d fuse start 34 S . start 41 0 6 . || true; \
 	fi
 
 install-data-local:

Reply via email to