Fixed get_xattr_acl() -- it needed to zero *len_p.
[rsync/rsync.git] / receiver.c
index d09296d..a05d204 100644 (file)
@@ -60,7 +60,7 @@ extern struct filter_list_struct server_filter_list;
 static struct bitbag *delayed_bits = NULL;
 static int phase = 0, redoing = 0;
 /* We're either updating the basis file or an identical copy: */
-static int updating_basis;
+static int updating_basis_or_equiv;
 
 /*
  * get_tmpname() - create a tmp filename for a given filename
@@ -83,10 +83,10 @@ static int updating_basis;
  *   As long as it's unique, rsync will work.
  */
 
-int get_tmpname(char *fnametmp, char *fname)
+int get_tmpname(char *fnametmp, const char *fname)
 {
        int maxname, added, length = 0;
-       char *f;
+       const char *f;
 
        if (tmpdir) {
                /* Note: this can't overflow, so the return value is safe */
@@ -123,6 +123,43 @@ int get_tmpname(char *fnametmp, char *fname)
        return 1;
 }
 
+/* Opens a temporary file for writing.
+ * Success: Writes name into fnametmp, returns fd.
+ * Failure: Clobbers fnametmp, returns -1.
+ * Calling cleanup_set() is the caller's job. */
+int open_tmpfile(char *fnametmp, const char *fname, struct file_struct *file)
+{
+       int fd;
+
+       if (!get_tmpname(fnametmp, fname))
+               return -1;
+
+       /* We initially set the perms without the setuid/setgid bits or group
+        * access to ensure that there is no race condition.  They will be
+        * correctly updated after the right owner and group info is set.
+        * (Thanks to snabb@epipe.fi for pointing this out.) */
+       fd = do_mkstemp(fnametmp, file->mode & INITACCESSPERMS);
+
+#if 0
+       /* In most cases parent directories will already exist because their
+        * information should have been previously transferred, but that may
+        * not be the case with -R */
+       if (fd == -1 && relative_paths && errno == ENOENT
+           && create_directory_path(fnametmp) == 0) {
+               /* Get back to name with XXXXXX in it. */
+               get_tmpname(fnametmp, fname);
+               fd = do_mkstemp(fnametmp, file->mode & INITACCESSPERMS);
+       }
+#endif
+
+       if (fd == -1) {
+               rsyserr(FERROR, errno, "mkstemp %s failed",
+                       full_fname(fnametmp));
+               return -1;
+       }
+
+       return fd;
+}
 
 static int receive_data(int f_in, char *fname_r, int fd_r, OFF_T size_r,
                        const char *fname, int fd, OFF_T total_size)
@@ -222,7 +259,7 @@ static int receive_data(int f_in, char *fname_r, int fd_r, OFF_T size_r,
                        sum_update(map, len);
                }
 
-               if (updating_basis) {
+               if (updating_basis_or_equiv) {
                        if (offset == offset2 && fd != -1) {
                                OFF_T pos;
                                if (flush_write_file(fd) < 0)
@@ -516,14 +553,18 @@ int recv_files(int f_in, char *local_name)
                                break;
                        }
                        if (!fnamecmp || (server_filter_list.head
-                         && check_filter(&server_filter_list, fname, 0) < 0))
+                         && check_filter(&server_filter_list, fname, 0) < 0)) {
                                fnamecmp = fname;
+                               fnamecmp_type = FNAMECMP_FNAME;
+                       }
                } else {
                        /* Reminder: --inplace && --partial-dir are never
                         * enabled at the same time. */
                        if (inplace && make_backups > 0) {
                                if (!(fnamecmp = get_backup_name(fname)))
                                        fnamecmp = fname;
+                               else
+                                       fnamecmp_type = FNAMECMP_BACKUP;
                        } else if (partial_dir && partialptr)
                                fnamecmp = partialptr;
                        else
@@ -549,7 +590,9 @@ int recv_files(int f_in, char *local_name)
                                fd1 = do_open(fnamecmp, O_RDONLY, 0);
                        }
                }
-               updating_basis = inplace && fnamecmp == fname;
+
+               updating_basis_or_equiv = inplace
+                   && (fnamecmp == fname || fnamecmp_type == FNAMECMP_BACKUP);
 
                if (fd1 == -1) {
                        st.st_mode = 0;
@@ -606,52 +649,20 @@ int recv_files(int f_in, char *local_name)
                        if (fd2 == -1) {
                                rsyserr(FERROR, errno, "open %s failed",
                                        full_fname(fname));
-                               discard_receive_data(f_in, F_LENGTH(file));
-                               if (fd1 != -1)
-                                       close(fd1);
-                               if (inc_recurse)
-                                       send_msg_int(MSG_NO_SEND, ndx);
-                               continue;
                        }
                } else {
-                       if (!get_tmpname(fnametmp,fname)) {
-                               discard_receive_data(f_in, F_LENGTH(file));
-                               if (fd1 != -1)
-                                       close(fd1);
-                               if (inc_recurse)
-                                       send_msg_int(MSG_NO_SEND, ndx);
-                               continue;
-                       }
-
-                       /* we initially set the perms without the
-                        * setuid/setgid bits to ensure that there is no race
-                        * condition. They are then correctly updated after
-                        * the lchown. Thanks to snabb@epipe.fi for pointing
-                        * this out.  We also set it initially without group
-                        * access because of a similar race condition. */
-                       fd2 = do_mkstemp(fnametmp, file->mode & INITACCESSPERMS);
-
-                       /* in most cases parent directories will already exist
-                        * because their information should have been previously
-                        * transferred, but that may not be the case with -R */
-                       if (fd2 == -1 && relative_paths && errno == ENOENT
-                           && create_directory_path(fnametmp) == 0) {
-                               /* Get back to name with XXXXXX in it. */
-                               get_tmpname(fnametmp, fname);
-                               fd2 = do_mkstemp(fnametmp, file->mode & INITACCESSPERMS);
-                       }
-                       if (fd2 == -1) {
-                               rsyserr(FERROR, errno, "mkstemp %s failed",
-                                       full_fname(fnametmp));
-                               discard_receive_data(f_in, F_LENGTH(file));
-                               if (fd1 != -1)
-                                       close(fd1);
-                               if (inc_recurse)
-                                       send_msg_int(MSG_NO_SEND, ndx);
-                               continue;
-                       }
+                       fd2 = open_tmpfile(fnametmp, fname, file);
+                       if (fd2 != -1)
+                               cleanup_set(fnametmp, partialptr, file, fd1, fd2);
+               }
 
-                       cleanup_set(fnametmp, partialptr, file, fd1, fd2);
+               if (fd2 == -1) {
+                       discard_receive_data(f_in, F_LENGTH(file));
+                       if (fd1 != -1)
+                               close(fd1);
+                       if (inc_recurse)
+                               send_msg_int(MSG_NO_SEND, ndx);
+                       continue;
                }
 
                /* log the transfer */