backup.c

説明を見る。
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 int backup_dir_len;
00025 extern unsigned int backup_dir_remainder;
00026 extern char backup_dir_buf[MAXPATHLEN];
00027 extern char *backup_suffix;
00028 extern char *backup_dir;
00029 
00030 extern int am_root;
00031 extern int preserve_acls;
00032 extern int preserve_xattrs;
00033 extern int preserve_devices;
00034 extern int preserve_specials;
00035 extern int preserve_links;
00036 extern int safe_symlinks;
00037 
00038 /* make a complete pathname for backup file */
00039 char *get_backup_name(char *fname)
00040 {
00041         if (backup_dir) {
00042                 if (stringjoin(backup_dir_buf + backup_dir_len, backup_dir_remainder,
00043                                fname, backup_suffix, NULL) < backup_dir_remainder)
00044                         return backup_dir_buf;
00045         } else {
00046                 if (stringjoin(backup_dir_buf, MAXPATHLEN,
00047                                fname, backup_suffix, NULL) < MAXPATHLEN)
00048                         return backup_dir_buf;
00049         }
00050 
00051         rprintf(FERROR, "backup filename too long\n");
00052         return NULL;
00053 }
00054 
00055 /* simple backup creates a backup with a suffix in the same directory */
00056 static int make_simple_backup(char *fname)
00057 {
00058         int rename_errno;
00059         char *fnamebak = get_backup_name(fname);
00060 
00061         if (!fnamebak)
00062                 return 0;
00063 
00064         while (1) {
00065                 if (do_rename(fname, fnamebak) == 0) {
00066                         if (verbose > 1) {
00067                                 rprintf(FINFO, "backed up %s to %s\n",
00068                                         fname, fnamebak);
00069                         }
00070                         break;
00071                 }
00072                 /* cygwin (at least version b19) reports EINVAL */
00073                 if (errno == ENOENT || errno == EINVAL)
00074                         break;
00075 
00076                 rename_errno = errno;
00077                 if (errno == EISDIR && do_rmdir(fnamebak) == 0)
00078                         continue;
00079                 if (errno == ENOTDIR && do_unlink(fnamebak) == 0)
00080                         continue;
00081 
00082                 rsyserr(FERROR, rename_errno, "rename %s to backup %s",
00083                         fname, fnamebak);
00084                 errno = rename_errno;
00085                 return 0;
00086         }
00087 
00088         return 1;
00089 }
00090 
00091 
00092 /****************************************************************************
00093 Create a directory given an absolute path, perms based upon another directory
00094 path
00095 ****************************************************************************/
00096 static int make_bak_dir(char *fullpath)
00097 {
00098         STRUCT_STAT st;
00099         char *rel = fullpath + backup_dir_len;
00100         char *end = rel + strlen(rel);
00101         char *p = end;
00102 
00103         while (strncmp(fullpath, "./", 2) == 0)
00104                 fullpath += 2;
00105 
00106         /* Try to find an existing dir, starting from the deepest dir. */
00107         while (1) {
00108                 if (--p == fullpath) {
00109                         p += strlen(p);
00110                         goto failure;
00111                 }
00112                 if (*p == '/') {
00113                         *p = '\0';
00114                         if (mkdir_defmode(fullpath) == 0)
00115                                 break;
00116                         if (errno != ENOENT) {
00117                                 rsyserr(FERROR, errno,
00118                                         "make_bak_dir mkdir %s failed",
00119                                         full_fname(fullpath));
00120                                 goto failure;
00121                         }
00122                 }
00123         }
00124 
00125         /* Make all the dirs that we didn't find on the way here. */
00126         while (1) {
00127                 if (p >= rel) {
00128                         /* Try to transfer the directory settings of the
00129                          * actual dir that the files are coming from. */
00130                         if (do_stat(rel, &st) < 0) {
00131                                 rsyserr(FERROR, errno,
00132                                         "make_bak_dir stat %s failed",
00133                                         full_fname(rel));
00134                         } else {
00135                                 do_lchown(fullpath, st.st_uid, st.st_gid);
00136                                 do_chmod(fullpath, st.st_mode);
00137 #ifdef SUPPORT_ACLS
00138                                 if (preserve_acls)
00139                                         dup_acl(end, fullpath, st.st_mode);
00140 #endif
00141 #ifdef SUPPORT_XATTRS
00142                                 if (preserve_xattrs)
00143                                         dup_xattr(end, fullpath );
00144 #endif
00145                         }
00146                 }
00147                 *p = '/';
00148                 p += strlen(p);
00149                 if (p == end)
00150                         break;
00151                 if (mkdir_defmode(fullpath) < 0) {
00152                         rsyserr(FERROR, errno, "make_bak_dir mkdir %s failed",
00153                                 full_fname(fullpath));
00154                         goto failure;
00155                 }
00156         }
00157         return 0;
00158 
00159   failure:
00160         while (p != end) {
00161                 *p = '/';
00162                 p += strlen(p);
00163         }
00164         return -1;
00165 }
00166 
00167 /* robustly move a file, creating new directory structures if necessary */
00168 static int robust_move(char *src, char *dst)
00169 {
00170         if (robust_rename(src, dst, NULL, 0755) < 0
00171          && (errno != ENOENT || make_bak_dir(dst) < 0
00172           || robust_rename(src, dst, NULL, 0755) < 0))
00173                 return -1;
00174         return 0;
00175 }
00176 
00177 
00178 /* If we have a --backup-dir, then we get here from make_backup().
00179  * We will move the file to be deleted into a parallel directory tree. */
00180 static int keep_backup(char *fname)
00181 {
00182         STRUCT_STAT st;
00183         struct file_struct *file;
00184         char *buf;
00185         int kept = 0;
00186         int ret_code;
00187 
00188         /* return if no file to keep */
00189         if (do_lstat(fname, &st) < 0)
00190                 return 1;
00191 
00192         if (!(file = make_file(fname, NULL, NULL, 0, NO_FILTERS)))
00193                 return 1; /* the file could have disappeared */
00194 
00195         if (!(buf = get_backup_name(fname)))
00196                 return 0;
00197 
00198 #ifdef SUPPORT_ACLS
00199         if (preserve_acls)
00200                 push_keep_backup_acl(file, fname, buf);
00201 #endif
00202 #ifdef SUPPORT_XATTRS
00203         if (preserve_xattrs)
00204                 push_keep_backup_xattr(file, fname, buf);
00205 #endif
00206 
00207         /* Check to see if this is a device file, or link */
00208         if ((am_root && preserve_devices && IS_DEVICE(file->mode))
00209          || (preserve_specials && IS_SPECIAL(file->mode))) {
00210                 do_unlink(buf);
00211                 if (do_mknod(buf, file->mode, file->u.rdev) < 0
00212                     && (errno != ENOENT || make_bak_dir(buf) < 0
00213                      || do_mknod(buf, file->mode, file->u.rdev) < 0)) {
00214                         rsyserr(FERROR, errno, "mknod %s failed",
00215                                 full_fname(buf));
00216                 } else if (verbose > 2) {
00217                         rprintf(FINFO, "make_backup: DEVICE %s successful.\n",
00218                                 fname);
00219                 }
00220                 kept = 1;
00221                 do_unlink(fname);
00222         }
00223 
00224         if (!kept && S_ISDIR(file->mode)) {
00225                 /* make an empty directory */
00226                 if (do_mkdir(buf, file->mode) < 0
00227                     && (errno != ENOENT || make_bak_dir(buf) < 0
00228                      || do_mkdir(buf, file->mode) < 0)) {
00229                         rsyserr(FINFO, errno, "mkdir %s failed",
00230                                 full_fname(buf));
00231                 }
00232 
00233                 ret_code = do_rmdir(fname);
00234                 if (verbose > 2) {
00235                         rprintf(FINFO, "make_backup: RMDIR %s returns %i\n",
00236                                 full_fname(fname), ret_code);
00237                 }
00238                 kept = 1;
00239         }
00240 
00241 #ifdef SUPPORT_LINKS
00242         if (!kept && preserve_links && S_ISLNK(file->mode)) {
00243                 if (safe_symlinks && unsafe_symlink(file->u.link, buf)) {
00244                         if (verbose) {
00245                                 rprintf(FINFO, "ignoring unsafe symlink %s -> %s\n",
00246                                         full_fname(buf), file->u.link);
00247                         }
00248                         kept = 1;
00249                 } else {
00250                         do_unlink(buf);
00251                         if (do_symlink(file->u.link, buf) < 0
00252                             && (errno != ENOENT || make_bak_dir(buf) < 0
00253                              || do_symlink(file->u.link, buf) < 0)) {
00254                                 rsyserr(FERROR, errno, "link %s -> \"%s\"",
00255                                         full_fname(buf),
00256                                         file->u.link);
00257                         }
00258                         do_unlink(fname);
00259                         kept = 1;
00260                 }
00261         }
00262 #endif
00263 
00264         if (!kept && !S_ISREG(file->mode)) {
00265                 rprintf(FINFO, "make_bak: skipping non-regular file %s\n",
00266                         fname);
00267                 return 1;
00268         }
00269 
00270         /* move to keep tree if a file */
00271         if (!kept) {
00272                 if (robust_move(fname, buf) != 0) {
00273                         rsyserr(FERROR, errno, "keep_backup failed: %s -> \"%s\"",
00274                                 full_fname(fname), buf);
00275                 } else if (st.st_nlink > 1) {
00276                         /* If someone has hard-linked the file into the backup
00277                          * dir, rename() might return success but do nothing! */
00278                         robust_unlink(fname); /* Just in case... */
00279                 }
00280         }
00281         set_file_attrs(buf, file, NULL, 0);
00282 #ifdef SUPPORT_ACLS
00283         if (preserve_acls)
00284                 cleanup_keep_backup_acl();
00285 #endif
00286 #ifdef SUPPORT_XATTRS
00287         if (preserve_xattrs)
00288                 cleanup_keep_backup_xattr();
00289 #endif
00290         free(file);
00291 
00292         if (verbose > 1) {
00293                 rprintf(FINFO, "backed up %s to %s\n",
00294                         fname, buf);
00295         }
00296         return 1;
00297 }
00298 
00299 
00300 /* main backup switch routine */
00301 int make_backup(char *fname)
00302 {
00303         if (backup_dir)
00304                 return keep_backup(fname);
00305         return make_simple_backup(fname);
00306 }

rsyncに対してSat Dec 5 19:45:40 2009に生成されました。  doxygen 1.4.7