static int daemon_opt; /* sets am_daemon after option error-reporting */
static int modify_window_set;
static int daemon_opt; /* sets am_daemon after option error-reporting */
static int modify_window_set;
rprintf(F," --modify-window=NUM compare mod times with reduced accuracy\n");
rprintf(F," -T, --temp-dir=DIR create temporary files in directory DIR\n");
rprintf(F," --compare-dest=DIR also compare destination files relative to DIR\n");
rprintf(F," --modify-window=NUM compare mod times with reduced accuracy\n");
rprintf(F," -T, --temp-dir=DIR create temporary files in directory DIR\n");
rprintf(F," --compare-dest=DIR also compare destination files relative to DIR\n");
- rprintf(F," --link-dest=DIR create hardlinks to DIR for unchanged files\n");
+ rprintf(F," --copy-dest=DIR ... and include copies of unchanged files\n");
+ rprintf(F," --link-dest=DIR hardlink to files in DIR when unchanged\n");
rprintf(F," -P equivalent to --partial --progress\n");
rprintf(F," -z, --compress compress file data\n");
rprintf(F," -C, --cvs-exclude auto ignore files in the same way CVS does\n");
rprintf(F," -P equivalent to --partial --progress\n");
rprintf(F," -z, --compress compress file data\n");
rprintf(F," -C, --cvs-exclude auto ignore files in the same way CVS does\n");
rprintf(F," --files-from=FILE read FILE for list of source-file names\n");
rprintf(F," -0, --from0 all *-from file lists are delimited by nulls\n");
rprintf(F," --version print version number\n");
rprintf(F," --files-from=FILE read FILE for list of source-file names\n");
rprintf(F," -0, --from0 all *-from file lists are delimited by nulls\n");
rprintf(F," --version print version number\n");
rprintf(F," --blocking-io use blocking I/O for the remote shell\n");
rprintf(F," --no-blocking-io turn off --blocking-io\n");
rprintf(F," --stats give some file transfer stats\n");
rprintf(F," --blocking-io use blocking I/O for the remote shell\n");
rprintf(F," --no-blocking-io turn off --blocking-io\n");
rprintf(F," --stats give some file transfer stats\n");
}
enum {OPT_VERSION = 1000, OPT_DAEMON, OPT_SENDER, OPT_EXCLUDE, OPT_EXCLUDE_FROM,
}
enum {OPT_VERSION = 1000, OPT_DAEMON, OPT_SENDER, OPT_EXCLUDE, OPT_EXCLUDE_FROM,
- OPT_DELETE_AFTER, OPT_DELETE_EXCLUDED, OPT_LINK_DEST,
+ OPT_DELETE_AFTER, OPT_DELETE_EXCLUDED,
+ OPT_COMPARE_DEST, OPT_COPY_DEST, OPT_LINK_DEST,
OPT_INCLUDE, OPT_INCLUDE_FROM, OPT_MODIFY_WINDOW,
OPT_READ_BATCH, OPT_WRITE_BATCH, OPT_TIMEOUT, OPT_MAX_SIZE,
OPT_REFUSED_BASE = 9000};
OPT_INCLUDE, OPT_INCLUDE_FROM, OPT_MODIFY_WINDOW,
OPT_READ_BATCH, OPT_WRITE_BATCH, OPT_TIMEOUT, OPT_MAX_SIZE,
OPT_REFUSED_BASE = 9000};
{"relative", 'R', POPT_ARG_VAL, &relative_paths, 1, 0, 0 },
{"no-relative", 0, POPT_ARG_VAL, &relative_paths, 0, 0, 0 },
{"rsh", 'e', POPT_ARG_STRING, &shell_cmd, 0, 0, 0 },
{"relative", 'R', POPT_ARG_VAL, &relative_paths, 1, 0, 0 },
{"no-relative", 0, POPT_ARG_VAL, &relative_paths, 0, 0, 0 },
{"rsh", 'e', POPT_ARG_STRING, &shell_cmd, 0, 0, 0 },
- {"block-size", 'B', POPT_ARG_INT, &block_size, 0, 0, 0 },
+ {"block-size", 'B', POPT_ARG_LONG, &block_size, 0, 0, 0 },
{"max-delete", 0, POPT_ARG_INT, &max_delete, 0, 0, 0 },
{"max-size", 0, POPT_ARG_STRING, &max_size_arg, OPT_MAX_SIZE, 0, 0 },
{"timeout", 0, POPT_ARG_INT, &io_timeout, OPT_TIMEOUT, 0, 0 },
{"temp-dir", 'T', POPT_ARG_STRING, &tmpdir, 0, 0, 0 },
{"max-delete", 0, POPT_ARG_INT, &max_delete, 0, 0, 0 },
{"max-size", 0, POPT_ARG_STRING, &max_size_arg, OPT_MAX_SIZE, 0, 0 },
{"timeout", 0, POPT_ARG_INT, &io_timeout, OPT_TIMEOUT, 0, 0 },
{"temp-dir", 'T', POPT_ARG_STRING, &tmpdir, 0, 0, 0 },
- {"compare-dest", 0, POPT_ARG_STRING, &compare_dest, 0, 0, 0 },
- {"link-dest", 0, POPT_ARG_STRING, &compare_dest, OPT_LINK_DEST, 0, 0 },
+ {"compare-dest", 0, POPT_ARG_STRING, 0, OPT_COMPARE_DEST, 0, 0 },
+ {"copy-dest", 0, POPT_ARG_STRING, 0, OPT_COPY_DEST, 0, 0 },
+ {"link-dest", 0, POPT_ARG_STRING, 0, OPT_LINK_DEST, 0, 0 },
/* TODO: Should this take an optional int giving the compression level? */
{"compress", 'z', POPT_ARG_NONE, &do_compression, 0, 0, 0 },
{"stats", 0, POPT_ARG_NONE, &do_stats, 0, 0, 0 },
/* TODO: Should this take an optional int giving the compression level? */
{"compress", 'z', POPT_ARG_NONE, &do_compression, 0, 0, 0 },
{"stats", 0, POPT_ARG_NONE, &do_stats, 0, 0, 0 },
{"blocking-io", 0, POPT_ARG_VAL, &blocking_io, 1, 0, 0 },
{"no-blocking-io", 0, POPT_ARG_VAL, &blocking_io, 0, 0, 0 },
{0, 'P', POPT_ARG_NONE, 0, 'P', 0, 0 },
{"blocking-io", 0, POPT_ARG_VAL, &blocking_io, 1, 0, 0 },
{"no-blocking-io", 0, POPT_ARG_VAL, &blocking_io, 0, 0, 0 },
{0, 'P', POPT_ARG_NONE, 0, 'P', 0, 0 },
{"log-format", 0, POPT_ARG_STRING, &log_format, 0, 0, 0 },
{"bwlimit", 0, POPT_ARG_INT, &bwlimit, 0, 0, 0 },
{"backup-dir", 0, POPT_ARG_STRING, &backup_dir, 0, 0, 0 },
{"log-format", 0, POPT_ARG_STRING, &log_format, 0, 0, 0 },
{"bwlimit", 0, POPT_ARG_INT, &bwlimit, 0, 0, 0 },
{"backup-dir", 0, POPT_ARG_STRING, &backup_dir, 0, 0, 0 },
{"config", 0, POPT_ARG_STRING, 0, OPT_DAEMON, 0, 0 },
{"daemon", 0, POPT_ARG_NONE, 0, OPT_DAEMON, 0, 0 },
{"no-detach", 0, POPT_ARG_NONE, 0, OPT_DAEMON, 0, 0 },
{"config", 0, POPT_ARG_STRING, 0, OPT_DAEMON, 0, 0 },
{"daemon", 0, POPT_ARG_NONE, 0, OPT_DAEMON, 0, 0 },
{"no-detach", 0, POPT_ARG_NONE, 0, OPT_DAEMON, 0, 0 },
#else
snprintf(err_buf, sizeof err_buf,
"hard links are not supported on this %s\n",
#else
snprintf(err_buf, sizeof err_buf,
"hard links are not supported on this %s\n",
+ case OPT_COPY_DEST:
+ copy_dest = 1;
+ dest_option = "--copy-dest";
+ goto set_dest_dir;
+
+ case OPT_COMPARE_DEST:
+ compare_dest = 1;
+ dest_option = "--compare-dest";
+ set_dest_dir:
+ if (basis_dir_cnt >= MAX_BASIS_DIRS-1) {
+ snprintf(err_buf, sizeof err_buf,
+ "ERROR: at most %d %s args may be specified\n",
+ MAX_BASIS_DIRS, dest_option);
+ return 0;
+ }
+ arg = poptGetOptArg(pc);
+ if (sanitize_paths)
+ arg = sanitize_path(NULL, arg, NULL, 0);
+ basis_dir[basis_dir_cnt++] = (char *)arg;
+ break;
+
default:
/* A large opt value means that set_refuse_options()
* turned this option off (opt-BASE is its index). */
default:
/* A large opt value means that set_refuse_options()
* turned this option off (opt-BASE is its index). */
+ if (compare_dest + copy_dest + link_dest > 1) {
+ snprintf(err_buf, sizeof err_buf,
+ "You may not mix --compare-dest, --copy-dest, and --link-dest.\n");
+ return 0;
+ }
+
tmpdir = sanitize_path(NULL, tmpdir, NULL, 0);
if (partial_dir)
partial_dir = sanitize_path(NULL, partial_dir, NULL, 0);
tmpdir = sanitize_path(NULL, tmpdir, NULL, 0);
if (partial_dir)
partial_dir = sanitize_path(NULL, partial_dir, NULL, 0);
if (backup_dir)
backup_dir = sanitize_path(NULL, backup_dir, NULL, 0);
if (files_from)
if (backup_dir)
backup_dir = sanitize_path(NULL, backup_dir, NULL, 0);
if (files_from)
}
if (server_exclude_list.head && !am_sender) {
struct exclude_list_struct *elp = &server_exclude_list;
}
if (server_exclude_list.head && !am_sender) {
struct exclude_list_struct *elp = &server_exclude_list;
- if (compare_dest) {
- clean_fname(compare_dest, 1);
- if (check_exclude(elp, compare_dest, 1) < 0)
+ for (i = 0; i < basis_dir_cnt; i++) {
+ clean_fname(basis_dir[i], 1);
+ if (check_exclude(elp, basis_dir[i], 1) < 0)
snprintf(err_buf, sizeof err_buf,
"--inplace does not yet work with %s\n",
snprintf(err_buf, sizeof err_buf,
"--inplace does not yet work with %s\n",
/* the server only needs this option if it is not the sender,
* and it may be an older version that doesn't know this
* option, so don't send it if client is the sender.
*/
/* the server only needs this option if it is not the sender,
* and it may be an older version that doesn't know this
* option, so don't send it if client is the sender.
*/
- args[ac++] = link_dest ? "--link-dest" : "--compare-dest";
- args[ac++] = compare_dest;
+ int i;
+ for (i = 0; i < basis_dir_cnt; i++) {
+ args[ac++] = dest_option;
+ args[ac++] = basis_dir[i];
+ }