The improved --xattrs option is landing on the trunk.
[rsync/rsync.git] / generator.c
index e80daf2..09c6b7d 100644 (file)
@@ -36,6 +36,7 @@ extern int relative_paths;
 extern int implied_dirs;
 extern int keep_dirlinks;
 extern int preserve_acls;
+extern int preserve_xattrs;
 extern int preserve_links;
 extern int preserve_devices;
 extern int preserve_specials;
@@ -532,11 +533,19 @@ int unchanged_attrs(const char *fname, struct file_struct *file, statx *sxp)
                        return 0;
        }
 #endif
+#ifdef SUPPORT_XATTRS
+       if (preserve_xattrs) {
+               if (!XATTR_READY(*sxp))
+                       get_xattr(fname, sxp);
+               if (xattr_diff(file, sxp, 0))
+                       return 0;
+       }
+#endif
 
        return 1;
 }
 
-void itemize(const char *fname, struct file_struct *file, int ndx, int statret,
+void itemize(const char *fnamecmp, struct file_struct *file, int ndx, int statret,
             statx *sxp, int32 iflags, uchar fnamecmp_type,
             const char *xname)
 {
@@ -562,16 +571,29 @@ void itemize(const char *fname, struct file_struct *file, int ndx, int statret,
 #ifdef SUPPORT_ACLS
                if (preserve_acls && !S_ISLNK(file->mode)) {
                        if (!ACL_READY(*sxp))
-                               get_acl(fname, sxp);
+                               get_acl(fnamecmp, sxp);
                        if (set_acl(NULL, file, sxp) == 0)
                                iflags |= ITEM_REPORT_ACL;
                }
 #endif
-       } else
+#ifdef SUPPORT_XATTRS
+               if (preserve_xattrs) {
+                       if (!XATTR_READY(*sxp))
+                               get_xattr(fnamecmp, sxp);
+                       if (xattr_diff(file, sxp, 1))
+                               iflags |= ITEM_REPORT_XATTR;
+               }
+#endif
+       } else {
+#ifdef SUPPORT_XATTRS
+               if (preserve_xattrs && xattr_diff(file, NULL, 1))
+                       iflags |= ITEM_REPORT_XATTR;
+#endif
                iflags |= ITEM_IS_NEW;
+       }
 
        iflags &= 0xffff;
-       if ((iflags & SIGNIFICANT_ITEM_FLAGS || verbose > 1
+       if ((iflags & (SIGNIFICANT_ITEM_FLAGS|ITEM_REPORT_XATTR) || verbose > 1
          || stdout_format_has_i > 1 || (xname && *xname)) && !read_batch) {
                if (protocol_version >= 29) {
                        if (ndx >= 0)
@@ -581,6 +603,10 @@ void itemize(const char *fname, struct file_struct *file, int ndx, int statret,
                                write_byte(sock_f_out, fnamecmp_type);
                        if (iflags & ITEM_XNAME_FOLLOWS)
                                write_vstring(sock_f_out, xname, strlen(xname));
+#ifdef SUPPORT_XATTRS
+                       if (iflags & ITEM_REPORT_XATTR && !dry_run)
+                               send_xattr_request(NULL, file, sock_f_out);
+#endif
                } else if (ndx >= 0) {
                        enum logcode code = logfile_format_has_i ? FINFO : FCLIENT;
                        log_item(code, file, &stats, iflags, xname);
@@ -598,7 +624,7 @@ int unchanged_file(char *fn, struct file_struct *file, STRUCT_STAT *st)
        /* if always checksum is set then we use the checksum instead
           of the file time to determine whether to sync */
        if (always_checksum > 0 && S_ISREG(st->st_mode)) {
-               char sum[MD4_SUM_LENGTH];
+               char sum[MAX_DIGEST_LEN];
                file_checksum(fn, sum, st->st_size);
                return memcmp(sum, F_SUM(file), checksum_len) == 0;
        }
@@ -855,14 +881,14 @@ static int try_dests_reg(struct file_struct *file, char *fname, int ndx,
                        if (preserve_hard_links && F_IS_HLINKED(file))
                                finish_hard_link(file, fname, &sxp->st, itemizing, code, j);
                        if (itemizing && (verbose > 1 || stdout_format_has_i > 1)) {
-                               itemize(fname, file, ndx, 1, sxp,
+                               itemize(cmpbuf, file, ndx, 1, sxp,
                                        ITEM_LOCAL_CHANGE | ITEM_XNAME_FOLLOWS,
                                        0, "");
                        }
                } else
 #endif
                if (itemizing)
-                       itemize(fname, file, ndx, 0, sxp, 0, 0, NULL);
+                       itemize(cmpbuf, file, ndx, 0, sxp, 0, 0, NULL);
                if (verbose > 1 && maybe_ATTRS_REPORT)
                        rprintf(FCLIENT, "%s is uptodate\n", fname);
                return -2;
@@ -879,9 +905,13 @@ static int try_dests_reg(struct file_struct *file, char *fname, int ndx,
                        }
                        return -1;
                }
+               set_file_attrs(fname, file, NULL, cmpbuf, 0);
                if (itemizing)
-                       itemize(fname, file, ndx, 0, sxp, ITEM_LOCAL_CHANGE, 0, NULL);
-               set_file_attrs(fname, file, NULL, 0);
+                       itemize(cmpbuf, file, ndx, 0, sxp, ITEM_LOCAL_CHANGE, 0, NULL);
+#ifdef SUPPORT_XATTRS
+               if (preserve_xattrs)
+                       xattr_clear_locals(file);
+#endif
                if (maybe_ATTRS_REPORT
                 && ((!itemizing && verbose && match_level == 2)
                  || (verbose > 1 && match_level == 3))) {
@@ -1029,7 +1059,7 @@ static int try_dests_non(struct file_struct *file, char *fname, int ndx,
                            : ITEM_LOCAL_CHANGE
                             + (match_level == 3 ? ITEM_XNAME_FOLLOWS : 0);
                        char *lp = match_level == 3 ? "" : NULL;
-                       itemize(fname, file, ndx, 0, sxp, chg + ITEM_MATCHED, 0, lp);
+                       itemize(cmpbuf, file, ndx, 0, sxp, chg + ITEM_MATCHED, 0, lp);
                }
                if (verbose > 1 && maybe_ATTRS_REPORT) {
                        rprintf(FCLIENT, "%s%s is uptodate\n",
@@ -1111,6 +1141,9 @@ static void recv_generator(char *fname, struct file_struct *file, int ndx,
        }
 #ifdef SUPPORT_ACLS
        sx.acc_acl = sx.def_acl = NULL;
+#endif
+#ifdef SUPPORT_XATTRS
+       sx.xattr = NULL;
 #endif
        if (dry_run > 1) {
                if (fuzzy_dirlist) {
@@ -1224,7 +1257,7 @@ static void recv_generator(char *fname, struct file_struct *file, int ndx,
                                goto cleanup;
                        }
                }
-               if (set_file_attrs(fname, file, real_ret ? NULL : &real_sx, 0)
+               if (set_file_attrs(fname, file, real_ret ? NULL : &real_sx, NULL, 0)
                    && verbose && code != FNONE && f_out != -1)
                        rprintf(code, "%s/\n", fname);
                if (real_ret != 0 && one_file_system)
@@ -1278,9 +1311,9 @@ static void recv_generator(char *fname, struct file_struct *file, int ndx,
                        else if ((len = readlink(fname, lnk, MAXPATHLEN-1)) > 0
                              && strncmp(lnk, sl, len) == 0 && sl[len] == '\0') {
                                /* The link is pointing to the right place. */
+                               set_file_attrs(fname, file, &sx, NULL, maybe_ATTRS_REPORT);
                                if (itemizing)
                                        itemize(fname, file, ndx, 0, &sx, 0, 0, NULL);
-                               set_file_attrs(fname, file, &sx, maybe_ATTRS_REPORT);
 #ifdef SUPPORT_HARD_LINKS
                                if (preserve_hard_links && F_IS_HLINKED(file))
                                        finish_hard_link(file, fname, &sx.st, itemizing, code, -1);
@@ -1317,7 +1350,7 @@ static void recv_generator(char *fname, struct file_struct *file, int ndx,
                        rsyserr(FERROR, errno, "symlink %s -> \"%s\" failed",
                                full_fname(fname), sl);
                } else {
-                       set_file_attrs(fname, file, NULL, 0);
+                       set_file_attrs(fname, file, NULL, NULL, 0);
                        if (itemizing) {
                                itemize(fname, file, ndx, statret, &sx,
                                        ITEM_LOCAL_CHANGE, 0, NULL);
@@ -1357,9 +1390,9 @@ static void recv_generator(char *fname, struct file_struct *file, int ndx,
                         && BITS_EQUAL(sx.st.st_mode, file->mode, _S_IFMT)
                         && sx.st.st_rdev == rdev) {
                                /* The device or special file is identical. */
+                               set_file_attrs(fname, file, &sx, NULL, maybe_ATTRS_REPORT);
                                if (itemizing)
                                        itemize(fname, file, ndx, 0, &sx, 0, 0, NULL);
-                               set_file_attrs(fname, file, &sx, maybe_ATTRS_REPORT);
 #ifdef SUPPORT_HARD_LINKS
                                if (preserve_hard_links && F_IS_HLINKED(file))
                                        finish_hard_link(file, fname, &sx.st, itemizing, code, -1);
@@ -1399,7 +1432,7 @@ static void recv_generator(char *fname, struct file_struct *file, int ndx,
                        rsyserr(FERROR, errno, "mknod %s failed",
                                full_fname(fname));
                } else {
-                       set_file_attrs(fname, file, NULL, 0);
+                       set_file_attrs(fname, file, NULL, NULL, 0);
                        if (itemizing) {
                                itemize(fname, file, ndx, statret, &sx,
                                        ITEM_LOCAL_CHANGE, 0, NULL);
@@ -1529,9 +1562,9 @@ static void recv_generator(char *fname, struct file_struct *file, int ndx,
                        do_unlink(partialptr);
                        handle_partial_dir(partialptr, PDIR_DELETE);
                }
+               set_file_attrs(fname, file, &sx, NULL, maybe_ATTRS_REPORT);
                if (itemizing)
                        itemize(fnamecmp, file, ndx, statret, &sx, 0, 0, NULL);
-               set_file_attrs(fname, file, &sx, maybe_ATTRS_REPORT);
 #ifdef SUPPORT_HARD_LINKS
                if (preserve_hard_links && F_IS_HLINKED(file))
                        finish_hard_link(file, fname, &sx.st, itemizing, code, -1);
@@ -1635,6 +1668,10 @@ static void recv_generator(char *fname, struct file_struct *file, int ndx,
 #ifdef SUPPORT_ACLS
                if (preserve_acls)
                        free_acl(&real_sx);
+#endif
+#ifdef SUPPORT_XATTRS
+               if (preserve_xattrs)
+                       free_xattr(&real_sx);
 #endif
        }
 
@@ -1657,7 +1694,7 @@ static void recv_generator(char *fname, struct file_struct *file, int ndx,
 
        if (f_copy >= 0) {
                close(f_copy);
-               set_file_attrs(backupptr, back_file, NULL, 0);
+               set_file_attrs(backupptr, back_file, NULL, NULL, 0);
                if (verbose > 1) {
                        rprintf(FINFO, "backed up %s to %s\n",
                                fname, backupptr);
@@ -1671,6 +1708,10 @@ static void recv_generator(char *fname, struct file_struct *file, int ndx,
 #ifdef SUPPORT_ACLS
        if (preserve_acls)
                free_acl(&sx);
+#endif
+#ifdef SUPPORT_XATTRS
+       if (preserve_xattrs)
+               free_xattr(&sx);
 #endif
        return;
 }
@@ -1902,8 +1943,10 @@ void generate_files(int f_out, const char *local_name)
                        break;
                }
 
-               while (!cur_flist->next && !flist_eof) {
+               while (1) {
                        check_for_finished_files(itemizing, code, 1);
+                       if (cur_flist->next || flist_eof)
+                               break;
                        wait_for_receiver();
                }
        } while ((cur_flist = cur_flist->next) != NULL);
@@ -1914,8 +1957,10 @@ void generate_files(int f_out, const char *local_name)
        if (verbose > 2)
                rprintf(FINFO, "generate_files phase=%d\n", phase);
 
-       while (!msgdone_cnt) {
+       while (1) {
                check_for_finished_files(itemizing, code, 1);
+               if (msgdone_cnt)
+                       break;
                wait_for_receiver();
        }
 
@@ -1929,8 +1974,10 @@ void generate_files(int f_out, const char *local_name)
                write_ndx(f_out, NDX_DONE);
 
        /* Read MSG_DONE for the redo phase (and any prior messages). */
-       while (msgdone_cnt <= 1) {
+       while (1) {
                check_for_finished_files(itemizing, code, 0);
+               if (msgdone_cnt > 1)
+                       break;
                wait_for_receiver();
        }