Manpage improvements for --stats, --human-readable, and --list-only.
[rsync/rsync.git] / backup.c
index 8512e00..e535e6f 100644 (file)
--- a/backup.c
+++ b/backup.c
@@ -34,6 +34,26 @@ extern char backup_dir_buf[MAXPATHLEN];
 extern char *backup_suffix;
 extern char *backup_dir;
 
+/* Returns -1 on error, 0 on missing dir, and 1 on present dir. */
+static int validate_backup_dir(void)
+{
+       STRUCT_STAT st;
+
+       if (do_lstat(backup_dir_buf, &st) < 0) {
+               if (errno == ENOENT)
+                       return 0;
+               rsyserr(FERROR, errno, "backup lstat %s failed", backup_dir_buf);
+               return -1;
+       }
+       if (!S_ISDIR(st.st_mode)) {
+               int flags = get_del_for_flag(st.st_mode) | DEL_FOR_BACKUP | DEL_RECURSE;
+               if (delete_item(backup_dir_buf, st.st_mode, flags) == 0)
+                       return 0;
+               return -1;
+       }
+       return 1;
+}
+
 /* Create a backup path from the given fname, putting the result into
  * backup_dir_buf.  Any new directories (compared to the prior backup
  * path) are ensured to exist as directories, replacing anything else
@@ -41,7 +61,7 @@ extern char *backup_dir;
 static BOOL copy_valid_path(const char *fname)
 {
        const char *f;
-       int flags;
+       int val;
        BOOL ret = True;
        stat_x sx;
        char *b, *rel = backup_dir_buf + backup_dir_len, *name = rel;
@@ -62,17 +82,10 @@ static BOOL copy_valid_path(const char *fname)
                        return True;
                *b = '\0';
 
-               if (do_lstat(backup_dir_buf, &sx.st) < 0) {
-                       if (errno == ENOENT)
-                               break;
-                       rsyserr(FERROR, errno, "backup lstat %s failed", backup_dir_buf);
-                       *name = '\0';
-                       return False;
-               }
-               if (!S_ISDIR(sx.st.st_mode)) {
-                       flags = get_del_for_flag(sx.st.st_mode) | DEL_FOR_BACKUP | DEL_RECURSE;
-                       if (delete_item(backup_dir_buf, sx.st.st_mode, flags) == 0)
-                               break;
+               val = validate_backup_dir();
+               if (val == 0)
+                       break;
+               if (val < 0) {
                        *name = '\0';
                        return False;
                }
@@ -85,11 +98,18 @@ static BOOL copy_valid_path(const char *fname)
        for ( ; b; name = b + 1, b = strchr(name, '/')) {
                *b = '\0';
 
-               if (mkdir_defmode(backup_dir_buf) < 0) {
-                       rsyserr(FERROR, errno, "backup mkdir %s failed", backup_dir_buf);
+               while (do_mkdir(backup_dir_buf, ACCESSPERMS) < 0) {
+                       if (errno == EEXIST) {
+                               val = validate_backup_dir();
+                               if (val > 0)
+                                       break;
+                               if (val == 0)
+                                       continue;
+                       } else
+                               rsyserr(FERROR, errno, "backup mkdir %s failed", backup_dir_buf);
                        *name = '\0';
                        ret = False;
-                       break;
+                       goto cleanup;
                }
 
                /* Try to transfer the directory settings of the actual dir
@@ -121,6 +141,8 @@ static BOOL copy_valid_path(const char *fname)
                *b = '/';
        }
 
+  cleanup:
+
 #ifdef SUPPORT_ACLS
        uncache_tmp_acls();
 #endif
@@ -138,13 +160,13 @@ char *get_backup_name(const char *fname)
                /* copy fname into backup_dir_buf while validating the dirs. */
                if (copy_valid_path(fname))
                        return backup_dir_buf;
+               /* copy_valid_path() has printed an error message. */
                return NULL;
-       } else {
-               if (stringjoin(backup_dir_buf, MAXPATHLEN,
-                              fname, backup_suffix, NULL) < MAXPATHLEN)
-                       return backup_dir_buf;
        }
 
+       if (stringjoin(backup_dir_buf, MAXPATHLEN, fname, backup_suffix, NULL) < MAXPATHLEN)
+               return backup_dir_buf;
+
        rprintf(FERROR, "backup filename too long\n");
        return NULL;
 }
@@ -254,8 +276,8 @@ int make_backup(const char *fname, BOOL prefer_rename)
                const char *sl = F_SYMLINK(file);
                if (safe_symlinks && unsafe_symlink(sl, fname)) {
                        if (INFO_GTE(SYMSAFE, 1)) {
-                               rprintf(FINFO, "ignoring unsafe symlink %s -> %s\n",
-                                       full_fname(buf), sl);
+                               rprintf(FINFO, "not backing up unsafe symlink \"%s\" -> \"%s\"\n",
+                                       fname, sl);
                        }
                        ret = 2;
                } else {