If there is no lchown(), don't try to set the user & group of a symlink.
[rsync/rsync.git] / receiver.c
index 059f762..f10f25d 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;
@@ -31,6 +30,7 @@ extern int dry_run;
 extern int read_batch;
 extern int batch_gen_fd;
 extern int am_server;
+extern int protocol_version;
 extern int relative_paths;
 extern int keep_dirlinks;
 extern int preserve_hard_links;
@@ -38,7 +38,8 @@ extern int preserve_perms;
 extern int cvs_exclude;
 extern int io_error;
 extern char *tmpdir;
-extern char *compare_dest;
+extern char *partial_dir;
+extern char *basis_dir[];
 extern int make_backups;
 extern int do_progress;
 extern char *backup_dir;
@@ -65,10 +66,6 @@ static void delete_one(char *fn, int is_dir)
                        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",
@@ -120,22 +117,22 @@ void delete_files(struct file_list *flist)
                        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",
                                                        safe_fname(f));
                                        }
-                               } else {
-                                       int mode = local_file_list->files[i]->mode;
+                               } else
                                        delete_one(f, S_ISDIR(mode) != 0);
-                               }
                                deletion_count++;
                        }
                }
@@ -212,17 +209,18 @@ static int receive_data(int f_in, char *fname_r, int fd_r, OFF_T size_r,
        static char file_sum2[MD4_SUM_LENGTH];
        struct map_struct *mapbuf;
        struct sum_struct sum;
-       unsigned int len;
+       int32 len;
        OFF_T offset = 0;
-       OFF_T offset2, seekto = 0;
+       OFF_T offset2;
        char *data;
-       int i;
+       int32 i;
        char *map = NULL;
 
        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((OFF_T)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",
                                safe_fname(fname_r), (double)size_r);
@@ -245,61 +243,56 @@ static int receive_data(int f_in, char *fname_r, int fd_r, OFF_T size_r,
                        stats.literal_data += i;
                        cleanup_got_literal = 1;
 
-                       sum_update(data,i);
+                       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;
                }
 
                i = -(i+1);
-               offset2 = i*(OFF_T)sum.blength;
+               offset2 = i * (OFF_T)sum.blength;
                len = sum.blength;
                if (i == (int)sum.count-1 && sum.remainder != 0)
                        len = sum.remainder;
 
                stats.matched_data += len;
 
-               if (verbose > 3)
-                       rprintf(FINFO,"chunk[%d] of size %d at %.0f offset=%.0f\n",
-                               i,len,(double)offset2,(double)offset);
+               if (verbose > 3) {
+                       rprintf(FINFO,
+                               "chunk[%d] of size %ld at %.0f offset=%.0f\n",
+                               i, (long)len, (double)offset2, (double)offset);
+               }
 
                if (mapbuf) {
                        map = map_ptr(mapbuf,offset2,len);
 
                        see_token(map, len);
-                       sum_update(map,len);
+                       sum_update(map, len);
                }
 
                if (inplace) {
-                       if (offset == offset2) {
-                               seekto = offset += len;
-                               continue;
-                       }
-                       if (seekto && fd != -1) {
-                               flush_write_file(fd);
-                               if (do_lseek(fd, seekto, SEEK_SET) != seekto) {
+                       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);
                                }
-                               seekto = 0;
+                               continue;
                        }
                }
-               if (fd != -1 && write_file(fd, map, len) != (int)len) {
-                       rsyserr(FERROR, errno, "write failed on %s",
-                               full_fname(fname));
-                       exit_cleanup(RERR_FILEIO);
-               }
+               if (fd != -1 && write_file(fd, map, len) != (int)len)
+                       goto report_write_error;
                offset += len;
        }
 
-       flush_write_file(fd);
+       if (flush_write_file(fd) < 0)
+               goto report_write_error;
 
 #ifdef HAVE_FTRUNCATE
        if (inplace && fd != -1)
@@ -310,6 +303,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);
@@ -339,7 +333,8 @@ static void discard_receive_data(int f_in, OFF_T length)
  * main routine for receiver process.
  *
  * Receiver process runs on the same host as the generator process. */
-int recv_files(int f_in, struct file_list *flist, char *local_name)
+int recv_files(int f_in, struct file_list *flist, char *local_name,
+              int f_in_name)
 {
        int next_gen_i = -1;
        int fd1,fd2;
@@ -347,7 +342,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;
@@ -368,8 +363,13 @@ int recv_files(int f_in, struct file_list *flist, char *local_name)
                i = read_int(f_in);
                if (i == -1) {
                        if (read_batch) {
-                               if (next_gen_i != flist->count)
-                                       while (read_int(batch_gen_fd) != -1) {}
+                               if (next_gen_i != flist->count) {
+                                       do {
+                                               if (f_in_name >= 0
+                                                   && next_gen_i >= 0)
+                                                       read_byte(f_in_name);
+                                       } while (read_int(batch_gen_fd) != -1);
+                               }
                                next_gen_i = -1;
                        }
 
@@ -415,10 +415,10 @@ int recv_files(int f_in, struct file_list *flist, char *local_name)
                if (verbose > 2)
                        rprintf(FINFO, "recv_files(%s)\n", safe_fname(fname));
 
-               fnamecmp = fname;
-
                if (read_batch) {
                        while (i > next_gen_i) {
+                               if (f_in_name >= 0 && next_gen_i >= 0)
+                                       read_byte(f_in_name);
                                next_gen_i = read_int(batch_gen_fd);
                                if (next_gen_i == -1)
                                        next_gen_i = flist->count;
@@ -429,31 +429,43 @@ int recv_files(int f_in, struct file_list *flist, char *local_name)
                                discard_receive_data(f_in, file->length);
                                continue;
                        }
+                       next_gen_i = -1;
                }
 
                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",
-                                       safe_fname(fname));
-                       }
-                       discard_receive_data(f_in, file->length);
-                       continue;
+                       rprintf(FERROR, "attempt to hack rsync failed.\n");
+                       exit_cleanup(RERR_PROTOCOL);
                }
 
+               partialptr = partial_dir ? partial_dir_fname(fname) : fname;
+
+               if (f_in_name >= 0) {
+                       uchar j;
+                       switch (j = read_byte(f_in_name)) {
+                       case FNAMECMP_FNAME:
+                               fnamecmp = fname;
+                               break;
+                       case FNAMECMP_PARTIAL_DIR:
+                               fnamecmp = partialptr ? partialptr : fname;
+                               break;
+                       case FNAMECMP_BACKUP:
+                               fnamecmp = get_backup_name(fname);
+                               break;
+                       case FNAMECMP_BASIS_DIR:
+                       default:
+                               pathjoin(fnamecmpbuf, sizeof fnamecmpbuf,
+                                        basis_dir[j], fname);
+                               fnamecmp = fnamecmpbuf;
+                               break;
+                       }
+               } else
+                       fnamecmp = fname;
+
                /* open the file */
                fd1 = do_open(fnamecmp, O_RDONLY, 0);
 
-               if (fd1 == -1 && compare_dest != NULL) {
-                       /* try the file at compare_dest instead */
-                       pathjoin(fnamecmpbuf, sizeof fnamecmpbuf,
-                                compare_dest, fname);
-                       fnamecmp = fnamecmpbuf;
-                       fd1 = do_open(fnamecmp, O_RDONLY, 0);
-               }
-
                if (fd1 != -1 && do_fstat(fd1,&st) != 0) {
                        rsyserr(FERROR, errno, "fstat %s failed",
                                full_fname(fnamecmp));
@@ -489,10 +501,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);
@@ -533,7 +545,8 @@ 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) /* log the transfer */
@@ -553,10 +566,20 @@ int recv_files(int f_in, struct file_list *flist, char *local_name)
                        exit_cleanup(RERR_FILEIO);
                }
 
-               if (recv_ok || keep_partial || inplace)
+               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();
 
@@ -564,9 +587,13 @@ int recv_files(int f_in, struct file_list *flist, char *local_name)
                        int msgtype = csum_length == SUM_LENGTH || read_batch ?
                                FERROR : FINFO;
                        if (msgtype == FERROR || verbose) {
-                               char *errstr, *redostr;
-                               char *keptstr = keep_partial || inplace ?
-                                       "retain" : "discard";
+                               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 = "";
@@ -575,7 +602,7 @@ int recv_files(int f_in, struct file_list *flist, char *local_name)
                                        redostr = " (will try again)";
                                }
                                rprintf(msgtype,
-                                       "%s: %s failed verification -- update %sed%s.\n",
+                                       "%s: %s failed verification -- update %s%s.\n",
                                        errstr, safe_fname(fname),
                                        keptstr, redostr);
                        }