From 66203a982b3d249bafda9b9272c4c103c19e4a9b Mon Sep 17 00:00:00 2001 From: Andrew Tridgell Date: Mon, 24 Jan 2000 04:58:53 +0000 Subject: [PATCH] added --backup-dir option from Bob Edwards this is very useful for incremental backups --- backup.c | 135 ++++++++++++++++++++++++++++++++++++++++++++++++++++- flist.c | 5 +- options.c | 19 +++++++- receiver.c | 4 +- rsync.c | 3 -- rsync.yo | 5 ++ 6 files changed, 163 insertions(+), 8 deletions(-) diff --git a/backup.c b/backup.c index 54d5fae8..24f8523a 100644 --- a/backup.c +++ b/backup.c @@ -22,9 +22,11 @@ extern int verbose; extern char *backup_suffix; +extern char *backup_dir; -int make_backup(char *fname) +/* simple backup creates a backup with a suffix in the same directory */ +static int make_simple_backup(char *fname) { char fnamebak[MAXPATHLEN]; if (strlen(fname) + strlen(backup_suffix) > (MAXPATHLEN-1)) { @@ -44,3 +46,134 @@ int make_backup(char *fname) } return 1; } + + +/* recursively make a directory path */ +static int make_dir(char *name, int mask) +{ + char newdir [MAXPATHLEN]; + char *p, *d; + + /* copy pathname over, look for last '/' */ + for (p = d = newdir; *name; *d++ = *name++) + if (*name == '/') + p = d; + if (p == newdir) + return 0; + *p = 0; + + /* make the new directory, if that fails then make its parent */ + while (do_mkdir (newdir, mask) != 0) + if ((errno != ENOENT) || !make_dir (newdir, mask)) + return 0; + + return 1; +} /* make_dir */ + + +/* robustly move a file, creating new directory structures if necessary */ +static int robust_move(char *src, char *dst) +{ + int keep_trying = 4; + int keep_path_extfs = 0; + int failed; + + while (keep_trying) { + if (keep_path_extfs) + failed = copy_file (src, dst, 0755); + else + failed = robust_rename (src, dst); + + if (failed) { + if (verbose > 2) + rprintf (FERROR, "robust_move failed: %s(%d)\n", + strerror (errno), errno); + switch (errno) { + /* external filesystem */ + case EXDEV: + keep_path_extfs = 1; + keep_trying--; + break; + /* no directory to write to */ + case ENOENT: + make_dir (dst, 0755); + keep_trying--; + break; + default: + keep_trying = 0; + } /* switch */ + } else + keep_trying = 0; + } /* while */ + return (!failed); +} /* robust_move */ + + +/* if we have a backup_dir, then we get here from make_backup(). + We will move the file to be deleted into a parallel directory tree */ +static int keep_backup(char *fname) +{ + static int initialised; + + char keep_name [MAXPATHLEN]; + STRUCT_STAT st; + struct file_struct *file; + + if (!initialised) { + if (backup_dir[strlen(backup_dir) - 1] == '/') + backup_dir[strlen(backup_dir) - 1] = 0; + if (verbose > 0) + rprintf (FINFO, "backup_dir is %s\n", backup_dir); + initialised = 1; + } + + /* return if no file to keep */ +#if SUPPORT_LINKS + if (do_lstat (fname, &st)) return 1; +#else + if (do_stat (fname, &st)) return 1; +#endif + + file = make_file (0, fname); + + /* make a complete pathname for backup file */ + if (strlen(backup_dir) + strlen(fname) > (MAXPATHLEN - 1)) { + rprintf (FERROR, "keep_backup filename too long\n"); + return 0; + } + slprintf(keep_name, sizeof (keep_name), "%s/%s", backup_dir, fname); + + if (!S_ISDIR(file->mode)) { + /* move to keep tree if a file */ + if (!robust_move (fname, keep_name)) + rprintf(FERROR, "keep_backup failed %s -> %s : %s\n", + fname, keep_name, strerror(errno)); + } else { + /* this bit only used to "keep" empty directories */ + /* make the parent directories */ + make_dir (keep_name, 0755); + /* now make the (empty) directory */ + do_mkdir (keep_name, file->mode); + if (verbose > 1) + rprintf (FINFO, "keep_backup: made empty dir: %s\n", + keep_name); + } + + set_perms (keep_name, file, NULL, 0); + free_file (file); + free (file); + if (verbose > 1) + rprintf (FINFO, "keep_backup %s -> %s\n", fname, keep_name); + return 1; +} /* keep_backup */ + + +/* main backup switch routine */ +int make_backup(char *fname) +{ + if (backup_dir) + return (keep_backup(fname)); + else + return (make_simple_backup(fname)); +} + diff --git a/flist.c b/flist.c index a653f14a..14fa5a3f 100644 --- a/flist.c +++ b/flist.c @@ -409,7 +409,8 @@ static int skip_filesystem(char *fname, STRUCT_STAT *st) return (st2.st_dev != filesystem_dev); } -static struct file_struct *make_file(int f, char *fname) +/* create a file_struct for a named file */ +struct file_struct *make_file(int f, char *fname) { struct file_struct *file; STRUCT_STAT st; @@ -921,7 +922,7 @@ int flist_find(struct file_list *flist,struct file_struct *f) /* * free up one file */ -static void free_file(struct file_struct *file) +void free_file(struct file_struct *file) { if (!file) return; if (file->basename) free(file->basename); diff --git a/options.c b/options.c index 8a3f7b71..642a9f28 100644 --- a/options.c +++ b/options.c @@ -74,6 +74,7 @@ char *shell_cmd = NULL; char *log_format = NULL; char *password_file = NULL; char *rsync_path = RSYNC_NAME; +char *backup_dir = NULL; int rsync_port = RSYNC_PORT; int verbose = 0; @@ -107,6 +108,7 @@ void usage(int F) rprintf(F," -r, --recursive recurse into directories\n"); rprintf(F," -R, --relative use relative path names\n"); rprintf(F," -b, --backup make backups (default %s suffix)\n",BACKUP_SUFFIX); + rprintf(F," --backup-dir make backups into this directory"); rprintf(F," --suffix=SUFFIX override backup suffix\n"); rprintf(F," -u, --update update only (don't overwrite newer files)\n"); rprintf(F," -l, --links preserve soft links\n"); @@ -169,7 +171,7 @@ enum {OPT_VERSION, OPT_SUFFIX, OPT_SENDER, OPT_SERVER, OPT_EXCLUDE, OPT_INCLUDE, OPT_INCLUDE_FROM, OPT_STATS, OPT_PARTIAL, OPT_PROGRESS, OPT_COPY_UNSAFE_LINKS, OPT_SAFE_LINKS, OPT_COMPARE_DEST, OPT_LOG_FORMAT, OPT_PASSWORD_FILE, OPT_SIZE_ONLY, OPT_ADDRESS, - OPT_DELETE_AFTER, OPT_EXISTING, OPT_MAX_DELETE}; + OPT_DELETE_AFTER, OPT_EXISTING, OPT_MAX_DELETE, OPT_BACKUP_DIR}; static char *short_options = "oblLWHpguDCtcahvqrRIxnSe:B:T:zP"; @@ -231,6 +233,7 @@ static struct option long_options[] = { {"log-format", 1, 0, OPT_LOG_FORMAT}, {"address", 1, 0, OPT_ADDRESS}, {"max-delete", 1, 0, OPT_MAX_DELETE}, + {"backup-dir", 1, 0, OPT_BACKUP_DIR}, {0,0,0,0}}; @@ -553,6 +556,10 @@ int parse_arguments(int argc, char *argv[], int frommain) } break; + case OPT_BACKUP_DIR: + backup_dir = optarg; + break; + default: slprintf(err_buf,sizeof(err_buf),"unrecognised option\n"); return 0; @@ -562,6 +569,8 @@ int parse_arguments(int argc, char *argv[], int frommain) } +/* need to pass all the valid options from the client to the server */ + void server_options(char **args,int *argc) { int ac = *argc; @@ -680,6 +689,14 @@ void server_options(char **args,int *argc) args[ac++] = tmpdir; } + if (backup_dir && am_sender) { + /* only the receiver needs this option, if we are the sender + * then we need to send it to the receiver. + */ + args[ac++] = "--backup-dir"; + args[ac++] = backup_dir; + } + if (compare_dest && am_sender) { /* the server only needs this option if it is not the sender, * and it may be an older version that doesn't know this diff --git a/receiver.c b/receiver.c index e0c99d10..20afb4fb 100644 --- a/receiver.c +++ b/receiver.c @@ -36,7 +36,6 @@ extern char *compare_dest; extern int make_backups; extern char *backup_suffix; - static struct delete_list { dev_t dev; INO_T inode; @@ -146,6 +145,7 @@ static void delete_files(struct file_list *flist) if (-1 == flist_find(flist,local_file_list->files[i])) { char *f = f_name(local_file_list->files[i]); int k = strlen(f) - strlen(backup_suffix); +/* Hi Andrew, do we really need to play with backup_suffix here? */ if (make_backups && ((k <= 0) || (strcmp(f+k,backup_suffix) != 0))) { (void) make_backup(f); @@ -291,6 +291,8 @@ static int receive_data(int f_in,struct map_struct *buf,int fd,char *fname, } +/* main routine for receiver process. Receiver process runs on the + same host as the generator process. */ int recv_files(int f_in,struct file_list *flist,char *local_name,int f_gen) { diff --git a/rsync.c b/rsync.c index a2b432a2..039e1cd5 100644 --- a/rsync.c +++ b/rsync.c @@ -259,6 +259,3 @@ void finish_transfer(char *fname, char *fnametmp, struct file_struct *file) set_perms(fname,file,NULL,0); } } - - - diff --git a/rsync.yo b/rsync.yo index 3fd7122e..90406aec 100644 --- a/rsync.yo +++ b/rsync.yo @@ -223,6 +223,7 @@ verb( -r, --recursive recurse into directories -R, --relative use relative path names -b, --backup make backups (default ~ suffix) + --backup-dir=DIR put backups in the specified directory --suffix=SUFFIX override backup suffix -u, --update update only (don't overwrite newer files) -l, --links preserve soft links @@ -348,6 +349,10 @@ dit(bf(-b, --backup)) With this option preexisting destination files are renamed with a ~ extension as each file is transferred. You can control the backup suffix using the --suffix option. +dit(bf(--backup-dir=DIR)) In combination with the --backup option, this +tells rsync to store all backups in the specified directory. This is +very useful for incremental backups. + dit(bf(--suffix=SUFFIX)) This option allows you to override the default backup suffix used with the -b option. The default is a ~. -- 2.34.1