X-Git-Url: https://mattmccutchen.net/rsync/rsync.git/blobdiff_plain/3696674bc62b0c1250027dbeedafdd7ebafdcf8b..da7acc5e425e3221a24925b864bec1abbe8d4901:/options.c diff --git a/options.c b/options.c index 5af0a319..a8c5b49f 100644 --- a/options.c +++ b/options.c @@ -3,7 +3,7 @@ * * Copyright (C) 1998-2001 Andrew Tridgell * Copyright (C) 2000, 2001, 2002 Martin Pool - * Copyright (C) 2002-2009 Wayne Davison + * Copyright (C) 2002-2011 Wayne Davison * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -29,8 +29,8 @@ extern int local_server; extern int sanitize_paths; extern int daemon_over_rsh; extern unsigned int module_dirlen; -extern struct filter_list_struct filter_list; -extern struct filter_list_struct daemon_filter_list; +extern filter_rule_list filter_list; +extern filter_rule_list daemon_filter_list; int make_backups = 0; @@ -73,6 +73,7 @@ int remove_source_files = 0; int one_file_system = 0; int protocol_version = PROTOCOL_VERSION; int sparse_files = 0; +int preallocate_files = 0; int do_compression = 0; int def_compress_level = Z_DEFAULT_COMPRESSION; int am_root = 0; /* 0 = normal, 1 = root, 2 = --super, -1 = --fake-super */ @@ -93,7 +94,7 @@ char *files_from = NULL; int filesfrom_fd = -1; char *filesfrom_host = NULL; int eol_nulls = 0; -int protect_args = 0; +int protect_args = -1; int human_readable = 1; int recurse = 0; int allow_inc_recurse = 1; @@ -204,18 +205,18 @@ struct chmod_mode_struct *chmod_modes = NULL; static const char *debug_verbosity[] = { /*0*/ NULL, /*1*/ NULL, - /*2*/ "bind,cmd,connect,del,deltasum,dup,filter,flist,iconv", - /*3*/ "acl,backup,deltasum2,del2,exit,filter2,flist2,fuzzy,genr,own,recv,send,time", - /*4*/ "cmd2,deltasum3,del3,exit2,flist3,iconv2,own2,proto,time2", - /*5*/ "chdir,deltasum4,flist4,fuzzy2,hash,hlink", + /*2*/ "BIND,CMD,CONNECT,DEL,DELTASUM,DUP,FILTER,FLIST,ICONV", + /*3*/ "ACL,BACKUP,DELTASUM2,DEL2,EXIT,FILTER2,FLIST2,FUZZY,GENR,OWN,RECV,SEND,TIME", + /*4*/ "CMD2,DELTASUM3,DEL3,EXIT2,FLIST3,ICONV2,OWN2,PROTO,TIME2", + /*5*/ "CHDIR,DELTASUM4,FLIST4,FUZZY2,HASH,HLINK", }; #define MAX_VERBOSITY ((int)(sizeof debug_verbosity / sizeof debug_verbosity[0]) - 1) static const char *info_verbosity[1+MAX_VERBOSITY] = { /*0*/ NULL, - /*1*/ "copy,del,flist,misc,name,stats,symsafe", - /*2*/ "backup,mount,name2,remove,skip", + /*1*/ "COPY,DEL,FLIST,MISC,NAME,STATS,SYMSAFE", + /*2*/ "BACKUP,MISC2,MOUNT,NAME2,REMOVE,SKIP", }; #define MAX_OUT_LEVEL 4 /* The largest N allowed for any flagN word. */ @@ -248,7 +249,7 @@ static struct output_struct info_words[COUNT_INFO+1] = { INFO_WORD(COPY, W_REC, "Mention files copied locally on the receiving side"), INFO_WORD(DEL, W_REC, "Mention deletions on the receiving side"), INFO_WORD(FLIST, W_CLI, "Mention file-list receiving/sending (levels 1-2)"), - INFO_WORD(MISC, W_SND|W_REC, "Mention miscellaneous information"), + INFO_WORD(MISC, W_SND|W_REC, "Mention miscellaneous information (levels 1-2)"), INFO_WORD(MOUNT, W_SND|W_REC, "Mention mounts that were found or skipped"), INFO_WORD(NAME, W_SND|W_REC, "Mention 1) updated file/dir names, 2) unchanged names"), INFO_WORD(PROGRESS, W_CLI, "Mention 1) per-file progress or 2) total transfer progress"), @@ -271,14 +272,15 @@ static struct output_struct debug_words[COUNT_DEBUG+1] = { DEBUG_WORD(DEL, W_REC, "Debug delete actions (levels 1-3)"), DEBUG_WORD(DELTASUM, W_SND|W_REC, "Debug delta-transfer checksumming (levels 1-4)"), DEBUG_WORD(DUP, W_REC, "Debug weeding of duplicate names"), - DEBUG_WORD(EXIT, W_CLI|W_SRV, "Debug exit events (levels 1-2)"), + DEBUG_WORD(EXIT, W_CLI|W_SRV, "Debug exit events (levels 1-3)"), DEBUG_WORD(FILTER, W_SND|W_REC, "Debug filter actions (levels 1-2)"), DEBUG_WORD(FLIST, W_SND|W_REC, "Debug file-list operations (levels 1-4)"), DEBUG_WORD(FUZZY, W_REC, "Debug fuzzy scoring (levels 1-2)"), DEBUG_WORD(GENR, W_REC, "Debug generator functions"), DEBUG_WORD(HASH, W_SND|W_REC, "Debug hashtable code"), - DEBUG_WORD(HLINK, W_SND|W_REC, "Debug hard-link actions"), + DEBUG_WORD(HLINK, W_SND|W_REC, "Debug hard-link actions (levels 1-3)"), DEBUG_WORD(ICONV, W_CLI|W_SRV, "Debug iconv character conversions (levels 1-2)"), + DEBUG_WORD(IO, W_CLI|W_SRV, "Debug I/O routines (levels 1-4)"), DEBUG_WORD(OWN, W_REC, "Debug ownership changes in users & groups (levels 1-2)"), DEBUG_WORD(PROTO, W_CLI|W_SRV, "Debug protocol information"), DEBUG_WORD(RECV, W_REC, "Debug receiver functions"), @@ -292,6 +294,7 @@ static int do_stats = 0; static int do_progress = 0; static int daemon_opt; /* sets am_daemon after option error-reporting */ static int omit_dir_times = 0; +static int omit_link_times = 0; static int F_option_cnt = 0; static int modify_window_set; static int itemize_changes = 0; @@ -300,7 +303,7 @@ static int refused_partial, refused_progress, refused_delete_before; static int refused_delete_during; static int refused_inplace, refused_no_iconv; static BOOL usermap_via_chown, groupmap_via_chown; -static char *max_size_arg, *min_size_arg; +static char *bwlimit_arg, *max_size_arg, *min_size_arg; static char tmp_partialdir[] = ".~tmp~"; /** Local address to bind. As a character string because it's @@ -560,6 +563,7 @@ static void print_rsync_version(enum logcode f) char const *got_socketpair = "no "; char const *have_inplace = "no "; char const *hardlinks = "no "; + char const *prealloc = "no "; char const *symtimes = "no "; char const *acls = "no "; char const *xattrs = "no "; @@ -581,6 +585,9 @@ static void print_rsync_version(enum logcode f) #ifdef SUPPORT_HARD_LINKS hardlinks = ""; #endif +#ifdef SUPPORT_PREALLOCATION + prealloc = ""; +#endif #ifdef SUPPORT_ACLS acls = ""; #endif @@ -596,13 +603,13 @@ static void print_rsync_version(enum logcode f) #ifdef ICONV_OPTION iconv = ""; #endif -#if defined HAVE_LUTIMES && defined HAVE_UTIMES +#ifdef CAN_SET_SYMLINK_TIMES symtimes = ""; #endif rprintf(f, "%s version %s protocol version %d%s\n", RSYNC_NAME, RSYNC_VERSION, PROTOCOL_VERSION, subprotocol); - rprintf(f, "Copyright (C) 1996-2009 by Andrew Tridgell, Wayne Davison, and others.\n"); + rprintf(f, "Copyright (C) 1996-2011 by Andrew Tridgell, Wayne Davison, and others.\n"); rprintf(f, "Web site: http://rsync.samba.org/\n"); rprintf(f, "Capabilities:\n"); rprintf(f, " %d-bit files, %d-bit inums, %d-bit timestamps, %d-bit long ints,\n", @@ -612,8 +619,8 @@ static void print_rsync_version(enum logcode f) (int)(sizeof (int64) * 8)); rprintf(f, " %ssocketpairs, %shardlinks, %ssymlinks, %sIPv6, batchfiles, %sinplace,\n", got_socketpair, hardlinks, links, ipv6, have_inplace); - rprintf(f, " %sappend, %sACLs, %sxattrs, %siconv, %ssymtimes\n", - have_inplace, acls, xattrs, iconv, symtimes); + rprintf(f, " %sappend, %sACLs, %sxattrs, %siconv, %ssymtimes, %sprealloc\n", + have_inplace, acls, xattrs, iconv, symtimes, prealloc); #ifdef MAINTAINER_MODE rprintf(f, "Panic Action: \"%s\"\n", get_panic_action()); @@ -698,11 +705,17 @@ void usage(enum logcode F) rprintf(F," -D same as --devices --specials\n"); rprintf(F," -t, --times preserve modification times\n"); rprintf(F," -O, --omit-dir-times omit directories from --times\n"); + rprintf(F," -J, --omit-link-times omit symlinks from --times\n"); rprintf(F," --super receiver attempts super-user activities\n"); #ifdef SUPPORT_XATTRS rprintf(F," --fake-super store/recover privileged attrs using xattrs\n"); #endif rprintf(F," -S, --sparse handle sparse files efficiently\n"); +#ifdef SUPPORT_PREALLOCATION + rprintf(F," --preallocate allocate dest files before writing them\n"); +#else + rprintf(F," --preallocate pre-allocate dest files on remote receiver\n"); +#endif rprintf(F," -n, --dry-run perform a trial run with no changes made\n"); rprintf(F," -W, --whole-file copy files whole (without delta-xfer algorithm)\n"); rprintf(F," -x, --one-file-system don't cross filesystem boundaries\n"); @@ -774,7 +787,7 @@ void usage(enum logcode F) rprintf(F," --log-file-format=FMT log updates using the specified FMT\n"); rprintf(F," --password-file=FILE read daemon-access password from FILE\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," --bwlimit=RATE limit socket I/O bandwidth\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"); @@ -798,7 +811,7 @@ enum {OPT_VERSION = 1000, OPT_DAEMON, OPT_SENDER, OPT_EXCLUDE, OPT_EXCLUDE_FROM, OPT_INCLUDE, OPT_INCLUDE_FROM, OPT_MODIFY_WINDOW, OPT_MIN_SIZE, OPT_CHMOD, OPT_READ_BATCH, OPT_WRITE_BATCH, OPT_ONLY_WRITE_BATCH, OPT_MAX_SIZE, OPT_NO_D, OPT_APPEND, OPT_NO_ICONV, OPT_INFO, OPT_DEBUG, - OPT_USERMAP, OPT_GROUPMAP, OPT_CHOWN, + OPT_USERMAP, OPT_GROUPMAP, OPT_CHOWN, OPT_BWLIMIT, OPT_SERVER, OPT_REFUSED_BASE = 9000}; static struct poptOption long_options[] = { @@ -842,12 +855,15 @@ static struct poptOption long_options[] = { {"xattrs", 'X', POPT_ARG_NONE, 0, 'X', 0, 0 }, {"no-xattrs", 0, POPT_ARG_VAL, &preserve_xattrs, 0, 0, 0 }, {"no-X", 0, POPT_ARG_VAL, &preserve_xattrs, 0, 0, 0 }, - {"times", 't', POPT_ARG_VAL, &preserve_times, 2, 0, 0 }, + {"times", 't', POPT_ARG_VAL, &preserve_times, 1, 0, 0 }, {"no-times", 0, POPT_ARG_VAL, &preserve_times, 0, 0, 0 }, {"no-t", 0, POPT_ARG_VAL, &preserve_times, 0, 0, 0 }, {"omit-dir-times", 'O', POPT_ARG_VAL, &omit_dir_times, 1, 0, 0 }, {"no-omit-dir-times",0, POPT_ARG_VAL, &omit_dir_times, 0, 0, 0 }, {"no-O", 0, POPT_ARG_VAL, &omit_dir_times, 0, 0, 0 }, + {"omit-link-times", 'J', POPT_ARG_VAL, &omit_link_times, 1, 0, 0 }, + {"no-omit-link-times",0, POPT_ARG_VAL, &omit_link_times, 0, 0, 0 }, + {"no-J", 0, POPT_ARG_VAL, &omit_link_times, 0, 0, 0 }, {"modify-window", 0, POPT_ARG_INT, &modify_window, OPT_MODIFY_WINDOW, 0, 0 }, {"super", 0, POPT_ARG_VAL, &am_root, 2, 0, 0 }, {"no-super", 0, POPT_ARG_VAL, &am_root, 0, 0, 0 }, @@ -888,8 +904,8 @@ static struct poptOption long_options[] = { {"ignore-times", 'I', POPT_ARG_NONE, &ignore_times, 0, 0, 0 }, {"size-only", 0, POPT_ARG_NONE, &size_only, 0, 0, 0 }, {"one-file-system", 'x', POPT_ARG_NONE, 0, 'x', 0, 0 }, - {"no-one-file-system",'x',POPT_ARG_VAL, &one_file_system, 0, 0, 0 }, - {"no-x", 'x', POPT_ARG_VAL, &one_file_system, 0, 0, 0 }, + {"no-one-file-system",0, POPT_ARG_VAL, &one_file_system, 0, 0, 0 }, + {"no-x", 0, POPT_ARG_VAL, &one_file_system, 0, 0, 0 }, {"update", 'u', POPT_ARG_NONE, &update_only, 0, 0, 0 }, {"existing", 0, POPT_ARG_NONE, &ignore_non_existing, 0, 0, 0 }, {"ignore-non-existing",0,POPT_ARG_NONE, &ignore_non_existing, 0, 0, 0 }, @@ -899,6 +915,7 @@ static struct poptOption long_options[] = { {"sparse", 'S', POPT_ARG_VAL, &sparse_files, 1, 0, 0 }, {"no-sparse", 0, POPT_ARG_VAL, &sparse_files, 0, 0, 0 }, {"no-S", 0, POPT_ARG_VAL, &sparse_files, 0, 0, 0 }, + {"preallocate", 0, POPT_ARG_NONE, &preallocate_files, 0, 0, 0}, {"inplace", 0, POPT_ARG_VAL, &inplace, 1, 0, 0 }, {"no-inplace", 0, POPT_ARG_VAL, &inplace, 0, 0, 0 }, {"append", 0, POPT_ARG_NONE, 0, OPT_APPEND, 0, 0 }, @@ -963,7 +980,7 @@ static struct poptOption long_options[] = { {"itemize-changes", 'i', POPT_ARG_NONE, 0, 'i', 0, 0 }, {"no-itemize-changes",0, POPT_ARG_VAL, &itemize_changes, 0, 0, 0 }, {"no-i", 0, POPT_ARG_VAL, &itemize_changes, 0, 0, 0 }, - {"bwlimit", 0, POPT_ARG_INT, &bwlimit, 0, 0, 0 }, + {"bwlimit", 0, POPT_ARG_STRING, &bwlimit_arg, OPT_BWLIMIT, 0, 0 }, {"no-bwlimit", 0, POPT_ARG_VAL, &bwlimit, 0, 0, 0 }, {"backup", 'b', POPT_ARG_VAL, &make_backups, 1, 0, 0 }, {"no-backup", 0, POPT_ARG_VAL, &make_backups, 0, 0, 0 }, @@ -1028,7 +1045,7 @@ static void daemon_usage(enum logcode F) rprintf(F,"\n"); rprintf(F,"Usage: rsync --daemon [OPTION]...\n"); rprintf(F," --address=ADDRESS bind to the specified address\n"); - rprintf(F," --bwlimit=KBPS limit I/O bandwidth; KBytes per second\n"); + rprintf(F," --bwlimit=RATE limit socket I/O bandwidth\n"); rprintf(F," --config=FILE specify alternate rsyncd.conf file\n"); rprintf(F," -M, --dparam=OVERRIDE override global daemon config parameter\n"); rprintf(F," --no-detach do not detach from the parent\n"); @@ -1219,7 +1236,7 @@ static OFF_T parse_size_arg(char **size_arg, char def_suf) size += atoi(arg), make_compatible = 1, arg += 2; if (*arg) return -1; - if (size > 0 && make_compatible) { + if (size > 0 && make_compatible && def_suf == 'b') { /* We convert this manually because we may need %lld precision, * and that's not a portable sprintf() escape. */ char buf[128], *s = buf + sizeof buf - 1; @@ -1277,7 +1294,7 @@ int parse_arguments(int *argc_p, const char ***argv_p) } #ifdef ICONV_OPTION - if (!am_daemon && !protect_args && (arg = getenv("RSYNC_ICONV")) != NULL && *arg) + if (!am_daemon && protect_args <= 0 && (arg = getenv("RSYNC_ICONV")) != NULL && *arg) iconv_opt = strdup(arg); #endif @@ -1332,6 +1349,7 @@ int parse_arguments(int *argc_p, const char ***argv_p) #ifdef ICONV_OPTION iconv_opt = NULL; #endif + protect_args = 0; poptFreeContext(pc); pc = poptGetContext(RSYNC_NAME, argc, argv, long_daemon_options, 0); @@ -1399,17 +1417,18 @@ int parse_arguments(int *argc_p, const char ***argv_p) break; case OPT_FILTER: - parse_rule(&filter_list, poptGetOptArg(pc), 0, 0); + parse_filter_str(&filter_list, poptGetOptArg(pc), + rule_template(0), 0); break; case OPT_EXCLUDE: - parse_rule(&filter_list, poptGetOptArg(pc), - 0, XFLG_OLD_PREFIXES); + parse_filter_str(&filter_list, poptGetOptArg(pc), + rule_template(0), XFLG_OLD_PREFIXES); break; case OPT_INCLUDE: - parse_rule(&filter_list, poptGetOptArg(pc), - MATCHFLG_INCLUDE, XFLG_OLD_PREFIXES); + parse_filter_str(&filter_list, poptGetOptArg(pc), + rule_template(FILTRULE_INCLUDE), XFLG_OLD_PREFIXES); break; case OPT_EXCLUDE_FROM: @@ -1419,20 +1438,22 @@ int parse_arguments(int *argc_p, const char ***argv_p) arg = sanitize_path(NULL, arg, NULL, 0, SP_DEFAULT); if (daemon_filter_list.head) { int rej; - char *dir, *cp = strdup(arg); + char *cp = strdup(arg); if (!cp) out_of_memory("parse_arguments"); if (!*cp) - goto options_rejected; - dir = cp + (*cp == '/' ? module_dirlen : 0); - clean_fname(dir, CFN_COLLAPSE_DOT_DOT_DIRS); - rej = check_filter(&daemon_filter_list, FLOG, dir, 0) < 0; + rej = 1; + else { + char *dir = cp + (*cp == '/' ? module_dirlen : 0); + clean_fname(dir, CFN_COLLAPSE_DOT_DOT_DIRS); + rej = check_filter(&daemon_filter_list, FLOG, dir, 0) < 0; + } free(cp); if (rej) goto options_rejected; } parse_filter_file(&filter_list, arg, - opt == OPT_INCLUDE_FROM ? MATCHFLG_INCLUDE : 0, + rule_template(opt == OPT_INCLUDE_FROM ? FILTRULE_INCLUDE : 0), XFLG_FATAL_ERRORS | XFLG_OLD_PREFIXES); break; @@ -1447,7 +1468,7 @@ int parse_arguments(int *argc_p, const char ***argv_p) preserve_links = 1; #endif preserve_perms = 1; - preserve_times = 2; + preserve_times = 1; preserve_gid = 1; preserve_uid = 1; preserve_devices = 1; @@ -1489,10 +1510,10 @@ int parse_arguments(int *argc_p, const char ***argv_p) case 'F': switch (++F_option_cnt) { case 1: - parse_rule(&filter_list,": /.rsync-filter",0,0); + parse_filter_str(&filter_list,": /.rsync-filter",rule_template(0),0); break; case 2: - parse_rule(&filter_list,"- .rsync-filter",0,0); + parse_filter_str(&filter_list,"- .rsync-filter",rule_template(0),0); break; } break; @@ -1581,6 +1602,23 @@ int parse_arguments(int *argc_p, const char ***argv_p) } break; + case OPT_BWLIMIT: + { + OFF_T limit = parse_size_arg(&bwlimit_arg, 'K'); + if (limit < 0) { + snprintf(err_buf, sizeof err_buf, + "--bwlimit value is invalid: %s\n", bwlimit_arg); + return 0; + } + bwlimit = (limit + 512) / 1024; + if (limit && !bwlimit) { + snprintf(err_buf, sizeof err_buf, + "--bwlimit value is too small: %s\n", bwlimit_arg); + return 0; + } + } + break; + case OPT_APPEND: if (am_server) append_mode++; @@ -1757,6 +1795,20 @@ int parse_arguments(int *argc_p, const char ***argv_p) } } + if (protect_args < 0) { + if (am_server) + protect_args = 0; + else if ((arg = getenv("RSYNC_PROTECT_ARGS")) != NULL && *arg) + protect_args = atoi(arg) ? 1 : 0; + else { +#ifdef RSYNC_USE_PROTECTED_ARGS + protect_args = 1; +#else + protect_args = 0; +#endif + } + } + if (human_readable > 1 && argc == 2 && !am_server) { /* Allow the old meaning of 'h' (--help) on its own. */ usage(FINFO); @@ -1854,6 +1906,12 @@ int parse_arguments(int *argc_p, const char ***argv_p) "--read-batch cannot be used with --files-from\n"); return 0; } + if (read_batch && remove_source_files) { + snprintf(err_buf, sizeof err_buf, + "--read-batch cannot be used with --remove-%s-files\n", + remove_source_files == 1 ? "source" : "sent"); + return 0; + } if (batch_name && strlen(batch_name) > MAX_BATCH_NAME_LEN) { snprintf(err_buf, sizeof err_buf, "the batch-file name must be %d characters or less.\n", @@ -1889,7 +1947,7 @@ int parse_arguments(int *argc_p, const char ***argv_p) list_only |= 1; if (xfer_dirs >= 4) { - parse_rule(&filter_list, "- /*/*", 0, 0); + parse_filter_str(&filter_list, "- /*/*", rule_template(0), 0); recurse = xfer_dirs = 1; } else if (recurse) xfer_dirs = 1; @@ -1923,7 +1981,7 @@ int parse_arguments(int *argc_p, const char ***argv_p) } if (!xfer_dirs && delete_mode) { snprintf(err_buf, sizeof err_buf, - "--delete does not work without -r or -d.\n"); + "--delete does not work without --recursive (-r) or --dirs (-d).\n"); return 0; } @@ -1966,7 +2024,7 @@ int parse_arguments(int *argc_p, const char ***argv_p) backup_dir = sanitize_path(NULL, backup_dir, NULL, 0, SP_DEFAULT); } if (daemon_filter_list.head && !am_sender) { - struct filter_list_struct *elp = &daemon_filter_list; + filter_rule_list *elp = &daemon_filter_list; if (tmpdir) { char *dir; if (!*tmpdir) @@ -1997,38 +2055,54 @@ int parse_arguments(int *argc_p, const char ***argv_p) return 0; } if (backup_dir) { + size_t len; while (*backup_dir == '.' && backup_dir[1] == '/') backup_dir += 2; if (*backup_dir == '.' && backup_dir[1] == '\0') backup_dir++; - backup_dir_len = strlcpy(backup_dir_buf, backup_dir, sizeof backup_dir_buf); - backup_dir_remainder = sizeof backup_dir_buf - backup_dir_len; - if (backup_dir_remainder < 128) { + len = strlcpy(backup_dir_buf, backup_dir, sizeof backup_dir_buf); + if (len > sizeof backup_dir_buf - 128) { snprintf(err_buf, sizeof err_buf, "the --backup-dir path is WAY too long.\n"); return 0; } - if (backup_dir_len && backup_dir_buf[backup_dir_len - 1] != '/') { + backup_dir_len = (int)len; + if (!backup_dir_len) { + backup_dir_len = -1; + backup_dir = NULL; + } else if (backup_dir_buf[backup_dir_len - 1] != '/') { backup_dir_buf[backup_dir_len++] = '/'; backup_dir_buf[backup_dir_len] = '\0'; } + backup_dir_remainder = sizeof backup_dir_buf - backup_dir_len; + } + if (backup_dir) { + /* No need for a suffix or a protect rule. */ } else if (!backup_suffix_len && (!am_server || !am_sender)) { snprintf(err_buf, sizeof err_buf, - "--suffix cannot be a null string without --backup-dir\n"); + "--suffix cannot be empty %s\n", backup_dir_len < 0 + ? "when --backup-dir is the same as the dest dir" + : "without a --backup-dir"); return 0; } else if (make_backups && delete_mode && !delete_excluded && !am_server) { snprintf(backup_dir_buf, sizeof backup_dir_buf, "P *%s", backup_suffix); - parse_rule(&filter_list, backup_dir_buf, 0, 0); + parse_filter_str(&filter_list, backup_dir_buf, rule_template(0), 0); + } + + if (preserve_times) { + preserve_times = PRESERVE_FILE_TIMES; + if (!omit_dir_times) + preserve_times |= PRESERVE_DIR_TIMES; +#ifdef CAN_SET_SYMLINK_TIMES + if (!omit_link_times) + preserve_times |= PRESERVE_LINK_TIMES; +#endif } if (make_backups && !backup_dir) { omit_dir_times = 0; /* Implied, so avoid -O to sender. */ - if (preserve_times > 1) - preserve_times = 1; - } else if (omit_dir_times) { - if (preserve_times > 1) - preserve_times = 1; + preserve_times &= ~PRESERVE_DIR_TIMES; } if (stdout_format) { @@ -2154,7 +2228,7 @@ int parse_arguments(int *argc_p, const char ***argv_p) if (files_from) { char *h, *p; int q; - if (argc > 2 || (!am_daemon && argc == 1)) { + if (argc > 2 || (!am_daemon && !am_server && argc == 1)) { usage(FERROR); exit_cleanup(RERR_SYNTAX); } @@ -2265,6 +2339,8 @@ void server_options(char **args, int *argc_p) argstr[x++] = 'm'; if (omit_dir_times) argstr[x++] = 'O'; + if (omit_link_times) + argstr[x++] = 'J'; } else { if (copy_links) argstr[x++] = 'L'; @@ -2343,7 +2419,7 @@ void server_options(char **args, int *argc_p) argstr[x++] = '.'; if (allow_inc_recurse) argstr[x++] = 'i'; -#if defined HAVE_LUTIMES && defined HAVE_UTIMES +#ifdef CAN_SET_SYMLINK_TIMES argstr[x++] = 'L'; #endif #ifdef ICONV_OPTION @@ -2611,6 +2687,9 @@ void server_options(char **args, int *argc_p) else if (remove_source_files) args[ac++] = "--remove-sent-files"; + if (preallocate_files && am_sender) + args[ac++] = "--preallocate"; + if (ac > MAX_SERVER_ARGS) { /* Not possible... */ rprintf(FERROR, "argc overflow in server_options().\n"); exit_cleanup(RERR_MALLOC);