From 378a074c82bdb393b5780832598aaa1c648926b8 Mon Sep 17 00:00:00 2001 From: Andrew Tridgell Date: Thu, 27 Jan 2000 02:45:56 +0000 Subject: [PATCH] patch from James Delahanty to make --backup-dir work cross-filesystem --- backup.c | 141 ++++++++++++++++++++++++++++++++++++++++++++++++------- 1 file changed, 123 insertions(+), 18 deletions(-) diff --git a/backup.c b/backup.c index 24f8523a..ee323f3f 100644 --- a/backup.c +++ b/backup.c @@ -25,6 +25,11 @@ extern char *backup_suffix; extern char *backup_dir; +extern int am_root; +extern int preserve_devices; +extern int preserve_links; +extern int preserve_hard_links; + /* simple backup creates a backup with a suffix in the same directory */ static int make_simple_backup(char *fname) { @@ -71,6 +76,56 @@ static int make_dir(char *name, int mask) } /* make_dir */ +/**************************************************************************** +Create a directory given an absolute path, perms based upon another directory +path +****************************************************************************/ +static int make_bak_dir(char *fname,char *bak_path) +{ + STRUCT_STAT st; + STRUCT_STAT *st2; + char fullpath[MAXPATHLEN]; + extern int orig_umask; + char *p; + char *q; + + while(strncmp(bak_path,"./",2)==0) bak_path += 2; + + if(bak_path[strlen(bak_path)-1]!='/') { + slprintf(fullpath,sizeof(fullpath),"%s/",bak_path); + } else { + slprintf(fullpath,sizeof(fullpath),"%s",bak_path); + } + p=fullpath; + q=&fullpath[strlen(fullpath)]; /* End of bak_path string */ + strcat(fullpath,fname); + + /* Make the directories */ + while ((p=strchr(p,'/'))) { + *p = 0; + if(do_lstat(fullpath,&st)!=0) { + do_mkdir(fullpath,0777 & ~orig_umask); + if(p>q) { + if(do_lstat(q,&st)!=0) { + rprintf(FERROR,"make_bak_dir stat %s : %s\n",fullpath,strerror(errno)); + } else { + st2=&st; + set_modtime(fullpath,st2->st_mtime); + if(do_lchown(fullpath,st2->st_uid,st2->st_gid)!=0) { + rprintf(FERROR,"make_bak_dir chown %s : %s\n",fullpath,strerror(errno)); + }; + if(do_chmod(fullpath,st2->st_mode)!=0) { + rprintf(FERROR,"make_bak_dir failed to set permissions on %s : %s\n",fullpath,strerror(errno)); + }; + }; + } + }; + *p = '/'; + p++; + } + return 0; +} + /* robustly move a file, creating new directory structures if necessary */ static int robust_move(char *src, char *dst) { @@ -113,12 +168,16 @@ static int robust_move(char *src, char *dst) 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; + int kept=0; + int ret_code; + if (!initialised) { if (backup_dir[strlen(backup_dir) - 1] == '/') backup_dir[strlen(backup_dir) - 1] = 0; @@ -136,32 +195,78 @@ static int keep_backup(char *fname) 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); + /* 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); + + +#ifdef HAVE_MKNOD + /* Check to see if this is a device file, or link */ + if(IS_DEVICE(file->mode)) { + if(am_root && preserve_devices) { + make_bak_dir(fname,backup_dir); + if(do_mknod(keep_name,file->mode,file->rdev)!=0) { + rprintf(FERROR,"mknod %s : %s\n",keep_name,strerror(errno)); + } else { + if(verbose>2) + rprintf(FINFO,"make_backup : DEVICE %s successful.\n",fname); + }; + }; + kept=1; + do_unlink(fname); + }; +#endif + + if(!kept && S_ISDIR(file->mode)) { + /* make an empty directory */ + make_bak_dir(fname,backup_dir); + do_mkdir(keep_name,file->mode); + ret_code=do_rmdir(fname); + if(verbose>2) + rprintf(FINFO,"make_backup : RMDIR %s returns %i\n",fname,ret_code); + kept=1; + }; + +#if SUPPORT_LINKS + if(!kept && preserve_links && S_ISLNK(file->mode)) { + extern int safe_symlinks; + if (safe_symlinks && unsafe_symlink(file->link, keep_name)) { + if (verbose) { + rprintf(FINFO,"ignoring unsafe symlink %s -> %s\n", + keep_name,file->link); + } + kept=1; + } + make_bak_dir(fname,backup_dir); + if(do_symlink(file->link,keep_name) != 0) { + rprintf(FERROR,"link %s -> %s : %s\n",keep_name,file->link,strerror(errno)); + }; + do_unlink(fname); + kept=1; + }; +#endif + if(!kept && preserve_hard_links && check_hard_link(file)) { + if(verbose > 1) rprintf(FINFO,"%s is a hard link\n",f_name(file)); + }; + + if(!kept && !S_ISREG(file->mode)) { + rprintf(FINFO,"make_bak: skipping non-regular file %s\n",fname); + } - if (!S_ISDIR(file->mode)) { /* move to keep tree if a file */ + if(!kept) { 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; -- 2.34.1