--- generator.c.orig 2011-03-26 11:17:14.000000000 -0600 +++ generator.c 2011-08-23 23:28:30.000000000 -0600 @@ -54,6 +54,7 @@ extern int delay_updates; extern int update_only; extern int ignore_existing; +extern int rename_existing; extern int ignore_non_existing; extern int inplace; extern int append_mode; @@ -1442,6 +1443,105 @@ goto cleanup; } + /* --rename-existing */ + /* If rename is not possible, revert to --ignore-existing behavior */ + if (rename_existing > 0 && statret == 0 && S_ISREG(sx.st.st_mode) + && (!is_dir || !S_ISDIR(sx.st.st_mode))) { + char *new_fname, *base_fname, *ext, *p, *q; + STRUCT_STAT st; + char uniq[32]; + int count, renamed, len, ret; + + if (verbose > 2) + rprintf(FINFO, "starting rename-existing processing for fname %s\n", fname); + + /* get base_fname and ext */ + base_fname = malloc(strlen(fname) + 1); + if (base_fname == NULL) { + rsyserr(FERROR, errno, "base_fname malloc failed"); + goto cleanup; + } + ext = strrchr(fname, '.'); + p = fname; + q = base_fname; + while (p != ext && *p != '\0') { + *q++ = *p++; + } + *q = '\0'; + + if (verbose > 2) + rprintf(FINFO, "base_fname is %s, ext is %s, fname is %s\n", base_fname, ext, fname); + + /* get seed uniq value in hex */ + snprintf(uniq, sizeof uniq, "_%x", (int)time(NULL)); + + /* alloc new filename mem, +2 for count_str */ + len = strlen(fname) + strlen(uniq) + 2; + if (len > MAXPATHLEN) { + rprintf(FERROR, "error new_fname is larger than MAXPATHLEN\n"); + free(base_fname); + goto cleanup; + } + len = len + 1; /* \0 */ + new_fname = malloc(len); + if (new_fname == NULL) { + rsyserr(FERROR, errno, "new_fname malloc failed"); + free(base_fname); + goto cleanup; + } + + count = 0; + renamed = 0; + while (renamed != 1 && count <= 255) { + /* build new filename */ + snprintf(new_fname, len, "%s%s%x%s", base_fname, uniq, count, ext ? ext : ""); + + if (verbose > 2) + rprintf(FINFO, "attempting to use new_fname of %s\n", new_fname); + + /* attempt to move the file */ + ret = link_stat(new_fname, &st, 0); + if (ret != 0 && errno == ENOENT) { + if (verbose > 2) + rprintf(FINFO, "new_fname %s does not exist\n", new_fname); + if (do_rename(fname, new_fname) == 0) { + if (verbose > 2) + rprintf(FINFO, "do_rename from %s to %s succeeded\n", fname, new_fname); + renamed = 1; + break; + } else { + rprintf(FERROR, "do_rename from %s to %s failed\n", fname, new_fname); + } + } else { + if (ret == 0) { + if (verbose > 2) + rprintf(FINFO, "new_fname %s exists\n", new_fname); + } else { + rsyserr(FERROR, errno, "link_stat new_fname failed"); + } + } + count++; + } + + if (renamed == 1) { + if (verbose > 2) { + rprintf(FINFO, "rename-existing on receiver success (%s renamed to %s)\n", fname, new_fname); + } else { + rprintf(FLOG, "rename-existing on receiver success (%s renamed to %s)\n", fname, new_fname); + } + } else { + rprintf(FERROR, "rename-existing on receiver did not succeed for %s, skipping\n", fname); + goto cleanup; + } + + free(base_fname); + free(new_fname); + + /* Redo statret, since the file has moved */ + statret = link_stat(fname, &sx.st, keep_dirlinks && is_dir); + stat_errno = errno; + } + fnamecmp = fname; if (is_dir) { --- options.c.orig 2011-08-06 22:01:22.000000000 -0600 +++ options.c 2011-08-23 18:05:01.000000000 -0600 @@ -109,6 +109,7 @@ int fuzzy_basis = 0; size_t bwlimit_writemax = 0; int ignore_existing = 0; +int rename_existing = 0; int ignore_non_existing = 0; int need_messages_from_generator = 0; int max_delete = INT_MIN; @@ -365,6 +366,7 @@ rprintf(F," --rsync-path=PROGRAM specify the rsync to run on the remote machine\n"); rprintf(F," --existing skip creating new files on receiver\n"); rprintf(F," --ignore-existing skip updating files that already exist on receiver\n"); + rprintf(F," --rename-existing rename files on receiver that already exist on receiver\n"); rprintf(F," --remove-source-files sender removes synchronized files (non-dirs)\n"); rprintf(F," --del an alias for --delete-during\n"); rprintf(F," --delete delete extraneous files from destination dirs\n"); @@ -536,6 +538,7 @@ {"existing", 0, POPT_ARG_NONE, &ignore_non_existing, 0, 0, 0 }, {"ignore-non-existing",0,POPT_ARG_NONE, &ignore_non_existing, 0, 0, 0 }, {"ignore-existing", 0, POPT_ARG_NONE, &ignore_existing, 0, 0, 0 }, + {"rename-existing", 0, POPT_ARG_NONE, &rename_existing, 0, 0, 0 }, {"max-size", 0, POPT_ARG_STRING, &max_size_arg, OPT_MAX_SIZE, 0, 0 }, {"min-size", 0, POPT_ARG_STRING, &min_size_arg, OPT_MIN_SIZE, 0, 0 }, {"sparse", 'S', POPT_ARG_VAL, &sparse_files, 1, 0, 0 }, @@ -2021,6 +2024,9 @@ if (ignore_existing) args[ac++] = "--ignore-existing"; + if (rename_existing) + args[ac++] = "--rename-existing"; + /* Backward compatibility: send --existing, not --ignore-non-existing. */ if (ignore_non_existing) args[ac++] = "--existing";