./configure (optional if already run)
make
-based-on: 1c7785ab1ecfe81f7b4f257f8a2bec2f68d43d58
+based-on: 6c8ca91c731b7bf2b081694bda85b7dadc2b7aff
diff --git a/generator.c b/generator.c
--- a/generator.c
+++ b/generator.c
-@@ -64,6 +64,7 @@ extern int append_mode;
+@@ -67,6 +67,7 @@ extern int append_mode;
extern int make_backups;
extern int csum_length;
extern int ignore_times;
extern int size_only;
extern OFF_T max_size;
extern OFF_T min_size;
-@@ -580,7 +581,7 @@ void itemize(const char *fnamecmp, struct file_struct *file, int ndx, int statre
- /* Perform our quick-check heuristic for determining if a file is unchanged. */
- int unchanged_file(char *fn, struct file_struct *file, STRUCT_STAT *st)
+@@ -618,7 +619,7 @@ int quick_check_ok(enum filetype ftype, const char *fn, struct file_struct *file
{
-- if (st->st_size != F_LENGTH(file))
-+ if (!times_only && st->st_size != F_LENGTH(file))
- return 0;
+ switch (ftype) {
+ case FT_REG:
+- if (st->st_size != F_LENGTH(file))
++ if (!times_only && st->st_size != F_LENGTH(file))
+ return 0;
- /* if always checksum is set then we use the checksum instead
+ /* If always_checksum is set then we use the checksum instead
diff --git a/main.c b/main.c
--- a/main.c
+++ b/main.c
-@@ -179,7 +179,7 @@ int shell_exec(const char *cmd)
+@@ -191,7 +191,7 @@ int shell_exec(const char *cmd)
}
/* Wait for a process to exit, calling io_flush while waiting. */
diff --git a/options.c b/options.c
--- a/options.c
+++ b/options.c
-@@ -112,6 +112,7 @@ int safe_symlinks = 0;
+@@ -119,6 +119,7 @@ int safe_symlinks = 0;
int copy_unsafe_links = 0;
int munge_symlinks = 0;
int size_only = 0;
int daemon_bwlimit = 0;
int bwlimit = 0;
int fuzzy_basis = 0;
-@@ -171,6 +172,8 @@ char *logfile_name = NULL;
+@@ -179,6 +180,8 @@ char *logfile_name = NULL;
char *logfile_format = NULL;
char *stdout_format = NULL;
char *password_file = NULL;
+char *source_filter = NULL;
+char *dest_filter = NULL;
+ char *early_input_file = NULL;
char *rsync_path = RSYNC_PATH;
char *backup_dir = NULL;
- char backup_dir_buf[MAXPATHLEN];
-@@ -765,6 +768,7 @@ void usage(enum logcode F)
- rprintf(F," -I, --ignore-times don't skip files that match in size and mod-time\n");
- rprintf(F," -M, --remote-option=OPTION send OPTION to the remote side only\n");
- rprintf(F," --size-only skip files that match in size\n");
-+ rprintf(F," --times-only skip files that match in mod-time\n");
- rprintf(F," -@, --modify-window=NUM set the accuracy for mod-time comparisons\n");
- rprintf(F," -T, --temp-dir=DIR create temporary files in directory DIR\n");
- rprintf(F," -y, --fuzzy find similar file for basis if no dest file\n");
-@@ -808,6 +812,8 @@ void usage(enum logcode F)
- rprintf(F," --write-batch=FILE write a batched update to FILE\n");
- rprintf(F," --only-write-batch=FILE like --write-batch but w/o updating destination\n");
- rprintf(F," --read-batch=FILE read a batched update from FILE\n");
-+ rprintf(F," --source-filter=COMMAND filter file through COMMAND at source\n");
-+ rprintf(F," --dest-filter=COMMAND filter file through COMMAND at destination\n");
- rprintf(F," --protocol=NUM force an older protocol version to be used\n");
- #ifdef ICONV_OPTION
- rprintf(F," --iconv=CONVERT_SPEC request charset conversion of filenames\n");
-@@ -928,6 +934,7 @@ static struct poptOption long_options[] = {
+@@ -689,6 +692,7 @@ static struct poptOption long_options[] = {
{"chmod", 0, POPT_ARG_STRING, 0, OPT_CHMOD, 0, 0 },
{"ignore-times", 'I', POPT_ARG_NONE, &ignore_times, 0, 0, 0 },
{"size-only", 0, POPT_ARG_NONE, &size_only, 0, 0, 0 },
{"one-file-system", 'x', POPT_ARG_NONE, 0, 'x', 0, 0 },
{"no-one-file-system",0, POPT_ARG_VAL, &one_file_system, 0, 0, 0 },
{"no-x", 0, POPT_ARG_VAL, &one_file_system, 0, 0, 0 },
-@@ -1053,6 +1060,8 @@ static struct poptOption long_options[] = {
- {"password-file", 0, POPT_ARG_STRING, &password_file, 0, 0, 0 },
+@@ -829,6 +833,8 @@ static struct poptOption long_options[] = {
+ {"early-input", 0, POPT_ARG_STRING, &early_input_file, 0, 0, 0 },
{"blocking-io", 0, POPT_ARG_VAL, &blocking_io, 1, 0, 0 },
{"no-blocking-io", 0, POPT_ARG_VAL, &blocking_io, 0, 0, 0 },
+ {"source-filter", 0, POPT_ARG_STRING, &source_filter, 0, 0, 0 },
+ {"dest-filter", 0, POPT_ARG_STRING, &dest_filter, 0, 0, 0 },
- #ifdef HAVE_SETVBUF
{"outbuf", 0, POPT_ARG_STRING, &outbuf_mode, 0, 0, 0 },
- #endif
-@@ -2360,6 +2369,16 @@ int parse_arguments(int *argc_p, const char ***argv_p)
+ {"remote-option", 'M', POPT_ARG_STRING, 0, 'M', 0, 0 },
+ {"protocol", 0, POPT_ARG_INT, &protocol_version, 0, 0, 0 },
+@@ -2444,6 +2450,16 @@ int parse_arguments(int *argc_p, const char ***argv_p)
}
}
if (files_from) {
char *h, *p;
int q;
-@@ -2730,6 +2749,25 @@ void server_options(char **args, int *argc_p)
+@@ -2852,6 +2868,25 @@ void server_options(char **args, int *argc_p)
else if (missing_args == 1 && !am_sender)
args[ac++] = "--ignore-missing-args";
extern char *logfile_name;
extern int remote_option_cnt;
extern const char **remote_options;
-@@ -178,3 +179,77 @@ pid_t local_child(int argc, char **argv, int *f_in, int *f_out,
+@@ -176,3 +177,77 @@ pid_t local_child(int argc, char **argv, int *f_in, int *f_out,
return pid;
}
diff --git a/receiver.c b/receiver.c
--- a/receiver.c
+++ b/receiver.c
-@@ -59,6 +59,7 @@ extern BOOL want_progress_now;
+@@ -60,6 +60,7 @@ extern BOOL want_progress_now;
extern mode_t orig_umask;
extern struct stats stats;
extern char *tmpdir;
extern char *partial_dir;
extern char *basis_dir[MAX_BASIS_DIRS+1];
extern char sender_file_sum[MAX_DIGEST_LEN];
-@@ -531,6 +532,8 @@ int recv_files(int f_in, int f_out, char *local_name)
+@@ -528,6 +529,7 @@ int recv_files(int f_in, int f_out, char *local_name)
+ char *fnametmp, fnametmpbuf[MAXPATHLEN];
+ char *fnamecmp, *partialptr;
+ char fnamecmpbuf[MAXPATHLEN];
++ char *filter_argv[MAX_FILTER_ARGS + 1];
+ uchar fnamecmp_type;
+ struct file_struct *file;
+ int itemizing = am_server ? logfile_format_has_i : stdout_format_has_i;
+@@ -538,6 +540,7 @@ int recv_files(int f_in, int f_out, char *local_name)
const char *parent_dirname = "";
#endif
- int ndx, recv_ok;
+ int ndx, recv_ok, one_inplace;
+ pid_t pid = 0;
-+ char *filter_argv[MAX_FILTER_ARGS + 1];
if (DEBUG_GTE(RECV, 1))
rprintf(FINFO, "recv_files(%d) starting\n", cur_flist->used);
-@@ -538,6 +541,23 @@ int recv_files(int f_in, int f_out, char *local_name)
- if (delay_updates)
- delayed_bits = bitbag_create(cur_flist->used + 1);
+@@ -548,6 +551,23 @@ int recv_files(int f_in, int f_out, char *local_name)
+ if (whole_file < 0)
+ whole_file = 0;
+ if (dest_filter) {
+ char *p;
progress_init();
while (1) {
-@@ -859,6 +879,9 @@ int recv_files(int f_in, int f_out, char *local_name)
+@@ -873,6 +893,9 @@ int recv_files(int f_in, int f_out, char *local_name)
else if (!am_server && INFO_GTE(NAME, 1) && INFO_EQ(PROGRESS, 1))
rprintf(FINFO, "%s\n", fname);
+ pid = run_filter(filter_argv, fd2, &fd2);
+
/* recv file data */
- recv_ok = receive_data(f_in, fnamecmp, fd1, st.st_size, fname, fd2, file);
+ recv_ok = receive_data(f_in, fnamecmp, fd1, st.st_size, fname, fd2, file, inplace || one_inplace);
-@@ -874,6 +897,16 @@ int recv_files(int f_in, int f_out, char *local_name)
+@@ -888,6 +911,16 @@ int recv_files(int f_in, int f_out, char *local_name)
exit_cleanup(RERR_FILEIO);
}
if ((recv_ok && (!delay_updates || !partialptr)) || inplace) {
if (partialptr == fname)
partialptr = NULL;
+diff --git a/rsync.1.md b/rsync.1.md
+--- a/rsync.1.md
++++ b/rsync.1.md
+@@ -504,6 +504,7 @@ has its own detailed description later in this manpage.
+ --contimeout=SECONDS set daemon connection timeout in seconds
+ --ignore-times, -I don't skip files that match size and time
+ --size-only skip files that match in size
++--times-only skip files that match in mod-time
+ --modify-window=NUM, -@ set the accuracy for mod-time comparisons
+ --temp-dir=DIR, -T create temporary files in directory DIR
+ --fuzzy, -y find similar file for basis if no dest file
+@@ -553,6 +554,8 @@ has its own detailed description later in this manpage.
+ --write-batch=FILE write a batched update to FILE
+ --only-write-batch=FILE like --write-batch but w/o updating dest
+ --read-batch=FILE read a batched update from FILE
++--source-filter=COMMAND filter file through COMMAND at source
++--dest-filter=COMMAND filter file through COMMAND at destination
+ --protocol=NUM force an older protocol version to be used
+ --iconv=CONVERT_SPEC request charset conversion of filenames
+ --checksum-seed=NUM set block/file checksum seed (advanced)
+@@ -3713,6 +3716,36 @@ expand it.
+ [`--write-batch`](#opt). If _FILE_ is `-`, the batch data will be read
+ from standard input. See the "BATCH MODE" section for details.
+
++0. `--source-filter=COMMAND`
++
++ This option allows the user to specify a filter program that will be
++ applied to the contents of all transferred regular files before the data is
++ sent to destination. COMMAND will receive the data on its standard input
++ and it should write the filtered data to standard output. COMMAND should
++ exit non-zero if it cannot process the data or if it encounters an error
++ when writing the data to stdout.
++
++ Example: `--source-filter="gzip -9"` will cause remote files to be
++ compressed. Use of `--source-filter` automatically enables
++ [`--whole-file`](#opt). If your filter does not output the same number of
++ bytes that it received on input, you should use `--times-only` to
++ disable size and content checks on subsequent rsync runs.
++
++0. `--dest-filter=COMMAND`
++
++ This option allows you to specify a filter program that will be applied to
++ the contents of all transferred regular files before the data is written to
++ disk. COMMAND will receive the data on its standard input and it should
++ write the filtered data to standard output. COMMAND should exit non-zero
++ if it cannot process the data or if it encounters an error when writing the
++ data to stdout.
++
++ Example: --dest-filter="gzip -9" will cause remote files to be compressed.
++ Use of --dest-filter automatically enables --whole-file. If your filter
++ does not output the same number of bytes that it received on input, you
++ should use --times-only to disable size and content checks on subsequent
++ rsync runs.
++
+ 0. `--protocol=NUM`
+
+ Force an older protocol version to be used. This is useful for creating a
diff --git a/rsync.h b/rsync.h
--- a/rsync.h
+++ b/rsync.h
-@@ -151,6 +151,7 @@
+@@ -169,6 +169,7 @@
#define IOERR_DEL_LIMIT (1<<2)
#define MAX_ARGS 1000
#define MAX_BASIS_DIRS 20
#define MAX_SERVER_ARGS (MAX_BASIS_DIRS*2 + 100)
-diff --git a/rsync.yo b/rsync.yo
---- a/rsync.yo
-+++ b/rsync.yo
-@@ -423,6 +423,7 @@ to the detailed description below for a complete description. verb(
- --contimeout=SECONDS set daemon connection timeout in seconds
- -I, --ignore-times don't skip files that match size and time
- --size-only skip files that match in size
-+ --times-only skip files that match in mod-time
- -@, --modify-window=NUM set the accuracy for mod-time comparisons
- -T, --temp-dir=DIR create temporary files in directory DIR
- -y, --fuzzy find similar file for basis if no dest file
-@@ -465,6 +466,8 @@ to the detailed description below for a complete description. verb(
- --write-batch=FILE write a batched update to FILE
- --only-write-batch=FILE like --write-batch but w/o updating dest
- --read-batch=FILE read a batched update from FILE
-+ --source-filter=COMMAND filter file through COMMAND at source
-+ --dest-filter=COMMAND filter file through COMMAND at destination
- --protocol=NUM force an older protocol version to be used
- --iconv=CONVERT_SPEC request charset conversion of filenames
- --checksum-seed=NUM set block/file checksum seed (advanced)
-@@ -2714,6 +2717,33 @@ file previously generated by bf(--write-batch).
- If em(FILE) is bf(-), the batch data will be read from standard input.
- See the "BATCH MODE" section for details.
-
-+dit(bf(--source-filter=COMMAND)) This option allows the user to specify a
-+filter program that will be applied to the contents of all transferred
-+regular files before the data is sent to destination. COMMAND will receive
-+the data on its standard input and it should write the filtered data to
-+standard output. COMMAND should exit non-zero if it cannot process the
-+data or if it encounters an error when writing the data to stdout.
-+
-+Example: --source-filter="gzip -9" will cause remote files to be
-+compressed.
-+Use of --source-filter automatically enables --whole-file.
-+If your filter does not output the same number of bytes that it received on
-+input, you should use --times-only to disable size and content checks on
-+subsequent rsync runs.
-+
-+dit(bf(--dest-filter=COMMAND)) This option allows you to specify a filter
-+program that will be applied to the contents of all transferred regular
-+files before the data is written to disk. COMMAND will receive the data on
-+its standard input and it should write the filtered data to standard
-+output. COMMAND should exit non-zero if it cannot process the data or if
-+it encounters an error when writing the data to stdout.
-+
-+Example: --dest-filter="gzip -9" will cause remote files to be compressed.
-+Use of --dest-filter automatically enables --whole-file.
-+If your filter does not output the same number of bytes that it
-+received on input, you should use --times-only to disable size and
-+content checks on subsequent rsync runs.
-+
- )
- description(
-
diff --git a/sender.c b/sender.c
--- a/sender.c
+++ b/sender.c
-@@ -46,6 +46,7 @@ extern int batch_fd;
+@@ -21,6 +21,7 @@
+
+ #include "rsync.h"
+ #include "inums.h"
++#include "ifuncs.h"
+
+ extern int do_xfers;
+ extern int am_server;
+@@ -50,6 +51,7 @@ extern int batch_fd;
extern int write_batch;
extern int file_old_total;
extern BOOL want_progress_now;
+extern char *source_filter;
extern struct stats stats;
extern struct file_list *cur_flist, *first_flist, *dir_flist;
-
-@@ -203,6 +204,26 @@ void send_files(int f_in, int f_out)
+ extern char num_dev_ino_buf[4 + 8 + 8];
+@@ -211,6 +213,26 @@ void send_files(int f_in, int f_out)
int f_xfer = write_batch < 0 ? batch_fd : f_out;
int save_io_error = io_error;
int ndx, j;
if (DEBUG_GTE(SEND, 1))
rprintf(FINFO, "send_files starting\n");
-@@ -339,6 +360,7 @@ void send_files(int f_in, int f_out)
+@@ -348,6 +370,7 @@ void send_files(int f_in, int f_out)
exit_cleanup(RERR_PROTOCOL);
}
fd = do_open(fname, O_RDONLY, 0);
if (fd == -1) {
if (errno == ENOENT) {
-@@ -360,6 +382,33 @@ void send_files(int f_in, int f_out)
+@@ -367,6 +390,33 @@ void send_files(int f_in, int f_out)
continue;
}
/* map the local file */
if (do_fstat(fd, &st) != 0) {
io_error |= IOERR_GENERAL;
-@@ -412,6 +461,8 @@ void send_files(int f_in, int f_out)
+@@ -437,6 +487,8 @@ void send_files(int f_in, int f_out)
}
}
close(fd);