Make idev, hlink and file_struct + strings use allocation
[rsync/rsync.git] / backup.c
index a824474..248ae90 100644 (file)
--- a/backup.c
+++ b/backup.c
@@ -25,22 +25,25 @@ extern int backup_suffix_len;
 extern int backup_dir_len;
 extern char *backup_suffix;
 extern char *backup_dir;
+extern struct file_struct **hlink_list;
 
 extern int am_root;
 extern int preserve_devices;
 extern int preserve_links;
 extern int preserve_hard_links;
+extern int orig_umask;
 
 /* simple backup creates a backup with a suffix in the same directory */
 static int make_simple_backup(char *fname)
 {
        char fnamebak[MAXPATHLEN];
-       if (strlen(fname) + backup_suffix_len > MAXPATHLEN-1) {
+
+       if (stringjoin(fnamebak, sizeof fnamebak, fname, backup_suffix, NULL)
+           >= sizeof fnamebak) {
                rprintf(FERROR, "backup filename too long\n");
                return 0;
        }
 
-       snprintf(fnamebak, sizeof(fnamebak), "%s%s", fname, backup_suffix);
        if (do_rename(fname, fnamebak) != 0) {
                /* cygwin (at least version b19) reports EINVAL */
                if (errno != ENOENT && errno != EINVAL) {
@@ -87,20 +90,20 @@ static int make_bak_dir(char *fname, char *bak_path)
        STRUCT_STAT st;
        STRUCT_STAT *st2;
        char fullpath[MAXPATHLEN];
-       extern int orig_umask;
        char *p;
        char *q;
 
        while(strncmp(bak_path, "./", 2) == 0) bak_path += 2;
 
-       if (bak_path[strlen(bak_path)-1] != '/') {
-               snprintf(fullpath, sizeof(fullpath), "%s/", bak_path);
-       } else {
-               snprintf(fullpath, sizeof(fullpath), "%s", bak_path);
+       if (pathjoin(fullpath, sizeof fullpath, bak_path, fname)
+           >= sizeof fullpath) {
+               rprintf(FERROR, "backup dirname too long\n");
+               return 0;
        }
        p = fullpath;
-       q = &fullpath[strlen(fullpath)];  /* End of bak_path string */
-       strcat(fullpath, fname);
+       q = fullpath + strlen(bak_path);
+       if (*q == '/')
+               q++; /* Point past the middle '/' added by pathjoin(). */
 
        /* Make the directories */
        while ((p = strchr(p, '/')) != NULL) {
@@ -125,8 +128,7 @@ static int make_bak_dir(char *fname, char *bak_path)
                                }
                        }
                }
-               *p = '/';
-               p++;
+               *p++ = '/';
        }
        return 0;
 }
@@ -175,13 +177,10 @@ static int robust_move(char *src, char *dst)
    We will move the file to be deleted into a parallel directory tree */
 static int keep_backup(char *fname)
 {
-
        static int initialised;
-
-       char keep_name [MAXPATHLEN];
+       char keep_name[MAXPATHLEN];
        STRUCT_STAT st;
        struct file_struct *file;
-
        int kept = 0;
        int ret_code;
 
@@ -190,6 +189,7 @@ static int keep_backup(char *fname)
                        backup_dir[--backup_dir_len] = '\0';
                if (verbose > 0)
                        rprintf(FINFO, "backup_dir is %s\n", backup_dir);
+
                initialised = 1;
        }
 
@@ -206,20 +206,19 @@ static int keep_backup(char *fname)
        if (!file) return 1;
 
        /* make a complete pathname for backup file */
-       if (backup_dir_len+strlen(fname)+backup_suffix_len > MAXPATHLEN-1) {
+       if (stringjoin(keep_name, sizeof keep_name,
+                      backup_dir, "/", fname, backup_suffix, NULL)
+           >= sizeof keep_name) {
                rprintf(FERROR, "keep_backup filename too long\n");
                return 0;
        }
 
-       snprintf(keep_name, sizeof (keep_name), "%s/%s%s",
-           backup_dir, fname, backup_suffix);
-
 #ifdef HAVE_MKNOD
        /* Check to see if this is a device file, or link */
        if (IS_DEVICE(file->mode)) {
                if (am_root && preserve_devices) {
                        make_bak_dir(fname, backup_dir);
-                       if (do_mknod(keep_name, file->mode, file->rdev) != 0) {
+                       if (do_mknod(keep_name, file->mode, file->u.rdev) != 0) {
                                rprintf(FERROR, "mknod %s failed: %s\n",
                                        full_fname(keep_name), strerror(errno));
                        } else if (verbose > 2) {
@@ -249,23 +248,24 @@ static int keep_backup(char *fname)
 #if SUPPORT_LINKS
        if (!kept && preserve_links && S_ISLNK(file->mode)) {
                extern int safe_symlinks;
-               if (safe_symlinks && unsafe_symlink(file->link, keep_name)) {
+               if (safe_symlinks && unsafe_symlink(file->u.link, keep_name)) {
                        if (verbose) {
                                rprintf(FINFO, "ignoring unsafe symlink %s -> %s\n",
-                                       full_fname(keep_name), file->link);
+                                       full_fname(keep_name), file->u.link);
                        }
                        kept = 1;
                }
                make_bak_dir(fname, backup_dir);
-               if (do_symlink(file->link, keep_name) != 0) {
+               if (do_symlink(file->u.link, keep_name) != 0) {
                        rprintf(FERROR, "link %s -> %s : %s\n",
-                               full_fname(keep_name), file->link, strerror(errno));
+                               full_fname(keep_name), file->u.link, strerror(errno));
                }
                do_unlink(fname);
                kept = 1;
        }
 #endif
-       if (!kept && preserve_hard_links && check_hard_link(file)) {
+       if (!kept && preserve_hard_links && file->link_u.links
+           && hlink_list[file->F_HLINDEX] != file) {
                if (verbose > 1)
                        rprintf(FINFO, "%s is a hard link\n", f_name(file));
        }
@@ -283,7 +283,6 @@ static int keep_backup(char *fname)
                }
        }
        set_perms(keep_name, file, NULL, 0);
-       free_file(file);
        free(file);
 
        if (verbose > 1)