Annotation of embedaddon/rsync/backup.c, revision 1.1

1.1     ! misho       1: /*
        !             2:  * Backup handling code.
        !             3:  *
        !             4:  * Copyright (C) 1999 Andrew Tridgell
        !             5:  * Copyright (C) 2003-2009 Wayne Davison
        !             6:  *
        !             7:  * This program is free software; you can redistribute it and/or modify
        !             8:  * it under the terms of the GNU General Public License as published by
        !             9:  * the Free Software Foundation; either version 3 of the License, or
        !            10:  * (at your option) any later version.
        !            11:  *
        !            12:  * This program is distributed in the hope that it will be useful,
        !            13:  * but WITHOUT ANY WARRANTY; without even the implied warranty of
        !            14:  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
        !            15:  * GNU General Public License for more details.
        !            16:  *
        !            17:  * You should have received a copy of the GNU General Public License along
        !            18:  * with this program; if not, visit the http://fsf.org website.
        !            19:  */
        !            20: 
        !            21: #include "rsync.h"
        !            22: 
        !            23: extern int verbose;
        !            24: extern int am_root;
        !            25: extern int preserve_acls;
        !            26: extern int preserve_xattrs;
        !            27: extern int preserve_devices;
        !            28: extern int preserve_specials;
        !            29: extern int preserve_links;
        !            30: extern int safe_symlinks;
        !            31: extern int backup_dir_len;
        !            32: extern unsigned int backup_dir_remainder;
        !            33: extern char backup_dir_buf[MAXPATHLEN];
        !            34: extern char *backup_suffix;
        !            35: extern char *backup_dir;
        !            36: 
        !            37: /* make a complete pathname for backup file */
        !            38: char *get_backup_name(const char *fname)
        !            39: {
        !            40:        if (backup_dir) {
        !            41:                if (stringjoin(backup_dir_buf + backup_dir_len, backup_dir_remainder,
        !            42:                               fname, backup_suffix, NULL) < backup_dir_remainder)
        !            43:                        return backup_dir_buf;
        !            44:        } else {
        !            45:                if (stringjoin(backup_dir_buf, MAXPATHLEN,
        !            46:                               fname, backup_suffix, NULL) < MAXPATHLEN)
        !            47:                        return backup_dir_buf;
        !            48:        }
        !            49: 
        !            50:        rprintf(FERROR, "backup filename too long\n");
        !            51:        return NULL;
        !            52: }
        !            53: 
        !            54: /* simple backup creates a backup with a suffix in the same directory */
        !            55: static int make_simple_backup(const char *fname)
        !            56: {
        !            57:        int rename_errno;
        !            58:        const char *fnamebak = get_backup_name(fname);
        !            59: 
        !            60:        if (!fnamebak)
        !            61:                return 0;
        !            62: 
        !            63:        while (1) {
        !            64:                if (do_rename(fname, fnamebak) == 0) {
        !            65:                        if (verbose > 1) {
        !            66:                                rprintf(FINFO, "backed up %s to %s\n",
        !            67:                                        fname, fnamebak);
        !            68:                        }
        !            69:                        break;
        !            70:                }
        !            71:                /* cygwin (at least version b19) reports EINVAL */
        !            72:                if (errno == ENOENT || errno == EINVAL)
        !            73:                        break;
        !            74: 
        !            75:                rename_errno = errno;
        !            76:                if (errno == EISDIR && do_rmdir(fnamebak) == 0)
        !            77:                        continue;
        !            78:                if (errno == ENOTDIR && do_unlink(fnamebak) == 0)
        !            79:                        continue;
        !            80: 
        !            81:                rsyserr(FERROR, rename_errno, "rename %s to backup %s",
        !            82:                        fname, fnamebak);
        !            83:                errno = rename_errno;
        !            84:                return 0;
        !            85:        }
        !            86: 
        !            87:        return 1;
        !            88: }
        !            89: 
        !            90: 
        !            91: /****************************************************************************
        !            92: Create a directory given an absolute path, perms based upon another directory
        !            93: path
        !            94: ****************************************************************************/
        !            95: int make_bak_dir(const char *fullpath)
        !            96: {
        !            97:        char fbuf[MAXPATHLEN], *rel, *end, *p;
        !            98:        struct file_struct *file;
        !            99:        int len = backup_dir_len;
        !           100:        stat_x sx;
        !           101: 
        !           102:        while (*fullpath == '.' && fullpath[1] == '/') {
        !           103:                fullpath += 2;
        !           104:                len -= 2;
        !           105:        }
        !           106: 
        !           107:        if (strlcpy(fbuf, fullpath, sizeof fbuf) >= sizeof fbuf)
        !           108:                return -1;
        !           109: 
        !           110:        rel = fbuf + len;
        !           111:        end = p = rel + strlen(rel);
        !           112: 
        !           113:        /* Try to find an existing dir, starting from the deepest dir. */
        !           114:        while (1) {
        !           115:                if (--p == fbuf)
        !           116:                        return -1;
        !           117:                if (*p == '/') {
        !           118:                        *p = '\0';
        !           119:                        if (mkdir_defmode(fbuf) == 0)
        !           120:                                break;
        !           121:                        if (errno != ENOENT) {
        !           122:                                rsyserr(FERROR, errno,
        !           123:                                        "make_bak_dir mkdir %s failed",
        !           124:                                        full_fname(fbuf));
        !           125:                                return -1;
        !           126:                        }
        !           127:                }
        !           128:        }
        !           129: 
        !           130:        /* Make all the dirs that we didn't find on the way here. */
        !           131:        while (1) {
        !           132:                if (p >= rel) {
        !           133:                        /* Try to transfer the directory settings of the
        !           134:                         * actual dir that the files are coming from. */
        !           135:                        if (x_stat(rel, &sx.st, NULL) < 0) {
        !           136:                                rsyserr(FERROR, errno,
        !           137:                                        "make_bak_dir stat %s failed",
        !           138:                                        full_fname(rel));
        !           139:                        } else {
        !           140: #ifdef SUPPORT_ACLS
        !           141:                                sx.acc_acl = sx.def_acl = NULL;
        !           142: #endif
        !           143: #ifdef SUPPORT_XATTRS
        !           144:                                sx.xattr = NULL;
        !           145: #endif
        !           146:                                if (!(file = make_file(rel, NULL, NULL, 0, NO_FILTERS)))
        !           147:                                        continue;
        !           148: #ifdef SUPPORT_ACLS
        !           149:                                if (preserve_acls && !S_ISLNK(file->mode)) {
        !           150:                                        get_acl(rel, &sx);
        !           151:                                        cache_tmp_acl(file, &sx);
        !           152:                                        free_acl(&sx);
        !           153:                                }
        !           154: #endif
        !           155: #ifdef SUPPORT_XATTRS
        !           156:                                if (preserve_xattrs) {
        !           157:                                        get_xattr(rel, &sx);
        !           158:                                        cache_tmp_xattr(file, &sx);
        !           159:                                        free_xattr(&sx);
        !           160:                                }
        !           161: #endif
        !           162:                                set_file_attrs(fbuf, file, NULL, NULL, 0);
        !           163:                                unmake_file(file);
        !           164: #ifdef SUPPORT_ACLS
        !           165:                                uncache_tmp_acls();
        !           166: #endif
        !           167: #ifdef SUPPORT_XATTRS
        !           168:                                uncache_tmp_xattrs();
        !           169: #endif
        !           170:                        }
        !           171:                }
        !           172:                *p = '/';
        !           173:                p += strlen(p);
        !           174:                if (p == end)
        !           175:                        break;
        !           176:                if (mkdir_defmode(fbuf) < 0) {
        !           177:                        rsyserr(FERROR, errno, "make_bak_dir mkdir %s failed",
        !           178:                                full_fname(fbuf));
        !           179:                        return -1;
        !           180:                }
        !           181:        }
        !           182: 
        !           183:        return 0;
        !           184: }
        !           185: 
        !           186: /* robustly move a file, creating new directory structures if necessary */
        !           187: static int robust_move(const char *src, char *dst)
        !           188: {
        !           189:        if (robust_rename(src, dst, NULL, 0755) < 0) {
        !           190:                int save_errno = errno ? errno : EINVAL; /* 0 paranoia */
        !           191:                if (errno == ENOENT && make_bak_dir(dst) == 0) {
        !           192:                        if (robust_rename(src, dst, NULL, 0755) < 0)
        !           193:                                save_errno = errno ? errno : save_errno;
        !           194:                        else
        !           195:                                save_errno = 0;
        !           196:                }
        !           197:                if (save_errno) {
        !           198:                        errno = save_errno;
        !           199:                        return -1;
        !           200:                }
        !           201:        }
        !           202:        return 0;
        !           203: }
        !           204: 
        !           205: 
        !           206: /* If we have a --backup-dir, then we get here from make_backup().
        !           207:  * We will move the file to be deleted into a parallel directory tree. */
        !           208: static int keep_backup(const char *fname)
        !           209: {
        !           210:        stat_x sx;
        !           211:        struct file_struct *file;
        !           212:        char *buf;
        !           213:        int save_preserve_xattrs = preserve_xattrs;
        !           214:        int kept = 0;
        !           215:        int ret_code;
        !           216: 
        !           217:        /* return if no file to keep */
        !           218:        if (x_lstat(fname, &sx.st, NULL) < 0)
        !           219:                return 1;
        !           220: #ifdef SUPPORT_ACLS
        !           221:        sx.acc_acl = sx.def_acl = NULL;
        !           222: #endif
        !           223: #ifdef SUPPORT_XATTRS
        !           224:        sx.xattr = NULL;
        !           225: #endif
        !           226: 
        !           227:        if (!(file = make_file(fname, NULL, NULL, 0, NO_FILTERS)))
        !           228:                return 1; /* the file could have disappeared */
        !           229: 
        !           230:        if (!(buf = get_backup_name(fname))) {
        !           231:                unmake_file(file);
        !           232: #ifdef SUPPORT_ACLS
        !           233:                uncache_tmp_acls();
        !           234: #endif
        !           235: #ifdef SUPPORT_XATTRS
        !           236:                uncache_tmp_xattrs();
        !           237: #endif
        !           238:                return 0;
        !           239:        }
        !           240: 
        !           241: #ifdef SUPPORT_ACLS
        !           242:        if (preserve_acls && !S_ISLNK(file->mode)) {
        !           243:                get_acl(fname, &sx);
        !           244:                cache_tmp_acl(file, &sx);
        !           245:                free_acl(&sx);
        !           246:        }
        !           247: #endif
        !           248: #ifdef SUPPORT_XATTRS
        !           249:        if (preserve_xattrs) {
        !           250:                get_xattr(fname, &sx);
        !           251:                cache_tmp_xattr(file, &sx);
        !           252:                free_xattr(&sx);
        !           253:        }
        !           254: #endif
        !           255: 
        !           256:        /* Check to see if this is a device file, or link */
        !           257:        if ((am_root && preserve_devices && IS_DEVICE(file->mode))
        !           258:         || (preserve_specials && IS_SPECIAL(file->mode))) {
        !           259:                int save_errno;
        !           260:                do_unlink(buf);
        !           261:                if (do_mknod(buf, file->mode, sx.st.st_rdev) < 0) {
        !           262:                        save_errno = errno ? errno : EINVAL; /* 0 paranoia */
        !           263:                        if (errno == ENOENT && make_bak_dir(buf) == 0) {
        !           264:                                if (do_mknod(buf, file->mode, sx.st.st_rdev) < 0)
        !           265:                                        save_errno = errno ? errno : save_errno;
        !           266:                                else
        !           267:                                        save_errno = 0;
        !           268:                        }
        !           269:                        if (save_errno) {
        !           270:                                rsyserr(FERROR, save_errno, "mknod %s failed",
        !           271:                                        full_fname(buf));
        !           272:                        }
        !           273:                } else
        !           274:                        save_errno = 0;
        !           275:                if (verbose > 2 && save_errno == 0) {
        !           276:                        rprintf(FINFO, "make_backup: DEVICE %s successful.\n",
        !           277:                                fname);
        !           278:                }
        !           279:                kept = 1;
        !           280:                do_unlink(fname);
        !           281:        }
        !           282: 
        !           283:        if (!kept && S_ISDIR(file->mode)) {
        !           284:                /* make an empty directory */
        !           285:                if (do_mkdir(buf, file->mode) < 0) {
        !           286:                        int save_errno = errno ? errno : EINVAL; /* 0 paranoia */
        !           287:                        if (errno == ENOENT && make_bak_dir(buf) == 0) {
        !           288:                                if (do_mkdir(buf, file->mode) < 0)
        !           289:                                        save_errno = errno ? errno : save_errno;
        !           290:                                else
        !           291:                                        save_errno = 0;
        !           292:                        }
        !           293:                        if (save_errno) {
        !           294:                                rsyserr(FINFO, save_errno, "mkdir %s failed",
        !           295:                                        full_fname(buf));
        !           296:                        }
        !           297:                }
        !           298: 
        !           299:                ret_code = do_rmdir(fname);
        !           300:                if (verbose > 2) {
        !           301:                        rprintf(FINFO, "make_backup: RMDIR %s returns %i\n",
        !           302:                                full_fname(fname), ret_code);
        !           303:                }
        !           304:                kept = 1;
        !           305:        }
        !           306: 
        !           307: #ifdef SUPPORT_LINKS
        !           308:        if (!kept && preserve_links && S_ISLNK(file->mode)) {
        !           309:                const char *sl = F_SYMLINK(file);
        !           310:                if (safe_symlinks && unsafe_symlink(sl, fname)) {
        !           311:                        if (verbose) {
        !           312:                                rprintf(FINFO, "not backing up unsafe symlink \"%s\" -> \"%s\"\n",
        !           313:                                        fname, sl);
        !           314:                        }
        !           315:                        kept = 1;
        !           316:                } else {
        !           317:                        do_unlink(buf);
        !           318:                        if (do_symlink(sl, buf) < 0) {
        !           319:                                int save_errno = errno ? errno : EINVAL; /* 0 paranoia */
        !           320:                                if (errno == ENOENT && make_bak_dir(buf) == 0) {
        !           321:                                        if (do_symlink(sl, buf) < 0)
        !           322:                                                save_errno = errno ? errno : save_errno;
        !           323:                                        else
        !           324:                                                save_errno = 0;
        !           325:                                }
        !           326:                                if (save_errno) {
        !           327:                                        rsyserr(FERROR, save_errno, "link %s -> \"%s\"",
        !           328:                                                full_fname(buf), sl);
        !           329:                                }
        !           330:                        }
        !           331:                        do_unlink(fname);
        !           332:                        kept = 1;
        !           333:                }
        !           334:        }
        !           335: #endif
        !           336: 
        !           337:        if (!kept && !S_ISREG(file->mode)) {
        !           338:                rprintf(FINFO, "make_bak: skipping non-regular file %s\n",
        !           339:                        fname);
        !           340:                unmake_file(file);
        !           341: #ifdef SUPPORT_ACLS
        !           342:                uncache_tmp_acls();
        !           343: #endif
        !           344: #ifdef SUPPORT_XATTRS
        !           345:                uncache_tmp_xattrs();
        !           346: #endif
        !           347:                return 1;
        !           348:        }
        !           349: 
        !           350:        /* move to keep tree if a file */
        !           351:        if (!kept) {
        !           352:                if (robust_move(fname, buf) != 0) {
        !           353:                        rsyserr(FERROR, errno, "keep_backup failed: %s -> \"%s\"",
        !           354:                                full_fname(fname), buf);
        !           355:                } else if (sx.st.st_nlink > 1) {
        !           356:                        /* If someone has hard-linked the file into the backup
        !           357:                         * dir, rename() might return success but do nothing! */
        !           358:                        robust_unlink(fname); /* Just in case... */
        !           359:                }
        !           360:        }
        !           361:        preserve_xattrs = 0;
        !           362:        set_file_attrs(buf, file, NULL, fname, 0);
        !           363:        preserve_xattrs = save_preserve_xattrs;
        !           364:        unmake_file(file);
        !           365: #ifdef SUPPORT_ACLS
        !           366:        uncache_tmp_acls();
        !           367: #endif
        !           368: #ifdef SUPPORT_XATTRS
        !           369:        uncache_tmp_xattrs();
        !           370: #endif
        !           371: 
        !           372:        if (verbose > 1) {
        !           373:                rprintf(FINFO, "backed up %s to %s\n",
        !           374:                        fname, buf);
        !           375:        }
        !           376:        return 1;
        !           377: }
        !           378: 
        !           379: 
        !           380: /* main backup switch routine */
        !           381: int make_backup(const char *fname)
        !           382: {
        !           383:        if (backup_dir)
        !           384:                return keep_backup(fname);
        !           385:        return make_simple_backup(fname);
        !           386: }

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