int update_only = 0;
int cvs_exclude = 0;
int dry_run = 0;
+int do_xfers = 1;
int ignore_times = 0;
int delete_mode = 0;
int delete_during = 0;
char backup_dir_buf[MAXPATHLEN];
int rsync_port = 0;
int compare_dest = 0;
+int copy_dest = 0;
int link_dest = 0;
int basis_dir_cnt = 0;
+char *dest_option = NULL;
int verbose = 0;
int quiet = 0;
-int itemize_changes = 0;
int log_before_transfer = 0;
int log_format_has_i = 0;
int log_format_has_o_or_i = 0;
static int daemon_opt; /* sets am_daemon after option error-reporting */
static int F_option_cnt = 0;
static int modify_window_set;
+static int itemize_changes = 0;
static int refused_delete, refused_archive_part;
static int refused_partial, refused_progress, refused_delete_before;
-static char *dest_option = NULL;
static char *max_size_arg;
static char partialdir_for_delayupdate[] = ".~tmp~";
rprintf(F," -x, --one-file-system don't cross filesystem boundaries\n");
rprintf(F," -B, --block-size=SIZE force a fixed checksum block-size\n");
rprintf(F," -e, --rsh=COMMAND specify the remote shell to use\n");
- rprintf(F," --rsync-path=PATH specify path to rsync on the remote machine\n");
+ rprintf(F," --rsync-path=PROGRAM specify the rsync to run on the remote machine\n");
rprintf(F," --existing only update files that already exist on receiver\n");
rprintf(F," --ignore-existing ignore files that already exist on receiving side\n");
rprintf(F," --remove-sent-files sent files/symlinks are removed from sending side\n");
rprintf(F," -T, --temp-dir=DIR create temporary files in directory DIR\n");
rprintf(F," -y, --fuzzy find similar file for basis if no dest file\n");
rprintf(F," --compare-dest=DIR also compare destination files relative to DIR\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," -z, --compress compress file data during the transfer\n");
rprintf(F," -C, --cvs-exclude auto-ignore files the same way CVS does\n");
rprintf(F," --files-from=FILE read list of source-file names from FILE\n");
rprintf(F," -0, --from0 all *-from file lists are delimited by nulls\n");
rprintf(F," --version print version number\n");
+ rprintf(F," --address=ADDRESS bind address for outgoing socket to daemon\n");
rprintf(F," --port=PORT specify double-colon alternate port number\n");
rprintf(F," --blocking-io use blocking I/O for the remote shell\n");
rprintf(F," --no-blocking-io turn off blocking I/O when it is the default\n");
rprintf(F," --list-only list the files instead of copying them\n");
rprintf(F," --bwlimit=KBPS limit I/O bandwidth; KBytes per second\n");
rprintf(F," --write-batch=FILE write a batched update to FILE\n");
+ rprintf(F," --only-write-batch=FILE like --write-batch but w/o updating destination\n");
rprintf(F," --read-batch=FILE read a batched update from FILE\n");
+ rprintf(F," --protocol=NUM force an older protocol version to be used\n");
#ifdef INET6
rprintf(F," -4, --ipv4 prefer IPv4\n");
rprintf(F," -6, --ipv6 prefer IPv6\n");
}
enum {OPT_VERSION = 1000, OPT_DAEMON, OPT_SENDER, OPT_EXCLUDE, OPT_EXCLUDE_FROM,
- OPT_FILTER, OPT_COMPARE_DEST, OPT_LINK_DEST,
+ OPT_FILTER, 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_READ_BATCH, OPT_WRITE_BATCH, OPT_ONLY_WRITE_BATCH,
+ OPT_TIMEOUT, OPT_MAX_SIZE,
OPT_REFUSED_BASE = 9000};
static struct poptOption long_options[] = {
{"archive", 'a', POPT_ARG_NONE, &archive_mode, 0, 0, 0 },
{"server", 0, POPT_ARG_NONE, &am_server, 0, 0, 0 },
{"sender", 0, POPT_ARG_NONE, 0, OPT_SENDER, 0, 0 },
- {"recursive", 'r', POPT_ARG_VAL, &recurse, -1, 0, 0 },
+ {"recursive", 'r', POPT_ARG_NONE, &recurse, 0, 0, 0 },
{"list-only", 0, POPT_ARG_VAL, &list_only, 2, 0, 0 },
{"relative", 'R', POPT_ARG_VAL, &relative_paths, 1, 0, 0 },
{"no-relative", 0, POPT_ARG_VAL, &relative_paths, 0, 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, 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 },
{"fuzzy", 'y', POPT_ARG_NONE, &fuzzy_basis, 0, 0, 0 },
/* TODO: Should this take an optional int giving the compression level? */
{"no-blocking-io", 0, POPT_ARG_VAL, &blocking_io, 0, 0, 0 },
{0, 'F', POPT_ARG_NONE, 0, 'F', 0, 0 },
{0, 'P', POPT_ARG_NONE, 0, 'P', 0, 0 },
+ {"address", 0, POPT_ARG_STRING, &bind_address, 0, 0, 0 },
{"port", 0, POPT_ARG_INT, &rsync_port, 0, 0, 0 },
{"log-format", 0, POPT_ARG_STRING, &log_format, 0, 0, 0 },
{"itemize-changes", 'i', POPT_ARG_NONE, &itemize_changes, 0, 0, 0 },
{"hard-links", 'H', POPT_ARG_NONE, &preserve_hard_links, 0, 0, 0 },
{"read-batch", 0, POPT_ARG_STRING, &batch_name, OPT_READ_BATCH, 0, 0 },
{"write-batch", 0, POPT_ARG_STRING, &batch_name, OPT_WRITE_BATCH, 0, 0 },
+ {"only-write-batch", 0, POPT_ARG_STRING, &batch_name, OPT_ONLY_WRITE_BATCH, 0, 0 },
{"files-from", 0, POPT_ARG_STRING, &files_from, 0, 0, 0 },
{"from0", '0', POPT_ARG_NONE, &eol_nulls, 0, 0, 0},
{"no-implied-dirs", 0, POPT_ARG_VAL, &implied_dirs, 0, 0, 0 },
{"ipv6", '6', POPT_ARG_VAL, &default_af_hint, AF_INET6, 0, 0 },
#endif
/* All these options switch us into daemon-mode option-parsing. */
- {"address", 0, POPT_ARG_STRING, 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 },
{"detach", 0, POPT_ARG_NONE, 0, OPT_DAEMON, 0, 0 },
write_batch = 1;
break;
+ case OPT_ONLY_WRITE_BATCH:
+ /* batch_name is already set */
+ write_batch = -1;
+ break;
+
case OPT_READ_BATCH:
/* batch_name is already set */
read_batch = 1;
return 0;
#endif
+ 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";
"--write-batch and --read-batch can not be used together\n");
return 0;
}
- if (write_batch || read_batch) {
- if (dry_run) {
- snprintf(err_buf, sizeof err_buf,
- "--%s-batch cannot be used with --dry_run (-n)\n",
- write_batch ? "write" : "read");
- return 0;
- }
+ if (write_batch > 0 || read_batch) {
if (am_server) {
rprintf(FINFO,
"ignoring --%s-batch option sent to server\n",
* batch args to server. */
read_batch = write_batch = 0;
batch_name = NULL;
- }
+ } else if (dry_run)
+ write_batch = 0;
}
if (read_batch && files_from) {
snprintf(err_buf, sizeof err_buf,
return 0;
}
- if (compare_dest + link_dest > 1) {
+ if (compare_dest + copy_dest + link_dest > 1) {
snprintf(err_buf, sizeof err_buf,
- "You may not mix --compare-dest and --link-dest.\n");
+ "You may not mix --compare-dest, --copy-dest, and --link-dest.\n");
return 0;
}
return 0;
}
if (!files_from)
- recurse = -1; /* infinite recursion */
+ recurse = 1;
#ifdef SUPPORT_LINKS
preserve_links = 1;
#endif
omit_dir_times = 1;
if (log_format) {
- if (strstr(log_format, "%i") != NULL)
+ if (log_format_has(log_format, 'i'))
log_format_has_i = 1;
- if (strstr(log_format, "%b") == NULL
- && strstr(log_format, "%c") == NULL)
+ if (!log_format_has(log_format, 'b')
+ && !log_format_has(log_format, 'c'))
log_before_transfer = !am_server;
} else if (itemize_changes) {
log_format = "%i %n%L";
&& !am_server)
verbose = 1;
+ if (dry_run)
+ do_xfers = 0;
+
if (verbose && !log_format) {
log_format = "%n%L";
log_before_transfer = !am_server;
}
- if (log_format_has_i
- || (log_format && strstr(log_format, "%o") != NULL))
+ if (log_format_has_i || log_format_has(log_format, 'o'))
log_format_has_o_or_i = 1;
if (daemon_bwlimit && (!bwlimit || bwlimit > daemon_bwlimit))
argstr[x++] = 'b';
if (update_only)
argstr[x++] = 'u';
- if (dry_run)
+ if (!do_xfers)
argstr[x++] = 'n';
if (preserve_links)
argstr[x++] = 'l';
argstr[x++] = 'O';
if (preserve_perms)
argstr[x++] = 'p';
- if (recurse < 0)
+ if (recurse)
argstr[x++] = 'r';
if (always_checksum)
argstr[x++] = 'c';
/* This is a complete hack - blame Rusty. FIXME!
* This hack is only needed for older rsync versions that
* don't understand the --list-only option. */
- if (list_only == 1 && recurse >= 0)
+ if (list_only == 1 && !recurse)
argstr[x++] = 'r';
argstr[x] = 0;
args[ac++] = "--delete-after";
if (force_delete)
args[ac++] = "--force";
+ if (write_batch < 0)
+ args[ac++] = "--only-write-batch=X";
}
if (size_only)
if (*s == '[' && (p = strchr(s, ']')) != NULL) {
s++;
hostlen = p - s;
- if (*p == ':')
- *port_ptr = atoi(p+1);
- else if (!*port_ptr)
- *port_ptr = RSYNC_PORT;
+ if (p[1] == ':')
+ *port_ptr = atoi(p+2);
} else {
if ((p = strchr(s, ':')) != NULL) {
hostlen = p - s;
*port_ptr = atoi(p+1);
- } else if (!*port_ptr)
- *port_ptr = RSYNC_PORT;
+ }
}
+ if (!*port_ptr)
+ *port_ptr = RSYNC_PORT;
*host_ptr = new_array(char, hostlen + 1);
strlcpy(*host_ptr, s, hostlen + 1);
return path;
*p = ']';
if (not_host)
return NULL;
+ p++;
} else {
if (!(p = strchr(s, ':')))
return NULL;