Always include lib/snprintf.o when we include lib/compat.o.
[rsync/rsync.git] / receiver.c
index fcde60f..3618ed1 100644 (file)
@@ -22,7 +22,6 @@
 
 extern int verbose;
 extern int recurse;
-extern int delete_mode;
 extern int delete_after;
 extern int max_delete;
 extern int csum_length;
@@ -38,6 +37,7 @@ extern int preserve_perms;
 extern int cvs_exclude;
 extern int io_error;
 extern char *tmpdir;
+extern char *partial_dir;
 extern char *compare_dest;
 extern int make_backups;
 extern int do_progress;
@@ -62,20 +62,18 @@ static void delete_one(char *fn, int is_dir)
                        rsyserr(FERROR, errno, "delete_one: unlink %s failed",
                                full_fname(fn));
                } else if (verbose)
-                       rprintf(FINFO, "deleting %s\n", fn);
+                       rprintf(FINFO, "deleting %s\n", safe_fname(fn));
        } else {
                if (do_rmdir(fn) != 0) {
-                       if (errno == ENOTDIR && keep_dirlinks) {
-                               delete_one(fn, 0);
-                               return;
-                       }
                        if (errno != ENOTEMPTY && errno != EEXIST) {
                                rsyserr(FERROR, errno,
                                        "delete_one: rmdir %s failed",
                                        full_fname(fn));
                        }
-               } else if (verbose)
-                       rprintf(FINFO, "deleting directory %s\n", fn);
+               } else if (verbose) {
+                       rprintf(FINFO, "deleting directory %s\n",
+                               safe_fname(fn));
+               }
        }
 }
 
@@ -115,23 +113,25 @@ void delete_files(struct file_list *flist)
                        continue;
 
                if (verbose > 1)
-                       rprintf(FINFO, "deleting in %s\n", fbuf);
+                       rprintf(FINFO, "deleting in %s\n", safe_fname(fbuf));
 
                for (i = local_file_list->count-1; i >= 0; i--) {
-                       if (max_delete && deletion_count > max_delete)
+                       if (max_delete && deletion_count >= max_delete)
                                break;
                        if (!local_file_list->files[i]->basename)
                                continue;
                        if (flist_find(flist,local_file_list->files[i]) < 0) {
                                char *f = f_name(local_file_list->files[i]);
-                               if (make_backups && (backup_dir || !is_backup_file(f))) {
+                               int mode = local_file_list->files[i]->mode;
+                               if (make_backups && (backup_dir || !is_backup_file(f))
+                                 && !S_ISDIR(mode)) {
                                        make_backup(f);
-                                       if (verbose)
-                                               rprintf(FINFO, "deleting %s\n", f);
-                               } else {
-                                       int mode = local_file_list->files[i]->mode;
+                                       if (verbose) {
+                                               rprintf(FINFO, "deleting %s\n",
+                                                       safe_fname(f));
+                                       }
+                               } else
                                        delete_one(f, S_ISDIR(mode) != 0);
-                               }
                                deletion_count++;
                        }
                }
@@ -218,10 +218,11 @@ static int receive_data(int f_in, char *fname_r, int fd_r, OFF_T size_r,
        read_sum_head(f_in, &sum);
 
        if (fd_r >= 0 && size_r > 0) {
-               mapbuf = map_file(fd_r, size_r, sum.blength);
+               OFF_T map_size = MAX(sum.blength * 2, 16*1024);
+               mapbuf = map_file(fd_r, size_r, map_size, sum.blength);
                if (verbose > 2) {
                        rprintf(FINFO, "recv mapped %s of size %.0f\n",
-                               fname_r, (double)size_r);
+                               safe_fname(fname_r), (double)size_r);
                }
        } else
                mapbuf = NULL;
@@ -243,11 +244,8 @@ static int receive_data(int f_in, char *fname_r, int fd_r, OFF_T size_r,
 
                        sum_update(data,i);
 
-                       if (fd != -1 && write_file(fd,data,i) != i) {
-                               rsyserr(FERROR, errno, "write failed on %s",
-                                       full_fname(fname));
-                               exit_cleanup(RERR_FILEIO);
-                       }
+                       if (fd != -1 && write_file(fd,data,i) != i)
+                               goto report_write_error;
                        offset += i;
                        continue;
                }
@@ -271,29 +269,29 @@ static int receive_data(int f_in, char *fname_r, int fd_r, OFF_T size_r,
                        sum_update(map,len);
                }
 
-               if (!inplace || offset != offset2) {
-                       if (fd != -1 && write_file(fd, map, len) != (int)len) {
-                               rsyserr(FERROR, errno, "write failed on %s",
-                                       full_fname(fname));
-                               exit_cleanup(RERR_FILEIO);
-                       }
-               } else {
-                       flush_write_file(fd);
-                       if (do_lseek(fd,(OFF_T)len,SEEK_CUR) != offset+len) {
-                               rprintf(FERROR, "lseek failed on %s: %s, %lli, %lli, %i\n",
-                                       full_fname(fname), strerror(errno),
-                                       do_lseek(fd, 0, SEEK_CUR),
-                                       offset + len, i);
-                               exit_cleanup(RERR_FILEIO);
+               if (inplace) {
+                       if (offset == offset2 && fd != -1) {
+                               if (flush_write_file(fd) < 0)
+                                       goto report_write_error;
+                               offset += len;
+                               if (do_lseek(fd, len, SEEK_CUR) != offset) {
+                                       rsyserr(FERROR, errno,
+                                               "lseek failed on %s",
+                                               full_fname(fname));
+                                       exit_cleanup(RERR_FILEIO);
+                               }
+                               continue;
                        }
                }
+               if (fd != -1 && write_file(fd, map, len) != (int)len)
+                       goto report_write_error;
                offset += len;
        }
 
        flush_write_file(fd);
 
 #ifdef HAVE_FTRUNCATE
-       if (inplace)
+       if (inplace && fd != -1)
                ftruncate(fd, offset);
 #endif
 
@@ -301,6 +299,7 @@ static int receive_data(int f_in, char *fname_r, int fd_r, OFF_T size_r,
                end_progress(total_size);
 
        if (fd != -1 && offset > 0 && sparse_end(fd) != 0) {
+           report_write_error:
                rsyserr(FERROR, errno, "write failed on %s",
                        full_fname(fname));
                exit_cleanup(RERR_FILEIO);
@@ -338,7 +337,7 @@ int recv_files(int f_in, struct file_list *flist, char *local_name)
        char *fname, fbuf[MAXPATHLEN];
        char template[MAXPATHLEN];
        char fnametmp[MAXPATHLEN];
-       char *fnamecmp;
+       char *fnamecmp, *partialptr;
        char fnamecmpbuf[MAXPATHLEN];
        struct file_struct *file;
        struct stats initial_stats;
@@ -396,17 +395,15 @@ int recv_files(int f_in, struct file_list *flist, char *local_name)
                        fname = f_name_to(file, fbuf);
 
                if (dry_run) {
-                       if (!am_server && verbose)
-                               rprintf(FINFO, "%s\n", fname);
+                       if (!am_server && verbose) /* log the transfer */
+                               rprintf(FINFO, "%s\n", safe_fname(fname));
                        continue;
                }
 
                initial_stats = stats;
 
                if (verbose > 2)
-                       rprintf(FINFO,"recv_files(%s)\n",fname);
-
-               fnamecmp = fname;
+                       rprintf(FINFO, "recv_files(%s)\n", safe_fname(fname));
 
                if (read_batch) {
                        while (i > next_gen_i) {
@@ -416,7 +413,7 @@ int recv_files(int f_in, struct file_list *flist, char *local_name)
                        }
                        if (i < next_gen_i) {
                                rprintf(FINFO, "skipping update for \"%s\"\n",
-                                       fname);
+                                       safe_fname(fname));
                                discard_receive_data(f_in, file->length);
                                continue;
                        }
@@ -425,18 +422,31 @@ int recv_files(int f_in, struct file_list *flist, char *local_name)
                if (server_exclude_list.head
                    && check_exclude(&server_exclude_list, fname,
                                     S_ISDIR(file->mode)) < 0) {
-                       if (verbose) {
-                               rprintf(FINFO,
-                                       "skipping server-excluded update for \"%s\"\n",
-                                       fname);
-                       }
-                       discard_receive_data(f_in, file->length);
-                       continue;
+                       rprintf(FERROR, "attempt to hack rsync failed.\n");
+                       exit_cleanup(RERR_PROTOCOL);
+               }
+
+               if (partial_dir) {
+                       if ((partialptr = partial_dir_fname(fname)) != NULL)
+                               fnamecmp = partialptr;
+                       else
+                               fnamecmp = fname;
+               } else
+                       fnamecmp = partialptr = fname;
+
+               if (inplace && make_backups) {
+                       if (!(fnamecmp = get_backup_name(fname)))
+                               fnamecmp = partialptr;
                }
 
                /* open the file */
                fd1 = do_open(fnamecmp, O_RDONLY, 0);
 
+               if (fd1 == -1 && fnamecmp != fname) {
+                       fnamecmp = fname;
+                       fd1 = do_open(fnamecmp, O_RDONLY, 0);
+               }
+
                if (fd1 == -1 && compare_dest != NULL) {
                        /* try the file at compare_dest instead */
                        pathjoin(fnamecmpbuf, sizeof fnamecmpbuf,
@@ -480,10 +490,10 @@ int recv_files(int f_in, struct file_list *flist, char *local_name)
 
                /* We now check to see if we are writing file "inplace" */
                if (inplace)  {
-                       fd2 = do_open(fnamecmp, O_WRONLY|O_CREAT, 0);
+                       fd2 = do_open(fname, O_WRONLY|O_CREAT, 0);
                        if (fd2 == -1) {
                                rsyserr(FERROR, errno, "open %s failed",
-                                       full_fname(fnamecmp));
+                                       full_fname(fname));
                                discard_receive_data(f_in, file->length);
                                if (fd1 != -1)
                                        close(fd1);
@@ -524,11 +534,12 @@ int recv_files(int f_in, struct file_list *flist, char *local_name)
                                continue;
                        }
 
-                       cleanup_set(fnametmp, fname, file, fd1, fd2);
+                       if (partialptr)
+                               cleanup_set(fnametmp, partialptr, file, fd1, fd2);
                }
 
-               if (!am_server && verbose)
-                       rprintf(FINFO, "%s\n", fname);
+               if (!am_server && verbose) /* log the transfer */
+                       rprintf(FINFO, "%s\n", safe_fname(fname));
 
                /* recv file data */
                recv_ok = receive_data(f_in, fnamecmp, fd1, st.st_size,
@@ -544,21 +555,48 @@ int recv_files(int f_in, struct file_list *flist, char *local_name)
                        exit_cleanup(RERR_FILEIO);
                }
 
-               if (recv_ok || keep_partial)
+               if (recv_ok || inplace)
                        finish_transfer(fname, fnametmp, file, recv_ok);
-               else
+               else if (keep_partial && partialptr
+                   && handle_partial_dir(partialptr, PDIR_CREATE))
+                       finish_transfer(partialptr, fnametmp, file, 0);
+               else {
+                       partialptr = NULL;
                        do_unlink(fnametmp);
+               }
+
+               if (partialptr != fname && fnamecmp == partialptr && recv_ok) {
+                       do_unlink(partialptr);
+                       handle_partial_dir(partialptr, PDIR_DELETE);
+               }
 
                cleanup_disable();
 
                if (!recv_ok) {
-                       if (csum_length == SUM_LENGTH) {
-                               rprintf(FERROR,"ERROR: file corruption in %s. File changed during transfer?\n",
-                                       full_fname(fname));
-                       } else {
+                       int msgtype = csum_length == SUM_LENGTH || read_batch ?
+                               FERROR : FINFO;
+                       if (msgtype == FERROR || verbose) {
+                               char *errstr, *redostr, *keptstr;
+                               if (!(keep_partial && partialptr) && !inplace)
+                                       keptstr = "discarded";
+                               else if (partial_dir)
+                                       keptstr = "put into partial-dir";
+                               else
+                                       keptstr = "retained";
+                               if (msgtype == FERROR) {
+                                       errstr = "ERROR";
+                                       redostr = "";
+                               } else {
+                                       errstr = "WARNING";
+                                       redostr = " (will try again)";
+                               }
+                               rprintf(msgtype,
+                                       "%s: %s failed verification -- update %s%s.\n",
+                                       errstr, safe_fname(fname),
+                                       keptstr, redostr);
+                       }
+                       if (csum_length != SUM_LENGTH) {
                                char buf[4];
-                               if (verbose > 1)
-                                       rprintf(FINFO,"redoing %s(%d)\n",fname,i);
                                SIVAL(buf, 0, i);
                                send_msg(MSG_REDO, buf, 4);
                        }