aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMiklos Szeredi <miklos@szeredi.hu>2006-01-09 16:51:06 +0000
committerMiklos Szeredi <miklos@szeredi.hu>2006-01-09 16:51:06 +0000
commit3f854ace05e48378a522395ed764249b1079e9da (patch)
treec744e3d009b06e3d918fdb22b617a51bd45d326d
parent6a6476b52b064ae082d73d991a7280a11ba1da73 (diff)
downloadsshfs-3f854ace05e48378a522395ed764249b1079e9da.tar
sshfs-3f854ace05e48378a522395ed764249b1079e9da.tar.gz
sshfs-3f854ace05e48378a522395ed764249b1079e9da.tar.bz2
sshfs-3f854ace05e48378a522395ed764249b1079e9da.zip
fix
-rw-r--r--ChangeLog7
-rw-r--r--Makefile.am7
-rw-r--r--cache.c2
-rw-r--r--compat/fuse_opt.c359
-rw-r--r--compat/fuse_opt.h227
-rw-r--r--configure.ac6
-rw-r--r--sshfs.c100
7 files changed, 652 insertions, 56 deletions
diff --git a/ChangeLog b/ChangeLog
index 80fad67..4b73c44 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,7 +1,10 @@
2006-01-09 Miklos Szeredi <miklos@szeredi.hu>
- * Added 'workaround=symlink' option to "fix-up" absolute symlinks.
- Patch by Paul Jarc
+ * Added 'transform_symlinks' option to "fix-up" absolute symlinks.
+ Patch by Paul Jarc
+
+ * Add option parsing implementation, so linking with older than
+ 2.5.0 libfuse still works.
2005-12-09 Miklos Szeredi <miklos@szeredi.hu>
diff --git a/Makefile.am b/Makefile.am
index 0b5298b..56a57bf 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -1,5 +1,10 @@
## Process this file with automake to produce Makefile.in
bin_PROGRAMS = sshfs
-sshfs_SOURCES = sshfs.c cache.c cache.h
+
+if FUSE_OPT_COMPAT
+compat_sources = compat/fuse_opt.c compat/fuse_opt.h
+endif
+
+sshfs_SOURCES = sshfs.c cache.c cache.h $(compat_sources)
sshfs_CPPFLAGS = -DFUSE_USE_VERSION=25
diff --git a/cache.c b/cache.c
index af98ea1..fae5fd4 100644
--- a/cache.c
+++ b/cache.c
@@ -537,5 +537,5 @@ int cache_parse_options(struct fuse_args *args)
cache.link_timeout = DEFAULT_CACHE_TIMEOUT;
cache.on = 1;
- return fuse_opt_parse(0, NULL, &cache, cache_opts, NULL, args);
+ return fuse_opt_parse(args, &cache, cache_opts, NULL);
}
diff --git a/compat/fuse_opt.c b/compat/fuse_opt.c
new file mode 100644
index 0000000..2ac499c
--- /dev/null
+++ b/compat/fuse_opt.c
@@ -0,0 +1,359 @@
+/*
+ FUSE: Filesystem in Userspace
+ Copyright (C) 2001-2006 Miklos Szeredi <miklos@szeredi.hu>
+
+ This program can be distributed under the terms of the GNU LGPL.
+ See the file COPYING.LIB
+*/
+
+#include "fuse_opt.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <assert.h>
+
+struct fuse_opt_context {
+ void *data;
+ const struct fuse_opt *opt;
+ fuse_opt_proc_t proc;
+ int argctr;
+ int argc;
+ char **argv;
+ struct fuse_args outargs;
+ char *opts;
+ int nonopt;
+};
+
+void fuse_opt_free_args(struct fuse_args *args)
+{
+ if (args && args->argv && args->allocated) {
+ int i;
+ for (i = 0; i < args->argc; i++)
+ free(args->argv[i]);
+ free(args->argv);
+ args->argv = NULL;
+ args->allocated = 0;
+ }
+}
+
+static int alloc_failed(void)
+{
+ fprintf(stderr, "fuse: memory allocation failed\n");
+ return -1;
+}
+
+int fuse_opt_add_arg(struct fuse_args *args, const char *arg)
+{
+ char **newargv;
+ char *newarg;
+
+ assert(!args->argv || args->allocated);
+
+ newargv = realloc(args->argv, (args->argc + 2) * sizeof(char *));
+ newarg = newargv ? strdup(arg) : NULL;
+ if (!newargv || !newarg)
+ return alloc_failed();
+
+ args->argv = newargv;
+ args->allocated = 1;
+ args->argv[args->argc++] = newarg;
+ args->argv[args->argc] = NULL;
+ return 0;
+}
+
+static int next_arg(struct fuse_opt_context *ctx, const char *opt)
+{
+ if (ctx->argctr + 1 >= ctx->argc) {
+ fprintf(stderr, "fuse: missing argument after `%s'\n", opt);
+ return -1;
+ }
+ ctx->argctr++;
+ return 0;
+}
+
+static int add_arg(struct fuse_opt_context *ctx, const char *arg)
+{
+ return fuse_opt_add_arg(&ctx->outargs, arg);
+}
+
+int fuse_opt_add_opt(char **opts, const char *opt)
+{
+ char *newopts;
+ if (!*opts)
+ newopts = strdup(opt);
+ else {
+ unsigned oldlen = strlen(*opts);
+ newopts = realloc(*opts, oldlen + 1 + strlen(opt) + 1);
+ if (newopts) {
+ newopts[oldlen] = ',';
+ strcpy(newopts + oldlen + 1, opt);
+ }
+ }
+ 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);
+}
+
+static int insert_arg(struct fuse_opt_context *ctx, int pos, const char *arg)
+{
+ assert(pos <= ctx->outargs.argc);
+ if (add_arg(ctx, arg) == -1)
+ return -1;
+
+ if (pos != ctx->outargs.argc - 1) {
+ char *newarg = ctx->outargs.argv[ctx->outargs.argc - 1];
+ memmove(&ctx->outargs.argv[pos + 1], &ctx->outargs.argv[pos],
+ sizeof(char *) * (ctx->outargs.argc - pos - 1));
+ ctx->outargs.argv[pos] = newarg;
+ }
+ return 0;
+}
+
+static int call_proc(struct fuse_opt_context *ctx, const char *arg, int key,
+ int iso)
+{
+ if (ctx->proc) {
+ int res = ctx->proc(ctx->data, arg, key, &ctx->outargs);
+ if (res == -1 || !res)
+ return res;
+ }
+ if (iso)
+ return add_opt(ctx, arg);
+ else
+ return add_arg(ctx, arg);
+}
+
+static int match_template(const char *t, const char *arg, unsigned *sepp)
+{
+ int arglen = strlen(arg);
+ const char *sep = strchr(t, '=');
+ sep = sep ? sep : strchr(t, ' ');
+ if (sep && (!sep[1] || sep[1] == '%')) {
+ int tlen = sep - t;
+ if (sep[0] == '=')
+ tlen ++;
+ if (arglen >= tlen && strncmp(arg, t, tlen) == 0) {
+ *sepp = sep - t;
+ return 1;
+ }
+ }
+ if (strcmp(t, arg) == 0) {
+ *sepp = 0;
+ return 1;
+ }
+ return 0;
+}
+
+static const struct fuse_opt *find_opt(const struct fuse_opt *opt,
+ const char *arg, unsigned *sepp)
+{
+ for (; opt && opt->template; opt++)
+ if (match_template(opt->template, arg, sepp))
+ return opt;
+ return NULL;
+}
+
+int fuse_opt_match(const struct fuse_opt *opts, const char *opt)
+{
+ unsigned dummy;
+ return find_opt(opts, opt, &dummy) ? 1 : 0;
+}
+
+static int process_opt_param(void *var, const char *format, const char *param,
+ const char *arg)
+{
+ assert(format[0] == '%');
+ if (format[1] == 's') {
+ char *copy = strdup(param);
+ if (!copy)
+ return alloc_failed();
+
+ *(char **) var = copy;
+ } else {
+ if (sscanf(param, format, var) != 1) {
+ fprintf(stderr, "fuse: invalid parameter in option `%s'\n", arg);
+ return -1;
+ }
+ }
+ return 0;
+}
+
+static int process_opt(struct fuse_opt_context *ctx,
+ const struct fuse_opt *opt, unsigned sep,
+ const char *arg, int iso)
+{
+ if (opt->offset == -1U) {
+ if (call_proc(ctx, arg, opt->value, iso) == -1)
+ return -1;
+ } else {
+ void *var = ctx->data + opt->offset;
+ if (sep && opt->template[sep + 1]) {
+ const char *param = arg + sep;
+ if (opt->template[sep] == '=')
+ param ++;
+ if (process_opt_param(var, opt->template + sep + 1,
+ param, arg) == -1)
+ return -1;
+ } else
+ *(int *)var = opt->value;
+ }
+ return 0;
+}
+
+static int process_opt_sep_arg(struct fuse_opt_context *ctx,
+ const struct fuse_opt *opt, unsigned sep,
+ const char *arg, int iso)
+{
+ int res;
+ char *newarg;
+ char *param;
+
+ if (next_arg(ctx, arg) == -1)
+ return -1;
+
+ param = ctx->argv[ctx->argctr];
+ newarg = malloc(sep + strlen(param) + 1);
+ if (!newarg)
+ return alloc_failed();
+
+ memcpy(newarg, arg, sep);
+ strcpy(newarg + sep, param);
+ res = process_opt(ctx, opt, sep, newarg, iso);
+ free(newarg);
+
+ return res;
+}
+
+static int process_gopt(struct fuse_opt_context *ctx, const char *arg, int iso)
+{
+ unsigned sep;
+ const struct fuse_opt *opt = find_opt(ctx->opt, arg, &sep);
+ if (opt) {
+ for (; opt; opt = find_opt(opt + 1, arg, &sep)) {
+ int res;
+ if (sep && opt->template[sep] == ' ' && !arg[sep])
+ res = process_opt_sep_arg(ctx, opt, sep, arg, iso);
+ else
+ res = process_opt(ctx, opt, sep, arg, iso);
+ if (res == -1)
+ return -1;
+ }
+ return 0;
+ } else
+ return call_proc(ctx, arg, FUSE_OPT_KEY_OPT, iso);
+}
+
+static int process_real_option_group(struct fuse_opt_context *ctx, char *opts)
+{
+ char *sep;
+
+ do {
+ int res;
+ sep = strchr(opts, ',');
+ if (sep)
+ *sep = '\0';
+ res = process_gopt(ctx, opts, 1);
+ if (res == -1)
+ return -1;
+ opts = sep + 1;
+ } while (sep);
+
+ return 0;
+}
+
+static int process_option_group(struct fuse_opt_context *ctx, const char *opts)
+{
+ int res;
+ char *copy;
+ const char *sep = strchr(opts, ',');
+ if (!sep)
+ return process_gopt(ctx, opts, 1);
+
+ copy = strdup(opts);
+ if (!copy) {
+ fprintf(stderr, "fuse: memory allocation failed\n");
+ return -1;
+ }
+ res = process_real_option_group(ctx, copy);
+ free(copy);
+ return res;
+}
+
+static int process_one(struct fuse_opt_context *ctx, const char *arg)
+{
+ if (ctx->nonopt || arg[0] != '-')
+ return call_proc(ctx, arg, FUSE_OPT_KEY_NONOPT, 0);
+ else if (arg[1] == 'o') {
+ if (arg[2])
+ return process_option_group(ctx, arg + 2);
+ else {
+ if (next_arg(ctx, arg) == -1)
+ return -1;
+
+ return process_option_group(ctx, ctx->argv[ctx->argctr]);
+ }
+ } else if (arg[1] == '-' && !arg[2]) {
+ if (add_arg(ctx, arg) == -1)
+ return -1;
+ ctx->nonopt = ctx->outargs.argc;
+ return 0;
+ } else
+ return process_gopt(ctx, arg, 0);
+}
+
+static int opt_parse(struct fuse_opt_context *ctx)
+{
+ if (ctx->argc) {
+ if (add_arg(ctx, ctx->argv[0]) == -1)
+ return -1;
+ }
+
+ for (ctx->argctr = 1; ctx->argctr < ctx->argc; ctx->argctr++)
+ if (process_one(ctx, ctx->argv[ctx->argctr]) == -1)
+ return -1;
+
+ if (ctx->opts) {
+ if (insert_arg(ctx, 1, "-o") == -1 ||
+ insert_arg(ctx, 2, ctx->opts) == -1)
+ return -1;
+ }
+ if (ctx->nonopt && ctx->nonopt == ctx->outargs.argc)
+ ctx->outargs.argv[--ctx->outargs.argc] = NULL;
+
+ return 0;
+}
+
+int fuse_opt_parse(struct fuse_args *args, void *data,
+ const struct fuse_opt opts[], fuse_opt_proc_t proc)
+{
+ int res;
+ struct fuse_opt_context ctx = {
+ .data = data,
+ .opt = opts,
+ .proc = proc,
+ };
+
+ if (!args || !args->argv || !args->argc)
+ return 0;
+
+ ctx.argc = args->argc;
+ ctx.argv = args->argv;
+
+ res = opt_parse(&ctx);
+ if (res != -1) {
+ struct fuse_args tmp = *args;
+ *args = ctx.outargs;
+ ctx.outargs = tmp;
+ }
+ free(ctx.opts);
+ fuse_opt_free_args(&ctx.outargs);
+ return res;
+}
diff --git a/compat/fuse_opt.h b/compat/fuse_opt.h
new file mode 100644
index 0000000..2ef5d56
--- /dev/null
+++ b/compat/fuse_opt.h
@@ -0,0 +1,227 @@
+/*
+ FUSE: Filesystem in Userspace
+ Copyright (C) 2001-2006 Miklos Szeredi <miklos@szeredi.hu>
+
+ This program can be distributed under the terms of the GNU GPL.
+ See the file COPYING.
+*/
+
+#ifndef _FUSE_OPT_H_
+#define _FUSE_OPT_H_
+
+/* This file defines the option parsing interface of FUSE */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * Option description
+ *
+ * This structure describes a single option, and and action associated
+ * with it, in case it matches.
+ *
+ * More than one such match may occur, in which case the action for
+ * each match is executed.
+ *
+ * There are three possible actions in case of a match:
+ *
+ * i) An integer (int or unsigned) variable determined by 'offset' is
+ * set to 'value'
+ *
+ * ii) The processing function is called, with 'value' as the key
+ *
+ * iii) An integer (any) or string (char *) variable determined by
+ * 'offset' is set to the value of an option parameter
+ *
+ * 'offset' should normally be either set to
+ *
+ * - 'offsetof(struct foo, member)' actions i) and iii)
+ *
+ * - -1 action ii)
+ *
+ * The 'offsetof()' macro is defined in the <stddef.h> header.
+ *
+ * The template determines which options match, and also have an
+ * effect on the action. Normally the action is either i) or ii), but
+ * if a format is present in the template, then action iii) is
+ * performed.
+ *
+ * The types of templates are:
+ *
+ * 1) "-x", "-foo", "--foo", "--foo-bar", etc. These match only
+ * themselves. Invalid values are "--" and anything beginning
+ * with "-o"
+ *
+ * 2) "foo", "foo-bar", etc. These match "-ofoo", "-ofoo-bar" or
+ * the relevant option in a comma separated option list
+ *
+ * 3) "bar=", "--foo=", etc. These are variations of 1) and 2)
+ * which have a parameter
+ *
+ * 4) "bar=%s", "--foo=%lu", etc. Same matching as above but perform
+ * action iii).
+ *
+ * 5) "-x ", etc. Matches either "-xparam" or "-x param" as
+ * two separate arguments
+ *
+ * 6) "-x %s", etc. Combination of 4) and 5)
+ *
+ * If the format is "%s", memory is allocated for the string unlike
+ * with scanf().
+ */
+struct fuse_opt {
+ /** Matching template and optional parameter formatting */
+ const char *template;
+
+ /**
+ * Offset of variable within 'data' parameter of fuse_opt_parse()
+ * or -1
+ */
+ unsigned long offset;
+
+ /**
+ * Value to set the variable to, or to be passed as 'key' to the
+ * processing function. Ignored if template a format
+ */
+ int value;
+};
+
+/**
+ * Key option. In case of a match, the processing function will be
+ * called with the specified key.
+ */
+#define FUSE_OPT_KEY(template, key) { template, -1U, key }
+
+/**
+ * Last option. An array of 'struct fuse_opt' must end with a NULL
+ * template value
+ */
+#define FUSE_OPT_END { .template = NULL }
+
+/**
+ * Argument list
+ */
+struct fuse_args {
+ /** Argument count */
+ int argc;
+
+ /** Argument vector. NULL terminated */
+ char **argv;
+
+ /** Is 'argv' allocated? */
+ int allocated;
+};
+
+/**
+ * Initializer for 'struct fuse_args'
+ */
+#define FUSE_ARGS_INIT(argc, argv) { argc, argv, 0 }
+
+/**
+ * Key value passed to the processing function if an option did not
+ * match any templated
+ */
+#define FUSE_OPT_KEY_OPT -1
+
+/**
+ * Key value passed to the processing function for all non-options
+ *
+ * Non-options are the arguments beginning with a charater other than
+ * '-' or all arguments after the special '--' option
+ */
+#define FUSE_OPT_KEY_NONOPT -2
+
+/**
+ * Processing function
+ *
+ * This function is called if
+ * - option did not match any 'struct fuse_opt'
+ * - argument is a non-option
+ * - option did match and offset was set to -1
+ *
+ * The 'arg' parameter will always contain the whole argument or
+ * option including the parameter if exists. A two-argument option
+ * ("-x foo") is always converted to single arguemnt option of the
+ * form "-xfoo" before this function is called.
+ *
+ * Options of the form '-ofoo' are passed to this function without the
+ * '-o' prefix.
+ *
+ * The return value of this function determines whether this argument
+ * is to be inserted into the output argument vector, or discarded.
+ *
+ * @param data is the user data passed to the fuse_opt_parse() function
+ * @param arg is the whole argument or option
+ * @param key determines why the processing function was called
+ * @param outargs the current output argument list
+ * @return -1 on error, 0 if arg is to be discarded, 1 if arg should be kept
+ */
+typedef int (*fuse_opt_proc_t)(void *data, const char *arg, int key,
+ struct fuse_args *outargs);
+
+/**
+ * Option parsing function
+ *
+ * If 'args' was returned from a previous call to fuse_opt_parse() or
+ * it was constructed from
+ *
+ * A NULL 'args' is equivalent to an empty argument vector
+ *
+ * A NULL 'opts' is equivalent to an 'opts' array containing a single
+ * end marker
+ *
+ * A NULL 'proc' is equivalent to a processing function always
+ * returning '1'
+ *
+ * @param args is the input and output argument list
+ * @param data is the user data
+ * @param opts is the option description array
+ * @param proc is the processing function
+ * @return -1 on error, 0 on success
+ */
+int fuse_opt_parse(struct fuse_args *args, void *data,
+ const struct fuse_opt opts[], fuse_opt_proc_t proc);
+
+/**
+ * Add an option to a comma separated option list
+ *
+ * @param opts is a pointer to an option list, may point to a NULL value
+ * @param opt is the option to add
+ * @return -1 on allocation error, 0 on success
+ */
+int fuse_opt_add_opt(char **opts, const char *opt);
+
+/**
+ * Add an argument to a NULL terminated argument vector
+ *
+ * @param args is the structure containing the current argument list
+ * @param arg is the new argument to add
+ * @return -1 on allocation error, 0 on success
+ */
+int fuse_opt_add_arg(struct fuse_args *args, const char *arg);
+
+/**
+ * Free the contents of argument list
+ *
+ * The structure itself is not freed
+ *
+ * @param args is the structure containing the argument list
+ */
+void fuse_opt_free_args(struct fuse_args *args);
+
+
+/**
+ * Check if an option matches
+ *
+ * @param opts is the option description array
+ * @param opt is the option to match
+ * @return 1 if a match is found, 0 if not
+ */
+int fuse_opt_match(const struct fuse_opt opts[], const char *opt);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _FUSE_OPT_H_ */
diff --git a/configure.ac b/configure.ac
index 314d00f..6366ec2 100644
--- a/configure.ac
+++ b/configure.ac
@@ -7,6 +7,12 @@ export PKG_CONFIG_PATH=/usr/local/lib/pkgconfig:$PKG_CONFIG_PATH
PKG_CHECK_MODULES(SSHFS, [fuse >= 2.2 glib-2.0])
CFLAGS="$CFLAGS -Wall -W -D_REENTRANT $SSHFS_CFLAGS"
LIBS="$SSHFS_LIBS"
+have_fuse_opt_parse=no
+AC_CHECK_FUNC([fuse_opt_parse], [have_fuse_opt_parse=yes])
+if test "$have_fuse_opt_parse" = no; then
+ CFLAGS="$CFLAGS -Icompat"
+fi
+AM_CONDITIONAL(FUSE_OPT_COMPAT, test "$have_fuse_opt_parse" = no)
AC_CONFIG_FILES([Makefile])
AC_OUTPUT
diff --git a/sshfs.c b/sshfs.c
index c84cc10..c4d6fc4 100644
--- a/sshfs.c
+++ b/sshfs.c
@@ -145,9 +145,10 @@ struct sshfs {
char *directport;
char *ssh_command;
char *sftp_server;
+ char *mountpoint;
struct fuse_args ssh_args;
int rename_workaround;
- int symlink_workaround;
+ int transform_symlinks;
int detect_uid;
unsigned max_read;
unsigned ssh_ver;
@@ -226,7 +227,6 @@ enum {
};
#define SSHFS_OPT(t, p, v) { t, offsetof(struct sshfs, p), v }
-#define SSHFS_KEY(t, k) { t, FUSE_OPT_OFFSET_KEY, k }
static struct fuse_opt sshfs_opts[] = {
SSHFS_OPT("directport=%s", directport, 0),
@@ -236,24 +236,22 @@ static struct fuse_opt sshfs_opts[] = {
SSHFS_OPT("ssh_protocol=%u", ssh_ver, 0),
SSHFS_OPT("-1", ssh_ver, 1),
SSHFS_OPT("workaround=none", rename_workaround, 0),
- SSHFS_OPT("workaround=none", symlink_workaround, 0),
SSHFS_OPT("workaround=rename", rename_workaround, 1),
- SSHFS_OPT("workaround=symlink", symlink_workaround, 1),
SSHFS_OPT("workaround=all", rename_workaround, 1),
- SSHFS_OPT("workaround=all", symlink_workaround, 1),
SSHFS_OPT("idmap=none", detect_uid, 0),
SSHFS_OPT("idmap=user", detect_uid, 1),
SSHFS_OPT("sshfs_sync", sync_write, 1),
SSHFS_OPT("no_readahead", sync_read, 1),
SSHFS_OPT("sshfs_debug", debug, 1),
SSHFS_OPT("reconnect", reconnect, 1),
-
- SSHFS_KEY("-p ", KEY_PORT),
- SSHFS_KEY("-C", KEY_COMPRESS),
- SSHFS_KEY("-V", KEY_VERSION),
- SSHFS_KEY("--version", KEY_VERSION),
- SSHFS_KEY("-h", KEY_HELP),
- SSHFS_KEY("--help", KEY_HELP),
+ SSHFS_OPT("transform_symlinks", transform_symlinks, 1),
+
+ FUSE_OPT_KEY("-p ", KEY_PORT),
+ FUSE_OPT_KEY("-C", KEY_COMPRESS),
+ FUSE_OPT_KEY("-V", KEY_VERSION),
+ FUSE_OPT_KEY("--version", KEY_VERSION),
+ FUSE_OPT_KEY("-h", KEY_HELP),
+ FUSE_OPT_KEY("--help", KEY_HELP),
FUSE_OPT_END
};
@@ -1162,18 +1160,17 @@ static int sshfs_readlink(const char *path, char *linkbuf, size_t size)
char *link;
err = -EIO;
if(buf_get_uint32(&name, &count) != -1 && count == 1 &&
- buf_get_string(&name, &link) != -1) {
- if (size>0) {
- if (link[0]=='/') {
- size_t len=sshfs.symlink_prefix_len;
- if (len>size-1) len=size-1;
- memcpy(linkbuf, sshfs.symlink_prefix, len);
- linkbuf+=len;
- size-=len;
- }
- strncpy(linkbuf, link, size-1);
- linkbuf[size-1] = '\0';
+ buf_get_string(&name, &link) != -1 && size > 0) {
+ if (link[0] == '/' && sshfs.symlink_prefix_len) {
+ size_t len = sshfs.symlink_prefix_len;
+ if (len > size - 1)
+ len = size - 1;
+ memcpy(linkbuf, sshfs.symlink_prefix, len);
+ linkbuf += len;
+ size -= len;
}
+ strncpy(linkbuf, link, size - 1);
+ linkbuf[size - 1] = '\0';
free(link);
err = 0;
}
@@ -1912,8 +1909,12 @@ static void usage(const char *progname)
fprintf(stderr,
"usage: %s [user@]host:[dir]] mountpoint [options]\n"
"\n"
-"SSHFS Options:\n"
-" -V show version information\n"
+"general options:\n"
+" -o opt,[opt...] mount options\n"
+" -h --help print help\n"
+" -V --version print version\n"
+"\n"
+"SSHFS options:\n"
" -p PORT equivalent to '-o port=PORT'\n"
" -C equivalent to '-o compression=yes'\n"
" -1 equivalent to '-o ssh_protocol=1'\n"
@@ -1928,7 +1929,6 @@ static void usage(const char *progname)
" none no workarounds enabled (default)\n"
" all all workarounds enabled\n"
" rename work around problem renaming to existing file\n"
-" symlink prepend mountpoint to absolute symlink targets\n"
" -o idmap=TYPE user/group ID mapping, possible types are:\n"
" none no translation of the ID space (default)\n"
" user only translate UID of connecting user\n"
@@ -1936,6 +1936,7 @@ static void usage(const char *progname)
" -o ssh_protocol=N ssh protocol to use (default: 2)\n"
" -o sftp_server=SERV path to sftp server or subsystem (default: sftp)\n"
" -o directport=PORT directly connect to PORT bypassing ssh\n"
+" -o transform_symlinks prepend mountpoint to absolute symlink targets\n"
" -o SSHOPT=VAL ssh options (see man ssh_config)\n"
"\n", progname);
}
@@ -1975,7 +1976,8 @@ static int sshfs_opt_proc(void *data, const char *arg, int key,
if (!sshfs.host && strchr(arg, ':')) {
sshfs.host = strdup(arg);
return 0;
- }
+ } else if (!sshfs.mountpoint)
+ sshfs.mountpoint = strdup(arg);
return 1;
case KEY_PORT:
@@ -1996,6 +1998,10 @@ static int sshfs_opt_proc(void *data, const char *arg, int key,
case KEY_VERSION:
fprintf(stderr, "SSHFS version %s\n", PACKAGE_VERSION);
+#if FUSE_VERSION >= 25
+ fuse_opt_add_arg(outargs, "--version");
+ fuse_main(outargs->argc, outargs->argv, &sshfs_oper.oper);
+#endif
exit(0);
default:
@@ -2007,7 +2013,7 @@ static int sshfs_opt_proc(void *data, const char *arg, int key,
int main(int argc, char *argv[])
{
int res;
- struct fuse_args outargs;
+ struct fuse_args args = FUSE_ARGS_INIT(argc, argv);
char *tmp;
char *fsname;
char *base_path;
@@ -2021,8 +2027,7 @@ int main(int argc, char *argv[])
ssh_add_arg("-a");
ssh_add_arg("-oClearAllForwardings=yes");
- if (fuse_opt_parse(argc, argv, &sshfs, sshfs_opts, sshfs_opt_proc,
- &outargs) == -1)
+ if (fuse_opt_parse(&args, &sshfs, sshfs_opts, sshfs_opt_proc) == -1)
exit(1);
if (!sshfs.host) {
@@ -2073,7 +2078,7 @@ int main(int argc, char *argv[])
if (res == -1)
exit(1);
- res = cache_parse_options(&outargs);
+ res = cache_parse_options(&args);
if (res == -1)
exit(1);
@@ -2082,37 +2087,28 @@ int main(int argc, char *argv[])
if (sshfs.max_read > 65536)
sshfs.max_read = 65536;
- if (sshfs.symlink_workaround && outargs.argv[1] == NULL) {
- fprintf(stderr, "symlink workaround failed: no mountpoint given\n");
+ if (sshfs.transform_symlinks && !sshfs.mountpoint) {
+ fprintf(stderr, "cannot transform symlinks: no mountpoint given\n");
exit(1);
}
- if (!sshfs.symlink_workaround)
- sshfs.symlink_prefix_len=0;
- else if (realpath(outargs.argv[1], sshfs.symlink_prefix)!=NULL)
- sshfs.symlink_prefix_len=strlen(sshfs.symlink_prefix);
+ if (!sshfs.transform_symlinks)
+ sshfs.symlink_prefix_len = 0;
+ else if (realpath(sshfs.mountpoint, sshfs.symlink_prefix) != NULL)
+ sshfs.symlink_prefix_len = strlen(sshfs.symlink_prefix);
else {
- sshfs.symlink_prefix_len=strlen(outargs.argv[1]);
- if (outargs.argv[1][sshfs.symlink_prefix_len-1]=='/')
- --sshfs.symlink_prefix_len;
- if (outargs.argv[1][0]=='/' &&
- sshfs.symlink_prefix_len<=sizeof sshfs.symlink_prefix) {
- memcpy(sshfs.symlink_prefix, outargs.argv[1],
- sshfs.symlink_prefix_len);
- } else {
- perror("unable to normalize mount path");
- exit(1);
- }
+ perror("unable to normalize mount path");
+ exit(1);
}
tmp = g_strdup_printf("-omax_read=%u", sshfs.max_read);
- fuse_opt_add_arg(&outargs, tmp);
+ fuse_opt_add_arg(&args, tmp);
g_free(tmp);
tmp = g_strdup_printf("-ofsname=sshfs#%s", fsname);
- fuse_opt_add_arg(&outargs, tmp);
+ fuse_opt_add_arg(&args, tmp);
g_free(tmp);
g_free(fsname);
- res = fuse_main(outargs.argc, outargs.argv, cache_init(&sshfs_oper));
- fuse_opt_free_args(&outargs);
+ res = fuse_main(args.argc, args.argv, cache_init(&sshfs_oper));
+ fuse_opt_free_args(&args);
fuse_opt_free_args(&sshfs.ssh_args);
free(sshfs.directport);