X-Git-Url: https://mattmccutchen.net/rsync/rsync.git/blobdiff_plain/58cf354711f9e7eb2ec2a54b5f623abb860dafcf..5250c3bc20b0855f477b6b91457a745c105b3ac2:/options.c diff --git a/options.c b/options.c index 0c64eaa1..d4a0f8f6 100644 --- a/options.c +++ b/options.c @@ -81,6 +81,7 @@ int am_sender = 0; int am_starting_up = 1; int relative_paths = -1; int implied_dirs = 1; +int missing_args = 0; /* 0 = FERROR_XFER, 1 = ignore, 2 = delete */ int numeric_ids = 0; int msgs2stderr = 0; int allow_8bit_chars = 0; @@ -718,6 +719,8 @@ void usage(enum logcode F) rprintf(F," --delete-delay find deletions during, delete after\n"); rprintf(F," --delete-after receiver deletes after transfer, not during\n"); rprintf(F," --delete-excluded also delete excluded files from destination dirs\n"); + rprintf(F," --ignore-missing-args ignore missing source args without error\n"); + rprintf(F," --delete-missing-args delete missing source args from destination\n"); rprintf(F," --ignore-errors delete even if there are I/O errors\n"); rprintf(F," --force force deletion of directories even if not empty\n"); rprintf(F," --max-delete=NUM don't delete more than NUM files\n"); @@ -908,6 +911,8 @@ static struct poptOption long_options[] = { {"delete-delay", 0, POPT_ARG_VAL, &delete_during, 2, 0, 0 }, {"delete-after", 0, POPT_ARG_NONE, &delete_after, 0, 0, 0 }, {"delete-excluded", 0, POPT_ARG_NONE, &delete_excluded, 0, 0, 0 }, + {"delete-missing-args",0,POPT_BIT_SET, &missing_args, 2, 0, 0 }, + {"ignore-missing-args",0,POPT_BIT_SET, &missing_args, 1, 0, 0 }, {"remove-sent-files",0, POPT_ARG_VAL, &remove_source_files, 2, 0, 0 }, /* deprecated */ {"remove-source-files",0,POPT_ARG_VAL, &remove_source_files, 1, 0, 0 }, {"force", 0, POPT_ARG_VAL, &force_delete, 1, 0, 0 }, @@ -1849,6 +1854,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", @@ -1922,7 +1933,9 @@ int parse_arguments(int *argc_p, const char ***argv_p) return 0; } - if (delete_mode && refused_delete) { + if (missing_args == 3) /* simplify if both options were specified */ + missing_args = 2; + if (refused_delete && (delete_mode || missing_args == 2)) { create_refuse_error(refused_delete); return 0; } @@ -1990,22 +2003,32 @@ int parse_arguments(int *argc_p, const char ***argv_p) return 0; } if (backup_dir) { + 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 < 32) { + if (backup_dir_remainder < 128) { snprintf(err_buf, sizeof err_buf, "the --backup-dir path is WAY too long.\n"); return 0; } - if (backup_dir_buf[backup_dir_len - 1] != '/') { + 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'; } - if (INFO_GTE(BACKUP, 1) && !am_sender) - rprintf(FINFO, "backup_dir is %s\n", backup_dir_buf); + } + 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, @@ -2368,9 +2391,6 @@ void server_options(char **args, int *argc_p) if (protect_args && !local_server) /* unprotected args stop here */ args[ac++] = NULL; - if (do_stats) - args[ac++] = "--stats"; - if (list_only > 1) args[ac++] = "--list-only"; @@ -2472,6 +2492,8 @@ void server_options(char **args, int *argc_p) args[ac++] = "--super"; if (size_only) args[ac++] = "--size-only"; + if (do_stats) + args[ac++] = "--stats"; } else { if (skip_compress) { if (asprintf(&arg, "--skip-compress=%s", skip_compress) < 0) @@ -2480,6 +2502,13 @@ void server_options(char **args, int *argc_p) } } + /* --delete-missing-args needs the cooperation of both sides, but + * the sender can handle --ignore-missing-args by itself. */ + if (missing_args == 2) + args[ac++] = "--delete-missing-args"; + else if (missing_args == 1 && !am_sender) + args[ac++] = "--ignore-missing-args"; + if (modify_window_set) { if (asprintf(&arg, "--modify-window=%d", modify_window) < 0) goto oom; @@ -2626,17 +2655,18 @@ void server_options(char **args, int *argc_p) * (required for parsing) [ and ] chars elided from the returned string. */ static char *parse_hostspec(char *str, char **path_start_ptr, int *port_ptr) { - char *s = str; - char *host_start = str; + char *s, *host_start = str; int hostlen = 0, userlen = 0; char *ret; - for ( ; ; s++) { + for (s = str; ; s++) { if (!*s) { /* It is only OK if we run out of string with rsync:// */ - if (port_ptr) - break; - return NULL; + if (!port_ptr) + return NULL; + if (!hostlen) + hostlen = s - host_start; + break; } if (*s == ':' || *s == '/') { if (!hostlen) @@ -2647,7 +2677,7 @@ static char *parse_hostspec(char *str, char **path_start_ptr, int *port_ptr) } else if (port_ptr) { *port_ptr = atoi(s); while (isDigit(s)) s++; - if (*s++ != '/') + if (*s && *s++ != '/') return NULL; } break;