After applying this patch and running configure, you MUST run this command before "make": make proto --- orig/generator.c 2005-02-15 20:40:53 +++ generator.c 2005-02-15 20:43:59 @@ -38,6 +38,7 @@ extern int preserve_gid; extern int preserve_times; extern int omit_dir_times; extern int delete_during; +extern int remove_sent_files; extern int update_only; extern int opt_ignore_existing; extern int inplace; @@ -524,6 +525,11 @@ static void recv_generator(char *fname, itemize_changes ? "" : safe_fname(fname), safe_fname(file->u.link)); } + if (remove_sent_files) { + char numbuf[4]; + SIVAL(numbuf, 0, ndx); + io_multiplex_write(MSG_SUCCESS, numbuf, 4); + } } #endif return; --- orig/io.c 2005-02-03 02:04:20 +++ io.c 2005-02-15 20:43:59 @@ -244,6 +244,14 @@ static void read_msg_fd(void) read_loop(fd, buf, 4); redo_list_add(IVAL(buf,0)); break; + case MSG_SUCCESS: + if (len != 4) { + rprintf(FERROR, "invalid message %d:%d\n", tag, len); + exit_cleanup(RERR_STREAMIO); + } + read_loop(fd, buf, len); + io_multiplex_write(MSG_SUCCESS, buf, len); + break; case MSG_INFO: case MSG_ERROR: case MSG_LOG: @@ -677,6 +685,16 @@ static int readfd_unbuffered(int fd, cha read_loop(fd, iobuf_in, remaining); iobuf_in_ndx = 0; break; + case MSG_SUCCESS: + if (remaining != 4) { + rprintf(FERROR, "invalid multi-message %d:%ld\n", + tag, (long)remaining); + exit_cleanup(RERR_STREAMIO); + } + read_loop(fd, line, remaining); + successful_send(IVAL(line, 0)); + remaining = 0; + break; case MSG_INFO: case MSG_ERROR: if (remaining >= sizeof line) { --- orig/main.c 2005-02-15 19:27:04 +++ main.c 2005-02-15 20:43:59 @@ -33,12 +33,14 @@ extern int verbose; extern int itemize_changes; extern int blocking_io; extern int delete_before; +extern int remove_sent_files; extern int daemon_over_rsh; extern int do_stats; extern int dry_run; extern int list_only; extern int log_got_error; extern int module_id; +extern int need_messages_from_generator; extern int orig_umask; extern int copy_links; extern int keep_dirlinks; @@ -442,6 +444,12 @@ static void do_server_sender(int f_in, i exit_cleanup(RERR_SYNTAX); return; } + if (am_daemon && lp_read_only(module_id) && remove_sent_files) { + rprintf(FERROR, + "ERROR: --remove-sent-files cannot be used with a read-only module\n"); + exit_cleanup(RERR_SYNTAX); + return; + } if (!relative_paths && !push_dir(dir)) { rsyserr(FERROR, errno, "push_dir#3 %s failed", @@ -673,6 +681,8 @@ void start_server(int f_in, int f_out, i if (am_sender) { keep_dirlinks = 0; /* Must be disabled on the sender. */ + if (need_messages_from_generator) + io_start_multiplex_in(); recv_filter_list(f_in); do_server_sender(f_in, f_out, argc, argv); @@ -750,6 +760,9 @@ int client_run(int f_in, int f_out, pid_ exit_cleanup(status); } + if (need_messages_from_generator && !read_batch) + io_start_multiplex_out(); + if (argc == 0) list_only |= 1; --- orig/options.c 2005-02-15 19:27:05 +++ options.c 2005-02-15 20:44:00 @@ -59,6 +59,7 @@ int delete_during = 0; int delete_before = 0; int delete_after = 0; int delete_excluded = 0; +int remove_sent_files = 0; int one_file_system = 0; int protocol_version = PROTOCOL_VERSION; int sparse_files = 0; @@ -93,6 +94,7 @@ int fuzzy_basis = 0; size_t bwlimit_writemax = 0; int only_existing = 0; int opt_ignore_existing = 0; +int need_messages_from_generator = 0; int max_delete = 0; OFF_T max_size = 0; int ignore_errors = 0; @@ -285,6 +287,7 @@ void usage(enum logcode F) rprintf(F," --rsync-path=PATH specify path to rsync on the remote machine\n"); rprintf(F," --existing only update files that already exist on receiver\n"); rprintf(F," --ignore-existing ignore files that already exist on receiving side\n"); + rprintf(F," --remove-sent-files updated/sent files are removed from sending side\n"); rprintf(F," --del an alias for --delete-during\n"); rprintf(F," --delete delete files that don't exist on the sending side\n"); rprintf(F," --delete-before receiver deletes before transfer (default)\n"); @@ -368,6 +371,7 @@ static struct poptOption long_options[] {"delete-during", 0, POPT_ARG_NONE, &delete_during, 0, 0, 0 }, {"delete-after", 0, POPT_ARG_NONE, &delete_after, 0, 0, 0 }, {"delete-excluded", 0, POPT_ARG_NONE, &delete_excluded, 0, 0, 0 }, + {"remove-sent-files",0, POPT_ARG_NONE, &remove_sent_files, 0, 0, 0 }, {"force", 0, POPT_ARG_NONE, &force_delete, 0, 0, 0 }, {"numeric-ids", 0, POPT_ARG_NONE, &numeric_ids, 0, 0, 0 }, {"filter", 'f', POPT_ARG_STRING, 0, OPT_FILTER, 0, 0 }, @@ -961,6 +965,14 @@ int parse_arguments(int *argc, const cha return 0; } + if (remove_sent_files) { + if (refused_delete) { + create_refuse_error(refused_delete); + return 0; + } + need_messages_from_generator = 1; + } + *argv = poptGetArgs(pc); *argc = count_args(*argv); @@ -1393,6 +1405,9 @@ void server_options(char **args,int *arg if (fuzzy_basis && am_sender) args[ac++] = "--fuzzy"; + if (remove_sent_files) + args[ac++] = "--remove-sent-files"; + *argc = ac; return; --- orig/receiver.c 2005-02-15 19:27:05 +++ receiver.c 2005-02-15 20:44:00 @@ -42,6 +42,7 @@ extern int basis_dir_cnt; extern int make_backups; extern int do_progress; extern int cleanup_got_literal; +extern int remove_sent_files; extern int module_id; extern int ignore_errors; extern int orig_umask; @@ -307,7 +308,7 @@ int recv_files(int f_in, struct file_lis char *fname, fbuf[MAXPATHLEN]; char template[MAXPATHLEN]; char fnametmp[MAXPATHLEN]; - char *fnamecmp, *partialptr; + char *fnamecmp, *partialptr, numbuf[4]; char fnamecmpbuf[MAXPATHLEN]; uchar *delayed_bits = NULL; struct file_struct *file; @@ -569,7 +570,12 @@ int recv_files(int f_in, struct file_lis cleanup_disable(); - if (!recv_ok) { + if (recv_ok) { + if (remove_sent_files) { + SIVAL(numbuf, 0, i); + send_msg(MSG_SUCCESS, numbuf, 4); + } + } else { int msgtype = csum_length == SUM_LENGTH || read_batch ? FERROR : FINFO; if (msgtype == FERROR || verbose) { @@ -593,9 +599,8 @@ int recv_files(int f_in, struct file_lis keptstr, redostr); } if (csum_length != SUM_LENGTH) { - char buf[4]; - SIVAL(buf, 0, i); - send_msg(MSG_REDO, buf, 4); + SIVAL(numbuf, 0, i); + send_msg(MSG_REDO, numbuf, 4); } } } --- orig/rsync.h 2005-02-15 19:27:05 +++ rsync.h 2005-02-15 20:44:00 @@ -62,6 +62,7 @@ #define FLAG_MOUNT_POINT (1<<2) /* sender only */ #define FLAG_NO_FUZZY (1<<2) /* generator only */ #define FLAG_DEL_HERE (1<<3) /* receiver/generator */ +#define FLAG_SENT (1<<7) /* sender only */ /* update this if you make incompatible changes */ #define PROTOCOL_VERSION 29 @@ -144,6 +145,7 @@ enum logcode { FERROR=1, FINFO=2, FLOG=3 /* Messages types that are sent over the message channel. The logcode * values must all be present here with identical numbers. */ enum msgcode { + MSG_SUCCESS=6, /* successfully updated indicated flist index */ MSG_DONE=5, /* current phase is done */ MSG_REDO=4, /* reprocess indicated flist index */ MSG_ERROR=FERROR, MSG_INFO=FINFO, MSG_LOG=FLOG, /* remote logging */ --- orig/rsync.yo 2005-02-15 20:42:04 +++ rsync.yo 2005-02-15 20:44:02 @@ -332,6 +332,7 @@ to the detailed description below for a --rsync-path=PATH specify path to rsync on the remote machine --existing only update files that already exist --ignore-existing ignore files that already exist on receiver + --remove-sent-files sent files/symlinks are removed from sender --del an alias for --delete-during --delete delete files that don't exist on sender --delete-before receiver deletes before transfer (default) @@ -665,6 +666,11 @@ dit(bf(--ignore-existing)) This tells rsync not to update files that already exist on the destination. +dit(bf(--remove-sent-files)) This tells rsync to remove the source files +on the sending side that are successfully transferred to the receiving +side. Directories and devices are not removed, nor are files/symlinks +whose content was not updated (just changing attributes does not count). + dit(bf(--delete)) This tells rsync to delete extraneous files from the receiving side (ones that aren't on the sending side), but only for the directories that are being synchronized. You must have asked rsync to --- orig/sender.c 2005-02-15 19:27:05 +++ sender.c 2005-02-15 20:44:02 @@ -27,6 +27,7 @@ extern int io_error; extern int dry_run; extern int am_server; extern int am_daemon; +extern int remove_sent_files; extern int protocol_version; extern int updating_basis_file; extern int make_backups; @@ -95,7 +96,32 @@ static struct sum_struct *receive_sums(i return s; } +static struct file_list *the_flist; +void successful_send(int i) +{ + char fname[MAXPATHLEN]; + struct file_struct *file; + unsigned int offset; + + if (!the_flist || i < 0 || i >= the_flist->count) + return; + + file = the_flist->files[i]; + /* The generator can tell us about symlinks we didn't send. */ + if (!(file->flags & FLAG_SENT) && !S_ISLNK(file->mode)) + return; /* We didn't send it -- impossible! */ + if (file->dir.root) { + offset = stringjoin(fname, sizeof fname, + file->dir.root, "/", NULL); + } else + offset = 0; + f_name_to(file, fname + offset); + if (remove_sent_files && do_unlink(fname) == 0 && verbose) { + rprintf(FINFO, "sender removed %s\n", + safe_fname(fname + offset)); + } +} void send_files(struct file_list *flist, int f_out, int f_in) { @@ -114,6 +140,8 @@ void send_files(struct file_list *flist, if (verbose > 2) rprintf(FINFO, "send_files starting\n"); + the_flist = flist; + while (1) { unsigned int offset; @@ -256,6 +284,9 @@ void send_files(struct file_list *flist, rprintf(FINFO, "sender finished %s\n", safe_fname(fname)); } + + /* Flag that we actually sent this entry. */ + file->flags |= FLAG_SENT; } make_backups = save_make_backups;