Fixed several issues with preserving xattrs when using --backup.
[rsync/rsync.git] / rsync.c
diff --git a/rsync.c b/rsync.c
index 7505c63..9921da0 100644 (file)
--- a/rsync.c
+++ b/rsync.c
@@ -3,7 +3,7 @@
  *
  * Copyright (C) 1996 Andrew Tridgell
  * Copyright (C) 1996 Paul Mackerras
- * Copyright (C) 2003-2007 Wayne Davison
+ * Copyright (C) 2003-2008 Wayne Davison
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -205,6 +205,42 @@ int iconvbufs(iconv_t ic, xbuf *in, xbuf *out, int flags)
 }
 #endif
 
+void send_protected_args(int fd, char *args[])
+{
+       int i;
+#ifdef ICONV_OPTION
+       int convert = ic_send != (iconv_t)-1;
+       xbuf outbuf, inbuf;
+
+       if (convert)
+               alloc_xbuf(&outbuf, 1024);
+#endif
+
+       for (i = 0; args[i]; i++) {} /* find first NULL */
+       args[i] = "rsync"; /* set a new arg0 */
+       if (verbose > 1)
+               print_child_argv("protected args:", args + i + 1);
+       do {
+#ifdef ICONV_OPTION
+               if (convert) {
+                       INIT_XBUF_STRLEN(inbuf, args[i]);
+                       iconvbufs(ic_send, &inbuf, &outbuf,
+                                 ICB_EXPAND_OUT | ICB_INCLUDE_BAD | ICB_INCLUDE_INCOMPLETE);
+                       outbuf.buf[outbuf.len] = '\0';
+                       write_buf(fd, outbuf.buf, outbuf.len + 1);
+                       outbuf.len = 0;
+               } else
+#endif
+                       write_buf(fd, args[i], strlen(args[i]) + 1);
+       } while (args[++i]);
+       write_byte(fd, 0);
+
+#ifdef ICONV_OPTION
+       if (convert)
+               free(outbuf.buf);
+#endif
+}
+
 int read_ndx_and_attrs(int f_in, int *iflag_ptr, uchar *type_ptr,
                       char *buf, int *len_ptr)
 {
@@ -399,6 +435,8 @@ int set_file_attrs(const char *fname, struct file_struct *file, stat_x *sxp,
                }
                if (ret == 0) /* ret == 1 if symlink could not be set */
                        updated = 1;
+               else
+                       file->flags |= FLAG_TIME_FAILED;
        }
 
        change_uid = am_root && uid_ndx && sxp->st.st_uid != (uid_t)F_OWNER(file);
@@ -422,24 +460,24 @@ int set_file_attrs(const char *fname, struct file_struct *file, stat_x *sxp,
                                        fname, (unsigned)sxp->st.st_gid, F_GROUP(file));
                        }
                }
-               if (am_root < 0) {
-                       ;
-               } else if (do_lchown(fname,
-                   change_uid ? (uid_t)F_OWNER(file) : sxp->st.st_uid,
-                   change_gid ? (gid_t)F_GROUP(file) : sxp->st.st_gid) != 0) {
-                       /* shouldn't have attempted to change uid or gid
-                        * unless have the privilege */
-                       rsyserr(FERROR_XFER, errno, "%s %s failed",
-                           change_uid ? "chown" : "chgrp",
-                           full_fname(fname));
-                       goto cleanup;
-               } else
-               /* a lchown had been done - we have to re-stat if the
-                * destination had the setuid or setgid bits set due
-                * to the side effect of the chown call */
-               if (sxp->st.st_mode & (S_ISUID | S_ISGID)) {
-                       link_stat(fname, &sxp->st,
-                                 keep_dirlinks && S_ISDIR(sxp->st.st_mode));
+               if (am_root >= 0) {
+                       if (do_lchown(fname,
+                           change_uid ? (uid_t)F_OWNER(file) : sxp->st.st_uid,
+                           change_gid ? (gid_t)F_GROUP(file) : sxp->st.st_gid) != 0) {
+                               /* We shouldn't have attempted to change uid
+                                * or gid unless have the privilege. */
+                               rsyserr(FERROR_XFER, errno, "%s %s failed",
+                                   change_uid ? "chown" : "chgrp",
+                                   full_fname(fname));
+                               goto cleanup;
+                       }
+                       /* A lchown had been done, so we need to re-stat if
+                        * the destination had the setuid or setgid bits set
+                        * (due to the side effect of the chown call). */
+                       if (sxp->st.st_mode & (S_ISUID | S_ISGID)) {
+                               link_stat(fname, &sxp->st,
+                                         keep_dirlinks && S_ISDIR(sxp->st.st_mode));
+                       }
                }
                updated = 1;
        }
@@ -523,8 +561,11 @@ int finish_transfer(const char *fname, const char *fnametmp,
                goto do_set_file_attrs;
        }
 
-       if (make_backups > 0 && overwriting_basis && !make_backup(fname))
-               return 1;
+       if (make_backups > 0 && overwriting_basis) {
+               if (!make_backup(fname))
+                       return 1;
+               fnamecmp = get_backup_name(fname);
+       }
 
        /* Change permissions before putting the file into place. */
        set_file_attrs(fnametmp, file, NULL, fnamecmp,