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

1.1       misho       1: /*
                      2:  * Backup handling code.
                      3:  *
                      4:  * Copyright (C) 1999 Andrew Tridgell
1.1.1.2 ! misho       5:  * Copyright (C) 2003-2013 Wayne Davison
1.1       misho       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"
1.1.1.2 ! misho      22: #include "ifuncs.h"
1.1       misho      23: 
                     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: 
1.1.1.2 ! misho      37: /* Returns -1 on error, 0 on missing dir, and 1 on present dir. */
        !            38: static int validate_backup_dir(void)
1.1       misho      39: {
1.1.1.2 ! misho      40:        STRUCT_STAT st;
1.1       misho      41: 
1.1.1.2 ! misho      42:        if (do_lstat(backup_dir_buf, &st) < 0) {
        !            43:                if (errno == ENOENT)
        !            44:                        return 0;
        !            45:                rsyserr(FERROR, errno, "backup lstat %s failed", backup_dir_buf);
        !            46:                return -1;
        !            47:        }
        !            48:        if (!S_ISDIR(st.st_mode)) {
        !            49:                int flags = get_del_for_flag(st.st_mode) | DEL_FOR_BACKUP | DEL_RECURSE;
        !            50:                if (delete_item(backup_dir_buf, st.st_mode, flags) == 0)
        !            51:                        return 0;
        !            52:                return -1;
1.1       misho      53:        }
                     54:        return 1;
                     55: }
                     56: 
1.1.1.2 ! misho      57: /* Create a backup path from the given fname, putting the result into
        !            58:  * backup_dir_buf.  Any new directories (compared to the prior backup
        !            59:  * path) are ensured to exist as directories, replacing anything else
        !            60:  * that may be in the way (e.g. a symlink). */
        !            61: static BOOL copy_valid_path(const char *fname)
1.1       misho      62: {
1.1.1.2 ! misho      63:        const char *f;
        !            64:        int val;
        !            65:        BOOL ret = True;
1.1       misho      66:        stat_x sx;
1.1.1.2 ! misho      67:        char *b, *rel = backup_dir_buf + backup_dir_len, *name = rel;
1.1       misho      68: 
1.1.1.2 ! misho      69:        for (f = fname, b = rel; *f && *f == *b; f++, b++) {
        !            70:                if (*b == '/')
        !            71:                        name = b + 1;
1.1       misho      72:        }
                     73: 
1.1.1.2 ! misho      74:        if (stringjoin(rel, backup_dir_remainder, fname, backup_suffix, NULL) >= backup_dir_remainder) {
        !            75:                rprintf(FERROR, "backup filename too long\n");
        !            76:                *name = '\0';
        !            77:                return False;
        !            78:        }
1.1       misho      79: 
1.1.1.2 ! misho      80:        for ( ; ; name = b + 1) {
        !            81:                if ((b = strchr(name, '/')) == NULL)
        !            82:                        return True;
        !            83:                *b = '\0';
1.1       misho      84: 
1.1.1.2 ! misho      85:                val = validate_backup_dir();
        !            86:                if (val == 0)
        !            87:                        break;
        !            88:                if (val < 0) {
        !            89:                        *name = '\0';
        !            90:                        return False;
1.1       misho      91:                }
1.1.1.2 ! misho      92: 
        !            93:                *b = '/';
1.1       misho      94:        }
                     95: 
1.1.1.2 ! misho      96:        init_stat_x(&sx);
        !            97: 
        !            98:        for ( ; b; name = b + 1, b = strchr(name, '/')) {
        !            99:                *b = '\0';
        !           100: 
        !           101:                while (do_mkdir(backup_dir_buf, ACCESSPERMS) < 0) {
        !           102:                        if (errno == EEXIST) {
        !           103:                                val = validate_backup_dir();
        !           104:                                if (val > 0)
        !           105:                                        break;
        !           106:                                if (val == 0)
1.1       misho     107:                                        continue;
1.1.1.2 ! misho     108:                        } else
        !           109:                                rsyserr(FERROR, errno, "backup mkdir %s failed", backup_dir_buf);
        !           110:                        *name = '\0';
        !           111:                        ret = False;
        !           112:                        goto cleanup;
        !           113:                }
        !           114: 
        !           115:                /* Try to transfer the directory settings of the actual dir
        !           116:                 * that the files are coming from. */
        !           117:                if (x_stat(rel, &sx.st, NULL) < 0)
        !           118:                        rsyserr(FERROR, errno, "backup stat %s failed", full_fname(rel));
        !           119:                else {
        !           120:                        struct file_struct *file;
        !           121:                        if (!(file = make_file(rel, NULL, NULL, 0, NO_FILTERS)))
        !           122:                                continue;
1.1       misho     123: #ifdef SUPPORT_ACLS
1.1.1.2 ! misho     124:                        if (preserve_acls && !S_ISLNK(file->mode)) {
        !           125:                                get_acl(rel, &sx);
        !           126:                                cache_tmp_acl(file, &sx);
        !           127:                                free_acl(&sx);
        !           128:                        }
1.1       misho     129: #endif
                    130: #ifdef SUPPORT_XATTRS
1.1.1.2 ! misho     131:                        if (preserve_xattrs) {
        !           132:                                get_xattr(rel, &sx);
        !           133:                                cache_tmp_xattr(file, &sx);
        !           134:                                free_xattr(&sx);
        !           135:                        }
1.1       misho     136: #endif
1.1.1.2 ! misho     137:                        set_file_attrs(backup_dir_buf, file, NULL, NULL, 0);
        !           138:                        unmake_file(file);
        !           139:                }
        !           140: 
        !           141:                *b = '/';
        !           142:        }
        !           143: 
        !           144:   cleanup:
        !           145: 
1.1       misho     146: #ifdef SUPPORT_ACLS
1.1.1.2 ! misho     147:        uncache_tmp_acls();
1.1       misho     148: #endif
                    149: #ifdef SUPPORT_XATTRS
1.1.1.2 ! misho     150:        uncache_tmp_xattrs();
1.1       misho     151: #endif
1.1.1.2 ! misho     152: 
        !           153:        return ret;
        !           154: }
        !           155: 
        !           156: /* Make a complete pathname for backup file and verify any new path elements. */
        !           157: char *get_backup_name(const char *fname)
        !           158: {
        !           159:        if (backup_dir) {
        !           160:                /* copy fname into backup_dir_buf while validating the dirs. */
        !           161:                if (copy_valid_path(fname))
        !           162:                        return backup_dir_buf;
        !           163:                /* copy_valid_path() has printed an error message. */
        !           164:                return NULL;
1.1       misho     165:        }
                    166: 
1.1.1.2 ! misho     167:        if (stringjoin(backup_dir_buf, MAXPATHLEN, fname, backup_suffix, NULL) < MAXPATHLEN)
        !           168:                return backup_dir_buf;
        !           169: 
        !           170:        rprintf(FERROR, "backup filename too long\n");
        !           171:        return NULL;
1.1       misho     172: }
                    173: 
1.1.1.2 ! misho     174: /* Has same return codes as make_backup(). */
        !           175: static inline int link_or_rename(const char *from, const char *to,
        !           176:                                 BOOL prefer_rename, STRUCT_STAT *stp)
1.1       misho     177: {
1.1.1.2 ! misho     178: #ifdef SUPPORT_HARD_LINKS
        !           179:        if (!prefer_rename) {
        !           180: #ifndef CAN_HARDLINK_SYMLINK
        !           181:                if (S_ISLNK(stp->st_mode))
        !           182:                        return 0; /* Use copy code. */
        !           183: #endif
        !           184: #ifndef CAN_HARDLINK_SPECIAL
        !           185:                if (IS_SPECIAL(stp->st_mode) || IS_DEVICE(stp->st_mode))
        !           186:                        return 0; /* Use copy code. */
        !           187: #endif
        !           188:                if (do_link(from, to) == 0) {
        !           189:                        if (DEBUG_GTE(BACKUP, 1))
        !           190:                                rprintf(FINFO, "make_backup: HLINK %s successful.\n", from);
        !           191:                        return 2;
        !           192:                }
        !           193:                /* We prefer to rename a regular file rather than copy it. */
        !           194:                if (!S_ISREG(stp->st_mode) || errno == EEXIST || errno == EISDIR)
        !           195:                        return 0;
        !           196:        }
        !           197: #endif
        !           198:        if (do_rename(from, to) == 0) {
        !           199:                if (stp->st_nlink > 1 && !S_ISDIR(stp->st_mode)) {
        !           200:                        /* If someone has hard-linked the file into the backup
        !           201:                         * dir, rename() might return success but do nothing! */
        !           202:                        robust_unlink(from); /* Just in case... */
1.1       misho     203:                }
1.1.1.2 ! misho     204:                if (DEBUG_GTE(BACKUP, 1))
        !           205:                        rprintf(FINFO, "make_backup: RENAME %s successful.\n", from);
        !           206:                return 1;
1.1       misho     207:        }
                    208:        return 0;
                    209: }
                    210: 
1.1.1.2 ! misho     211: /* Hard-link, rename, or copy an item to the backup name.  Returns 2 if item
        !           212:  * was duplicated into backup area, 1 if item was moved, or 0 for failure.*/
        !           213: int make_backup(const char *fname, BOOL prefer_rename)
1.1       misho     214: {
                    215:        stat_x sx;
                    216:        struct file_struct *file;
1.1.1.2 ! misho     217:        int save_preserve_xattrs;
        !           218:        char *buf = get_backup_name(fname);
        !           219:        int ret = 0;
1.1       misho     220: 
1.1.1.2 ! misho     221:        if (!buf)
        !           222:                return 0;
        !           223: 
        !           224:        init_stat_x(&sx);
        !           225:        /* Return success if no file to keep. */
1.1       misho     226:        if (x_lstat(fname, &sx.st, NULL) < 0)
                    227:                return 1;
                    228: 
1.1.1.2 ! misho     229:        /* Try a hard-link or a rename first.  Using rename is not atomic, but
        !           230:         * is more efficient than forcing a copy for larger files when no hard-
        !           231:         * linking is possible. */
        !           232:        if ((ret = link_or_rename(fname, buf, prefer_rename, &sx.st)) != 0)
        !           233:                goto success;
        !           234:        if (errno == EEXIST || errno == EISDIR) {
        !           235:                STRUCT_STAT bakst;
        !           236:                if (do_lstat(buf, &bakst) == 0) {
        !           237:                        int flags = get_del_for_flag(bakst.st_mode) | DEL_FOR_BACKUP | DEL_RECURSE;
        !           238:                        if (delete_item(buf, bakst.st_mode, flags) != 0)
        !           239:                                return 0;
        !           240:                }
        !           241:                if ((ret = link_or_rename(fname, buf, prefer_rename, &sx.st)) != 0)
        !           242:                        goto success;
1.1       misho     243:        }
                    244: 
1.1.1.2 ! misho     245:        /* Fall back to making a copy. */
        !           246:        if (!(file = make_file(fname, NULL, &sx.st, 0, NO_FILTERS)))
        !           247:                return 1; /* the file could have disappeared */
        !           248: 
1.1       misho     249: #ifdef SUPPORT_ACLS
                    250:        if (preserve_acls && !S_ISLNK(file->mode)) {
                    251:                get_acl(fname, &sx);
                    252:                cache_tmp_acl(file, &sx);
                    253:                free_acl(&sx);
                    254:        }
                    255: #endif
                    256: #ifdef SUPPORT_XATTRS
                    257:        if (preserve_xattrs) {
                    258:                get_xattr(fname, &sx);
                    259:                cache_tmp_xattr(file, &sx);
                    260:                free_xattr(&sx);
                    261:        }
                    262: #endif
                    263: 
                    264:        /* Check to see if this is a device file, or link */
                    265:        if ((am_root && preserve_devices && IS_DEVICE(file->mode))
                    266:         || (preserve_specials && IS_SPECIAL(file->mode))) {
1.1.1.2 ! misho     267:                if (do_mknod(buf, file->mode, sx.st.st_rdev) < 0)
        !           268:                        rsyserr(FERROR, errno, "mknod %s failed", full_fname(buf));
        !           269:                else if (DEBUG_GTE(BACKUP, 1))
        !           270:                        rprintf(FINFO, "make_backup: DEVICE %s successful.\n", fname);
        !           271:                ret = 2;
1.1       misho     272:        }
                    273: 
                    274: #ifdef SUPPORT_LINKS
1.1.1.2 ! misho     275:        if (!ret && preserve_links && S_ISLNK(file->mode)) {
1.1       misho     276:                const char *sl = F_SYMLINK(file);
                    277:                if (safe_symlinks && unsafe_symlink(sl, fname)) {
1.1.1.2 ! misho     278:                        if (INFO_GTE(SYMSAFE, 1)) {
1.1       misho     279:                                rprintf(FINFO, "not backing up unsafe symlink \"%s\" -> \"%s\"\n",
                    280:                                        fname, sl);
                    281:                        }
1.1.1.2 ! misho     282:                        ret = 2;
1.1       misho     283:                } else {
1.1.1.2 ! misho     284:                        if (do_symlink(sl, buf) < 0)
        !           285:                                rsyserr(FERROR, errno, "link %s -> \"%s\"", full_fname(buf), sl);
        !           286:                        else if (DEBUG_GTE(BACKUP, 1))
        !           287:                                rprintf(FINFO, "make_backup: SYMLINK %s successful.\n", fname);
        !           288:                        ret = 2;
1.1       misho     289:                }
                    290:        }
                    291: #endif
                    292: 
1.1.1.2 ! misho     293:        if (!ret && !S_ISREG(file->mode)) {
        !           294:                rprintf(FINFO, "make_bak: skipping non-regular file %s\n", fname);
1.1       misho     295:                unmake_file(file);
                    296: #ifdef SUPPORT_ACLS
                    297:                uncache_tmp_acls();
                    298: #endif
                    299: #ifdef SUPPORT_XATTRS
                    300:                uncache_tmp_xattrs();
                    301: #endif
1.1.1.2 ! misho     302:                return 2;
1.1       misho     303:        }
                    304: 
1.1.1.2 ! misho     305:        /* Copy to backup tree if a file. */
        !           306:        if (!ret) {
        !           307:                if (copy_file(fname, buf, -1, file->mode) < 0) {
1.1       misho     308:                        rsyserr(FERROR, errno, "keep_backup failed: %s -> \"%s\"",
                    309:                                full_fname(fname), buf);
1.1.1.2 ! misho     310:                        unmake_file(file);
        !           311: #ifdef SUPPORT_ACLS
        !           312:                        uncache_tmp_acls();
        !           313: #endif
        !           314: #ifdef SUPPORT_XATTRS
        !           315:                        uncache_tmp_xattrs();
        !           316: #endif
        !           317:                        return 0;
1.1       misho     318:                }
1.1.1.2 ! misho     319:                if (DEBUG_GTE(BACKUP, 1))
        !           320:                        rprintf(FINFO, "make_backup: COPY %s successful.\n", fname);
        !           321:                ret = 2;
1.1       misho     322:        }
1.1.1.2 ! misho     323: 
        !           324:        save_preserve_xattrs = preserve_xattrs;
1.1       misho     325:        preserve_xattrs = 0;
                    326:        set_file_attrs(buf, file, NULL, fname, 0);
                    327:        preserve_xattrs = save_preserve_xattrs;
1.1.1.2 ! misho     328: 
1.1       misho     329:        unmake_file(file);
                    330: #ifdef SUPPORT_ACLS
                    331:        uncache_tmp_acls();
                    332: #endif
                    333: #ifdef SUPPORT_XATTRS
                    334:        uncache_tmp_xattrs();
                    335: #endif
                    336: 
1.1.1.2 ! misho     337:   success:
        !           338:        if (INFO_GTE(BACKUP, 1))
        !           339:                rprintf(FINFO, "backed up %s to %s\n", fname, buf);
        !           340:        return ret;
1.1       misho     341: }

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