Bump the year to 2014.
[rsync.git] / rsync.c
diff --git a/rsync.c b/rsync.c
index c42d55352e1917ec5052c20418e9eedba8bf8dae..c498c44fdc013a56c3a385691fcb8294f3fccab9 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-2009 Wayne Davison
+ * Copyright (C) 2003-2014 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
@@ -35,12 +35,14 @@ extern int preserve_executability;
 extern int preserve_times;
 extern int am_root;
 extern int am_server;
+extern int am_daemon;
 extern int am_sender;
 extern int am_receiver;
 extern int am_generator;
 extern int am_starting_up;
 extern int allow_8bit_chars;
 extern int protocol_version;
+extern int got_kill_signal;
 extern int inc_recurse;
 extern int inplace;
 extern int flist_eof;
@@ -209,11 +211,16 @@ int iconvbufs(iconv_t ic, xbuf *in, xbuf *out, int flags)
                        if (errno == EINVAL) {
                                if (!(flags & ICB_INCLUDE_INCOMPLETE))
                                        goto finish;
+                               if (!ocnt)
+                                       goto e2big;
                        } else if (errno == EILSEQ) {
                                if (!(flags & ICB_INCLUDE_BAD))
                                        goto finish;
+                               if (!ocnt)
+                                       goto e2big;
                        } else if (errno == E2BIG) {
                                size_t siz;
+                         e2big:
                                opos = obuf - out->buf;
                                if (flags & ICB_CIRCULAR_OUT && out->pos > 1 && opos > out->pos) {
                                        /* We are in a divided circular buffer at the physical
@@ -241,6 +248,8 @@ int iconvbufs(iconv_t ic, xbuf *in, xbuf *out, int flags)
                        }
                        *obuf++ = *ibuf++;
                        ocnt--, icnt--;
+                       if (!icnt)
+                               break;
                }
        }
 
@@ -480,31 +489,6 @@ int set_file_attrs(const char *fname, struct file_struct *file, stat_x *sxp,
                get_acl(fname, sxp);
 #endif
 
-#ifdef SUPPORT_XATTRS
-       if (am_root < 0)
-               set_stat_xattr(fname, file, new_mode);
-       if (preserve_xattrs && fnamecmp)
-               set_xattr(fname, file, fnamecmp, sxp);
-#endif
-
-       if (!preserve_times
-        || (!(preserve_times & PRESERVE_DIR_TIMES) && S_ISDIR(sxp->st.st_mode))
-        || (!(preserve_times & PRESERVE_LINK_TIMES) && S_ISLNK(sxp->st.st_mode)))
-               flags |= ATTRS_SKIP_MTIME;
-       if (!(flags & ATTRS_SKIP_MTIME)
-           && cmp_time(sxp->st.st_mtime, file->modtime) != 0) {
-               int ret = set_modtime(fname, file->modtime, F_MOD_NSEC(file), sxp->st.st_mode);
-               if (ret < 0) {
-                       rsyserr(FERROR_XFER, errno, "failed to set times on %s",
-                               full_fname(fname));
-                       goto cleanup;
-               }
-               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);
        change_gid = gid_ndx && !(file->flags & FLAG_SKIP_GROUP)
                  && sxp->st.st_gid != (gid_t)F_GROUP(file);
@@ -552,6 +536,31 @@ int set_file_attrs(const char *fname, struct file_struct *file, stat_x *sxp,
                updated = 1;
        }
 
+#ifdef SUPPORT_XATTRS
+       if (am_root < 0)
+               set_stat_xattr(fname, file, new_mode);
+       if (preserve_xattrs && fnamecmp)
+               set_xattr(fname, file, fnamecmp, sxp);
+#endif
+
+       if (!preserve_times
+        || (!(preserve_times & PRESERVE_DIR_TIMES) && S_ISDIR(sxp->st.st_mode))
+        || (!(preserve_times & PRESERVE_LINK_TIMES) && S_ISLNK(sxp->st.st_mode)))
+               flags |= ATTRS_SKIP_MTIME;
+       if (!(flags & ATTRS_SKIP_MTIME)
+           && cmp_time(sxp->st.st_mtime, file->modtime) != 0) {
+               int ret = set_modtime(fname, file->modtime, F_MOD_NSEC(file), sxp->st.st_mode);
+               if (ret < 0) {
+                       rsyserr(FERROR_XFER, errno, "failed to set times on %s",
+                               full_fname(fname));
+                       goto cleanup;
+               }
+               if (ret == 0) /* ret == 1 if symlink could not be set */
+                       updated = 1;
+               else
+                       file->flags |= FLAG_TIME_FAILED;
+       }
+
 #ifdef SUPPORT_ACLS
        /* It's OK to call set_acl() now, even for a dir, as the generator
         * will enable owner-writability using chmod, if necessary.
@@ -586,20 +595,13 @@ int set_file_attrs(const char *fname, struct file_struct *file, stat_x *sxp,
                        rprintf(FCLIENT, "%s is uptodate\n", fname);
        }
   cleanup:
-       if (sxp == &sx2) {
-#ifdef SUPPORT_ACLS
-               if (preserve_acls)
-                       free_acl(&sx2);
-#endif
-#ifdef SUPPORT_XATTRS
-               if (preserve_xattrs)
-                       free_xattr(&sx2);
-#endif
-       }
+       if (sxp == &sx2)
+               free_stat_x(&sx2);
        return updated;
 }
 
-RETSIGTYPE sig_int(UNUSED(int val))
+/* This is only called for SIGINT, SIGHUP, and SIGTERM. */
+RETSIGTYPE sig_int(int sig_num)
 {
        /* KLUGE: if the user hits Ctrl-C while ssh is prompting
         * for a password, then our cleanup's sending of a SIGUSR1
@@ -610,6 +612,23 @@ RETSIGTYPE sig_int(UNUSED(int val))
         * not ssh waiting for a password, then this tiny delay
         * shouldn't hurt anything. */
        msleep(400);
+
+       /* If we're an rsync daemon listener (not a daemon server),
+        * we'll exit with status 0 if we received SIGTERM. */
+       if (am_daemon && !am_server && sig_num == SIGTERM)
+               exit_cleanup(0);
+
+       /* If the signal arrived on the server side (or for the receiver
+        * process on the client), we want to try to do a controlled shutdown
+        * that lets the client side (generator process) know what happened.
+        * To do this, we set a flag and let the normal process handle the
+        * shutdown.  We only attempt this if multiplexed IO is in effect and
+        * we didn't already set the flag. */
+       if (!got_kill_signal && (am_server || am_receiver)) {
+               got_kill_signal = sig_num;
+               return;
+       }
+
        exit_cleanup(RERR_SIGNAL);
 }