Main Page   Alphabetical List   Data Structures   File List   Data Fields   Globals   Related Pages  

backup.c

Go to the documentation of this file.
00001 /* 
00002    Copyright (C) Andrew Tridgell 1999
00003    
00004    This program is free software; you can redistribute it and/or modify
00005    it under the terms of the GNU General Public License as published by
00006    the Free Software Foundation; either version 2 of the License, or
00007    (at your option) any later version.
00008    
00009    This program is distributed in the hope that it will be useful,
00010    but WITHOUT ANY WARRANTY; without even the implied warranty of
00011    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00012    GNU General Public License for more details.
00013    
00014    You should have received a copy of the GNU General Public License
00015    along with this program; if not, write to the Free Software
00016    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
00017 */
00018 
00019 /* backup handling code */
00020 
00021 #include "rsync.h"
00022 
00023 extern int verbose;
00024 extern char *backup_suffix;
00025 extern char *backup_dir;
00026 
00027 
00028 extern int am_root;
00029 extern int preserve_devices;
00030 extern int preserve_links;
00031 extern int preserve_hard_links;
00032 
00033 /* simple backup creates a backup with a suffix in the same directory */
00034 static int make_simple_backup(char *fname)
00035 {
00036         char fnamebak[MAXPATHLEN];
00037         if (strlen(fname) + strlen(backup_suffix) > (MAXPATHLEN-1)) {
00038                 rprintf(FERROR,"backup filename too long\n");
00039                 return 0;
00040         }
00041 
00042         snprintf(fnamebak,sizeof(fnamebak),"%s%s",fname,backup_suffix);
00043         if (do_rename(fname,fnamebak) != 0) {
00044                 /* cygwin (at least version b19) reports EINVAL */
00045                 if (errno != ENOENT && errno != EINVAL) {
00046                         rsyserr(FERROR, errno, "rename %s to backup %s", fname, fnamebak);
00047                         return 0;
00048                 }
00049         } else if (verbose > 1) {
00050                 rprintf(FINFO,"backed up %s to %s\n",fname,fnamebak);
00051         }
00052         return 1;
00053 }
00054 
00055 
00056 /* recursively make a directory path */
00057 static int make_dir(char *name, int mask)
00058 {
00059         char newdir [MAXPATHLEN];
00060         char *p, *d;
00061 
00062         /* copy pathname over, look for last '/' */
00063         for (p = d = newdir; *name; *d++ = *name++)
00064                 if (*name == '/')
00065                         p = d;
00066         if (p == newdir)
00067                 return 0;
00068         *p = 0;
00069 
00070         /* make the new directory, if that fails then make its parent */
00071         while (do_mkdir (newdir, mask) != 0)
00072                 if ((errno != ENOENT) || !make_dir (newdir, mask))
00073                         return 0;
00074 
00075         return 1;
00076 } /* make_dir */
00077 
00078 
00079 /****************************************************************************
00080 Create a directory given an absolute path, perms based upon another directory
00081 path
00082 ****************************************************************************/
00083 static int make_bak_dir(char *fname,char *bak_path)
00084 {
00085         STRUCT_STAT st;
00086         STRUCT_STAT *st2;
00087         char fullpath[MAXPATHLEN];
00088         extern int orig_umask;
00089         char *p;
00090         char *q;
00091 
00092         while(strncmp(bak_path,"./",2)==0) bak_path += 2;
00093 
00094         if(bak_path[strlen(bak_path)-1]!='/') {
00095                 snprintf(fullpath,sizeof(fullpath),"%s/",bak_path);
00096         } else {
00097                 snprintf(fullpath,sizeof(fullpath),"%s",bak_path);
00098         }
00099         p=fullpath;
00100         q=&fullpath[strlen(fullpath)];  /* End of bak_path string */
00101         strcat(fullpath,fname);
00102 
00103         /* Make the directories */
00104         while ((p=strchr(p,'/'))) {
00105                 *p = 0;
00106                 if(do_lstat(fullpath,&st)!=0) {
00107                         do_mkdir(fullpath,0777 & ~orig_umask);
00108                         if(p>q) {
00109                                 if(do_lstat(q,&st)!=0) {
00110                                         rprintf(FERROR,"make_bak_dir stat %s : %s\n",fullpath,strerror(errno));
00111                                 } else {
00112                                         st2=&st;
00113                                         set_modtime(fullpath,st2->st_mtime);
00114                                         if(do_lchown(fullpath,st2->st_uid,st2->st_gid)!=0) {
00115                                                 rprintf(FERROR,"make_bak_dir chown %s : %s\n",fullpath,strerror(errno));
00116                                         };
00117                                         if(do_chmod(fullpath,st2->st_mode)!=0) {
00118                                                 rprintf(FERROR,"make_bak_dir failed to set permissions on %s : %s\n",fullpath,strerror(errno));
00119                                         };
00120                                 };
00121                         }
00122                 };
00123                 *p = '/';
00124                 p++;
00125         }
00126         return 0;
00127 }
00128 
00129 /* robustly move a file, creating new directory structures if necessary */
00130 static int robust_move(char *src, char *dst)
00131 {
00132         int keep_trying = 4;
00133         int keep_path_extfs = 0;
00134         int failed;
00135 
00136         while (keep_trying) {
00137                 if (keep_path_extfs) {
00138                         failed = copy_file(src, dst, 0755);
00139                         if (!failed) {
00140                                 do_unlink(src);
00141                         }
00142                 } else {
00143                         failed = robust_rename (src, dst);
00144                 }
00145 
00146                 if (failed) {
00147                         if (verbose > 2)
00148                                 rprintf (FERROR, "robust_move failed: %s(%d)\n",
00149                                         strerror (errno), errno);
00150                         switch (errno) {
00151                                 /* external filesystem */
00152                                 case EXDEV:
00153                                         keep_path_extfs = 1;
00154                                         keep_trying--;
00155                                         break;
00156                                 /* no directory to write to */
00157                                 case ENOENT:
00158                                         make_dir (dst, 0755);
00159                                         keep_trying--;
00160                                         break;
00161                                 default:
00162                                         keep_trying = 0;
00163                         } /* switch */
00164                 } else
00165                         keep_trying = 0;
00166         } /* while */
00167         return (!failed);
00168 } /* robust_move */
00169 
00170 
00171 /* if we have a backup_dir, then we get here from make_backup().
00172    We will move the file to be deleted into a parallel directory tree */
00173 static int keep_backup(char *fname)
00174 {
00175 
00176         static int initialised;
00177 
00178         char keep_name [MAXPATHLEN];
00179         STRUCT_STAT st;
00180         struct file_struct *file;
00181 
00182         int kept=0;
00183         int ret_code;
00184 
00185         if (!initialised) {
00186                 if (backup_dir[strlen(backup_dir) - 1] == '/')
00187                         backup_dir[strlen(backup_dir) - 1] = 0;
00188                 if (verbose > 0)
00189                         rprintf (FINFO, "backup_dir is %s\n", backup_dir);
00190                 initialised = 1;
00191         }
00192 
00193         /* return if no file to keep */
00194 #if SUPPORT_LINKS
00195         if (do_lstat (fname, &st)) return 1;
00196 #else
00197         if (do_stat (fname, &st)) return 1;
00198 #endif
00199 
00200         file = make_file(-1, fname, NULL, 1);
00201 
00202         /* the file could have disappeared */
00203         if (!file) return 1;
00204 
00205         /* make a complete pathname for backup file */
00206         if (strlen(backup_dir) + strlen(fname) > (MAXPATHLEN - 1)) {
00207                 rprintf (FERROR, "keep_backup filename too long\n");
00208                 return 0;
00209         }
00210 
00211         snprintf(keep_name, sizeof (keep_name), "%s/%s", backup_dir, fname);
00212 
00213 
00214 #ifdef HAVE_MKNOD
00215         /* Check to see if this is a device file, or link */
00216         if(IS_DEVICE(file->mode)) {
00217                 if(am_root && preserve_devices) {
00218                         make_bak_dir(fname,backup_dir);
00219                         if(do_mknod(keep_name,file->mode,file->rdev)!=0) {
00220                                 rprintf(FERROR,"mknod %s : %s\n",keep_name,strerror(errno));
00221                         } else {
00222                                 if(verbose>2)
00223                                         rprintf(FINFO,"make_backup : DEVICE %s successful.\n",fname);
00224                         };
00225                 };
00226                 kept=1;
00227                 do_unlink(fname);
00228         };
00229 #endif
00230 
00231         if(!kept && S_ISDIR(file->mode)) {
00232                 /* make an empty directory */
00233                 make_bak_dir(fname,backup_dir);
00234                 do_mkdir(keep_name,file->mode);
00235                 ret_code=do_rmdir(fname);
00236                 if(verbose>2)
00237                         rprintf(FINFO,"make_backup : RMDIR %s returns %i\n",fname,ret_code);
00238                 kept=1;
00239         };
00240 
00241 #if SUPPORT_LINKS
00242         if(!kept && preserve_links && S_ISLNK(file->mode)) {
00243                 extern int safe_symlinks;
00244                 if (safe_symlinks && unsafe_symlink(file->link, keep_name)) {
00245                         if (verbose) {
00246                                 rprintf(FINFO,"ignoring unsafe symlink %s -> %s\n",
00247                                         keep_name,file->link);
00248                         }
00249                         kept=1;
00250                 }
00251                 make_bak_dir(fname,backup_dir);
00252                 if(do_symlink(file->link,keep_name) != 0) {
00253                         rprintf(FERROR,"link %s -> %s : %s\n",keep_name,file->link,strerror(errno));
00254                 };
00255                 do_unlink(fname);
00256                 kept=1;
00257         };
00258 #endif
00259         if(!kept && preserve_hard_links && check_hard_link(file)) {
00260                 if(verbose > 1) rprintf(FINFO,"%s is a hard link\n",f_name(file));
00261         };
00262 
00263         if(!kept && !S_ISREG(file->mode)) {
00264                 rprintf(FINFO,"make_bak: skipping non-regular file %s\n",fname);
00265         }
00266 
00267         /* move to keep tree if a file */
00268         if(!kept) {
00269                 if (!robust_move (fname, keep_name))
00270                         rprintf(FERROR, "keep_backup failed %s -> %s : %s\n",
00271                                 fname, keep_name, strerror(errno));
00272         };
00273         set_perms (keep_name, file, NULL, 0);
00274         free_file (file);
00275         free (file);
00276 
00277         if (verbose > 1)
00278                 rprintf (FINFO, "keep_backup %s -> %s\n", fname, keep_name);
00279         return 1;
00280 } /* keep_backup */
00281 
00282 
00283 /* main backup switch routine */
00284 int make_backup(char *fname)
00285 {
00286         if (backup_dir)
00287                 return (keep_backup(fname));
00288         else
00289                 return (make_simple_backup(fname));
00290 }
00291 

Generated on Tue Apr 16 12:37:36 2002 for rsync by doxygen1.2.15