Avoid changing file_extra_cnt during deletion.
[rsync/rsync.git] / generator.c
index bec5c17..d17e3b9 100644 (file)
@@ -44,8 +44,6 @@ extern int preserve_hard_links;
 extern int preserve_executability;
 extern int preserve_perms;
 extern int preserve_times;
-extern int uid_ndx;
-extern int gid_ndx;
 extern int delete_mode;
 extern int delete_before;
 extern int delete_during;
@@ -278,7 +276,6 @@ static void delete_in_dir(char *fbuf, struct file_struct *file, dev_t *fs_dev)
        struct file_list *dirlist;
        char delbuf[MAXPATHLEN];
        int dlen, i;
-       int save_uid_ndx = uid_ndx;
 
        if (!fbuf) {
                change_local_filter_dir(NULL, 0, 0);
@@ -310,9 +307,6 @@ static void delete_in_dir(char *fbuf, struct file_struct *file, dev_t *fs_dev)
                        return;
        }
 
-       if (!uid_ndx)
-               uid_ndx = ++file_extra_cnt;
-
        dirlist = get_dirlist(fbuf, dlen, 0);
 
        /* If an item in dirlist is not found in flist, delete it
@@ -332,7 +326,7 @@ static void delete_in_dir(char *fbuf, struct file_struct *file, dev_t *fs_dev)
                 * a delete_item call with a DEL_MAKE_ROOM flag. */
                if (flist_find_ignore_dirness(cur_flist, fp) < 0) {
                        int flags = DEL_RECURSE;
-                       if (!(fp->mode & S_IWUSR) && !am_root && (uid_t)F_OWNER(fp) == our_uid)
+                       if (!(fp->mode & S_IWUSR) && !am_root && fp->flags & FLAG_OWNED_BY_US)
                                flags |= DEL_NO_UID_WRITE;
                        f_name(fp, delbuf);
                        if (delete_during == 2) {
@@ -344,11 +338,6 @@ static void delete_in_dir(char *fbuf, struct file_struct *file, dev_t *fs_dev)
        }
 
        flist_free(dirlist);
-
-       if (!save_uid_ndx) {
-               --file_extra_cnt;
-               uid_ndx = 0;
-       }
 }
 
 /* This deletes any files on the receiving side that are not present on the
@@ -388,46 +377,101 @@ static void do_delete_pass(void)
                rprintf(FINFO, "                    \r");
 }
 
-int unchanged_attrs(const char *fname, struct file_struct *file, stat_x *sxp)
+static inline int time_differs(struct file_struct *file, stat_x *sxp)
 {
-#ifndef CAN_SET_SYMLINK_TIMES
-       if (S_ISLNK(file->mode)) {
-               ;
-       } else
-#endif
-       if (preserve_times && cmp_time(sxp->st.st_mtime, file->modtime) != 0)
-               return 0;
+       return cmp_time(sxp->st.st_mtime, file->modtime);
+}
 
-       if (preserve_perms) {
-               if (!BITS_EQUAL(sxp->st.st_mode, file->mode, CHMOD_BITS))
-                       return 0;
-       } else if (preserve_executability
-        && ((sxp->st.st_mode & 0111 ? 1 : 0) ^ (file->mode & 0111 ? 1 : 0)))
-               return 0;
+static inline int perms_differ(struct file_struct *file, stat_x *sxp)
+{
+       if (preserve_perms)
+               return !BITS_EQUAL(sxp->st.st_mode, file->mode, CHMOD_BITS);
+
+       if (preserve_executability)
+               return (sxp->st.st_mode & 0111 ? 1 : 0) ^ (file->mode & 0111 ? 1 : 0);
+
+       return 0;
+}
 
+static inline int ownership_differs(struct file_struct *file, stat_x *sxp)
+{
        if (am_root && uid_ndx && sxp->st.st_uid != (uid_t)F_OWNER(file))
-               return 0;
+               return 1;
 
        if (gid_ndx && !(file->flags & FLAG_SKIP_GROUP) && sxp->st.st_gid != (gid_t)F_GROUP(file))
-               return 0;
+               return 1;
+
+       return 0;
+}
 
 #ifdef SUPPORT_ACLS
-       if (preserve_acls && !S_ISLNK(file->mode)) {
+static inline int acls_differ(const char *fname, struct file_struct *file, stat_x *sxp)
+{
+       if (preserve_acls) {
                if (!ACL_READY(*sxp))
                        get_acl(fname, sxp);
                if (set_acl(NULL, file, sxp, file->mode))
-                       return 0;
+                       return 1;
        }
+
+       return 0;
+}
 #endif
+
 #ifdef SUPPORT_XATTRS
+static inline int xattrs_differ(const char *fname, struct file_struct *file, stat_x *sxp)
+{
        if (preserve_xattrs) {
                if (!XATTR_READY(*sxp))
                        get_xattr(fname, sxp);
                if (xattr_diff(file, sxp, 0))
-                       return 0;
+                       return 1;
        }
+
+       return 0;
+}
 #endif
 
+int unchanged_attrs(const char *fname, struct file_struct *file, stat_x *sxp)
+{
+       if (S_ISLNK(file->mode)) {
+#ifdef CAN_SET_SYMLINK_TIMES
+               if (preserve_times & PRESERVE_LINK_TIMES && time_differs(file, sxp))
+                       return 0;
+#endif
+#ifdef CAN_CHMOD_SYMLINK
+               if (perms_differ(file, sxp))
+                       return 0;
+#endif
+#ifndef CAN_CHOWN_SYMLINK
+               if (ownership_differs(file, sxp))
+                       return 0;
+#endif
+#if defined SUPPORT_ACLS && 0 /* no current symlink-ACL support */
+               if (acls_differ(fname, file, sxp))
+                       return 0;
+#endif
+#if defined SUPPORT_XATTRS && !defined NO_SYMLINK_XATTRS
+               if (xattrs_differ(fname, file, sxp))
+                       return 0;
+#endif
+       } else {
+               if (preserve_times && time_differs(file, sxp))
+                       return 0;
+               if (perms_differ(file, sxp))
+                       return 0;
+               if (ownership_differs(file, sxp))
+                       return 0;
+#ifdef SUPPORT_ACLS
+               if (acls_differ(fname, file, sxp))
+                       return 0;
+#endif
+#ifdef SUPPORT_XATTRS
+               if (xattrs_differ(fname, file, sxp))
+                       return 0;
+#endif
+       }
+
        return 1;
 }
 
@@ -437,12 +481,9 @@ void itemize(const char *fnamecmp, struct file_struct *file, int ndx, int statre
 {
        if (statret >= 0) { /* A from-dest-dir statret can == 1! */
                int keep_time = !preserve_times ? 0
-                   : S_ISDIR(file->mode) ? preserve_times > 1 :
-#ifdef CAN_SET_SYMLINK_TIMES
-                   1;
-#else
-                   !S_ISLNK(file->mode);
-#endif
+                   : S_ISDIR(file->mode) ? preserve_times & PRESERVE_DIR_TIMES
+                   : S_ISLNK(file->mode) ? preserve_times & PRESERVE_LINK_TIMES
+                   : 1;
 
                if (S_ISREG(file->mode) && F_LENGTH(file) != sxp->st.st_size)
                        iflags |= ITEM_REPORT_SIZE;
@@ -567,6 +608,12 @@ static void sum_sizes_sqroot(struct sum_struct *sum, int64 len)
        int s2length;
        int64 l;
 
+       if (len < 0) {
+               /* The file length overflowed our int64 var, so we can't process this file. */
+               sum->count = -1; /* indicate overflow error */
+               return;
+       }
+
        if (block_size)
                blength = block_size;
        else if (len <= BLOCK_SIZE * BLOCK_SIZE)
@@ -1032,7 +1079,7 @@ static void list_file_entry(struct file_struct *f)
 #ifdef SUPPORT_LINKS
        if (preserve_links && S_ISLNK(f->mode)) {
                rprintf(FINFO, "%s %*s %s %s -> %s\n",
-                       permbuf, colwidth, comma_num(len),
+                       permbuf, colwidth, human_num(len),
                        timestring(f->modtime), f_name(f, NULL),
                        F_SYMLINK(f));
        } else
@@ -1043,7 +1090,7 @@ static void list_file_entry(struct file_struct *f)
                        f_name(f, NULL));
        } else {
                rprintf(FINFO, "%s %*s %s %s\n",
-                       permbuf, colwidth, comma_num(len),
+                       permbuf, colwidth, human_num(len),
                        timestring(f->modtime), f_name(f, NULL));
        }
 }
@@ -1119,6 +1166,7 @@ static void recv_generator(char *fname, struct file_struct *file, int ndx,
                skip_dir = NULL;
        }
 
+       init_stat_x(&sx);
        if (daemon_filter_list.head && (*fname != '.' || fname[1])) {
                if (check_filter(&daemon_filter_list, FLOG, fname, is_dir) < 0) {
                        if (is_dir < 0)
@@ -1136,7 +1184,6 @@ static void recv_generator(char *fname, struct file_struct *file, int ndx,
                }
        }
 
-       init_stat_x(&sx);
        if (dry_run > 1 || (dry_missing_dir && is_below(file, dry_missing_dir))) {
          parent_is_dry_missing:
                if (fuzzy_dirlist) {
@@ -1175,7 +1222,7 @@ static void recv_generator(char *fname, struct file_struct *file, int ndx,
 
                if (need_fuzzy_dirlist && S_ISREG(file->mode)) {
                        strlcpy(fnamecmpbuf, dn, sizeof fnamecmpbuf);
-                       fuzzy_dirlist = get_dirlist(fnamecmpbuf, -1, 1);
+                       fuzzy_dirlist = get_dirlist(fnamecmpbuf, -1, GDL_IGNORE_FILTER_RULES);
                        need_fuzzy_dirlist = 0;
                }
 
@@ -1224,9 +1271,18 @@ static void recv_generator(char *fname, struct file_struct *file, int ndx,
                goto cleanup;
        }
 
+       fnamecmp = fname;
+
        if (is_dir) {
+               mode_t added_perms;
                if (!implied_dirs && file->flags & FLAG_IMPLIED_DIR)
                        goto cleanup;
+               if (am_root < 0) {
+                       /* For --fake-super, the dir must be useable by the copying
+                        * user, just like it would be for root. */
+                       added_perms = S_IRUSR|S_IWUSR|S_IXUSR;
+               } else
+                       added_perms = 0;
                if (is_dir < 0) {
                        /* In inc_recurse mode we want to make sure any missing
                         * directories get created while we're still processing
@@ -1237,7 +1293,7 @@ static void recv_generator(char *fname, struct file_struct *file, int ndx,
                         && (S_ISDIR(sx.st.st_mode)
                          || delete_item(fname, sx.st.st_mode, del_opts | DEL_FOR_DIR) != 0))
                                goto cleanup; /* Any errors get reported later. */
-                       if (do_mkdir(fname, file->mode & 0700) == 0)
+                       if (do_mkdir(fname, (file->mode|added_perms) & 0700) == 0)
                                file->flags |= FLAG_DIR_CREATED;
                        goto cleanup;
                }
@@ -1271,17 +1327,19 @@ static void recv_generator(char *fname, struct file_struct *file, int ndx,
                                itemizing = 0;
                                code = FNONE;
                                statret = 1;
-                       } else if (j >= 0)
+                       } else if (j >= 0) {
                                statret = 1;
+                               fnamecmp = fnamecmpbuf;
+                       }
                }
                if (itemizing && f_out != -1) {
-                       itemize(fname, file, ndx, statret, &sx,
+                       itemize(fnamecmp, file, ndx, statret, &sx,
                                statret ? ITEM_LOCAL_CHANGE : 0, 0, NULL);
                }
-               if (real_ret != 0 && do_mkdir(fname,file->mode) < 0 && errno != EEXIST) {
+               if (real_ret != 0 && do_mkdir(fname,file->mode|added_perms) < 0 && errno != EEXIST) {
                        if (!relative_paths || errno != ENOENT
                         || make_path(fname, MKP_DROP_NAME | MKP_SKIP_SLASH) < 0
-                        || (do_mkdir(fname, file->mode) < 0 && errno != EEXIST)) {
+                        || (do_mkdir(fname, file->mode|added_perms) < 0 && errno != EEXIST)) {
                                rsyserr(FERROR_XFER, errno,
                                        "recv_generator: mkdir %s failed",
                                        full_fname(fname));
@@ -1354,10 +1412,11 @@ static void recv_generator(char *fname, struct file_struct *file, int ndx,
                const char *sl = F_SYMLINK(file);
                if (safe_symlinks && unsafe_symlink(sl, fname)) {
                        if (INFO_GTE(NAME, 1)) {
-                               if (solo_file)
+                               if (solo_file) {
                                        /* fname contains the destination path, but we
                                         * want to report the source path. */
                                        fname = f_name(file, NULL);
+                               }
                                rprintf(FINFO,
                                        "ignoring unsafe symlink \"%s\" -> \"%s\"\n",
                                        fname, sl);
@@ -1531,7 +1590,6 @@ static void recv_generator(char *fname, struct file_struct *file, int ndx,
                goto cleanup;
        }
 
-       fnamecmp = fname;
        fnamecmp_type = FNAMECMP_FNAME;
 
        if (statret == 0 && !S_ISREG(sx.st.st_mode)) {
@@ -2049,7 +2107,7 @@ void generate_files(int f_out, const char *local_name)
        }
        solo_file = local_name;
        dir_tweaking = !(list_only || solo_file || dry_run);
-       need_retouch_dir_times = preserve_times > 1;
+       need_retouch_dir_times = preserve_times & PRESERVE_DIR_TIMES;
        loopchk_limit = allowed_lull ? allowed_lull * 5 : 200;
        symlink_timeset_failed_flags = ITEM_REPORT_TIME
            | (protocol_version >= 30 || !am_server ? ITEM_REPORT_TIMEFAIL : 0);