X-Git-Url: https://mattmccutchen.net/rsync/rsync.git/blobdiff_plain/7842418b7b87c4c78ad8ad06fec44150c8aa0956..fe1c19dcdfa000c2461e85ed7bf712de49904377:/receiver.c diff --git a/receiver.c b/receiver.c index 01f79252..b674c14e 100644 --- a/receiver.c +++ b/receiver.c @@ -21,7 +21,6 @@ #include "rsync.h" extern int verbose; -extern int recurse; extern int delete_after; extern int csum_length; extern struct stats stats; @@ -48,6 +47,7 @@ extern int orig_umask; extern int keep_partial; extern int checksum_seed; extern int inplace; +extern int delay_updates; extern struct filter_list_struct server_filter_list; @@ -60,11 +60,16 @@ void delete_files(struct file_list *flist) int j; for (j = 0; j < flist->count; j++) { - if (!(flist->files[j]->flags & FLAG_DEL_START) - || !S_ISDIR(flist->files[j]->mode)) + struct file_struct *file = flist->files[j]; + + if (!(file->flags & FLAG_DEL_HERE)) continue; - delete_in_dir(flist, f_name_to(flist->files[j], fbuf)); + f_name_to(file, fbuf); + if (verbose > 1 && file->flags & FLAG_TOP_DIR) + rprintf(FINFO, "deleting in %s\n", safe_fname(fbuf)); + + delete_in_dir(flist, fbuf, file); } } @@ -118,7 +123,8 @@ static int get_tmpname(char *fnametmp, char *fname) maxname = MIN(MAXPATHLEN - 7 - length, NAME_MAX - 8); if (maxname < 1) { - rprintf(FERROR, "temporary filename too long: %s\n", fname); + rprintf(FERROR, "temporary filename too long: %s\n", + safe_fname(fname)); fnametmp[0] = '\0'; return 0; } @@ -222,7 +228,7 @@ static int receive_data(int f_in, char *fname_r, int fd_r, OFF_T size_r, if (flush_write_file(fd) < 0) goto report_write_error; -#ifdef HAVE_FTRUNCATE +#if HAVE_FTRUNCATE if (inplace && fd != -1) ftruncate(fd, offset); #endif @@ -272,6 +278,7 @@ int recv_files(int f_in, struct file_list *flist, char *local_name, char fnametmp[MAXPATHLEN]; char *fnamecmp, *partialptr; char fnamecmpbuf[MAXPATHLEN]; + uchar *delayed_bits = NULL; struct file_struct *file; struct stats initial_stats; int save_make_backups = make_backups; @@ -285,6 +292,13 @@ int recv_files(int f_in, struct file_list *flist, char *local_name, flist->hlink_pool = NULL; } + if (delay_updates) { + int sz = (flist->count + 7) / 8; + if (!(delayed_bits = new_array(uchar, sz))) + out_of_memory("recv_files"); + memset(delayed_bits, 0, sz); + } + while (1) { cleanup_disable(); @@ -321,16 +335,27 @@ int recv_files(int f_in, struct file_list *flist, char *local_name, } file = flist->files[i]; + if (S_ISDIR(file->mode)) { + rprintf(FERROR, "[%s] got index of directory: %d\n", + who_am_i(), i); + exit_cleanup(RERR_PROTOCOL); + } stats.current_file_index = i; stats.num_transferred_files++; stats.total_transferred_size += file->length; cleanup_got_literal = 0; - if (local_name) - fname = local_name; - else - fname = f_name_to(file, fbuf); + fname = local_name ? local_name : f_name_to(file, fbuf); + + if (server_filter_list.head + && check_filter(&server_filter_list, fname, 0) < 0) { + rprintf(FERROR, "attempt to hack rsync failed.\n"); + exit_cleanup(RERR_PROTOCOL); + } + + if (verbose > 2) + rprintf(FINFO, "recv_files(%s)\n", safe_fname(fname)); if (dry_run) { if (!am_server && verbose) /* log the transfer */ @@ -340,9 +365,6 @@ int recv_files(int f_in, struct file_list *flist, char *local_name, initial_stats = stats; - if (verbose > 2) - rprintf(FINFO, "recv_files(%s)\n", safe_fname(fname)); - if (read_batch) { while (i > next_gen_i) { if (f_in_name >= 0 && next_gen_i >= 0) @@ -360,13 +382,6 @@ int recv_files(int f_in, struct file_list *flist, char *local_name, next_gen_i = -1; } - if (server_filter_list.head - && check_filter(&server_filter_list, fname, - S_ISDIR(file->mode)) < 0) { - 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) { @@ -499,7 +514,7 @@ int recv_files(int f_in, struct file_list *flist, char *local_name, exit_cleanup(RERR_FILEIO); } - if (recv_ok || inplace) { + if ((recv_ok && (!delay_updates || !partialptr)) || inplace) { finish_transfer(fname, fnametmp, file, recv_ok, 1); if (partialptr != fname && fnamecmp == partialptr) { do_unlink(partialptr); @@ -509,6 +524,8 @@ int recv_files(int f_in, struct file_list *flist, char *local_name, && handle_partial_dir(partialptr, PDIR_CREATE)) { finish_transfer(partialptr, fnametmp, file, recv_ok, !partial_dir); + if (delay_updates && recv_ok) + delayed_bits[i/8] |= 1 << (i % 8); } else { partialptr = NULL; do_unlink(fnametmp); @@ -548,7 +565,36 @@ int recv_files(int f_in, struct file_list *flist, char *local_name, } make_backups = save_make_backups; - if (delete_after && recurse && !local_name && flist->count > 0) + if (delay_updates) { + for (i = 0; i < flist->count; i++) { + struct file_struct *file = flist->files[i]; + if (!file->basename + || !(delayed_bits[i/8] & (1 << (i % 8)))) + continue; + fname = local_name ? local_name : f_name(file); + partialptr = partial_dir_fname(fname); + if (partialptr) { + if (make_backups && !make_backup(fname)) + continue; + if (verbose > 2) { + rprintf(FINFO, "renaming %s to %s\n", + safe_fname(partialptr), + safe_fname(fname)); + } + if (do_rename(partialptr, fname) < 0) { + rsyserr(FERROR, errno, + "rename failed for %s (from %s)", + full_fname(fname), + safe_fname(partialptr)); + } else { + handle_partial_dir(partialptr, + PDIR_DELETE); + } + } + } + } + + if (delete_after && !local_name && flist->count > 0) delete_files(flist); if (verbose > 2)