From 4b93d353a2ac15b45b9e6064620bf93e41aa1b51 Mon Sep 17 00:00:00 2001 From: Andre Noll Date: Wed, 6 Jun 2018 15:08:24 +0200 Subject: [PATCH] Support multiple source directories. rsync is capable of copying multiple source directories to a single destination, but this is currently not supported by dss. This commit adds this functionality. The implementation is straight-forward, except that we don't want to add a trailing slash to every source directory. The new comment in dss.c explains this in more detail. Suggested-By: Sanja Jasek Tested-By: Sanja Jasek --- dss.c | 37 +++++++++++++++++++++++++++++-------- dss.suite | 7 +++++-- 2 files changed, 34 insertions(+), 10 deletions(-) diff --git a/dss.c b/dss.c index 8f632cb..f8bbb99 100644 --- a/dss.c +++ b/dss.c @@ -1417,14 +1417,35 @@ static void create_rsync_argv(char ***argv, int64_t *num) } else DSS_INFO_LOG(("no suitable reference snapshot found\n")); logname = dss_logname(); - if (use_rsync_locally(logname)) - (*argv)[i++] = dss_strdup(OPT_STRING_VAL(DSS, SOURCE_DIR)); - else - (*argv)[i++] = make_message("%s@%s:%s/", - OPT_GIVEN(DSS, REMOTE_USER)? - OPT_STRING_VAL(DSS, REMOTE_USER) : logname, - OPT_STRING_VAL(DSS, REMOTE_HOST), - OPT_STRING_VAL(DSS, SOURCE_DIR)); + N = OPT_GIVEN(DSS, SOURCE_DIR); + if (use_rsync_locally(logname)) { + for (j = 0; j < N; j++) + (*argv)[i++] = dss_strdup(lls_string_val(j, + OPT_RESULT(DSS, SOURCE_DIR))); + } else { + /* + * dss-1.0 and earlier did not support multiple source + * directories. These versions appended a slash to the end of + * the source directory to make sure that only the contents of + * the single source directory, but not the directory itself, + * are copied to the destination. For multiple source + * directories, however, this is not a good idea because the + * source directories may well contain identical file names, + * which would then be copied to the same location on the + * destination, overwriting each other. Moreover, we want the + * directory on the destination match the source. To preserve + * the old behaviour, we thus have to special-case N=1. + */ + for (j = 0; j < N; j++) { + (*argv)[i++] = make_message("%s@%s:%s%s", + OPT_GIVEN(DSS, REMOTE_USER)? + OPT_STRING_VAL(DSS, REMOTE_USER) : logname, + OPT_STRING_VAL(DSS, REMOTE_HOST), + lls_string_val(j, OPT_RESULT(DSS, SOURCE_DIR)), + N == 1? "/" : "" + ); + } + } free(logname); *num = get_current_time(); (*argv)[i++] = incomplete_name(*num); diff --git a/dss.suite b/dss.suite index 03e1474..16c7e58 100644 --- a/dss.suite +++ b/dss.suite @@ -62,13 +62,15 @@ caption = Subcommands typestr = dirname arg_info = required_arg arg_type = string + flag multiple [help] The directory on the remote host from which snapshots are taken. Of course, the user specified as --remote-user must have read access to this directory. - This option is mandatory for the create and run subcommands: It must - be given at the command line or in the config file. + This option is mandatory for the create and run subcommands: It may + be given multiple times to specify more than one source directory. + However, all source directories must reside on the same server. [/help] [option dest-dir] summary = where snapshots are stored @@ -80,6 +82,7 @@ caption = Subcommands written. This must be writable by the user who runs dss. This option is mandatory for all subcommands except kill. + Unlike --source-dir, this option may only be given once. [/help] [option mountpoint] summary = abort if destination directory is not a mountpoint -- 2.39.2