Making backup-dir-dels depend on backup-deleted.
[rsync-patches.git] / backup-dir-dels.diff
index e67ba210e1bcde61949b7fb3627f9eba88f6c713..3ee80a55d33b53d39533783def2da6a7eda9ce8a 100644 (file)
@@ -15,15 +15,16 @@ Marc St-Onge
 
 To use this patch, run these commands for a successful build:
 
+    patch -p1 <patches/backup-deleted.diff
     patch -p1 <patches/backup-dir-dels.diff
     ./configure                                 (optional if already run)
     make
 
-based-on: a01e3b490eb36ccf9e704840e1b6683dab867550
+based-on: patch/master/backup-deleted
 diff --git a/backup.c b/backup.c
 --- a/backup.c
 +++ b/backup.c
-@@ -29,29 +29,36 @@ extern int preserve_specials;
+@@ -29,25 +29,32 @@ extern int preserve_specials;
  extern int preserve_links;
  extern int safe_symlinks;
  extern int backup_dir_len;
@@ -39,7 +40,28 @@ diff --git a/backup.c b/backup.c
 +
 +static BOOL deleting;
  
- /* Create a backup path from the given fname, putting the result into
+ /* Returns -1 on error, 0 on missing dir, and 1 on present dir. */
+-static int validate_backup_dir(void)
++static int validate_backup_dir(const char *buf)
+ {
+       STRUCT_STAT st;
+-      if (do_lstat(backup_dir_buf, &st) < 0) {
++      if (do_lstat(buf, &st) < 0) {
+               if (errno == ENOENT)
+                       return 0;
+-              rsyserr(FERROR, errno, "backup lstat %s failed", backup_dir_buf);
++              rsyserr(FERROR, errno, "backup lstat %s failed", buf);
+               return -1;
+       }
+       if (!S_ISDIR(st.st_mode)) {
+               int flags = get_del_for_flag(st.st_mode) | DEL_FOR_BACKUP | DEL_RECURSE;
+-              if (delete_item(backup_dir_buf, st.st_mode, flags) == 0)
++              if (delete_item(buf, st.st_mode, flags) == 0)
+                       return 0;
+               return -1;
+       }
+@@ -58,20 +65,20 @@ static int validate_backup_dir(void)
   * backup_dir_buf.  Any new directories (compared to the prior backup
   * path) are ensured to exist as directories, replacing anything else
   * that may be in the way (e.g. a symlink). */
@@ -47,7 +69,7 @@ diff --git a/backup.c b/backup.c
 +static BOOL copy_valid_path(const char *fname, char *buf, int prefix_len, unsigned int remainder, const char *suffix)
  {
        const char *f;
-       int flags;
+       int val;
        BOOL ret = True;
        stat_x sx;
 -      char *b, *rel = backup_dir_buf + backup_dir_len, *name = rel;
@@ -63,38 +85,28 @@ diff --git a/backup.c b/backup.c
                rprintf(FERROR, "backup filename too long\n");
                *name = '\0';
                return False;
-@@ -62,16 +69,16 @@ static BOOL copy_valid_path(const char *fname)
+@@ -82,7 +89,7 @@ static BOOL copy_valid_path(const char *fname)
                        return True;
                *b = '\0';
  
--              if (do_lstat(backup_dir_buf, &sx.st) < 0) {
-+              if (do_lstat(buf, &sx.st) < 0) {
-                       if (errno == ENOENT)
-                               break;
--                      rsyserr(FERROR, errno, "backup lstat %s failed", backup_dir_buf);
-+                      rsyserr(FERROR, errno, "backup lstat %s failed", buf);
-                       *name = '\0';
-                       return False;
-               }
-               if (!S_ISDIR(sx.st.st_mode)) {
-                       flags = get_del_for_flag(sx.st.st_mode) | DEL_FOR_BACKUP | DEL_RECURSE;
--                      if (delete_item(backup_dir_buf, sx.st.st_mode, flags) == 0)
-+                      if (delete_item(buf, sx.st.st_mode, flags) == 0)
-                               break;
-                       *name = '\0';
-                       return False;
-@@ -85,8 +92,8 @@ static BOOL copy_valid_path(const char *fname)
+-              val = validate_backup_dir();
++              val = validate_backup_dir(buf);
+               if (val == 0)
+                       break;
+               if (val < 0) {
+@@ -98,9 +105,9 @@ static BOOL copy_valid_path(const char *fname)
        for ( ; b; name = b + 1, b = strchr(name, '/')) {
                *b = '\0';
  
--              if (mkdir_defmode(backup_dir_buf) < 0) {
--                      rsyserr(FERROR, errno, "backup mkdir %s failed", backup_dir_buf);
-+              if (mkdir_defmode(buf) < 0) {
-+                      rsyserr(FERROR, errno, "backup mkdir %s failed", buf);
-                       *name = '\0';
-                       ret = False;
-                       break;
-@@ -114,7 +121,7 @@ static BOOL copy_valid_path(const char *fname)
+-              while (do_mkdir(backup_dir_buf, ACCESSPERMS) < 0) {
++              while (do_mkdir(buf, ACCESSPERMS) < 0) {
+                       if (errno == EEXIST) {
+-                              val = validate_backup_dir();
++                              val = validate_backup_dir(buf);
+                               if (val > 0)
+                                       break;
+                               if (val == 0)
+@@ -134,7 +141,7 @@ static BOOL copy_valid_path(const char *fname)
                                free_xattr(&sx);
                        }
  #endif
@@ -103,7 +115,7 @@ diff --git a/backup.c b/backup.c
                        unmake_file(file);
                }
  
-@@ -134,15 +141,20 @@ static BOOL copy_valid_path(const char *fname)
+@@ -156,16 +163,21 @@ static BOOL copy_valid_path(const char *fname)
  /* Make a complete pathname for backup file and verify any new path elements. */
  char *get_backup_name(const char *fname)
  {
@@ -118,17 +130,18 @@ diff --git a/backup.c b/backup.c
 -                      return backup_dir_buf;
 +              if (copy_valid_path(fname, buf, prefix_len, remainder, suffix))
 +                      return buf;
+               /* copy_valid_path() has printed an error message. */
                return NULL;
-       } else {
-               if (stringjoin(backup_dir_buf, MAXPATHLEN,
--                             fname, backup_suffix, NULL) < MAXPATHLEN)
--                      return backup_dir_buf;
-+                             fname, suffix, NULL) < MAXPATHLEN)
-+                      return buf;
        }
  
+-      if (stringjoin(backup_dir_buf, MAXPATHLEN, fname, backup_suffix, NULL) < MAXPATHLEN)
+-              return backup_dir_buf;
++      if (stringjoin(backup_dir_buf, MAXPATHLEN, fname, suffix, NULL) < MAXPATHLEN)
++              return buf;
        rprintf(FERROR, "backup filename too long\n");
-@@ -317,3 +329,13 @@ int make_backup(const char *fname, BOOL prefer_rename)
+       return NULL;
+@@ -339,3 +351,13 @@ int make_backup(const char *fname, BOOL prefer_rename)
                rprintf(FINFO, "backed up %s to %s\n", fname, buf);
        return ret;
  }
@@ -145,17 +158,16 @@ diff --git a/backup.c b/backup.c
 diff --git a/delete.c b/delete.c
 --- a/delete.c
 +++ b/delete.c
-@@ -28,6 +28,9 @@ extern int max_delete;
+@@ -28,16 +28,23 @@ extern int max_delete;
  extern char *backup_dir;
  extern char *backup_suffix;
  extern int backup_suffix_len;
 +extern char *backup_dir_dels;
 +extern char *backup_suffix_dels;
 +extern int backup_suffix_dels_len;
- extern uid_t our_uid;
  extern struct stats stats;
  
-@@ -35,10 +38,14 @@ int ignore_perishable = 0;
+ int ignore_perishable = 0;
  int non_perishable_cnt = 0;
  int skipped_deletes = 0;
  
@@ -171,7 +183,7 @@ diff --git a/delete.c b/delete.c
  }
  
  /* The directory is about to be deleted: if DEL_RECURSE is given, delete all
-@@ -170,9 +177,9 @@ enum delret delete_item(char *fbuf, uint16 mode, uint16 flags)
+@@ -162,9 +169,9 @@ enum delret delete_item(char *fbuf, uint16 mode, uint16 flags)
                what = "rmdir";
                ok = do_rmdir(fbuf) == 0;
        } else {
@@ -186,7 +198,7 @@ diff --git a/delete.c b/delete.c
 diff --git a/options.c b/options.c
 --- a/options.c
 +++ b/options.c
-@@ -151,10 +151,14 @@ int no_detach
+@@ -152,10 +152,14 @@ int no_detach
  int write_batch = 0;
  int read_batch = 0;
  int backup_dir_len = 0;
@@ -201,7 +213,7 @@ diff --git a/options.c b/options.c
  char *tmpdir = NULL;
  char *partial_dir = NULL;
  char *basis_dir[MAX_BASIS_DIRS+1];
-@@ -166,7 +170,9 @@ char *stdout_format = NULL;
+@@ -167,7 +171,9 @@ char *stdout_format = NULL;
  char *password_file = NULL;
  char *rsync_path = RSYNC_PATH;
  char *backup_dir = NULL;
@@ -211,8 +223,8 @@ diff --git a/options.c b/options.c
  char *sockopts = NULL;
  char *usermap = NULL;
  char *groupmap = NULL;
-@@ -670,6 +676,8 @@ void usage(enum logcode F)
-   rprintf(F," -b, --backup                make backups (see --suffix & --backup-dir)\n");
+@@ -677,6 +683,8 @@ void usage(enum logcode F)
+   rprintf(F,"     --backup-deleted        make backups only of deleted files\n");
    rprintf(F,"     --backup-dir=DIR        make backups into hierarchy based in DIR\n");
    rprintf(F,"     --suffix=SUFFIX         set backup suffix (default %s w/o --backup-dir)\n",BACKUP_SUFFIX);
 +  rprintf(F,"     --backup-dir-dels=DIR   backup removed files into hierarchy based in DIR\n");
@@ -220,8 +232,8 @@ diff --git a/options.c b/options.c
    rprintf(F," -u, --update                skip files that are newer on the receiver\n");
    rprintf(F,"     --inplace               update destination files in-place (SEE MAN PAGE)\n");
    rprintf(F,"     --append                append data onto shorter files\n");
-@@ -969,7 +977,9 @@ static struct poptOption long_options[] = {
-   {"backup",          'b', POPT_ARG_VAL,    &make_backups, 1, 0, 0 },
+@@ -987,7 +995,9 @@ static struct poptOption long_options[] = {
+   {"backup-deleted",   0,  POPT_ARG_VAL,    &make_backups, 1, 0, 0 },
    {"no-backup",        0,  POPT_ARG_VAL,    &make_backups, 0, 0, 0 },
    {"backup-dir",       0,  POPT_ARG_STRING, &backup_dir, 0, 0, 0 },
 +  {"backup-dir-dels",  0,  POPT_ARG_STRING, &backup_dir_dels, 0, 0, 0 },
@@ -230,7 +242,7 @@ diff --git a/options.c b/options.c
    {"list-only",        0,  POPT_ARG_VAL,    &list_only, 2, 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 },
-@@ -2006,6 +2016,8 @@ int parse_arguments(int *argc_p, const char ***argv_p)
+@@ -2024,6 +2034,8 @@ int parse_arguments(int *argc_p, const char ***argv_p)
                        tmpdir = sanitize_path(NULL, tmpdir, NULL, 0, SP_DEFAULT);
                if (backup_dir)
                        backup_dir = sanitize_path(NULL, backup_dir, NULL, 0, SP_DEFAULT);
@@ -239,7 +251,7 @@ diff --git a/options.c b/options.c
        }
        if (daemon_filter_list.head && !am_sender) {
                filter_rule_list *elp = &daemon_filter_list;
-@@ -2027,6 +2039,14 @@ int parse_arguments(int *argc_p, const char ***argv_p)
+@@ -2045,6 +2057,14 @@ int parse_arguments(int *argc_p, const char ***argv_p)
                        if (check_filter(elp, FLOG, dir, 1) < 0)
                                goto options_rejected;
                }
@@ -254,7 +266,7 @@ diff --git a/options.c b/options.c
        }
  
        if (!backup_suffix)
-@@ -2038,6 +2058,20 @@ int parse_arguments(int *argc_p, const char ***argv_p)
+@@ -2056,6 +2076,20 @@ int parse_arguments(int *argc_p, const char ***argv_p)
                        backup_suffix);
                return 0;
        }
@@ -273,9 +285,9 @@ diff --git a/options.c b/options.c
 +              return 0;
 +      }
        if (backup_dir) {
+               size_t len;
                while (*backup_dir == '.' && backup_dir[1] == '/')
-                       backup_dir += 2;
-@@ -2071,6 +2105,34 @@ int parse_arguments(int *argc_p, const char ***argv_p)
+@@ -2091,6 +2125,34 @@ int parse_arguments(int *argc_p, const char ***argv_p)
                        "P *%s", backup_suffix);
                parse_filter_str(&filter_list, backup_dir_buf, rule_template(0), 0);
        }
@@ -308,9 +320,9 @@ diff --git a/options.c b/options.c
 +              parse_rule(&filter_list, backup_dir_dels_buf, 0, 0);
 +      }
  
-       if (make_backups && !backup_dir) {
-               omit_dir_times = 0; /* Implied, so avoid -O to sender. */
-@@ -2484,6 +2546,10 @@ void server_options(char **args, int *argc_p)
+       if (preserve_times) {
+               preserve_times = PRESERVE_FILE_TIMES;
+@@ -2512,6 +2574,10 @@ void server_options(char **args, int *argc_p)
                args[ac++] = "--backup-dir";
                args[ac++] = backup_dir;
        }
@@ -321,7 +333,7 @@ diff --git a/options.c b/options.c
  
        /* Only send --suffix if it specifies a non-default value. */
        if (strcmp(backup_suffix, backup_dir ? "" : BACKUP_SUFFIX) != 0) {
-@@ -2492,7 +2558,14 @@ void server_options(char **args, int *argc_p)
+@@ -2520,7 +2586,14 @@ void server_options(char **args, int *argc_p)
                        goto oom;
                args[ac++] = arg;
        }
@@ -335,5 +347,5 @@ diff --git a/options.c b/options.c
 +              args[ac++] = arg;
 +      }
        if (am_sender) {
-               if (max_delete > 0) {
-                       if (asprintf(&arg, "--max-delete=%d", max_delete) < 0)
+               /* A remote sender just needs the above -b option.
+                * A remote receiver will override that with this option. */