Annotation of embedaddon/rsync/patches/backup-dir-dels.diff, revision 1.1.1.1

1.1       misho       1: This patches creates two new command line options as follows:
                      2:        --backup-dir-dels=DIR
                      3:        --suffix-dels=SUFFIX
                      4: 
                      5: The backup-dir-dels and suffix-dels options give the ability to store
                      6: backup of removed files on the receiver in different directories or with
                      7: different suffix than the backup of files that have been changed but that
                      8: are still on the source drive.  Both commands can be combined.
                      9: 
                     10: The default behaviour if one or both of the options are not specified
                     11: is the previous behaviour, both backups use the same directory or
                     12: suffix.
                     13: 
                     14: Marc St-Onge
                     15: 
                     16: To use this patch, run these commands for a successful build:
                     17: 
                     18:     patch -p1 <patches/backup-deleted.diff
                     19:     patch -p1 <patches/backup-dir-dels.diff
                     20:     ./configure                                 (optional if already run)
                     21:     make
                     22: 
                     23: based-on: patch/master/backup-deleted
                     24: diff --git a/backup.c b/backup.c
                     25: --- a/backup.c
                     26: +++ b/backup.c
                     27: @@ -29,25 +29,32 @@ extern int preserve_specials;
                     28:  extern int preserve_links;
                     29:  extern int safe_symlinks;
                     30:  extern int backup_dir_len;
                     31: +extern int backup_dir_dels_len;
                     32:  extern unsigned int backup_dir_remainder;
                     33: +extern unsigned int backup_dir_dels_remainder;
                     34:  extern char backup_dir_buf[MAXPATHLEN];
                     35: +extern char backup_dir_dels_buf[MAXPATHLEN];
                     36:  extern char *backup_suffix;
                     37: +extern char *backup_suffix_dels;
                     38:  extern char *backup_dir;
                     39: +extern char *backup_dir_dels;
                     40: +
                     41: +static BOOL deleting;
                     42:  
                     43:  /* Returns -1 on error, 0 on missing dir, and 1 on present dir. */
                     44: -static int validate_backup_dir(void)
                     45: +static int validate_backup_dir(char *buf)
                     46:  {
                     47:        STRUCT_STAT st;
                     48:  
                     49: -      if (do_lstat(backup_dir_buf, &st) < 0) {
                     50: +      if (do_lstat(buf, &st) < 0) {
                     51:                if (errno == ENOENT)
                     52:                        return 0;
                     53: -              rsyserr(FERROR, errno, "backup lstat %s failed", backup_dir_buf);
                     54: +              rsyserr(FERROR, errno, "backup lstat %s failed", buf);
                     55:                return -1;
                     56:        }
                     57:        if (!S_ISDIR(st.st_mode)) {
                     58:                int flags = get_del_for_flag(st.st_mode) | DEL_FOR_BACKUP | DEL_RECURSE;
                     59: -              if (delete_item(backup_dir_buf, st.st_mode, flags) == 0)
                     60: +              if (delete_item(buf, st.st_mode, flags) == 0)
                     61:                        return 0;
                     62:                return -1;
                     63:        }
                     64: @@ -58,20 +65,20 @@ static int validate_backup_dir(void)
                     65:   * backup_dir_buf.  Any new directories (compared to the prior backup
                     66:   * path) are ensured to exist as directories, replacing anything else
                     67:   * that may be in the way (e.g. a symlink). */
                     68: -static BOOL copy_valid_path(const char *fname)
                     69: +static BOOL copy_valid_path(const char *fname, char *buf, int prefix_len, unsigned int remainder, const char *suffix)
                     70:  {
                     71:        const char *f;
                     72:        int val;
                     73:        BOOL ret = True;
                     74:        stat_x sx;
                     75: -      char *b, *rel = backup_dir_buf + backup_dir_len, *name = rel;
                     76: +      char *b, *rel = buf + prefix_len, *name = rel;
                     77:  
                     78:        for (f = fname, b = rel; *f && *f == *b; f++, b++) {
                     79:                if (*b == '/')
                     80:                        name = b + 1;
                     81:        }
                     82:  
                     83: -      if (stringjoin(rel, backup_dir_remainder, fname, backup_suffix, NULL) >= backup_dir_remainder) {
                     84: +      if (stringjoin(rel, remainder, fname, suffix, NULL) >= remainder) {
                     85:                rprintf(FERROR, "backup filename too long\n");
                     86:                *name = '\0';
                     87:                return False;
                     88: @@ -82,7 +89,7 @@ static BOOL copy_valid_path(const char *fname)
                     89:                        return True;
                     90:                *b = '\0';
                     91:  
                     92: -              val = validate_backup_dir();
                     93: +              val = validate_backup_dir(buf);
                     94:                if (val == 0)
                     95:                        break;
                     96:                if (val < 0) {
                     97: @@ -98,9 +105,9 @@ static BOOL copy_valid_path(const char *fname)
                     98:        for ( ; b; name = b + 1, b = strchr(name, '/')) {
                     99:                *b = '\0';
                    100:  
                    101: -              while (do_mkdir(backup_dir_buf, ACCESSPERMS) < 0) {
                    102: +              while (do_mkdir(buf, ACCESSPERMS) < 0) {
                    103:                        if (errno == EEXIST) {
                    104: -                              val = validate_backup_dir();
                    105: +                              val = validate_backup_dir(buf);
                    106:                                if (val > 0)
                    107:                                        break;
                    108:                                if (val == 0)
                    109: @@ -134,7 +141,7 @@ static BOOL copy_valid_path(const char *fname)
                    110:                                free_xattr(&sx);
                    111:                        }
                    112:  #endif
                    113: -                      set_file_attrs(backup_dir_buf, file, NULL, NULL, 0);
                    114: +                      set_file_attrs(buf, file, NULL, NULL, 0);
                    115:                        unmake_file(file);
                    116:                }
                    117:  
                    118: @@ -156,7 +163,12 @@ static BOOL copy_valid_path(const char *fname)
                    119:  /* Make a complete pathname for backup file and verify any new path elements. */
                    120:  char *get_backup_name(const char *fname)
                    121:  {
                    122: +      char *buf = deleting ? backup_dir_dels_buf : backup_dir_buf;
                    123: +      char *suffix = deleting ? backup_suffix_dels : backup_suffix;
                    124: +
                    125:        if (backup_dir) {
                    126: +              int prefix_len = deleting ? backup_dir_dels_len : backup_dir_len;
                    127: +              unsigned int remainder = deleting ? backup_dir_dels_remainder : backup_dir_remainder;
                    128:                static int initialized = 0;
                    129:                if (!initialized) {
                    130:                        int ret;
                    131: @@ -170,14 +182,14 @@ char *get_backup_name(const char *fname)
                    132:                        initialized = 1;
                    133:                }
                    134:                /* copy fname into backup_dir_buf while validating the dirs. */
                    135: -              if (copy_valid_path(fname))
                    136: -                      return backup_dir_buf;
                    137: +              if (copy_valid_path(fname, buf, prefix_len, remainder, suffix))
                    138: +                      return buf;
                    139:                /* copy_valid_path() has printed an error message. */
                    140:                return NULL;
                    141:        }
                    142:  
                    143: -      if (stringjoin(backup_dir_buf, MAXPATHLEN, fname, backup_suffix, NULL) < MAXPATHLEN)
                    144: -              return backup_dir_buf;
                    145: +      if (stringjoin(backup_dir_buf, MAXPATHLEN, fname, suffix, NULL) < MAXPATHLEN)
                    146: +              return buf;
                    147:  
                    148:        rprintf(FERROR, "backup filename too long\n");
                    149:        return NULL;
                    150: @@ -352,3 +364,13 @@ int make_backup(const char *fname, BOOL prefer_rename)
                    151:                rprintf(FINFO, "backed up %s to %s\n", fname, buf);
                    152:        return ret;
                    153:  }
                    154: +
                    155: +/* backup switch routine called only when backing-up removed file */
                    156: +int safe_delete(const char *fname)
                    157: +{
                    158: +      int ret;
                    159: +      deleting = 1;
                    160: +      ret = make_backup(fname, True);
                    161: +      deleting = 0;
                    162: +      return ret;
                    163: +}
                    164: diff --git a/delete.c b/delete.c
                    165: --- a/delete.c
                    166: +++ b/delete.c
                    167: @@ -28,16 +28,23 @@ extern int max_delete;
                    168:  extern char *backup_dir;
                    169:  extern char *backup_suffix;
                    170:  extern int backup_suffix_len;
                    171: +extern char *backup_dir_dels;
                    172: +extern char *backup_suffix_dels;
                    173: +extern int backup_suffix_dels_len;
                    174:  extern struct stats stats;
                    175:  
                    176:  int ignore_perishable = 0;
                    177:  int non_perishable_cnt = 0;
                    178:  int skipped_deletes = 0;
                    179:  
                    180: +/* Function now compares both backup_suffix and backup_suffix_dels. */
                    181:  static inline int is_backup_file(char *fn)
                    182:  {
                    183:        int k = strlen(fn) - backup_suffix_len;
                    184: -      return k > 0 && strcmp(fn+k, backup_suffix) == 0;
                    185: +      if (k > 0 && strcmp(fn+k, backup_suffix) == 0)
                    186: +              return 1;
                    187: +      k += backup_suffix_len - backup_suffix_dels_len;
                    188: +      return k > 0 && strcmp(fn+k, backup_suffix_dels) == 0;
                    189:  }
                    190:  
                    191:  /* The directory is about to be deleted: if DEL_RECURSE is given, delete all
                    192: @@ -162,9 +169,9 @@ enum delret delete_item(char *fbuf, uint16 mode, uint16 flags)
                    193:                what = "rmdir";
                    194:                ok = do_rmdir(fbuf) == 0;
                    195:        } else {
                    196: -              if (make_backups > 0 && !(flags & DEL_FOR_BACKUP) && (backup_dir || !is_backup_file(fbuf))) {
                    197: +              if (make_backups > 0 && !(flags & DEL_FOR_BACKUP) && (backup_dir_dels || !is_backup_file(fbuf))) {
                    198:                        what = "make_backup";
                    199: -                      ok = make_backup(fbuf, True);
                    200: +                      ok = safe_delete(fbuf);
                    201:                        if (ok == 2) {
                    202:                                what = "unlink";
                    203:                                ok = robust_unlink(fbuf) == 0;
                    204: diff --git a/options.c b/options.c
                    205: --- a/options.c
                    206: +++ b/options.c
                    207: @@ -157,10 +157,14 @@ int no_detach
                    208:  int write_batch = 0;
                    209:  int read_batch = 0;
                    210:  int backup_dir_len = 0;
                    211: +int backup_dir_dels_len = 0;
                    212:  int backup_suffix_len;
                    213: +int backup_suffix_dels_len;
                    214:  unsigned int backup_dir_remainder;
                    215: +unsigned int backup_dir_dels_remainder;
                    216:  
                    217:  char *backup_suffix = NULL;
                    218: +char *backup_suffix_dels = NULL;
                    219:  char *tmpdir = NULL;
                    220:  char *partial_dir = NULL;
                    221:  char *basis_dir[MAX_BASIS_DIRS+1];
                    222: @@ -173,7 +177,9 @@ char *password_file = NULL;
                    223:  char *early_input_file = NULL;
                    224:  char *rsync_path = RSYNC_PATH;
                    225:  char *backup_dir = NULL;
                    226: +char *backup_dir_dels = NULL;
                    227:  char backup_dir_buf[MAXPATHLEN];
                    228: +char backup_dir_dels_buf[MAXPATHLEN];
                    229:  char *sockopts = NULL;
                    230:  char *usermap = NULL;
                    231:  char *groupmap = NULL;
                    232: @@ -770,7 +776,9 @@ static struct poptOption long_options[] = {
                    233:    {"backup-deleted",   0,  POPT_ARG_VAL,    &make_backups, 1, 0, 0 },
                    234:    {"no-backup",        0,  POPT_ARG_VAL,    &make_backups, 0, 0, 0 },
                    235:    {"backup-dir",       0,  POPT_ARG_STRING, &backup_dir, 0, 0, 0 },
                    236: +  {"backup-dir-dels",  0,  POPT_ARG_STRING, &backup_dir_dels, 0, 0, 0 },
                    237:    {"suffix",           0,  POPT_ARG_STRING, &backup_suffix, 0, 0, 0 },
                    238: +  {"suffix-dels",      0,  POPT_ARG_STRING, &backup_suffix_dels, 0, 0, 0 },
                    239:    {"list-only",        0,  POPT_ARG_VAL,    &list_only, 2, 0, 0 },
                    240:    {"read-batch",       0,  POPT_ARG_STRING, &batch_name, OPT_READ_BATCH, 0, 0 },
                    241:    {"write-batch",      0,  POPT_ARG_STRING, &batch_name, OPT_WRITE_BATCH, 0, 0 },
                    242: @@ -2187,6 +2195,8 @@ int parse_arguments(int *argc_p, const char ***argv_p)
                    243:                        tmpdir = sanitize_path(NULL, tmpdir, NULL, 0, SP_DEFAULT);
                    244:                if (backup_dir)
                    245:                        backup_dir = sanitize_path(NULL, backup_dir, NULL, 0, SP_DEFAULT);
                    246: +              if (backup_dir_dels)
                    247: +                      backup_dir_dels = sanitize_path(NULL, backup_dir_dels, NULL, 0, SP_DEFAULT);
                    248:        }
                    249:        if (daemon_filter_list.head && !am_sender) {
                    250:                filter_rule_list *elp = &daemon_filter_list;
                    251: @@ -2208,6 +2218,14 @@ int parse_arguments(int *argc_p, const char ***argv_p)
                    252:                        if (check_filter(elp, FLOG, dir, 1) < 0)
                    253:                                goto options_rejected;
                    254:                }
                    255: +              /* Clean backup_dir_dels same as for backup_dir */
                    256: +              if (backup_dir_dels) {
                    257: +                      if (!*backup_dir_dels)
                    258: +                              goto options_rejected;
                    259: +                      clean_fname(backup_dir_dels, 1);
                    260: +                      if (check_filter(elp, FLOG, backup_dir_dels, 1) < 0)
                    261: +                              goto options_rejected;
                    262: +              }
                    263:        }
                    264:  
                    265:        if (!backup_suffix)
                    266: @@ -2219,6 +2237,20 @@ int parse_arguments(int *argc_p, const char ***argv_p)
                    267:                        backup_suffix);
                    268:                return 0;
                    269:        }
                    270: +      /* --suffix-dels defaults to --suffix, or empty for a client given an
                    271: +       * explicit --backup-dir-dels (just as --suffix defaults to empty when
                    272: +       * a --backup-dir is given).  The second case does not apply to the
                    273: +       * server for consistency with server_options, which sends --suffix-dels
                    274: +       * to the server iff it differs from --suffix. */
                    275: +      if (!backup_suffix_dels)
                    276: +              backup_suffix_dels = backup_dir_dels && !am_server ? "" : backup_suffix;
                    277: +      backup_suffix_dels_len = strlen(backup_suffix_dels);
                    278: +      if (strchr(backup_suffix_dels, '/') != NULL) {
                    279: +              snprintf(err_buf, sizeof err_buf,
                    280: +                      "--suffix-dels cannot contain slashes: %s\n",
                    281: +                      backup_suffix_dels);
                    282: +              return 0;
                    283: +      }
                    284:        if (backup_dir) {
                    285:                size_t len;
                    286:                make_backups = 1; /* --backup-dir implies --backup */
                    287: @@ -2255,6 +2287,34 @@ int parse_arguments(int *argc_p, const char ***argv_p)
                    288:                        "P *%s", backup_suffix);
                    289:                parse_filter_str(&filter_list, backup_dir_buf, rule_template(0), 0);
                    290:        }
                    291: +      if (backup_dir_dels) {
                    292: +              backup_dir_dels_len = strlcpy(backup_dir_dels_buf, backup_dir_dels, sizeof backup_dir_dels_buf);
                    293: +              backup_dir_dels_remainder = sizeof backup_dir_dels_buf - backup_dir_dels_len;
                    294: +              if (backup_dir_dels_remainder < 32) {
                    295: +                      snprintf(err_buf, sizeof err_buf,
                    296: +                              "the --backup-dir-dels path is WAY too long.\n");
                    297: +                      return 0;
                    298: +              }
                    299: +              if (backup_dir_dels_buf[backup_dir_dels_len - 1] != '/') {
                    300: +                      backup_dir_dels_buf[backup_dir_dels_len++] = '/';
                    301: +                      backup_dir_dels_buf[backup_dir_dels_len] = '\0';
                    302: +              }
                    303: +              if (INFO_GTE(BACKUP, 1) && !am_sender)
                    304: +                      rprintf(FINFO, "backup_dir_dels is %s\n", backup_dir_dels_buf);
                    305: +      } else if (backup_dir) {
                    306: +              backup_dir_dels = backup_dir;
                    307: +              backup_dir_dels_len = backup_dir_len;
                    308: +              backup_dir_dels_remainder = backup_dir_remainder;
                    309: +              strlcpy(backup_dir_dels_buf, backup_dir_buf, sizeof backup_dir_buf);
                    310: +      } else if (!backup_suffix_dels_len && (!am_server || !am_sender)) {
                    311: +              snprintf(err_buf, sizeof err_buf,
                    312: +                      "--suffix-dels cannot be a null string without --backup-dir-dels\n");
                    313: +              return 0;
                    314: +      } else if (make_backups && delete_mode && !delete_excluded && !am_server) {
                    315: +              snprintf(backup_dir_dels_buf, sizeof backup_dir_dels_buf,
                    316: +                      "P *%s", backup_suffix_dels);
                    317: +              parse_filter_str(&filter_list, backup_dir_dels_buf, rule_template(0), 0);
                    318: +      }
                    319:  
                    320:        if (preserve_times) {
                    321:                preserve_times = PRESERVE_FILE_TIMES;
                    322: @@ -2701,6 +2761,10 @@ void server_options(char **args, int *argc_p)
                    323:                args[ac++] = "--backup-dir";
                    324:                args[ac++] = backup_dir;
                    325:        }
                    326: +      if (backup_dir_dels && backup_dir_dels != backup_dir) {
                    327: +              args[ac++] = "--backup-dir-dels";
                    328: +              args[ac++] = backup_dir_dels;
                    329: +      }
                    330:  
                    331:        /* Only send --suffix if it specifies a non-default value. */
                    332:        if (strcmp(backup_suffix, backup_dir ? "" : BACKUP_SUFFIX) != 0) {
                    333: @@ -2709,6 +2773,14 @@ void server_options(char **args, int *argc_p)
                    334:                        goto oom;
                    335:                args[ac++] = arg;
                    336:        }
                    337: +      /* Only send --suffix-dels if it specifies a value different from the
                    338: +       * --suffix value, which would normally be used for deletions too. */
                    339: +      if (strcmp(backup_suffix_dels, backup_suffix) != 0) {
                    340: +              /* We use the following syntax to avoid weirdness with '~'. */
                    341: +              if (asprintf(&arg, "--suffix-dels=%s", backup_suffix_dels) < 0)
                    342: +                      goto oom;
                    343: +              args[ac++] = arg;
                    344: +      }
                    345:  
                    346:        if (checksum_choice) {
                    347:                if (asprintf(&arg, "--checksum-choice=%s", checksum_choice) < 0)
                    348: diff --git a/rsync.1.md b/rsync.1.md
                    349: --- a/rsync.1.md
                    350: +++ b/rsync.1.md
                    351: @@ -346,7 +346,9 @@ detailed description below for a complete description.
                    352:  --backup, -b             make backups (see --suffix & --backup-dir)
                    353:  --backup-deleted         make backups only of deleted files
                    354:  --backup-dir=DIR         make backups into hierarchy based in DIR
                    355: +--backup-dir-dels=DIR    backup removed files into hierarchy based in DIR
                    356:  --suffix=SUFFIX          backup suffix (default ~ w/o --backup-dir)
                    357: +--suffix-dels=SUFFIX     set removed-files suffix (def. --suffix w/o b-d-d)
                    358:  --update, -u             skip files that are newer on the receiver
                    359:  --inplace                update destination files in-place
                    360:  --append                 append data onto shorter files
                    361: diff -Nurp a/rsync.1 b/rsync.1
                    362: --- a/rsync.1
                    363: +++ b/rsync.1
                    364: @@ -422,7 +422,9 @@ detailed description below for a complet
                    365:  --backup, -b             make backups (see --suffix & --backup-dir)
                    366:  --backup-deleted         make backups only of deleted files
                    367:  --backup-dir=DIR         make backups into hierarchy based in DIR
                    368: +--backup-dir-dels=DIR    backup removed files into hierarchy based in DIR
                    369:  --suffix=SUFFIX          backup suffix (default ~ w/o --backup-dir)
                    370: +--suffix-dels=SUFFIX     set removed-files suffix (def. --suffix w/o b-d-d)
                    371:  --update, -u             skip files that are newer on the receiver
                    372:  --inplace                update destination files in-place
                    373:  --append                 append data onto shorter files
                    374: diff -Nurp a/rsync.1.html b/rsync.1.html
                    375: --- a/rsync.1.html
                    376: +++ b/rsync.1.html
                    377: @@ -337,7 +337,9 @@ detailed description below for a complet
                    378:  --backup, -b             make backups (see --suffix &amp; --backup-dir)
                    379:  --backup-deleted         make backups only of deleted files
                    380:  --backup-dir=DIR         make backups into hierarchy based in DIR
                    381: +--backup-dir-dels=DIR    backup removed files into hierarchy based in DIR
                    382:  --suffix=SUFFIX          backup suffix (default ~ w/o --backup-dir)
                    383: +--suffix-dels=SUFFIX     set removed-files suffix (def. --suffix w/o b-d-d)
                    384:  --update, -u             skip files that are newer on the receiver
                    385:  --inplace                update destination files in-place
                    386:  --append                 append data onto shorter files

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>