+Please CC me. I'm not subscribed.
+
+Attached is a patch against 2.5.4pre1 CVS current to add the
+--link-dest option so rsync will create hardlinks for
+unchanged regular files to a directory on the destination.
+This is like --compare-dest except that the result is not a
+sparse tree.
+
+Also included is extension to --(ex|in)clude-from to allow -
+for stdin.
+
+Could one of the maintainers please add this to the
+mainline?
+
+Thanks to Dave Dykstra for feedback on this.
+
+--
+________________________________________________________________
+ J.W. Schultz Pegasystems Technologies
+ email address: jw@pegasys.ws
+
+ Remember Cernan and Schmitt
+? options-merge.c
+Index: exclude.c
+===================================================================
+RCS file: /cvsroot/rsync/exclude.c,v
+retrieving revision 1.42
+diff -u -r1.42 exclude.c
+--- exclude.c 18 Feb 2002 19:10:28 -0000 1.42
++++ exclude.c 21 Mar 2002 23:31:25 -0000
+@@ -219,8 +219,14 @@
+ int fatal, int include)
+ {
+ struct exclude_struct **list=list1;
+- FILE *f = fopen(fname,"r");
++ FILE *f;
+ char line[MAXPATHLEN];
++
++ if (strcmp(fname, "-")) {
++ f = fopen(fname,"r");
++ } else {
++ f = fdopen(0, "r");
++ }
+ if (!f) {
+ if (fatal) {
+ rsyserr(FERROR, errno,
+Index: generator.c
+===================================================================
+RCS file: /cvsroot/rsync/generator.c,v
+retrieving revision 1.37
+diff -u -r1.37 generator.c
+--- generator.c 19 Mar 2002 20:16:42 -0000 1.37
++++ generator.c 21 Mar 2002 23:31:26 -0000
+@@ -41,6 +41,7 @@
+ extern int always_checksum;
+ extern int modify_window;
+ extern char *compare_dest;
++extern int link_dest;
+
+
+ /* choose whether to skip a particular file */
+@@ -50,6 +51,15 @@
+ if (st->st_size != file->length) {
+ return 0;
+ }
++ if (link_dest) {
++ if((st->st_mode & ~_S_IFMT) != (file->mode & ~_S_IFMT)) {
++ return 0;
++ }
++ if (st->st_uid != file->uid || st->st_gid != file->gid) {
++ return 0;
++ }
++ }
++
+
+ /* if always checksum is set then we use the checksum instead
+ of the file time to determine whether to sync */
+@@ -382,6 +392,17 @@
+ statret = -1;
+ if (statret == -1)
+ errno = saveerrno;
++#if HAVE_LINK
++ else if (link_dest)
++ if (do_link(fnamecmpbuf, fname) != 0) {
++ if (verbose > 0)
++ rprintf(FINFO,"link %s => %s : %s\n",
++ fnamecmpbuf,
++ fname,
++ strerror(errno));
++ fnamecmp = fnamecmpbuf;
++ }
++#endif
+ else
+ fnamecmp = fnamecmpbuf;
+ }
+Index: options.c
+===================================================================
+RCS file: /cvsroot/rsync/options.c,v
+retrieving revision 1.89
+diff -u -r1.89 options.c
+--- options.c 19 Mar 2002 20:16:42 -0000 1.89
++++ options.c 21 Mar 2002 23:31:27 -0000
+@@ -113,6 +113,7 @@
+ char *rsync_path = RSYNC_PATH;
+ char *backup_dir = NULL;
+ int rsync_port = RSYNC_PORT;
++int link_dest = 0;
+
+ int verbose = 0;
+ int quiet = 0;
+@@ -282,7 +283,7 @@
+ OPT_EXCLUDE_FROM, OPT_DELETE, OPT_DELETE_EXCLUDED, OPT_NUMERIC_IDS,
+ OPT_RSYNC_PATH, OPT_FORCE, OPT_TIMEOUT, OPT_DAEMON, OPT_CONFIG, OPT_PORT,
+ OPT_INCLUDE, OPT_INCLUDE_FROM, OPT_STATS, OPT_PARTIAL, OPT_PROGRESS,
+- OPT_COPY_UNSAFE_LINKS, OPT_SAFE_LINKS, OPT_COMPARE_DEST,
++ OPT_COPY_UNSAFE_LINKS, OPT_SAFE_LINKS, OPT_COMPARE_DEST, OPT_LINK_DEST,
+ OPT_LOG_FORMAT, OPT_PASSWORD_FILE, OPT_SIZE_ONLY, OPT_ADDRESS,
+ OPT_DELETE_AFTER, OPT_EXISTING, OPT_MAX_DELETE, OPT_BACKUP_DIR,
+ OPT_IGNORE_ERRORS, OPT_BWLIMIT, OPT_BLOCKING_IO,
+@@ -341,6 +342,7 @@
+ {"timeout", 0, POPT_ARG_INT, &io_timeout , 0, 0, 0 },
+ {"temp-dir", 'T', POPT_ARG_STRING, &tmpdir , 0, 0, 0 },
+ {"compare-dest", 0, POPT_ARG_STRING, &compare_dest , 0, 0, 0 },
++ {"link-dest", 0, POPT_ARG_STRING, 0, OPT_LINK_DEST, 0, 0 },
+ /* TODO: Should this take an optional int giving the compression level? */
+ {"compress", 'z', POPT_ARG_NONE, &do_compression , 0, 0, 0 },
+ {"daemon", 0, POPT_ARG_NONE, &am_daemon , 0, 0, 0 },
+@@ -562,6 +564,19 @@
+ /* popt stores the filename in batch_prefix for us */
+ read_batch = 1;
+ break;
++ case OPT_LINK_DEST:
++#if HAVE_LINK
++ compare_dest = poptGetOptArg(pc);
++ link_dest = 1;
++ break;
++#else
++ snprintf(err_buf,sizeof(err_buf),
++ "hard links are not supported on this %s\n",
++ am_server ? "server" : "client");
++ rprintf(FERROR,"ERROR: hard links not supported on this platform\n");
++ return 0;
++#endif
++
+
+ default:
+ /* FIXME: If --daemon is specified, then errors for later
+@@ -785,7 +800,7 @@
+ * and it may be an older version that doesn't know this
+ * option, so don't send it if client is the sender.
+ */
+- args[ac++] = "--compare-dest";
++ args[ac++] = link_dest ? "--link-dest" : "--compare-dest";
+ args[ac++] = compare_dest;
+ }
+
+Index: rsync.yo
+===================================================================
+RCS file: /cvsroot/rsync/rsync.yo,v
+retrieving revision 1.95
+diff -u -r1.95 rsync.yo
+--- rsync.yo 6 Feb 2002 21:20:49 -0000 1.95
++++ rsync.yo 21 Mar 2002 23:31:28 -0000
+@@ -261,6 +261,7 @@
+ --modify-window=NUM Timestamp window (seconds) for file match (default=0)
+ -T --temp-dir=DIR create temporary files in directory DIR
+ --compare-dest=DIR also compare destination files relative to DIR
++ --link-dest=DIR create hardlinks to DIR for unchanged files
+ -P equivalent to --partial --progress
+ -z, --compress compress file data
+ --exclude=PATTERN exclude files matching PATTERN
+@@ -531,6 +532,7 @@
+ option, but instead it adds all exclude patterns listed in the file
+ FILE to the exclude list. Blank lines in FILE and lines starting with
+ ';' or '#' are ignored.
++If \fIFILE\fP is \fB-\fP the list will be read from standard input.
+
+ dit(bf(--include=PATTERN)) This option tells rsync to not exclude the
+ specified pattern of filenames. This is useful as it allows you to
+@@ -541,6 +543,7 @@
+
+ dit(bf(--include-from=FILE)) This specifies a list of include patterns
+ from a file.
++If \fIFILE\fP is \fB-\fP the list will be read from standard input.
+
+ dit(bf(-C, --cvs-exclude)) This is a useful shorthand for excluding a
+ broad range of files that you often don't want to transfer between
+@@ -595,6 +598,11 @@
+ --partial because partially transferred files will remain in the new
+ temporary destination until they have a chance to be completed. If DIR is
+ a relative path, it is relative to the destination directory.
++
++dit(bf(--link-dest=DIR)) This option behaves like \fB--compare-dest\fP but
++also will create hard links from \fIDIR\fP to the destination directory for
++unchanged files. Files with changed ownership or permissions will not be
++linked.
+
+ dit(bf(-z, --compress)) With this option, rsync compresses any data from
+ the files that it sends to the destination machine. This