diff -urN --exclude=patches rsync-2.6.3/Makefile.in rsync-2.6.4/Makefile.in --- rsync-2.6.3/Makefile.in 2004-08-12 11:59:03.000000000 -0700 +++ rsync-2.6.4/Makefile.in 2004-11-02 08:47:15.000000000 -0800 @@ -41,7 +41,7 @@ popt/popthelp.o popt/poptparse.o OBJS=$(OBJS1) $(OBJS2) $(OBJS3) $(DAEMON_OBJ) $(LIBOBJ) $(ZLIBOBJ) @BUILD_POPT@ -TLS_OBJ = tls.o syscall.o lib/permstring.o +TLS_OBJ = tls.o syscall.o lib/compat.o lib/snprintf.o lib/permstring.o # Programs we must have to run the test cases CHECK_PROGS = rsync$(EXEEXT) tls$(EXEEXT) getgroups$(EXEEXT) getfsdev$(EXEEXT) \ @@ -83,7 +83,7 @@ getfsdev$(EXEEXT): getfsdev.o $(CC) $(CFLAGS) $(LDFLAGS) -o $@ getfsdev.o $(LIBS) -TRIMSLASH_OBJ = trimslash.o syscall.o +TRIMSLASH_OBJ = trimslash.o syscall.o lib/compat.o lib/snprintf.o trimslash$(EXEEXT): $(TRIMSLASH_OBJ) $(CC) $(CFLAGS) $(LDFLAGS) -o $@ $(TRIMSLASH_OBJ) $(LIBS) diff -urN --exclude=patches rsync-2.6.3/NEWS rsync-2.6.4/NEWS --- rsync-2.6.3/NEWS 2004-09-30 03:46:43.000000000 -0700 +++ rsync-2.6.4/NEWS 2005-03-30 11:41:51.000000000 -0800 @@ -1,252 +1,384 @@ -NEWS for rsync 2.6.3 (30 Sep 2004) -Protocol: 28 (unchanged) -Changes since 2.6.2: - - SECURITY FIXES: - - - A bug in the sanitize_path routine (which affects a non-chrooted - rsync daemon) could allow a user to craft a pathname that would get - transformed into an absolute path for certain options (but not for - file-transfer names). If you're running an rsync daemon with chroot - disabled, *please upgrade*, ESPECIALLY if the user privs you run - rsync under is anything above "nobody". - - OUTPUT CHANGES (ATTN: those using a script to parse the verbose output): - - - Please note that the 2-line footer (output when verbose) now uses the - term "sent" instead of "wrote" and "received" instead of "read". If - you are not parsing the numeric values out of this footer, a script - would be better off using the empty line prior to the footer as the - indicator that the verbose output is over. - - - The output from the --stats option was similarly affected to change - "written" to "sent" and "read" to "received". - - - Rsync ensures that a filename that contains a newline gets mentioned - with each newline transformed into a question mark (which prevents a - filename from causing an empty line to be output). - - - The "backed up ..." message that is output when at least 2 --verbose - options are specified is now the same both with and without the - --backup-dir option. - +NEWS for rsync 2.6.4 (30 March 2005) +Protocol: 29 (changed) +Changes since 2.6.3: + + OUTPUT CHANGES: + + - When rsync deletes a directory and outputs a verbose message about + it, it now appends a trailing slash to the name instead of (only + sometimes) outputting a preceding "directory " string. + + - The --stats output will contain file-list time-statistics if both + sides are 2.6.4, or if the local side is 2.6.4 and the files are + being pushed (since the stats come from the sending side). + (Requires protocol 29 for a pull.) + + - The "%o" (operation) log-format escape now has a third value (besides + "send" and "recv"): "del." (with trailing dot to make it 4 chars). + This changes the way deletions are logged in the daemon's log file. + + - When the --log-format option is combined with --verbose, rsync now + avoids outputting the name of the file twice in most circumstances. + As long as the --log-format item does not refer to any post-transfer + items (such as %b or %c), the --log-format message is output prior to + the transfer, so --verbose is now the equivalent of a --log-format of + '%n%L' (which outputs the name and any link info). If the log output + must occur after the transfer to be complete, the only time the name + is also output prior to the transfer is when --progress was specified + (so that the name will precede the progress stats, and the full + --log-format output will come after). + BUG FIXES: - - Fixed a crash bug that might appear when --delete was used and - multiple source directories were specified. - - - Fixed a 32-bit truncation of the file length when generating the - checksums. - - - The --backup code no longer attempts to create some directories - over and over again (generating warnings along the way). - - - Fixed a bug in the reading of the secrets file (by the daemon) and - the password file (by the client): the files no longer need to be - terminated by a newline for their content to be read in. - - - If a file has a read error on the sending side or the reconstructed - data doesn't match the expected checksum (perhaps due to the basis - file changing during the transfer), the receiver will no longer - retain the resulting file unless the --partial option was specified. - (Note: for the read-error detection to work, neither side can be - older than 2.6.3 -- older receivers will always retain the file, and - older senders don't tell the receiver that the file had a read - error.) - - - If a file gets resent in a single transfer and the --backup option - is enabled, rsync no longer performs a duplicate backup (it used to - overwrite the original file in the backup area). - - - Files specified in the daemon's "exclude" or "exclude from" config - items are now excluded from being uploaded (assuming that the module - allows uploading at all) in addition to the old download exclusion. - - - Got rid of a potential hang in the receiver when near the end of a - phase. - - - When using --backup without a --backup-dir, rsync no longer preserves - the modify time on directories. This avoids confusing NFS. - - - When --copy-links (-L) is specified, we now output a separate error - for a symlink that has no referent instead of claiming that a file - "vanished". - - - The --copy-links (-L) option no longer has the side-effect of telling - the receiving side to follow symlinks. See the --keep-dirlinks - option (mentioned below) for a way to specify that behavior. - - - Error messages from the daemon server's option-parsing (such as - refused options) are now successfully transferred back to the client - (the server used to fail to send the message because the socket - wasn't in the right state for the message to get through). - - - Most transfer errors that occur during a daemon transfer are now - returned to the user in addition to being logged (some messages are - intended to be daemon-only and are not affected by this). - - - Fixed a bug in the daemon authentication code when using one of the - batch-processing options. - - - We try to work around some buggy IPv6 implementations that fail to - implement IPV6_V6ONLY. This should fix the "address in use" error - that some daemons get when running on an OS with a buggy IPv6 - implementation. Also, if the new code gets this error, we might - suggest that the user specify --ipv4 or --ipv6 (if we think it will - help). - - - When the remote rsync dies, make a better effort to recover any error - messages it may have sent before dying (the local rsync used to just - die with a socket-write error). - - - When using --delete and a --backup-dir that contains files that are - hard-linked to their destination equivalents, rsync now makes sure - that removed files really get removed (avoids a really weird rename() - behavior). - - - Avoid a bogus run-time complaint about a lack of 64-bit integers when - the int64 type is defined as an off_t and it actually has 64-bits. - - - Added a configure check for open64() without mkstemp64() so that we - can avoid using mkstemp() when such a combination is encountered. - This bypasses a problem writing out large temp files on OSes such as - AIX and HP-UX. - - - Fixed an age-old crash problem with --read-batch on a local copy - (rsync was improperly assuming --whole-file for the local copy). - - - When --dry-run (-n) is used and the destination directory does not - exist, rsync now produces a correct report of files that would be - sent instead of dying with a chdir() error. - - - Fixed a bug that could cause a slow-to-connect rsync daemon to die - with an error instead of waiting for the connection to finish. - - - Fixed an ssh interaction that could cause output to be lost when the - user chose to combine the output of rsync's stdout and stderr (e.g. - using the "2>&1"). + - Restore the list-clearing behavior of "!" in a .cvsignore file (2.6.3 + was only treating it as a special token in an rsync include/exclude + file). + + - The combination of --verbose and --dry-run now mentions the full list + of changes that would be output without --dry-run. + + - Avoid a mkdir warning when removing a directory in the destination + that already exists in the --backup-dir. + + - An OS that has a binary mode for its files (such as cygwin) needed + setmode(fd, O_BINARY) called on the temp-file we opened with + mkstemp(). (Fix derived from the cygwin's 2.6.3 rsync package.) + + - Fixed a potential hang when verbosity is high, the client side is + the sender, and the file-list is large. + + - Fixed a potential protocol-corrupting bug where the generator could + merge a message from the receiver into the middle of a multiplexed + packet of data if only part of that data had been written out to the + socket when the message from the generator arrived. + + - We now check if the OS doesn't support using mknod() for creating + FIFOs and sockets, and compile-in some compatibility code using + mkfifo() and socket() when necessary. + + - Fixed an off-by-one error in the handling of --max-delete=N. Also, + if the --max-delete limit is exceeded during a run, we now output a + warning about this at the end of the run and exit with a new error + code (25). + + - One place in the code wasn't checking if fork() failed. + + - The "ignore nonreadable" daemon parameter used to erroneously affect + readable symlinks that pointed to a non-existent file. + + - If the OS does not have lchown() and a chown() of a symlink will + affect the referent of a symlink (as it should), we no longer try + to set the user and group of a symlink. + + - The generator now properly runs the hard-link loop and the dir-time + rewriting loop after we're sure that the redo phase is complete. + + - When --backup was specified with --partial-dir=DIR, where DIR is a + relative path, the backup code was erroneously trying to backup a + file that was put into the partial-dir. + + - If a file gets resent in a single transfer and the --backup option is + enabled along with --inplace, rsync no longer performs a duplicate + backup (it used to overwrite the first backup with the failed file). + + - One call to flush_write_file() was not being checked for an error. + + - The --no-relative option was not being sent from the client to a + server sender. + + - If an rsync daemon specified "dont compress = ..." for a file and the + client tried to specify --compress, the libz code was not handling a + compression level of 0 properly. This could cause a transfer failure + if the block-size for a file was large enough (e.g. rsync might have + exited with an error for large files). + + - Fixed a bug that would sometimes surface when using --compress and + sending a file with a block-size larger than 64K (either manually + specified, or computed due to the file being really large). Prior + versions of rsync would sometimes fail to decompress the data + properly, and thus the transferred file would fail its verification. + + - If a daemon can't open the specified log file (i.e. syslog is not + being used), die without crashing. We also output an error about + the failure on stderr (which will only be seen if --no-detach was + specified) and exit with a new error code (6). + + - A local transfer no longer duplicates all its include/exclude options + (since the forked process already has a copy of the exclude list, + there's no need to send them a set of duplicates). + + - When --progress is specified, the output of items that the generator + is creating (e.g. dirs, symlinks) is now integrated into the progress + output without overlapping it. (Requires protocol 29.) + + - When --timeout is specified, lulls that occur in the transfer while + the generator is doing work that does not generate socket traffic + (looking for changed files, deleting files, doing directory-time + touch-ups, etc.) will cause a new keep-alive packet to be sent that + should keep the transfer going as long as the generator continues to + make progress. (Requires protocol 29.) + + - The stat size of a device is not added to the total file size of the + items in the transfer (the size might be undefined on some OSes). + + - Fixed a problem with refused-option messages sometimes not making it + back to the client side when a remote --files-from was in effect and + the daemon was the receiver. + + - The --compare-dest option was not updating a file that differred in + (the preserved) attributes from the version in the compare-dest DIR. + + - When rsync is copying files into a write-protected directory, fixed + the change-report output for the directory so that we don't report + an identical directory as changed. ENHANCEMENTS: - - Added the --partial-dir=DIR option that lets you specify where to - (temporarily) put a partially transferred file (instead of over- - writing the destination file). E.g. --partial-dir=.rsync-partial - Also added support for the RSYNC_PARTIAL_DIR environment variable - that, when found, transforms a regular --partial option (such as - the convenient -P option) into one that also specifies a directory. - - - Added --keep-dirlinks (-K), which allows you to symlink a directory - onto another partition on the receiving side and have rsync treat it - as matching a normal directory from the sender. - - - Added the --inplace option that tells rsync to write each destination - file without using a temporary file. The matching of existing data - in the destination file can be severely limited by this, but there - are also cases where this is more efficient (such as appending data). - Use only when needed (see the man page for more details). - - - Added the "write only" option for the daemon's config file. - - - Added long-option names for -4 and -6 (namely --ipv4 and --ipv6) - and documented all these options in the man page. - - - Improved the handling of the --bwlimit option so that it's less - bursty, more accurate, and works properly over a larger range of - values. - - - The rsync daemon-over-ssh code now looks for SSH_CONNECTION and - SSH2_CLIENT in addition to SSH_CLIENT to figure out the IP address. - - - Added the --checksum-seed=N option for advanced users. - - - Batch writing/reading has a brand-new implementation that is simpler, - fixes a few weird problems with the old code (such as no longer - sprinkling the batch files into different dirs or even onto different - systems), and is much less intrusive into the code (making it easier - to maintain for the future). The new code generates just one data - file instead of three, which makes it possible to read the batch on - stdin via a remote shell. Also, the old requirement of forcing the - same fixed checksum-seed for all batch processing has been removed. - - - If an rsync daemon has a module set with "list = no" (which hides its - presence in the list of available modules), a user that fails to - authenticate gets the same "unknown module" error that they would get - if the module were actually unknown (while still logging the real - error to the daemon's log file). This prevents fishing for module - names. - - - The daemon's "refuse options" config item now allows you to match - option names using wildcards and/or the single-letter option names. - - - Each transferred file now gets its permissions and modified-time - updated before the temp-file gets moved into place. Previously, the - finished file would have a very brief window where its permissions - disallowed all group and world access. - - - Added the ability to parse a literal IPv6 address in an "rsync:" URL - (e.g. rsync://[2001:638:500:101::21]:873/module/dir). - - - The daemon's wildcard expanding code can now handle more than 1000 - filenames (it's now limited by memory instead of having a hard-wired - limit). - - INTERNAL: - - - Some cleanup in the exclude code has saved some per-exclude memory - and made the code easier to maintain. - - - Improved the argv-overflow checking for a remote command that has a - lot of args. - - - Use rsyserr() in the various places that were still calling rprintf() - with strerror() as an arg. + - Rsync now supports popt's option aliases, which means that you can + use /etc/popt and/or ~/.popt to create your own option aliases. - - If an rsync daemon is listening on multiple sockets (to handle both - IPv4 and IPv6 to a single port), we now close all the unneeded file - handles after we accept a connection (we used to close just one of - them). + - Added the --delete-during (--del) option which will delete files + from the receiving side incrementally as each directory in the + transfer is being processed. This makes it more efficient than the + default, before-the-transfer behavior, which is now also available as + --delete-before (and is still the default --delete-WHEN option that + will be chosen if --delete or --delete-excluded is specified without + a --delete-WHEN choice). All the --del* options infer --delete, so + an rsync daemon that refuses "delete" will still refuse to allow any + file-deleting options (including the new --remove-sent-files option). + + - All the --delete-WHEN options are now more memory efficient: + Previously an duplicate set of file-list objects was created on the + receiving side for the entire destination hierarchy. The new + algorithm only creates one directory of objects at a time (for files + inside the transfer). + + - Added the --copy-dest option, which works like --link-dest except + that it locally copies identical files instead of hard-linking them. + + - Added support for specifying multiple --compare-dest, --copy-dest, or + --link-dest options, but only of a single type. (Promoted from the + patches dir and enhanced.) (Requires protocol 29.) + + - Added the --max-size option. (Promoted from the patches dir.) + + - The daemon-mode options are now separated from the normal rsync + options so that they can't be mixed together. This makes it + impossible to start a daemon that has improper default option values + (which could cause problems when a client connects, such as hanging + or crashing). + + - The --bwlimit option may now be used in combination with --daemon + to specify both a default value for the daemon side and a value + that cannot be exceeded by a user-specified --bwlimit option. + + - Added the "port" parameter to the rsyncd.conf file. (Promoted from + the patches dir.) Also added "address". The command-line options + take precedence over a config-file option, as expected. + + - In _exit_cleanup(): when we are exiting with a partially-received + file, we now flush any data in the write-cache before closing the + partial file. + + - The --inplace support was enhanced to work with --compare-dest, + --link-dest, and (the new) --copy-dest options. (Requires protocol + 29.) + + - Added the --dirs (-d) option for an easier way to copy directories + without recursion. + + - Added the --list-only option, which is mainly a way for the client to + put the server into listing mode without needing to resort to any + internal option kluges (e.g. the age-old use of "-r --exclude="/*/*" + for a non-recursive listing). This option is used automatically + (behind the scenes) when a modern rsync speaks to a modern daemon, + but may also be specified manually if you want to force the use of + the --list-only option over a remote-shell connection. + + - Added the --omit-dir-times (-O) option, which will avoid updating + the modified time for directories when --times was specified. This + option will avoid an extra pass through the file-list at the end of + the transfer (to tweak all the directory times), which may provide + an appreciable speedup for a really large transfer. (Promoted from + the patches dir.) + + - Added the --filter (-f) option and its helper option, -F. Filter + rules are an extension to the existing include/exclude handling + that also supports nested filter files as well as per-directory + filter files (like .cvsignore, but with full filter-rule parsing). + This new option was chosen in order to ensure that all existing + include/exclude processing remained 100% compatible with older + versions. Protocol 29 is needed for full filter-rule support, but + backward-compatible rules work with earlier protocol versions. + (Promoted from the patches dir and enhanced.) + + - Added the --delay-updates option that puts all updated files into + a temporary directory (by default ".~tmp~", but settable via the + --partial-dir=DIR option) until the end of the transfer. This + makes the updates a little more atomic for a large transfer. + + - If rsync is put into the background, any output from --progress is + reduced. + + - Documented the "max verbosity" setting for rsyncd.conf. (This + setting was added a couple releases ago, but left undocumented.) + + - The sender and the generator now double-check the file-list index + they are given, and refuse to try to do a file transfer on a + non-file index (since that would indicate that something had gone + very wrong). + + - Added the --itemize-changes (-i) option, which is a way to output a + more detailed list of what files changed and in what way. The effect + is the same as specifying a --log-format of "%i %n%L" (see both the + rsync and rsyncd.conf manpages). Works with --dry-run too. + + - Added the --fuzzy (-y) option, which attempts to find a basis file + for a file that is being created from scratch. The current algorithm + only looks in the destination directory for the created file, but it + does attempt to find a match based on size/mod-time (in case the file + was renamed with no other changes) as well as based on a fuzzy + name-matching algorithm. This option requires protocol 29 because it + needs the new file-sorting order. (Promoted from patches dir and + enhanced.) (Requires protocol 29.) + + - Added the --remove-sent-files option, which lets you move files + between systems. + + - The hostname in HOST:PATH or HOST::PATH may now be an IPv6 literal + enclosed in '[' and ']' (e.g. "[::1]"). (We already allowed IPv6 + literals in the rsync://HOST:PORT/PATH format.) + + - When rsync recurses to build the file list, it no longer keeps open + one or more directory handles from the dir's parent dirs. + + - When building under windows, the default for --daemon is now to + avoid detaching, requiring the new --detach option to force rsync + to detach. + + - The --dry-run option can now be combined with either --write-batch or + --read-batch, allowing you to run a do-nothing test command to see + what would happen without --dry-run. + + - The daemon's "read only" config item now sets an internal read_only + variable that makes extra sure that no write/delete calls on the + read-only side can succeed. + + - The log-format % escapes can now have a numeric field width in + between the % and the escape letter (e.g. "%-40n %08p"). + + - Improved the option descriptions in the --help text. + + SUPPORT FILES: + + - Added atomic-rsync to the support dir: a perl script that will + transfer some files using rsync, and then move the updated files into + place all at once at the end of the transfer. Only works when + pulling, and uses --link-dest and a parallel hierarchy of files to + effect its update. + + - Added mnt-excl to the support dir: a perl script that takes the + /proc/mounts file and translates it into a set of excludes that will + exclude all mount points (even mapped mounts to the same disk). The + excludes are made relative to the specified source dir and properly + anchored. + + - Added savetransfer.c to the support dir: a C program that can make + a copy of all the data that flows over the wire. This lets you test + for data corruption (by saving the data on both the sending side and + the receiving side) and provides one way to debug a protocol error. + + - Added rrsync to the support dir: this is an updated version of Joe + Smith's restricted rsync perl script. This helps to ensure that only + certain rsync commands can be run by an ssh invocation. - - Optimized the handling of larger block sizes (rsync used to slow to a - crawl if the block size got too large). + INTERNAL: - - Optimized away a loop in hash_search(). + - Added better checking of the checksum-header values that come over + the socket. - - Some improvements to the sanitize_path() and clean_fname() functions - makes them more efficient and produce better results (while still - being compatible with the file-name cleaning that gets done on both - sides when sending the file-list). + - Merged a variety of file-deleting functions into a single function so + that it is easier to maintain. - - Got rid of alloc_sanitize_path() after adding a destination-buffer - arg to sanitize_path() made it possible to put all the former's - functionality into the latter. + - Improved the type of some variables (particularly blocksize vars) for + consistency and proper size. - - The file-list that is output when at least 4 verbose options are - specified reports the uid value on the sender even when rsync is - not running as root (since we might be sending to a root receiver). + - Got rid of the uint64 type (which we didn't need). + + - Use a slightly more compatible set of core #include directives. + + - Defined int32 in a way that ensures that the build dies if we can't + find a variable with at least 32 bits. + + PROTOCOL DIFFERENCES FOR VERSION 29: + + - A 16-bit flag-word is transmitted after every file-list index. This + indicates what is changing between the sender and the receiver. The + generator now transmits an index and a flag-word to indicate when + dirs and symlinks have changed (instead of producing a message), + which makes the outputting of the information more consistent and + less prone to screen corruption (because the local receiver/sender is + now outputting all the file-change info messages). + + - If a file is being hard-linked, the ITEM_XNAME_FOLLOWS bit is enabled + in the flag-word and the name of the file that was linked immediately + follows in vstring format (see below). + + - If a file is being transferred with an alternate-basis file, the + ITEM_BASIS_TYPE_FOLLOWS bit is enabled in the flag-word and a single + byte follows, indicating what type of basis file was chosen. If that + indicates that a fuzzy-match was selected, the ITEM_XNAME_FOLLOWS bit + is set in the flag-word and the name of the match in vstring format + follows the basis byte. A vstring is a variable length string that + has its size written prior to the string, and no terminating null. + If the string is from 1-127 bytes, the length is a single byte. If + it is from 128-32767 bytes, the length is written as ((len >> 8) | + 0x80) followed by (len % 0x100). + + - The sending of exclude names is done using filter-rule syntax. This + means that all names have a prefixed rule indicator, even excludes + (which used to be sent as a bare pattern, when possible). The -C + option will include the per-dir .cvsignore merge file in the list of + filter rules so it is positioned correctly (unlike in some older + transfer scenarios). + + - Rsync sorts the filename list in a different way: it sorts the subdir + names after the non-subdir names for each dir's contents, and it + always puts a dir's contents immediately after the dir's name in the + list. (Previously an item named "foo.txt" would sort in between + directory "foo/" and "foo/bar".) + + - When talking to a protocol 29 rsync daemon, a list-only request + is able to note this before the options are sent over the wire and + the new --list-only option is included in the options. + + - When the --stats bytes are sent over the wire (or stored in a batch), + they now include two elapsed-time values: one for how long it took to + build the file-list, and one for how long it took to send it over the + wire (each expressed in thousandths of a second). + + - When --delete-excluded is specified with some filter rules (AKA + excludes), a client sender will now initiate a send of the rules to + the receiver (older protocols used to omit the sending of excludes in + this situation since there were no receiver-specific rules that + survived --delete-excluded back then). Note that, as with all the + filter-list sending, only items that are significant to the other + side will actually be sent over the wire, so the filter-rule list + that is sent in this scenario is often empty. + + - An index equal to the file-list count is sent as a keep-alive packet + from the generator to the sender, which then forwards it on to the + receiver. This normally invalid index is only a valid keep-alive + packet if the 16-bit flag-word that follows it contains a single bit + (ITEM_IS_NEW, which is normally an illegal flag to appear alone). + + - A protocol-29 batch file includes a bit for the setting of the --dirs + option and for the setting of the --compress option. Also, the shell + script created by --write-batch will use the --filter option instead + of --exclude-from to capture any filter rules. BUILD CHANGES: - - Added a "gen" target to rebuild most of the generated files, - including configure, config.h.in, the man pages, and proto.h. - - - If "make proto" doesn't find some changes in the prototypes, the - proto.h file is left untouched (its time-stamp used to always be - updated). - - - The variable $STRIP (that is optionally set by the install-strip - target's rule) was changed to $INSTALL_STRIP because some systems - have $STRIP already set in the environment. - - - Fixed a build problem when SUPPORT_HARD_LINKS isn't defined. - - - When cross-compiling, the gettimeofday() function is now assumed to - be a modern version that takes two-args (since we can't test it). - - DEVELOPER RELATED: - - - The scripts in the testsuite dir were cleaned up a bit and a few - new tests added. - - - Some new diffs were added to the patches dir, and some accepted - ones were removed. + - Handle an operating system that use mkdev() in place of makedev(). + - Improved configure to better handle cross-compiling. diff -urN --exclude=patches rsync-2.6.3/OLDNEWS rsync-2.6.4/OLDNEWS --- rsync-2.6.3/OLDNEWS 2004-09-30 02:36:29.000000000 -0700 +++ rsync-2.6.4/OLDNEWS 2005-03-28 22:15:08.000000000 -0800 @@ -1,3 +1,256 @@ +NEWS for rsync 2.6.3 (30 Sep 2004) +Protocol: 28 (unchanged) +Changes since 2.6.2: + + SECURITY FIXES: + + - A bug in the sanitize_path routine (which affects a non-chrooted + rsync daemon) could allow a user to craft a pathname that would get + transformed into an absolute path for certain options (but not for + file-transfer names). If you're running an rsync daemon with chroot + disabled, *please upgrade*, ESPECIALLY if the user privs you run + rsync under is anything above "nobody". + + OUTPUT CHANGES (ATTN: those using a script to parse the verbose output): + + - Please note that the 2-line footer (output when verbose) now uses the + term "sent" instead of "wrote" and "received" instead of "read". If + you are not parsing the numeric values out of this footer, a script + would be better off using the empty line prior to the footer as the + indicator that the verbose output is over. + + - The output from the --stats option was similarly affected to change + "written" to "sent" and "read" to "received". + + - Rsync ensures that a filename that contains a newline gets mentioned + with each newline transformed into a question mark (which prevents a + filename from causing an empty line to be output). + + - The "backed up ..." message that is output when at least 2 --verbose + options are specified is now the same both with and without the + --backup-dir option. + + BUG FIXES: + + - Fixed a crash bug that might appear when --delete was used and + multiple source directories were specified. + + - Fixed a 32-bit truncation of the file length when generating the + checksums. + + - The --backup code no longer attempts to create some directories + over and over again (generating warnings along the way). + + - Fixed a bug in the reading of the secrets file (by the daemon) and + the password file (by the client): the files no longer need to be + terminated by a newline for their content to be read in. + + - If a file has a read error on the sending side or the reconstructed + data doesn't match the expected checksum (perhaps due to the basis + file changing during the transfer), the receiver will no longer + retain the resulting file unless the --partial option was specified. + (Note: for the read-error detection to work, neither side can be + older than 2.6.3 -- older receivers will always retain the file, and + older senders don't tell the receiver that the file had a read + error.) + + - If a file gets resent in a single transfer and the --backup option + is enabled, rsync no longer performs a duplicate backup (it used to + overwrite the original file in the backup area). + + - Files specified in the daemon's "exclude" or "exclude from" config + items are now excluded from being uploaded (assuming that the module + allows uploading at all) in addition to the old download exclusion. + + - Got rid of a potential hang in the receiver when near the end of a + phase. + + - When using --backup without a --backup-dir, rsync no longer preserves + the modify time on directories. This avoids confusing NFS. + + - When --copy-links (-L) is specified, we now output a separate error + for a symlink that has no referent instead of claiming that a file + "vanished". + + - The --copy-links (-L) option no longer has the side-effect of telling + the receiving side to follow symlinks. See the --keep-dirlinks + option (mentioned below) for a way to specify that behavior. + + - Error messages from the daemon server's option-parsing (such as + refused options) are now successfully transferred back to the client + (the server used to fail to send the message because the socket + wasn't in the right state for the message to get through). + + - Most transfer errors that occur during a daemon transfer are now + returned to the user in addition to being logged (some messages are + intended to be daemon-only and are not affected by this). + + - Fixed a bug in the daemon authentication code when using one of the + batch-processing options. + + - We try to work around some buggy IPv6 implementations that fail to + implement IPV6_V6ONLY. This should fix the "address in use" error + that some daemons get when running on an OS with a buggy IPv6 + implementation. Also, if the new code gets this error, we might + suggest that the user specify --ipv4 or --ipv6 (if we think it will + help). + + - When the remote rsync dies, make a better effort to recover any error + messages it may have sent before dying (the local rsync used to just + die with a socket-write error). + + - When using --delete and a --backup-dir that contains files that are + hard-linked to their destination equivalents, rsync now makes sure + that removed files really get removed (avoids a really weird rename() + behavior). + + - Avoid a bogus run-time complaint about a lack of 64-bit integers when + the int64 type is defined as an off_t and it actually has 64-bits. + + - Added a configure check for open64() without mkstemp64() so that we + can avoid using mkstemp() when such a combination is encountered. + This bypasses a problem writing out large temp files on OSes such as + AIX and HP-UX. + + - Fixed an age-old crash problem with --read-batch on a local copy + (rsync was improperly assuming --whole-file for the local copy). + + - When --dry-run (-n) is used and the destination directory does not + exist, rsync now produces a correct report of files that would be + sent instead of dying with a chdir() error. + + - Fixed a bug that could cause a slow-to-connect rsync daemon to die + with an error instead of waiting for the connection to finish. + + - Fixed an ssh interaction that could cause output to be lost when the + user chose to combine the output of rsync's stdout and stderr (e.g. + using the "2>&1"). + + ENHANCEMENTS: + + - Added the --partial-dir=DIR option that lets you specify where to + (temporarily) put a partially transferred file (instead of over- + writing the destination file). E.g. --partial-dir=.rsync-partial + Also added support for the RSYNC_PARTIAL_DIR environment variable + that, when found, transforms a regular --partial option (such as + the convenient -P option) into one that also specifies a directory. + + - Added --keep-dirlinks (-K), which allows you to symlink a directory + onto another partition on the receiving side and have rsync treat it + as matching a normal directory from the sender. + + - Added the --inplace option that tells rsync to write each destination + file without using a temporary file. The matching of existing data + in the destination file can be severely limited by this, but there + are also cases where this is more efficient (such as appending data). + Use only when needed (see the man page for more details). + + - Added the "write only" option for the daemon's config file. + + - Added long-option names for -4 and -6 (namely --ipv4 and --ipv6) + and documented all these options in the man page. + + - Improved the handling of the --bwlimit option so that it's less + bursty, more accurate, and works properly over a larger range of + values. + + - The rsync daemon-over-ssh code now looks for SSH_CONNECTION and + SSH2_CLIENT in addition to SSH_CLIENT to figure out the IP address. + + - Added the --checksum-seed=N option for advanced users. + + - Batch writing/reading has a brand-new implementation that is simpler, + fixes a few weird problems with the old code (such as no longer + sprinkling the batch files into different dirs or even onto different + systems), and is much less intrusive into the code (making it easier + to maintain for the future). The new code generates just one data + file instead of three, which makes it possible to read the batch on + stdin via a remote shell. Also, the old requirement of forcing the + same fixed checksum-seed for all batch processing has been removed. + + - If an rsync daemon has a module set with "list = no" (which hides its + presence in the list of available modules), a user that fails to + authenticate gets the same "unknown module" error that they would get + if the module were actually unknown (while still logging the real + error to the daemon's log file). This prevents fishing for module + names. + + - The daemon's "refuse options" config item now allows you to match + option names using wildcards and/or the single-letter option names. + + - Each transferred file now gets its permissions and modified-time + updated before the temp-file gets moved into place. Previously, the + finished file would have a very brief window where its permissions + disallowed all group and world access. + + - Added the ability to parse a literal IPv6 address in an "rsync:" URL + (e.g. rsync://[2001:638:500:101::21]:873/module/dir). + + - The daemon's wildcard expanding code can now handle more than 1000 + filenames (it's now limited by memory instead of having a hard-wired + limit). + + INTERNAL: + + - Some cleanup in the exclude code has saved some per-exclude memory + and made the code easier to maintain. + + - Improved the argv-overflow checking for a remote command that has a + lot of args. + + - Use rsyserr() in the various places that were still calling rprintf() + with strerror() as an arg. + + - If an rsync daemon is listening on multiple sockets (to handle both + IPv4 and IPv6 to a single port), we now close all the unneeded file + handles after we accept a connection (we used to close just one of + them). + + - Optimized the handling of larger block sizes (rsync used to slow to a + crawl if the block size got too large). + + - Optimized away a loop in hash_search(). + + - Some improvements to the sanitize_path() and clean_fname() functions + makes them more efficient and produce better results (while still + being compatible with the file-name cleaning that gets done on both + sides when sending the file-list). + + - Got rid of alloc_sanitize_path() after adding a destination-buffer + arg to sanitize_path() made it possible to put all the former's + functionality into the latter. + + - The file-list that is output when at least 4 verbose options are + specified reports the uid value on the sender even when rsync is + not running as root (since we might be sending to a root receiver). + + BUILD CHANGES: + + - Added a "gen" target to rebuild most of the generated files, + including configure, config.h.in, the man pages, and proto.h. + + - If "make proto" doesn't find some changes in the prototypes, the + proto.h file is left untouched (its time-stamp used to always be + updated). + + - The variable $STRIP (that is optionally set by the install-strip + target's rule) was changed to $INSTALL_STRIP because some systems + have $STRIP already set in the environment. + + - Fixed a build problem when SUPPORT_HARD_LINKS isn't defined. + + - When cross-compiling, the gettimeofday() function is now assumed to + be a modern version that takes two-args (since we can't test it). + + DEVELOPER RELATED: + + - The scripts in the testsuite dir were cleaned up a bit and a few + new tests added. + + - Some new diffs were added to the patches dir, and some accepted + ones were removed. + + NEWS for rsync 2.6.2 (30 Apr 2004) Protocol: 28 (unchanged) Changes since 2.6.1: @@ -789,7 +1042,8 @@ build farm. Partial Protocol History - RELEASE DATE VER. DATE OF COMMIT PROTOCOL + RELEASE DATE VER. DATE OF COMMIT* PROTOCOL + 30 Mar 2005 2.6.4 17 Jan 2005 29 30 Sep 2004 2.6.3 28 30 Apr 2004 2.6.2 28 26 Apr 2004 2.6.1 08 Jan 2004 28 diff -urN --exclude=patches rsync-2.6.3/README rsync-2.6.4/README --- rsync-2.6.3/README 2004-06-06 13:36:56.000000000 -0700 +++ rsync-2.6.4/README 2005-02-20 16:16:36.000000000 -0800 @@ -1,7 +1,7 @@ WHAT IS RSYNC? -------------- -rsync is a replacement for rcp that has many more features. +rsync is a replacement for scp/rcp that has many more features. rsync uses the "rsync algorithm" which provides a very fast method for bringing remote files into sync. It does this by sending just the @@ -31,7 +31,7 @@ Rsync normally uses ssh or rsh for communication. It does not need to be setuid and requires no special privileges for installation. You -must, however, have a working ssh or rsh system. Using ssh is +must, however, have a working ssh or rsh system. Using ssh is recommended for its security features. Alternatively, rsync can run in `daemon' mode, listening on a socket. @@ -102,8 +102,7 @@ cvs -d :pserver:cvs@pserver.samba.org:/cvsroot co rsync -Look at the cvs documentation, or http://samba.org/cvs.html, for more -details. +Look at the cvs documentation for more details. COPYRIGHT diff -urN --exclude=patches rsync-2.6.3/TODO rsync-2.6.4/TODO --- rsync-2.6.3/TODO 2004-06-06 13:41:01.000000000 -0700 +++ rsync-2.6.4/TODO 2005-02-28 19:11:28.000000000 -0800 @@ -1,15 +1,9 @@ -*- indented-text -*- BUGS --------------------------------------------------------------- -Fix progress indicator to not corrupt log -lchmod question Do not rely on having a group called "nobody" -Incorrect timestamps (Debian #100295) -Win32 FEATURES ------------------------------------------------------------ -server-imposed bandwidth limits -rsyncd over ssh Use chroot only if supported Allow supplementary groups in rsyncd.conf 2002/04/09 Handling IPv6 on old machines @@ -25,23 +19,18 @@ Create more granular verbosity jw 2003/05/15 DOCUMENTATION -------------------------------------------------------- -Update README Keep list of open issues and todos on the web site Perhaps redo manual as SGML LOGGING -------------------------------------------------------------- -Make dry run list all updates 2002/04/03 Memory accounting Improve error messages Better statistics: Rasmus 2002/03/08 Perhaps flush stdout like syslog Log deamon sessions that just list modules Log child death on signal -Keep stderr and stdout properly separated (Debian #23626) Log errors with function that reports process of origin verbose output David Stein 2001/12/20 -Add reason for transfer to file logging -debugging of daemon 2002/04/08 internationalization DEVELOPMENT -------------------------------------------------------- @@ -49,9 +38,6 @@ Use generic zlib 2002/02/25 TDB: 2002/03/12 Splint 2002/03/12 -Memory debugger -Create release script -Add machines to build farm PERFORMANCE ---------------------------------------------------------- File list structure in memory @@ -82,37 +68,6 @@ BUGS --------------------------------------------------------------- -Fix progress indicator to not corrupt log - - Progress indicator can produce corrupt output when transferring directories: - - main/binary-arm/ - main/binary-arm/admin/ - main/binary-arm/base/ - main/binary-arm/comm/8.56kB/s 0:00:52 - main/binary-arm/devel/ - main/binary-arm/doc/ - main/binary-arm/editors/ - main/binary-arm/electronics/s 0:00:53 - main/binary-arm/games/ - main/binary-arm/graphics/ - main/binary-arm/hamradio/ - main/binary-arm/interpreters/ - main/binary-arm/libs/6.61kB/s 0:00:54 - main/binary-arm/mail/ - main/binary-arm/math/ - main/binary-arm/misc/ - - -- -- - - -lchmod question - - I don't think we handle this properly on systems that don't have the - call. Are there any such? - - -- -- - Do not rely on having a group called "nobody" @@ -122,40 +77,8 @@ -- -- - -Incorrect timestamps (Debian #100295) - - A bit hard to believe, but apparently it happens. - - -- -- - - -Win32 - - Don't detach, because this messes up --srvany. - - http://sources.redhat.com/ml/cygwin/2001-08/msg00234.html - - - - -- -- - FEATURES ------------------------------------------------------------ -server-imposed bandwidth limits - - -- -- - - -rsyncd over ssh - - There are already some patches to do this. - - BitKeeper uses a server whose login shell is set to bkd. That's - probably a reasonable approach. - - -- -- - Use chroot only if supported @@ -223,14 +146,6 @@ multiple passive addresses. This might be a bit harder, because we may need to select on all of them. Hm. - Define a syntax for IPv6 literal addresses. Since they include - colons, they tend to break most naming systems, including ours. - Based on the HTTP IPv6 syntax, I think we should use - - rsync://[::1]/foo/bar [::1]::bar - - which should just take a small change to the parser code. - -- -- @@ -239,6 +154,7 @@ Transfer ACLs. Need to think of a standard representation. Probably better not to even try to convert between NT and POSIX. Possibly can share some code with Samba. + NOTE: there is a patch that implements this in the "patches" subdir. -- -- @@ -307,6 +223,8 @@ (Debian #23628) + NOTE: there is a patch that implements this in the "patches" subdir. + -- -- @@ -351,10 +269,6 @@ DOCUMENTATION -------------------------------------------------------- -Update README - - -- -- - Keep list of open issues and todos on the web site @@ -376,17 +290,6 @@ LOGGING -------------------------------------------------------------- -Make dry run list all updates 2002/04/03 - - --dry-run is too dry - - Mark Santcroos points out that -n fails to list files which have - only metadata changes, though it probably should. - - There may be a Debian bug about this as well. - - -- -- - Memory accounting @@ -468,11 +371,6 @@ -- -- -Keep stderr and stdout properly separated (Debian #23626) - - -- -- - - Log errors with function that reports process of origin Use a separate function for reporting errors; prefix it with @@ -484,29 +382,12 @@ verbose output David Stein 2001/12/20 - Indicate whether files are new, updated, or deleted - At end of transfer, show how many files were or were not transferred correctly. -- -- -Add reason for transfer to file logging - - Explain *why* every file is transferred or not (e.g. "local mtime - 123123 newer than 1283198") - - -- -- - - -debugging of daemon 2002/04/08 - - Add an rsyncd.conf parameter to turn on debugging on the server. - - -- -- - - internationalization Change to using gettext(). Probably need to ship this for platforms @@ -524,46 +405,16 @@ Handling duplicate names - We need to be careful of duplicate names getting into the file list. - See clean_flist(). This could happen if multiple arguments include - the same file. Bad. - - I think duplicates are only a problem if they're both flowing - through the pipeline at the same time. For example we might have - updated the first occurrence after reading the checksums for the - second. So possibly we just need to make sure that we don't have - both in the pipeline at the same time. - - Possibly if we did one directory at a time that would be sufficient. - - Alternatively we could pre-process the arguments to make sure no - duplicates will ever be inserted. There could be some bad cases - when we're collapsing symlinks. - - We could have a hash table. - - The root of the problem is that we do not want more than one file - list entry referring to the same file. At first glance there are - several ways this could happen: symlinks, hardlinks, and repeated - names on the command line. - - If names are repeated on the command line, they may be present in - different forms, perhaps by traversing directory paths in different - ways, traversing paths including symlinks. Also we need to allow - for expansion of globs by rsync. - - At the moment, clean_flist() requires having the entire file list in - memory. Duplicate names are detected just by a string comparison. - - We don't need to worry about hard links causing duplicates because - files are never updated in place. Similarly for symlinks. - - I think even if we're using a different symlink mode we don't need - to worry. - - Unless we're really clever this will introduce a protocol - incompatibility, so we need to be able to accept the old format as - well. + Some folks would like rsync to be deterministic in how it handles + duplicate names that come from mering multiple source directories + into a single destination directory; e.g. the last name wins. We + could do this by switching our sort algorithm to one that will + guarantee that the names won't be reordered. Alternately, we could + assign an ever-increasing number to each item as we insert it into + the list and then make sure that we leave the largest number when + cleaning the file list (see clean_flist()). Another solution would + be to add a hash table, and thus never put any duplicate names into + the file list (and bump the protocol to handle this). -- -- @@ -619,45 +470,6 @@ -- -- - -Memory debugger - - jra recommends Valgrind: - - http://devel-home.kde.org/~sewardj/ - - -- -- - - -Create release script - - Script would: - - Update spec files - - Build tar file; upload - - Send announcement to mailing list and c.o.l.a. - - Make freshmeat announcement - - Update web site - - -- -- - - -Add machines to build farm - - Cygwin (on different versions of Win32?) - - HP-UX variants (via HP?) - - SCO - - - - -- -- - PERFORMANCE ---------------------------------------------------------- File list structure in memory @@ -692,14 +504,10 @@ calculating MD4 checksums uses 90% of CPU and is unlikely to be useful. - Indeed for transfers over zlib or ssh we can also rely on the - transport to have quite strong protection against corruption. - - Perhaps we should have an option to disable this, - analogous to --whole-file, although it would default to - disabled. The file checksum takes up a definite space in - the protocol -- we can either set it to 0, or perhaps just - leave it out. + We should not allow it to be disabled separately from -W, though + as it is the only thing that lets us know when the rsync algorithm + got out of sync and messed the file up (i.e. if the basis file + changed between checksum generation and reception). -- -- @@ -842,5 +650,9 @@ Goswin Brederlow suggested this on Debian; I think tridge and I talked about it previous in relation to rproxy. + Addendum: It looks like someone is working on a version of this: + + http://zsync.moria.org.uk/ + -- -- diff -urN --exclude=patches rsync-2.6.3/access.c rsync-2.6.4/access.c --- rsync-2.6.3/access.c 2004-09-24 09:50:07.000000000 -0700 +++ rsync-2.6.4/access.c 2005-02-13 16:53:43.000000000 -0800 @@ -26,7 +26,8 @@ static int match_hostname(char *host, char *tok) { - if (!host || !*host) return 0; + if (!host || !*host) + return 0; return wildmatch(tok, host); } @@ -34,16 +35,16 @@ { int i; - for (i=0; i> 3; @@ -75,14 +76,14 @@ char *a = NULL, *t = NULL; unsigned int len; - if (!addr || !*addr) return 0; + if (!addr || !*addr) + return 0; p = strchr(tok,'/'); if (p) { *p = '\0'; len = p - tok; - } - else + } else len = strlen(tok); /* Fail quietly if tok is a hostname (not an address) */ @@ -218,12 +219,14 @@ char *tok; char *list2 = strdup(list); - if (!list2) out_of_memory("access_match"); + if (!list2) + out_of_memory("access_match"); strlower(list2); - if (host) strlower(host); + if (host) + strlower(host); - for (tok=strtok(list2," ,\t"); tok; tok=strtok(NULL," ,\t")) { + for (tok = strtok(list2, " ,\t"); tok; tok = strtok(NULL, " ,\t")) { if (match_hostname(host, tok) || match_address(addr, tok)) { free(list2); return 1; @@ -236,29 +239,25 @@ int allow_access(char *addr, char *host, char *allow_list, char *deny_list) { - /* if theres no deny list and no allow list then allow access */ - if ((!deny_list || !*deny_list) && (!allow_list || !*allow_list)) - return 1; - - /* if there is an allow list but no deny list then allow only hosts - on the allow list */ - if (!deny_list || !*deny_list) - return(access_match(allow_list, addr, host)); - - /* if theres a deny list but no allow list then allow - all hosts not on the deny list */ - if (!allow_list || !*allow_list) - return(!access_match(deny_list,addr,host)); - - /* if there are both type of list then allow all hosts on the - allow list */ - if (access_match(allow_list,addr,host)) - return 1; - - /* if there are both type of list and it's not on the allow then - allow it if its not on the deny */ - if (access_match(deny_list,addr,host)) + if (allow_list && !*allow_list) + allow_list = NULL; + if (deny_list && !*deny_list) + deny_list = NULL; + + /* If we match an allow-list item, we always allow access. */ + if (allow_list) { + if (access_match(allow_list, addr, host)) + return 1; + /* For an allow-list w/o a deny-list, disallow non-matches. */ + if (!deny_list) + return 0; + } + + /* If we match a deny-list item (and got past any allow-list + * items), we always disallow access. */ + if (deny_list && access_match(deny_list, addr, host)) return 0; + /* Allow all other access. */ return 1; } diff -urN --exclude=patches rsync-2.6.3/authenticate.c rsync-2.6.4/authenticate.c --- rsync-2.6.3/authenticate.c 2004-09-24 10:04:05.000000000 -0700 +++ rsync-2.6.4/authenticate.c 2005-02-07 12:36:43.000000000 -0800 @@ -87,7 +87,7 @@ return 0; if (do_stat(fname, &st) == -1) { - rsyserr(FLOG, errno, "stat(%s)", fname); + rsyserr(FLOG, errno, "stat(%s)", safe_fname(fname)); ok = 0; } else if (lp_strict_modes(module)) { if ((st.st_mode & 06) != 0) { @@ -156,14 +156,15 @@ return NULL; if ((fd = open(filename,O_RDONLY)) < 0) { - rsyserr(FERROR, errno, "could not open password file \"%s\"",filename); + rsyserr(FERROR, errno, "could not open password file \"%s\"", + safe_fname(filename)); if (envpw) rprintf(FERROR, "falling back to RSYNC_PASSWORD environment variable.\n"); return NULL; } if (do_stat(filename, &st) == -1) { - rsyserr(FERROR, errno, "stat(%s)", filename); + rsyserr(FERROR, errno, "stat(%s)", safe_fname(filename)); ok = 0; } else if ((st.st_mode & 06) != 0) { rprintf(FERROR,"password file must not be other-accessible\n"); diff -urN --exclude=patches rsync-2.6.3/backup.c rsync-2.6.4/backup.c --- rsync-2.6.3/backup.c 2004-09-20 12:46:45.000000000 -0700 +++ rsync-2.6.4/backup.c 2005-02-21 17:57:58.000000000 -0800 @@ -55,21 +55,37 @@ /* simple backup creates a backup with a suffix in the same directory */ static int make_simple_backup(char *fname) { + int rename_errno; char *fnamebak = get_backup_name(fname); if (!fnamebak) return 0; - if (do_rename(fname, fnamebak) != 0) { - /* cygwin (at least version b19) reports EINVAL */ - if (errno != ENOENT && errno != EINVAL) { - rsyserr(FERROR, errno, - "rename %s to backup %s", fname, fnamebak); - return 0; + while (1) { + if (do_rename(fname, fnamebak) == 0) { + if (verbose > 1) { + rprintf(FINFO, "backed up %s to %s\n", + safe_fname(fname), + safe_fname(fnamebak)); + } + break; } - } else if (verbose > 1) { - rprintf(FINFO, "backed up %s to %s\n", fname, fnamebak); + /* cygwin (at least version b19) reports EINVAL */ + if (errno == ENOENT || errno == EINVAL) + break; + + rename_errno = errno; + if (errno == EISDIR && do_rmdir(fnamebak) == 0) + continue; + if (errno == ENOTDIR && do_unlink(fnamebak) == 0) + continue; + + rsyserr(FERROR, rename_errno, "rename %s to backup %s", + safe_fname(fname), safe_fname(fnamebak)); + errno = rename_errno; + return 0; } + return 1; } @@ -162,21 +178,15 @@ int ret_code; /* return if no file to keep */ -#if SUPPORT_LINKS - ret_code = do_lstat(fname, &st); -#else - ret_code = do_stat(fname, &st); -#endif - if (ret_code < 0) + if (do_lstat(fname, &st) < 0) return 1; - if (!(file = make_file(fname, NULL, NO_EXCLUDES))) + if (!(file = make_file(fname, NULL, NO_FILTERS))) return 1; /* the file could have disappeared */ if (!(buf = get_backup_name(fname))) return 0; -#ifdef HAVE_MKNOD /* Check to see if this is a device file, or link */ if (IS_DEVICE(file->mode)) { if (am_root && preserve_devices) { @@ -188,13 +198,12 @@ } else if (verbose > 2) { rprintf(FINFO, "make_backup: DEVICE %s successful.\n", - fname); + safe_fname(fname)); } } kept = 1; do_unlink(fname); } -#endif if (!kept && S_ISDIR(file->mode)) { /* make an empty directory */ @@ -213,7 +222,7 @@ kept = 1; } -#if SUPPORT_LINKS +#ifdef SUPPORT_LINKS if (!kept && preserve_links && S_ISLNK(file->mode)) { if (safe_symlinks && unsafe_symlink(file->u.link, buf)) { if (verbose) { @@ -226,7 +235,7 @@ && (errno != ENOENT || make_bak_dir(buf) < 0 || do_symlink(file->u.link, buf) < 0)) { rsyserr(FERROR, errno, "link %s -> \"%s\"", - full_fname(buf), file->u.link); + full_fname(buf), safe_fname(file->u.link)); } do_unlink(fname); kept = 1; @@ -235,7 +244,7 @@ if (!kept && !S_ISREG(file->mode)) { rprintf(FINFO, "make_bak: skipping non-regular file %s\n", - fname); + safe_fname(fname)); return 1; } @@ -243,7 +252,7 @@ if (!kept) { if (robust_move(fname, buf) != 0) { rsyserr(FERROR, errno, "keep_backup failed: %s -> \"%s\"", - full_fname(fname), buf); + full_fname(fname), safe_fname(buf)); } else if (st.st_nlink > 1) { /* If someone has hard-linked the file into the backup * dir, rename() might return success but do nothing! */ @@ -253,8 +262,10 @@ set_perms(buf, file, NULL, 0); free(file); - if (verbose > 1) - rprintf(FINFO, "backed up %s to %s\n", fname, buf); + if (verbose > 1) { + rprintf(FINFO, "backed up %s to %s\n", + safe_fname(fname), safe_fname(buf)); + } return 1; } diff -urN --exclude=patches rsync-2.6.3/batch.c rsync-2.6.4/batch.c --- rsync-2.6.3/batch.c 2004-08-01 21:50:33.000000000 -0700 +++ rsync-2.6.4/batch.c 2005-03-26 21:02:49.000000000 -0800 @@ -8,26 +8,32 @@ #include "rsync.h" #include -extern char *batch_name; +extern int am_sender; extern int eol_nulls; extern int recurse; +extern int xfer_dirs; extern int preserve_links; extern int preserve_hard_links; extern int preserve_devices; extern int preserve_uid; extern int preserve_gid; extern int always_checksum; +extern int do_compression; +extern int protocol_version; +extern char *batch_name; -extern struct exclude_list_struct exclude_list; +extern struct filter_list_struct filter_list; static int *flag_ptr[] = { - &recurse, - &preserve_uid, - &preserve_gid, - &preserve_links, - &preserve_devices, - &preserve_hard_links, - &always_checksum, + &recurse, /* 0 */ + &preserve_uid, /* 1 */ + &preserve_gid, /* 2 */ + &preserve_links, /* 3 */ + &preserve_devices, /* 4 */ + &preserve_hard_links, /* 5 */ + &always_checksum, /* 6 */ + &xfer_dirs, /* 7 (protocol 29) */ + &do_compression, /* 8 (protocol 29) */ NULL }; @@ -39,6 +45,8 @@ "--devices (-D)", "--hard-links (-H)", "--checksum (-c)", + "--dirs (-d)", + "--compress (-z)", NULL }; @@ -48,6 +56,8 @@ /* Start the batch file with a bitmap of data-stream-affecting * flags. */ + if (protocol_version < 29) + flag_ptr[7] = NULL; for (i = 0, flags = 0; flag_ptr[i]; i++) { if (*flag_ptr[i]) flags |= 1 << i; @@ -59,6 +69,8 @@ { int i, flags; + if (protocol_version < 29) + flag_ptr[7] = NULL; for (i = 0, flags = read_int(fd); flag_ptr[i]; i++) { int set = flags & (1 << i) ? 1 : 0; if (*flag_ptr[i] != set) { @@ -70,6 +82,12 @@ *flag_ptr[i] = set; } } + if (protocol_version < 29) { + if (recurse) + xfer_dirs |= 1; + else if (xfer_dirs < 2) + xfer_dirs = 0; + } } static void write_arg(int fd, char *arg) @@ -95,19 +113,16 @@ write(fd, arg, strlen(arg)); } -static void write_excludes(int fd) +static void write_filter_rules(int fd) { - struct exclude_struct *ent; + struct filter_struct *ent; write_sbuf(fd, " <<'#E#'\n"); - for (ent = exclude_list.head; ent; ent = ent->next) { - char *p = ent->pattern; - if (ent->match_flags & MATCHFLG_INCLUDE) - write_buf(fd, "+ ", 2); - else if (((*p == '-' || *p == '+') && p[1] == ' ') - || *p == '#' || *p == ';') - write_buf(fd, "- ", 2); - write_sbuf(fd, p); + for (ent = filter_list.head; ent; ent = ent->next) { + unsigned int plen; + char *p = get_rule_prefix(ent->match_flags, "- ", 0, &plen); + write_buf(fd, p, plen); + write_sbuf(fd, ent->pattern); if (ent->match_flags & MATCHFLG_DIRECTORY) write_byte(fd, '/'); write_byte(fd, eol_nulls ? 0 : '\n'); @@ -132,23 +147,33 @@ fd = do_open(filename, O_WRONLY | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR | S_IEXEC); if (fd < 0) { - rsyserr(FERROR, errno, "Batch file %s open error", filename); + rsyserr(FERROR, errno, "Batch file %s open error", + safe_fname(filename)); exit_cleanup(1); } /* Write argvs info to BATCH.sh file */ write_arg(fd, argv[0]); - if (exclude_list.head) - write_sbuf(fd, " --exclude-from=-"); + if (filter_list.head) { + if (protocol_version >= 29) + write_sbuf(fd, " --filter=._-"); + else + write_sbuf(fd, " --exclude-from=-"); + } for (i = 1; i < argc - file_arg_cnt; i++) { p = argv[i]; if (strncmp(p, "--files-from", 12) == 0 + || strncmp(p, "--filter", 8) == 0 || strncmp(p, "--include", 9) == 0 || strncmp(p, "--exclude", 9) == 0) { if (strchr(p, '=') == NULL) i++; continue; } + if (strcmp(p, "-f") == 0) { + i++; + continue; + } write(fd, " ", 1); if (strncmp(p, "--write-batch", 13) == 0) { write(fd, "--read-batch", 12); @@ -159,18 +184,16 @@ } else write_arg(fd, p); } - if ((p = find_colon(argv[argc - 1])) != NULL) { - if (*++p == ':') - p++; - } else + if (!(p = check_for_hostspec(argv[argc - 1], &p, &i))) p = argv[argc - 1]; write(fd, " ${1:-", 6); write_arg(fd, p); write_byte(fd, '}'); - if (exclude_list.head) - write_excludes(fd); + if (filter_list.head) + write_filter_rules(fd); if (write(fd, "\n", 1) != 1 || close(fd) < 0) { - rsyserr(FERROR, errno, "Batch file %s write error", filename); + rsyserr(FERROR, errno, "Batch file %s write error", + safe_fname(filename)); exit_cleanup(1); } } @@ -187,25 +210,25 @@ rprintf(FINFO, "flist->length=%.0f\n", (double) fptr[i]->length); rprintf(FINFO, "flist->mode=%#o\n", (int) fptr[i]->mode); - rprintf(FINFO, "flist->basename=%s\n", fptr[i]->basename); - if (fptr[i]->dirname) + rprintf(FINFO, "flist->basename=%s\n", + safe_fname(fptr[i]->basename)); + if (fptr[i]->dirname) { rprintf(FINFO, "flist->dirname=%s\n", - fptr[i]->dirname); - if (fptr[i]->basedir) - rprintf(FINFO, "flist->basedir=%s\n", - fptr[i]->basedir); + safe_fname(fptr[i]->dirname)); + } + if (am_sender && fptr[i]->dir.root) { + rprintf(FINFO, "flist->dir.root=%s\n", + safe_fname(fptr[i]->dir.root)); + } } } +/* for debugging */ void show_argvs(int argc, char *argv[]) { - /* for debugging * */ - int i; - rprintf(FINFO, "BATCH.C:show_argvs,argc=%d\n", argc); - for (i = 0; i < argc; i++) { - /* if (argv[i]) */ - rprintf(FINFO, "i=%d,argv[i]=%s\n", i, argv[i]); - } + rprintf(FINFO, "BATCH.C:show_argvs,argc=%d\n", argc); + for (i = 0; i < argc; i++) + rprintf(FINFO, "i=%d,argv[i]=%s\n", i, safe_fname(argv[i])); } diff -urN --exclude=patches rsync-2.6.3/checksum.c rsync-2.6.4/checksum.c --- rsync-2.6.3/checksum.c 2004-08-03 08:37:54.000000000 -0700 +++ rsync-2.6.4/checksum.c 2005-01-01 13:08:05.000000000 -0800 @@ -30,9 +30,9 @@ a simple 32 bit checksum that can be upadted from either end (inspired by Mark Adler's Adler-32 checksum) */ -uint32 get_checksum1(char *buf1,int len) +uint32 get_checksum1(char *buf1, int32 len) { - int i; + int32 i; uint32 s1, s2; schar *buf = (schar *)buf1; @@ -49,18 +49,20 @@ } -void get_checksum2(char *buf,int len,char *sum) +void get_checksum2(char *buf, int32 len, char *sum) { - int i; + int32 i; static char *buf1; - static int len1; + static int32 len1; struct mdfour m; if (len > len1) { - if (buf1) free(buf1); + if (buf1) + free(buf1); buf1 = new_array(char, len+4); len1 = len; - if (!buf1) out_of_memory("get_checksum2"); + if (!buf1) + out_of_memory("get_checksum2"); } mdfour_begin(&m); @@ -125,7 +127,7 @@ } -static int sumresidue; +static int32 sumresidue; static char sumrbuf[CSUM_CHUNK]; static struct mdfour md; @@ -146,41 +148,37 @@ * @todo Perhaps get rid of md and just pass in the address each time. * Very slightly clearer and slower. **/ -void sum_update(char *p, int len) +void sum_update(char *p, int32 len) { - int i; if (len + sumresidue < CSUM_CHUNK) { - memcpy(sumrbuf+sumresidue, p, len); + memcpy(sumrbuf + sumresidue, p, len); sumresidue += len; return; } if (sumresidue) { - i = MIN(CSUM_CHUNK-sumresidue,len); - memcpy(sumrbuf+sumresidue,p,i); - mdfour_update(&md, (uchar *)sumrbuf, (i+sumresidue)); + int32 i = CSUM_CHUNK - sumresidue; + memcpy(sumrbuf + sumresidue, p, i); + mdfour_update(&md, (uchar *)sumrbuf, CSUM_CHUNK); len -= i; p += i; } - for(i = 0; i + CSUM_CHUNK <= len; i += CSUM_CHUNK) { - memcpy(sumrbuf,p+i,CSUM_CHUNK); - mdfour_update(&md, (uchar *)sumrbuf, CSUM_CHUNK); + while (len >= CSUM_CHUNK) { + mdfour_update(&md, (uchar *)p, CSUM_CHUNK); + len -= CSUM_CHUNK; + p += CSUM_CHUNK; } - if (len - i > 0) { - sumresidue = len-i; - memcpy(sumrbuf,p+i,sumresidue); - } else { - sumresidue = 0; - } + sumresidue = len; + if (sumresidue) + memcpy(sumrbuf, p, sumresidue); } void sum_end(char *sum) { - if (sumresidue || protocol_version >= 27) { + if (sumresidue || protocol_version >= 27) mdfour_update(&md, (uchar *)sumrbuf, sumresidue); - } mdfour_result(&md, (uchar *)sum); } diff -urN --exclude=patches rsync-2.6.3/cleanup.c rsync-2.6.4/cleanup.c --- rsync-2.6.3/cleanup.c 2004-07-29 09:06:38.000000000 -0700 +++ rsync-2.6.4/cleanup.c 2005-03-05 10:58:38.000000000 -0800 @@ -24,6 +24,7 @@ extern int io_error; extern int keep_partial; extern int log_got_error; +extern char *partial_dir; /** * Close all open sockets and files, allowing a (somewhat) graceful @@ -36,12 +37,11 @@ int max_fd; int fd; int ret; - struct stat st; + STRUCT_STAT st; max_fd = sysconf(_SC_OPEN_MAX) - 1; for (fd = max_fd; fd >= 0; fd--) { - ret = fstat(fd,&st); - if (fstat(fd,&st) == 0) { + if ((ret = do_fstat(fd, &st)) == 0) { if (is_a_socket(fd)) ret = shutdown(fd, 2); ret = close(fd); @@ -99,7 +99,7 @@ if (verbose > 3) { rprintf(FINFO,"_exit_cleanup(code=%d, file=%s, line=%d): entered\n", - code, file, line); + code, safe_fname(file), line); } if (cleanup_child_pid != -1) { @@ -117,9 +117,12 @@ cleanup_fname = NULL; if (cleanup_fd_r != -1) close(cleanup_fd_r); - if (cleanup_fd_w != -1) + if (cleanup_fd_w != -1) { + flush_write_file(cleanup_fd_w); close(cleanup_fd_w); - finish_transfer(cleanup_new_fname, fname, cleanup_file, 0); + } + finish_transfer(cleanup_new_fname, fname, cleanup_file, 0, + !partial_dir); } io_flush(FULL_FLUSH); if (cleanup_fname) @@ -133,10 +136,12 @@ } if (code == 0) { - if ((io_error & ~IOERR_VANISHED) || log_got_error) - code = RERR_PARTIAL; - else if (io_error) + if (io_error & IOERR_DEL_LIMIT) + code = RERR_DEL_LIMIT; + if (io_error & IOERR_VANISHED) code = RERR_VANISHED; + if (io_error & IOERR_GENERAL || log_got_error) + code = RERR_PARTIAL; } if (code) @@ -144,7 +149,7 @@ if (verbose > 2) { rprintf(FINFO,"_exit_cleanup(code=%d, file=%s, line=%d): about to call exit(%d)\n", - ocode, file, line, code); + ocode, safe_fname(file), line, code); } close_all(); diff -urN --exclude=patches rsync-2.6.3/clientname.c rsync-2.6.4/clientname.c --- rsync-2.6.3/clientname.c 2004-09-24 09:39:41.000000000 -0700 +++ rsync-2.6.4/clientname.c 2005-02-13 16:53:43.000000000 -0800 @@ -189,7 +189,7 @@ memset(sin, 0, sizeof *sin); sin->sin_family = AF_INET; *ss_len = sizeof (struct sockaddr_in); -#if HAVE_SOCKADDR_IN_LEN +#ifdef HAVE_SOCKADDR_IN_LEN sin->sin_len = *ss_len; #endif sin->sin_port = sin6.sin6_port; diff -urN --exclude=patches rsync-2.6.3/clientserver.c rsync-2.6.4/clientserver.c --- rsync-2.6.3/clientserver.c 2004-07-31 12:55:42.000000000 -0700 +++ rsync-2.6.4/clientserver.c 2005-03-30 16:21:15.000000000 -0800 @@ -27,32 +27,37 @@ #include "rsync.h" +extern int verbose; +extern int list_only; extern int am_sender; extern int am_server; extern int am_daemon; extern int am_root; -extern int module_id; -extern int read_only; -extern int verbose; extern int rsync_port; -extern int kludge_around_eof; +extern int kluge_around_eof; extern int daemon_over_rsh; -extern int list_only; extern int sanitize_paths; extern int filesfrom_fd; extern int remote_protocol; extern int protocol_version; extern int io_timeout; +extern int select_timeout; extern int orig_umask; extern int no_detach; extern int default_af_hint; extern char *bind_address; -extern struct exclude_list_struct server_exclude_list; -extern char *exclude_path_prefix; +extern struct filter_list_struct server_filter_list; extern char *config_file; extern char *files_from; char *auth_user; +int read_only = 0; +int daemon_log_format_has_i = 0; +int daemon_log_format_has_o_or_i = 0; +int module_id = -1; + +/* Length of lp_path() string when in daemon mode & not chrooted, else 0. */ +unsigned int module_dirlen = 0; /** * Run a client connected to an rsyncd. The alternative to this @@ -82,7 +87,7 @@ return -1; } - if ((p = strchr(host, '@')) != NULL) { + if ((p = strrchr(host, '@')) != NULL) { user = host; host = p+1; *p = '\0'; @@ -108,7 +113,7 @@ char *p; if (argc == 0 && !am_sender) - list_only = 1; + list_only |= 1; if (*path == '/') { rprintf(FERROR, @@ -121,19 +126,6 @@ if (!user) user = getenv("LOGNAME"); - /* set daemon_over_rsh to false since we need to build the - * true set of args passed through the rsh/ssh connection; - * this is a no-op for direct-socket-connection mode */ - daemon_over_rsh = 0; - server_options(sargs, &sargc); - - sargs[sargc++] = "."; - - if (path && *path) - sargs[sargc++] = path; - - sargs[sargc] = NULL; - io_printf(f_out, "@RSYNCD: %d\n", protocol_version); if (!read_line(f_in, line, sizeof line - 1)) { @@ -150,6 +142,25 @@ if (protocol_version > remote_protocol) protocol_version = remote_protocol; + if (list_only && protocol_version >= 29) + list_only |= 2; + + /* set daemon_over_rsh to false since we need to build the + * true set of args passed through the rsh/ssh connection; + * this is a no-op for direct-socket-connection mode */ + daemon_over_rsh = 0; + server_options(sargs, &sargc); + + sargs[sargc++] = "."; + + if (path && *path) + sargs[sargc++] = path; + + sargs[sargc] = NULL; + + if (verbose > 1) + print_child_argv(sargs); + p = strchr(path,'/'); if (p) *p = 0; io_printf(f_out, "%s\n", path); @@ -157,7 +168,7 @@ /* Old servers may just drop the connection here, rather than sending a proper EXIT command. Yuck. */ - kludge_around_eof = list_only && (protocol_version < 25); + kluge_around_eof = list_only && protocol_version < 25 ? 1 : 0; while (1) { if (!read_line(f_in, line, sizeof line - 1)) { @@ -190,7 +201,7 @@ rprintf(FINFO,"%s\n", line); } } - kludge_around_eof = False; + kluge_around_eof = 0; for (i = 0; i < sargc; i++) { io_printf(f_out, "%s\n", sargs[i]); @@ -246,13 +257,12 @@ if (!claim_connection(lp_lock_file(i), lp_max_connections(i))) { if (errno) { rsyserr(FLOG, errno, "failed to open lock file %s", - lp_lock_file(i)); - io_printf(f_out, "@ERROR: failed to open lock file %s\n", - lp_lock_file(i)); + safe_fname(lp_lock_file(i))); + io_printf(f_out, "@ERROR: failed to open lock file\n"); } else { rprintf(FLOG, "max connections (%d) reached\n", lp_max_connections(i)); - io_printf(f_out, "@ERROR: max connections (%d) reached - try again later\n", + io_printf(f_out, "@ERROR: max connections (%d) reached -- try again later\n", lp_max_connections(i)); } return -1; @@ -269,6 +279,17 @@ module_id = i; + if (lp_read_only(i)) + read_only = 1; + + if (lp_transfer_logging(i)) { + if (log_format_has(lp_log_format(i), 'i')) + daemon_log_format_has_i = 1; + if (daemon_log_format_has_i + || log_format_has(lp_log_format(i), 'o')) + daemon_log_format_has_o_or_i = 1; + } + am_root = (MY_UID() == 0); if (am_root) { @@ -300,26 +321,34 @@ /* TODO: Perhaps take a list of gids, and make them into the * supplementary groups. */ - exclude_path_prefix = use_chroot? "" : lp_path(i); - if (*exclude_path_prefix == '/' && !exclude_path_prefix[1]) - exclude_path_prefix = ""; + if (use_chroot) { + module_dirlen = 0; + set_filter_dir("/", 1); + } else { + module_dirlen = strlen(lp_path(i)); + set_filter_dir(lp_path(i), module_dirlen); + } + + p = lp_filter(i); + parse_rule(&server_filter_list, p, MATCHFLG_WORD_SPLIT, + XFLG_ANCHORED2ABS); p = lp_include_from(i); - add_exclude_file(&server_exclude_list, p, - XFLG_FATAL_ERRORS | XFLG_DEF_INCLUDE); + parse_filter_file(&server_filter_list, p, MATCHFLG_INCLUDE, + XFLG_ANCHORED2ABS | XFLG_OLD_PREFIXES | XFLG_FATAL_ERRORS); p = lp_include(i); - add_exclude(&server_exclude_list, p, - XFLG_WORD_SPLIT | XFLG_DEF_INCLUDE); + parse_rule(&server_filter_list, p, + MATCHFLG_INCLUDE | MATCHFLG_WORD_SPLIT, + XFLG_ANCHORED2ABS | XFLG_OLD_PREFIXES); p = lp_exclude_from(i); - add_exclude_file(&server_exclude_list, p, - XFLG_FATAL_ERRORS); + parse_filter_file(&server_filter_list, p, 0, + XFLG_ANCHORED2ABS | XFLG_OLD_PREFIXES | XFLG_FATAL_ERRORS); p = lp_exclude(i); - add_exclude(&server_exclude_list, p, XFLG_WORD_SPLIT); - - exclude_path_prefix = NULL; + parse_rule(&server_filter_list, p, MATCHFLG_WORD_SPLIT, + XFLG_ANCHORED2ABS | XFLG_OLD_PREFIXES); log_init(); @@ -337,20 +366,23 @@ * in which case we fail. */ if (chroot(lp_path(i))) { - rsyserr(FLOG, errno, "chroot %s failed", lp_path(i)); + rsyserr(FLOG, errno, "chroot %s failed", + safe_fname(lp_path(i))); io_printf(f_out, "@ERROR: chroot failed\n"); return -1; } if (!push_dir("/")) { - rsyserr(FLOG, errno, "chdir %s failed\n", lp_path(i)); + rsyserr(FLOG, errno, "chdir %s failed\n", + safe_fname(lp_path(i))); io_printf(f_out, "@ERROR: chdir failed\n"); return -1; } } else { if (!push_dir(lp_path(i))) { - rsyserr(FLOG, errno, "chdir %s failed\n", lp_path(i)); + rsyserr(FLOG, errno, "chdir %s failed\n", + safe_fname(lp_path(i))); io_printf(f_out, "@ERROR: chdir failed\n"); return -1; } @@ -429,6 +461,7 @@ start_glob = 1; } + verbose = 0; /* future verbosity is controlled by client options */ argp = argv; ret = parse_arguments(&argc, (const char ***) &argp, 0); @@ -462,8 +495,24 @@ * get the error back to the client. This means getting * the protocol setup finished first in later versions. */ setup_protocol(f_out, f_in); - if (files_from && !am_sender && strcmp(files_from, "-") != 0) - write_byte(f_out, 0); + if (!am_sender) { + /* Since we failed in our option parsing, we may not + * have finished parsing that the client sent us a + * --files-from option, so look for it manually. + * Without this, the socket would be in the wrong + * state for the upcoming error message. */ + if (!files_from) { + int i; + for (i = 0; i < argc; i++) { + if (strncmp(argv[i], "--files-from", 12) == 0) { + files_from = ""; + break; + } + } + } + if (files_from) + write_byte(f_out, 0); + } io_start_multiplex_out(); } @@ -473,8 +522,11 @@ exit_cleanup(RERR_UNSUPPORTED); } - if (lp_timeout(i)) + if (lp_timeout(i)) { io_timeout = lp_timeout(i); + if (io_timeout < select_timeout) + select_timeout = io_timeout; + } start_server(f_in, f_out, argc, argp); @@ -598,6 +650,11 @@ if (!lp_load(config_file, 1)) exit_cleanup(RERR_SYNTAX); + if (rsync_port == 0 && (rsync_port = lp_rsync_port()) == 0) + rsync_port = RSYNC_PORT; + if (bind_address == NULL && *lp_bind_address()) + bind_address = lp_bind_address(); + log_init(); rprintf(FLOG, "rsyncd version %s starting, listening on port %d\n", @@ -614,7 +671,8 @@ if ((fd = do_open(lp_pid_file(), O_WRONLY|O_CREAT|O_TRUNC, 0666 & ~orig_umask)) == -1) { cleanup_set_pid(0); - rsyserr(FLOG, errno, "failed to create pid file %s", pid_file); + rsyserr(FLOG, errno, "failed to create pid file %s", + safe_fname(pid_file)); exit_cleanup(RERR_FILEIO); } snprintf(pidbuf, sizeof pidbuf, "%ld\n", (long)pid); diff -urN --exclude=patches rsync-2.6.3/compat.c rsync-2.6.4/compat.c --- rsync-2.6.3/compat.c 2004-07-21 16:59:22.000000000 -0700 +++ rsync-2.6.4/compat.c 2005-03-09 10:53:55.000000000 -0800 @@ -30,9 +30,13 @@ extern int verbose; extern int am_server; extern int am_sender; +extern int inplace; +extern int fuzzy_basis; extern int read_batch; extern int checksum_seed; +extern int basis_dir_cnt; extern int protocol_version; +extern char *dest_option; void setup_protocol(int f_out,int f_in) { @@ -55,7 +59,7 @@ } if (remote_protocol < MIN_PROTOCOL_VERSION || remote_protocol > MAX_PROTOCOL_VERSION) { - rprintf(FERROR,"protocol version mismatch - is your shell clean?\n"); + rprintf(FERROR,"protocol version mismatch -- is your shell clean?\n"); rprintf(FERROR,"(see the rsync man page for an explanation)\n"); exit_cleanup(RERR_PROTOCOL); } @@ -74,6 +78,27 @@ exit_cleanup(RERR_PROTOCOL); } + if (fuzzy_basis && protocol_version < 29) { + rprintf(FERROR, + "--fuzzy requires protocol 29 or higher (negotiated %d).\n", + protocol_version); + exit_cleanup(RERR_PROTOCOL); + } + + if (basis_dir_cnt && inplace && protocol_version < 29) { + rprintf(FERROR, + "%s with --inplace requires protocol 29 or higher (negotiated %d).\n", + dest_option, protocol_version); + exit_cleanup(RERR_PROTOCOL); + } + + if (basis_dir_cnt > 1 && protocol_version < 29) { + rprintf(FERROR, + "Multiple %s options requires protocol 29 or higher (negotiated %d).\n", + dest_option, protocol_version); + exit_cleanup(RERR_PROTOCOL); + } + if (am_server) { if (!checksum_seed) checksum_seed = time(NULL); diff -urN --exclude=patches rsync-2.6.3/config.h.in rsync-2.6.4/config.h.in --- rsync-2.6.3/config.h.in 2004-08-02 14:54:49.000000000 -0700 +++ rsync-2.6.4/config.h.in 2005-02-21 10:58:10.000000000 -0800 @@ -1,5 +1,8 @@ /* config.h.in. Generated from configure.in by autoheader. */ +/* Define to 1 if chown modifies symlinks. */ +#undef CHOWN_MODIFIES_SYMLINK + /* Define to one of `_getb67', `GETB67', `getb67' for Cray-2 and Cray-YMP systems. This function is required for `alloca.c' support on those systems. */ @@ -12,6 +15,9 @@ this is either `int' or `gid_t'. */ #undef GETGROUPS_T +/* Define to 1 if the `getpgrp' function requires zero arguments. */ +#undef GETPGRP_VOID + /* Define to 1 if you have `alloca', as a function or macro. */ #undef HAVE_ALLOCA @@ -28,10 +34,10 @@ /* Define to 1 if you have the `asprintf' function. */ #undef HAVE_ASPRINTF -/* */ +/* Define to 1 if readdir() is broken */ #undef HAVE_BROKEN_READDIR -/* */ +/* Define to 1 if vsprintf has a C99-compatible return value */ #undef HAVE_C99_VSNPRINTF /* Define to 1 if you have the `chmod' function. */ @@ -43,7 +49,7 @@ /* Define to 1 if you have the header file. */ #undef HAVE_COMPAT_H -/* */ +/* Define to 1 if you have the "connect" function */ #undef HAVE_CONNECT /* Define to 1 if you have the header file. */ @@ -53,7 +59,7 @@ */ #undef HAVE_DIRENT_H -/* */ +/* Define to 1 if errno is declared in errno.h */ #undef HAVE_ERRNO_DECL /* Define to 1 if you have the `fchmod' function. */ @@ -71,7 +77,7 @@ /* Define to 1 if you have the `ftruncate' function. */ #undef HAVE_FTRUNCATE -/* Define if you have the `getaddrinfo' function. */ +/* Define to 1 if you have the "getaddrinfo" function. */ #undef HAVE_GETADDRINFO /* Define to 1 if you have the `getcwd' function. */ @@ -89,7 +95,10 @@ /* Define to 1 if you have the `getnameinfo' function. */ #undef HAVE_GETNAMEINFO -/* */ +/* Define to 1 if you have the `getpgrp' function. */ +#undef HAVE_GETPGRP + +/* Define to 1 if gettimeofday() takes a time-zone arg */ #undef HAVE_GETTIMEOFDAY_TZ /* Define to 1 if you have the `glob' function. */ @@ -134,8 +143,9 @@ /* Define to 1 if you have the `link' function. */ #undef HAVE_LINK -/* */ -#undef HAVE_LONGLONG +/* Define to 1 if long double works and has more range or precision than + double. */ +#undef HAVE_LONG_DOUBLE /* Define to 1 if you have the `mallinfo' function. */ #undef HAVE_MALLINFO @@ -170,9 +180,6 @@ /* Define to 1 if you have the header file. */ #undef HAVE_NETDB_H -/* */ -#undef HAVE_OFF64_T - /* Define to 1 if you have the `open64' function. */ #undef HAVE_OPEN64 @@ -182,18 +189,18 @@ /* remote shell is remsh not rsh */ #undef HAVE_REMSH -/* */ +/* Define to 1 if mkstemp() is available and works right */ #undef HAVE_SECURE_MKSTEMP /* Define to 1 if you have the `setgroups' function. */ #undef HAVE_SETGROUPS +/* Define to 1 if you have the `setmode' function. */ +#undef HAVE_SETMODE + /* Define to 1 if you have the `setsid' function. */ #undef HAVE_SETSID -/* */ -#undef HAVE_SHORT_INO_T - /* Define to 1 if you have the `snprintf' function. */ #undef HAVE_SNPRINTF @@ -206,10 +213,13 @@ /* Do we have sockaddr.sa_len? */ #undef HAVE_SOCKADDR_LEN -/* Define if you have strct sockaddr_storage. */ +/* Define to 1 if you have struct sockaddr_storage. */ #undef HAVE_SOCKADDR_STORAGE -/* */ +/* Do we have sockaddr_un.sun_len? */ +#undef HAVE_SOCKADDR_UN_LEN + +/* Define to 1 if you have the "socketpair" function */ #undef HAVE_SOCKETPAIR /* Define to 1 if you have the header file. */ @@ -251,6 +261,9 @@ /* Define to 1 if you have the `strtol' function. */ #undef HAVE_STRTOL +/* Define to 1 if you have struct stat64. */ +#undef HAVE_STRUCT_STAT64 + /* Define to 1 if `st_rdev' is member of `struct stat'. */ #undef HAVE_STRUCT_STAT_ST_RDEV @@ -301,13 +314,13 @@ /* Define to 1 if you have the header file. */ #undef HAVE_SYS_WAIT_H +/* Define to 1 if you have the `tcgetpgrp' function. */ +#undef HAVE_TCGETPGRP + /* Define to 1 if you have the header file. */ #undef HAVE_UNISTD_H -/* */ -#undef HAVE_UNSIGNED_CHAR - -/* */ +/* Define to 1 if you have the "struct utimbuf" type */ #undef HAVE_UTIMBUF /* Define to 1 if you have the `utime' function. */ @@ -322,6 +335,12 @@ /* Define to 1 if `utime(file, NULL)' sets file's timestamp to the present. */ #undef HAVE_UTIME_NULL +/* Define to 1 if you have the `vasprintf' function. */ +#undef HAVE_VASPRINTF + +/* Define to 1 if you have the `va_copy' function. */ +#undef HAVE_VA_COPY + /* Define to 1 if you have the `vsnprintf' function. */ #undef HAVE_VSNPRINTF @@ -331,6 +350,9 @@ /* Define to 1 if you have the `waitpid' function. */ #undef HAVE_WAITPID +/* Define to 1 if you have the `__va_copy' function. */ +#undef HAVE___VA_COPY + /* true if you have IPv6 */ #undef INET6 @@ -342,6 +364,12 @@ . */ #undef MAJOR_IN_SYSMACROS +/* Define to 1 if mknod() can create FIFOs. */ +#undef MKNOD_CREATES_FIFOS + +/* Define to 1 if mknod() can create sockets. */ +#undef MKNOD_CREATES_SOCKETS + /* Define to the address where bug reports for this package should be sent. */ #undef PACKAGE_BUGREPORT @@ -357,10 +385,10 @@ /* Define to the version of this package. */ #undef PACKAGE_VERSION -/* */ +/* Define to 1 if inet_aton() needs to be replaced */ #undef REPLACE_INET_ATON -/* */ +/* Define to 1 if inet_ntoa() needs to be replaced */ #undef REPLACE_INET_NTOA /* Define as the return type of signal handlers (`int' or `void'). */ @@ -378,15 +406,27 @@ /* rsync release version */ #undef RSYNC_VERSION -/* Define if sockets need to be shutdown */ +/* Define to 1 if sockets need to be shutdown */ #undef SHUTDOWN_ALL_SOCKETS +/* Define to 1 if "signed char" is a valid type */ +#undef SIGNED_CHAR_OK + /* The size of a `int', as computed by sizeof. */ #undef SIZEOF_INT /* The size of a `long', as computed by sizeof. */ #undef SIZEOF_LONG +/* The size of a `long long', as computed by sizeof. */ +#undef SIZEOF_LONG_LONG + +/* The size of a `off64_t', as computed by sizeof. */ +#undef SIZEOF_OFF64_T + +/* The size of a `off_t', as computed by sizeof. */ +#undef SIZEOF_OFF_T + /* The size of a `short', as computed by sizeof. */ #undef SIZEOF_SHORT @@ -426,9 +466,6 @@ #undef inline #endif -/* Define to `unsigned' if does not define. */ -#undef ino_t - /* Define to `int' if does not define. */ #undef mode_t diff -urN --exclude=patches rsync-2.6.3/configure rsync-2.6.4/configure --- rsync-2.6.3/configure 2004-09-30 09:35:56.000000000 -0700 +++ rsync-2.6.4/configure 2005-03-30 19:14:09.000000000 -0800 @@ -1314,7 +1314,7 @@ -RSYNC_VERSION=2.6.3 +RSYNC_VERSION=2.6.4 { echo "$as_me:$LINENO: Configuring rsync $RSYNC_VERSION" >&5 echo "$as_me: Configuring rsync $RSYNC_VERSION" >&6;} @@ -2757,7 +2757,7 @@ CFLAGS="$CFLAGS -DHAVE_CONFIG_H" # If GCC, turn on warnings. -if test "x$GCC" = "xyes" +if test x"$GCC" = x"yes" then CFLAGS="$CFLAGS -Wall -W" fi @@ -5920,9 +5920,9 @@ _ACEOF -echo "$as_me:$LINENO: checking for short" >&5 -echo $ECHO_N "checking for short... $ECHO_C" >&6 -if test "${ac_cv_type_short+set}" = set; then +echo "$as_me:$LINENO: checking for long long" >&5 +echo $ECHO_N "checking for long long... $ECHO_C" >&6 +if test "${ac_cv_type_long_long+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else cat >conftest.$ac_ext <<_ACEOF @@ -5935,9 +5935,9 @@ int main () { -if ((short *) 0) +if ((long long *) 0) return 0; -if (sizeof (short)) +if (sizeof (long long)) return 0; ; return 0; @@ -5964,24 +5964,24 @@ ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; }; then - ac_cv_type_short=yes + ac_cv_type_long_long=yes else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 -ac_cv_type_short=no +ac_cv_type_long_long=no fi rm -f conftest.err conftest.$ac_objext conftest.$ac_ext fi -echo "$as_me:$LINENO: result: $ac_cv_type_short" >&5 -echo "${ECHO_T}$ac_cv_type_short" >&6 +echo "$as_me:$LINENO: result: $ac_cv_type_long_long" >&5 +echo "${ECHO_T}$ac_cv_type_long_long" >&6 -echo "$as_me:$LINENO: checking size of short" >&5 -echo $ECHO_N "checking size of short... $ECHO_C" >&6 -if test "${ac_cv_sizeof_short+set}" = set; then +echo "$as_me:$LINENO: checking size of long long" >&5 +echo $ECHO_N "checking size of long long... $ECHO_C" >&6 +if test "${ac_cv_sizeof_long_long+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else - if test "$ac_cv_type_short" = yes; then + if test "$ac_cv_type_long_long" = yes; then # The cast to unsigned long works around a bug in the HP C Compiler # version HP92453-01 B.11.11.23709.GP, which incorrectly rejects # declarations like `int a3[[(sizeof (unsigned char)) >= 0]];'. @@ -5998,7 +5998,7 @@ int main () { -static int test_array [1 - 2 * !(((long) (sizeof (short))) >= 0)]; +static int test_array [1 - 2 * !(((long) (sizeof (long long))) >= 0)]; test_array [0] = 0 ; @@ -6038,7 +6038,7 @@ int main () { -static int test_array [1 - 2 * !(((long) (sizeof (short))) <= $ac_mid)]; +static int test_array [1 - 2 * !(((long) (sizeof (long long))) <= $ac_mid)]; test_array [0] = 0 ; @@ -6094,7 +6094,7 @@ int main () { -static int test_array [1 - 2 * !(((long) (sizeof (short))) < 0)]; +static int test_array [1 - 2 * !(((long) (sizeof (long long))) < 0)]; test_array [0] = 0 ; @@ -6134,7 +6134,7 @@ int main () { -static int test_array [1 - 2 * !(((long) (sizeof (short))) >= $ac_mid)]; +static int test_array [1 - 2 * !(((long) (sizeof (long long))) >= $ac_mid)]; test_array [0] = 0 ; @@ -6198,7 +6198,7 @@ int main () { -static int test_array [1 - 2 * !(((long) (sizeof (short))) <= $ac_mid)]; +static int test_array [1 - 2 * !(((long) (sizeof (long long))) <= $ac_mid)]; test_array [0] = 0 ; @@ -6236,10 +6236,10 @@ rm -f conftest.err conftest.$ac_objext conftest.$ac_ext done case $ac_lo in -?*) ac_cv_sizeof_short=$ac_lo;; -'') { { echo "$as_me:$LINENO: error: cannot compute sizeof (short), 77 +?*) ac_cv_sizeof_long_long=$ac_lo;; +'') { { echo "$as_me:$LINENO: error: cannot compute sizeof (long long), 77 See \`config.log' for more details." >&5 -echo "$as_me: error: cannot compute sizeof (short), 77 +echo "$as_me: error: cannot compute sizeof (long long), 77 See \`config.log' for more details." >&2;} { (exit 1); exit 1; }; } ;; esac @@ -6256,8 +6256,8 @@ cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ $ac_includes_default -long longval () { return (long) (sizeof (short)); } -unsigned long ulongval () { return (long) (sizeof (short)); } +long longval () { return (long) (sizeof (long long)); } +unsigned long ulongval () { return (long) (sizeof (long long)); } #include #include int @@ -6267,17 +6267,17 @@ FILE *f = fopen ("conftest.val", "w"); if (! f) exit (1); - if (((long) (sizeof (short))) < 0) + if (((long) (sizeof (long long))) < 0) { long i = longval (); - if (i != ((long) (sizeof (short)))) + if (i != ((long) (sizeof (long long)))) exit (1); fprintf (f, "%ld\n", i); } else { unsigned long i = ulongval (); - if (i != ((long) (sizeof (short)))) + if (i != ((long) (sizeof (long long)))) exit (1); fprintf (f, "%lu\n", i); } @@ -6298,16 +6298,16 @@ ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; }; then - ac_cv_sizeof_short=`cat conftest.val` + ac_cv_sizeof_long_long=`cat conftest.val` else echo "$as_me: program exited with status $ac_status" >&5 echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ( exit $ac_status ) -{ { echo "$as_me:$LINENO: error: cannot compute sizeof (short), 77 +{ { echo "$as_me:$LINENO: error: cannot compute sizeof (long long), 77 See \`config.log' for more details." >&5 -echo "$as_me: error: cannot compute sizeof (short), 77 +echo "$as_me: error: cannot compute sizeof (long long), 77 See \`config.log' for more details." >&2;} { (exit 1); exit 1; }; } fi @@ -6316,36 +6316,38 @@ fi rm -f conftest.val else - ac_cv_sizeof_short=0 + ac_cv_sizeof_long_long=0 fi fi -echo "$as_me:$LINENO: result: $ac_cv_sizeof_short" >&5 -echo "${ECHO_T}$ac_cv_sizeof_short" >&6 +echo "$as_me:$LINENO: result: $ac_cv_sizeof_long_long" >&5 +echo "${ECHO_T}$ac_cv_sizeof_long_long" >&6 cat >>confdefs.h <<_ACEOF -#define SIZEOF_SHORT $ac_cv_sizeof_short +#define SIZEOF_LONG_LONG $ac_cv_sizeof_long_long _ACEOF - -echo "$as_me:$LINENO: checking for inline" >&5 -echo $ECHO_N "checking for inline... $ECHO_C" >&6 -if test "${ac_cv_c_inline+set}" = set; then +echo "$as_me:$LINENO: checking for short" >&5 +echo $ECHO_N "checking for short... $ECHO_C" >&6 +if test "${ac_cv_type_short+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else - ac_cv_c_inline=no -for ac_kw in inline __inline__ __inline; do cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ -#ifndef __cplusplus -typedef int foo_t; -static $ac_kw foo_t static_foo () {return 0; } -$ac_kw foo_t foo () {return 0; } -#endif - +$ac_includes_default +int +main () +{ +if ((short *) 0) + return 0; +if (sizeof (short)) + return 0; + ; + return 0; +} _ACEOF rm -f conftest.$ac_objext if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 @@ -6368,62 +6370,43 @@ ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; }; then - ac_cv_c_inline=$ac_kw; break + ac_cv_type_short=yes else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 +ac_cv_type_short=no fi rm -f conftest.err conftest.$ac_objext conftest.$ac_ext -done - fi -echo "$as_me:$LINENO: result: $ac_cv_c_inline" >&5 -echo "${ECHO_T}$ac_cv_c_inline" >&6 - - -case $ac_cv_c_inline in - inline | yes) ;; - *) - case $ac_cv_c_inline in - no) ac_val=;; - *) ac_val=$ac_cv_c_inline;; - esac - cat >>confdefs.h <<_ACEOF -#ifndef __cplusplus -#define inline $ac_val -#endif -_ACEOF - ;; -esac - +echo "$as_me:$LINENO: result: $ac_cv_type_short" >&5 +echo "${ECHO_T}$ac_cv_type_short" >&6 -echo "$as_me:$LINENO: checking return type of signal handlers" >&5 -echo $ECHO_N "checking return type of signal handlers... $ECHO_C" >&6 -if test "${ac_cv_type_signal+set}" = set; then +echo "$as_me:$LINENO: checking size of short" >&5 +echo $ECHO_N "checking size of short... $ECHO_C" >&6 +if test "${ac_cv_sizeof_short+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else - cat >conftest.$ac_ext <<_ACEOF + if test "$ac_cv_type_short" = yes; then + # The cast to unsigned long works around a bug in the HP C Compiler + # version HP92453-01 B.11.11.23709.GP, which incorrectly rejects + # declarations like `int a3[[(sizeof (unsigned char)) >= 0]];'. + # This bug is HP SR number 8606223364. + if test "$cross_compiling" = yes; then + # Depending upon the size, compute the lo and hi bounds. +cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ -#include -#include -#ifdef signal -# undef signal -#endif -#ifdef __cplusplus -extern "C" void (*signal (int, void (*)(int)))(int); -#else -void (*signal ()) (); -#endif - +$ac_includes_default int main () { -int i; +static int test_array [1 - 2 * !(((long) (sizeof (short))) >= 0)]; +test_array [0] = 0 + ; return 0; } @@ -6449,67 +6432,9 @@ ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; }; then - ac_cv_type_signal=void -else - echo "$as_me: failed program was:" >&5 -sed 's/^/| /' conftest.$ac_ext >&5 - -ac_cv_type_signal=int -fi -rm -f conftest.err conftest.$ac_objext conftest.$ac_ext -fi -echo "$as_me:$LINENO: result: $ac_cv_type_signal" >&5 -echo "${ECHO_T}$ac_cv_type_signal" >&6 - -cat >>confdefs.h <<_ACEOF -#define RETSIGTYPE $ac_cv_type_signal -_ACEOF - - -echo "$as_me:$LINENO: checking for uid_t in sys/types.h" >&5 -echo $ECHO_N "checking for uid_t in sys/types.h... $ECHO_C" >&6 -if test "${ac_cv_type_uid_t+set}" = set; then - echo $ECHO_N "(cached) $ECHO_C" >&6 -else - cat >conftest.$ac_ext <<_ACEOF -/* confdefs.h. */ -_ACEOF -cat confdefs.h >>conftest.$ac_ext -cat >>conftest.$ac_ext <<_ACEOF -/* end confdefs.h. */ -#include - -_ACEOF -if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | - $EGREP "uid_t" >/dev/null 2>&1; then - ac_cv_type_uid_t=yes -else - ac_cv_type_uid_t=no -fi -rm -f conftest* - -fi -echo "$as_me:$LINENO: result: $ac_cv_type_uid_t" >&5 -echo "${ECHO_T}$ac_cv_type_uid_t" >&6 -if test $ac_cv_type_uid_t = no; then - -cat >>confdefs.h <<\_ACEOF -#define uid_t int -_ACEOF - - -cat >>confdefs.h <<\_ACEOF -#define gid_t int -_ACEOF - -fi - -echo "$as_me:$LINENO: checking for mode_t" >&5 -echo $ECHO_N "checking for mode_t... $ECHO_C" >&6 -if test "${ac_cv_type_mode_t+set}" = set; then - echo $ECHO_N "(cached) $ECHO_C" >&6 -else - cat >conftest.$ac_ext <<_ACEOF + ac_lo=0 ac_mid=0 + while :; do + cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext @@ -6519,10 +6444,9 @@ int main () { -if ((mode_t *) 0) - return 0; -if (sizeof (mode_t)) - return 0; +static int test_array [1 - 2 * !(((long) (sizeof (short))) <= $ac_mid)]; +test_array [0] = 0 + ; return 0; } @@ -6548,33 +6472,25 @@ ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; }; then - ac_cv_type_mode_t=yes + ac_hi=$ac_mid; break else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 -ac_cv_type_mode_t=no +ac_lo=`expr $ac_mid + 1` + if test $ac_lo -le $ac_mid; then + ac_lo= ac_hi= + break + fi + ac_mid=`expr 2 '*' $ac_mid + 1` fi rm -f conftest.err conftest.$ac_objext conftest.$ac_ext -fi -echo "$as_me:$LINENO: result: $ac_cv_type_mode_t" >&5 -echo "${ECHO_T}$ac_cv_type_mode_t" >&6 -if test $ac_cv_type_mode_t = yes; then - : + done else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 -cat >>confdefs.h <<_ACEOF -#define mode_t int -_ACEOF - -fi - -echo "$as_me:$LINENO: checking for off_t" >&5 -echo $ECHO_N "checking for off_t... $ECHO_C" >&6 -if test "${ac_cv_type_off_t+set}" = set; then - echo $ECHO_N "(cached) $ECHO_C" >&6 -else - cat >conftest.$ac_ext <<_ACEOF +cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext @@ -6584,10 +6500,9 @@ int main () { -if ((off_t *) 0) - return 0; -if (sizeof (off_t)) - return 0; +static int test_array [1 - 2 * !(((long) (sizeof (short))) < 0)]; +test_array [0] = 0 + ; return 0; } @@ -6613,33 +6528,1401 @@ ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; }; then - ac_cv_type_off_t=yes -else - echo "$as_me: failed program was:" >&5 -sed 's/^/| /' conftest.$ac_ext >&5 - -ac_cv_type_off_t=no -fi -rm -f conftest.err conftest.$ac_objext conftest.$ac_ext -fi -echo "$as_me:$LINENO: result: $ac_cv_type_off_t" >&5 -echo "${ECHO_T}$ac_cv_type_off_t" >&6 -if test $ac_cv_type_off_t = yes; then - : -else - -cat >>confdefs.h <<_ACEOF -#define off_t long -_ACEOF - -fi - -echo "$as_me:$LINENO: checking for size_t" >&5 -echo $ECHO_N "checking for size_t... $ECHO_C" >&6 -if test "${ac_cv_type_size_t+set}" = set; then - echo $ECHO_N "(cached) $ECHO_C" >&6 -else - cat >conftest.$ac_ext <<_ACEOF + ac_hi=-1 ac_mid=-1 + while :; do + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +$ac_includes_default +int +main () +{ +static int test_array [1 - 2 * !(((long) (sizeof (short))) >= $ac_mid)]; +test_array [0] = 0 + + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 + (eval $ac_compile) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest.$ac_objext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_lo=$ac_mid; break +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +ac_hi=`expr '(' $ac_mid ')' - 1` + if test $ac_mid -le $ac_hi; then + ac_lo= ac_hi= + break + fi + ac_mid=`expr 2 '*' $ac_mid` +fi +rm -f conftest.err conftest.$ac_objext conftest.$ac_ext + done +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +ac_lo= ac_hi= +fi +rm -f conftest.err conftest.$ac_objext conftest.$ac_ext +fi +rm -f conftest.err conftest.$ac_objext conftest.$ac_ext +# Binary search between lo and hi bounds. +while test "x$ac_lo" != "x$ac_hi"; do + ac_mid=`expr '(' $ac_hi - $ac_lo ')' / 2 + $ac_lo` + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +$ac_includes_default +int +main () +{ +static int test_array [1 - 2 * !(((long) (sizeof (short))) <= $ac_mid)]; +test_array [0] = 0 + + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 + (eval $ac_compile) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest.$ac_objext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_hi=$ac_mid +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +ac_lo=`expr '(' $ac_mid ')' + 1` +fi +rm -f conftest.err conftest.$ac_objext conftest.$ac_ext +done +case $ac_lo in +?*) ac_cv_sizeof_short=$ac_lo;; +'') { { echo "$as_me:$LINENO: error: cannot compute sizeof (short), 77 +See \`config.log' for more details." >&5 +echo "$as_me: error: cannot compute sizeof (short), 77 +See \`config.log' for more details." >&2;} + { (exit 1); exit 1; }; } ;; +esac +else + if test "$cross_compiling" = yes; then + { { echo "$as_me:$LINENO: error: internal error: not reached in cross-compile" >&5 +echo "$as_me: error: internal error: not reached in cross-compile" >&2;} + { (exit 1); exit 1; }; } +else + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +$ac_includes_default +long longval () { return (long) (sizeof (short)); } +unsigned long ulongval () { return (long) (sizeof (short)); } +#include +#include +int +main () +{ + + FILE *f = fopen ("conftest.val", "w"); + if (! f) + exit (1); + if (((long) (sizeof (short))) < 0) + { + long i = longval (); + if (i != ((long) (sizeof (short)))) + exit (1); + fprintf (f, "%ld\n", i); + } + else + { + unsigned long i = ulongval (); + if (i != ((long) (sizeof (short)))) + exit (1); + fprintf (f, "%lu\n", i); + } + exit (ferror (f) || fclose (f) != 0); + + ; + return 0; +} +_ACEOF +rm -f conftest$ac_exeext +if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 + (eval $ac_link) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { ac_try='./conftest$ac_exeext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_cv_sizeof_short=`cat conftest.val` +else + echo "$as_me: program exited with status $ac_status" >&5 +echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +( exit $ac_status ) +{ { echo "$as_me:$LINENO: error: cannot compute sizeof (short), 77 +See \`config.log' for more details." >&5 +echo "$as_me: error: cannot compute sizeof (short), 77 +See \`config.log' for more details." >&2;} + { (exit 1); exit 1; }; } +fi +rm -f core *.core gmon.out bb.out conftest$ac_exeext conftest.$ac_objext conftest.$ac_ext +fi +fi +rm -f conftest.val +else + ac_cv_sizeof_short=0 +fi +fi +echo "$as_me:$LINENO: result: $ac_cv_sizeof_short" >&5 +echo "${ECHO_T}$ac_cv_sizeof_short" >&6 +cat >>confdefs.h <<_ACEOF +#define SIZEOF_SHORT $ac_cv_sizeof_short +_ACEOF + + +echo "$as_me:$LINENO: checking for off_t" >&5 +echo $ECHO_N "checking for off_t... $ECHO_C" >&6 +if test "${ac_cv_type_off_t+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +$ac_includes_default +int +main () +{ +if ((off_t *) 0) + return 0; +if (sizeof (off_t)) + return 0; + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 + (eval $ac_compile) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest.$ac_objext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_cv_type_off_t=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +ac_cv_type_off_t=no +fi +rm -f conftest.err conftest.$ac_objext conftest.$ac_ext +fi +echo "$as_me:$LINENO: result: $ac_cv_type_off_t" >&5 +echo "${ECHO_T}$ac_cv_type_off_t" >&6 + +echo "$as_me:$LINENO: checking size of off_t" >&5 +echo $ECHO_N "checking size of off_t... $ECHO_C" >&6 +if test "${ac_cv_sizeof_off_t+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + if test "$ac_cv_type_off_t" = yes; then + # The cast to unsigned long works around a bug in the HP C Compiler + # version HP92453-01 B.11.11.23709.GP, which incorrectly rejects + # declarations like `int a3[[(sizeof (unsigned char)) >= 0]];'. + # This bug is HP SR number 8606223364. + if test "$cross_compiling" = yes; then + # Depending upon the size, compute the lo and hi bounds. +cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +$ac_includes_default +int +main () +{ +static int test_array [1 - 2 * !(((long) (sizeof (off_t))) >= 0)]; +test_array [0] = 0 + + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 + (eval $ac_compile) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest.$ac_objext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_lo=0 ac_mid=0 + while :; do + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +$ac_includes_default +int +main () +{ +static int test_array [1 - 2 * !(((long) (sizeof (off_t))) <= $ac_mid)]; +test_array [0] = 0 + + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 + (eval $ac_compile) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest.$ac_objext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_hi=$ac_mid; break +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +ac_lo=`expr $ac_mid + 1` + if test $ac_lo -le $ac_mid; then + ac_lo= ac_hi= + break + fi + ac_mid=`expr 2 '*' $ac_mid + 1` +fi +rm -f conftest.err conftest.$ac_objext conftest.$ac_ext + done +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +$ac_includes_default +int +main () +{ +static int test_array [1 - 2 * !(((long) (sizeof (off_t))) < 0)]; +test_array [0] = 0 + + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 + (eval $ac_compile) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest.$ac_objext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_hi=-1 ac_mid=-1 + while :; do + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +$ac_includes_default +int +main () +{ +static int test_array [1 - 2 * !(((long) (sizeof (off_t))) >= $ac_mid)]; +test_array [0] = 0 + + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 + (eval $ac_compile) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest.$ac_objext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_lo=$ac_mid; break +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +ac_hi=`expr '(' $ac_mid ')' - 1` + if test $ac_mid -le $ac_hi; then + ac_lo= ac_hi= + break + fi + ac_mid=`expr 2 '*' $ac_mid` +fi +rm -f conftest.err conftest.$ac_objext conftest.$ac_ext + done +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +ac_lo= ac_hi= +fi +rm -f conftest.err conftest.$ac_objext conftest.$ac_ext +fi +rm -f conftest.err conftest.$ac_objext conftest.$ac_ext +# Binary search between lo and hi bounds. +while test "x$ac_lo" != "x$ac_hi"; do + ac_mid=`expr '(' $ac_hi - $ac_lo ')' / 2 + $ac_lo` + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +$ac_includes_default +int +main () +{ +static int test_array [1 - 2 * !(((long) (sizeof (off_t))) <= $ac_mid)]; +test_array [0] = 0 + + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 + (eval $ac_compile) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest.$ac_objext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_hi=$ac_mid +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +ac_lo=`expr '(' $ac_mid ')' + 1` +fi +rm -f conftest.err conftest.$ac_objext conftest.$ac_ext +done +case $ac_lo in +?*) ac_cv_sizeof_off_t=$ac_lo;; +'') { { echo "$as_me:$LINENO: error: cannot compute sizeof (off_t), 77 +See \`config.log' for more details." >&5 +echo "$as_me: error: cannot compute sizeof (off_t), 77 +See \`config.log' for more details." >&2;} + { (exit 1); exit 1; }; } ;; +esac +else + if test "$cross_compiling" = yes; then + { { echo "$as_me:$LINENO: error: internal error: not reached in cross-compile" >&5 +echo "$as_me: error: internal error: not reached in cross-compile" >&2;} + { (exit 1); exit 1; }; } +else + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +$ac_includes_default +long longval () { return (long) (sizeof (off_t)); } +unsigned long ulongval () { return (long) (sizeof (off_t)); } +#include +#include +int +main () +{ + + FILE *f = fopen ("conftest.val", "w"); + if (! f) + exit (1); + if (((long) (sizeof (off_t))) < 0) + { + long i = longval (); + if (i != ((long) (sizeof (off_t)))) + exit (1); + fprintf (f, "%ld\n", i); + } + else + { + unsigned long i = ulongval (); + if (i != ((long) (sizeof (off_t)))) + exit (1); + fprintf (f, "%lu\n", i); + } + exit (ferror (f) || fclose (f) != 0); + + ; + return 0; +} +_ACEOF +rm -f conftest$ac_exeext +if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 + (eval $ac_link) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { ac_try='./conftest$ac_exeext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_cv_sizeof_off_t=`cat conftest.val` +else + echo "$as_me: program exited with status $ac_status" >&5 +echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +( exit $ac_status ) +{ { echo "$as_me:$LINENO: error: cannot compute sizeof (off_t), 77 +See \`config.log' for more details." >&5 +echo "$as_me: error: cannot compute sizeof (off_t), 77 +See \`config.log' for more details." >&2;} + { (exit 1); exit 1; }; } +fi +rm -f core *.core gmon.out bb.out conftest$ac_exeext conftest.$ac_objext conftest.$ac_ext +fi +fi +rm -f conftest.val +else + ac_cv_sizeof_off_t=0 +fi +fi +echo "$as_me:$LINENO: result: $ac_cv_sizeof_off_t" >&5 +echo "${ECHO_T}$ac_cv_sizeof_off_t" >&6 +cat >>confdefs.h <<_ACEOF +#define SIZEOF_OFF_T $ac_cv_sizeof_off_t +_ACEOF + + +echo "$as_me:$LINENO: checking for off64_t" >&5 +echo $ECHO_N "checking for off64_t... $ECHO_C" >&6 +if test "${ac_cv_type_off64_t+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +$ac_includes_default +int +main () +{ +if ((off64_t *) 0) + return 0; +if (sizeof (off64_t)) + return 0; + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 + (eval $ac_compile) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest.$ac_objext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_cv_type_off64_t=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +ac_cv_type_off64_t=no +fi +rm -f conftest.err conftest.$ac_objext conftest.$ac_ext +fi +echo "$as_me:$LINENO: result: $ac_cv_type_off64_t" >&5 +echo "${ECHO_T}$ac_cv_type_off64_t" >&6 + +echo "$as_me:$LINENO: checking size of off64_t" >&5 +echo $ECHO_N "checking size of off64_t... $ECHO_C" >&6 +if test "${ac_cv_sizeof_off64_t+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + if test "$ac_cv_type_off64_t" = yes; then + # The cast to unsigned long works around a bug in the HP C Compiler + # version HP92453-01 B.11.11.23709.GP, which incorrectly rejects + # declarations like `int a3[[(sizeof (unsigned char)) >= 0]];'. + # This bug is HP SR number 8606223364. + if test "$cross_compiling" = yes; then + # Depending upon the size, compute the lo and hi bounds. +cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +$ac_includes_default +int +main () +{ +static int test_array [1 - 2 * !(((long) (sizeof (off64_t))) >= 0)]; +test_array [0] = 0 + + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 + (eval $ac_compile) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest.$ac_objext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_lo=0 ac_mid=0 + while :; do + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +$ac_includes_default +int +main () +{ +static int test_array [1 - 2 * !(((long) (sizeof (off64_t))) <= $ac_mid)]; +test_array [0] = 0 + + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 + (eval $ac_compile) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest.$ac_objext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_hi=$ac_mid; break +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +ac_lo=`expr $ac_mid + 1` + if test $ac_lo -le $ac_mid; then + ac_lo= ac_hi= + break + fi + ac_mid=`expr 2 '*' $ac_mid + 1` +fi +rm -f conftest.err conftest.$ac_objext conftest.$ac_ext + done +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +$ac_includes_default +int +main () +{ +static int test_array [1 - 2 * !(((long) (sizeof (off64_t))) < 0)]; +test_array [0] = 0 + + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 + (eval $ac_compile) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest.$ac_objext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_hi=-1 ac_mid=-1 + while :; do + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +$ac_includes_default +int +main () +{ +static int test_array [1 - 2 * !(((long) (sizeof (off64_t))) >= $ac_mid)]; +test_array [0] = 0 + + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 + (eval $ac_compile) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest.$ac_objext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_lo=$ac_mid; break +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +ac_hi=`expr '(' $ac_mid ')' - 1` + if test $ac_mid -le $ac_hi; then + ac_lo= ac_hi= + break + fi + ac_mid=`expr 2 '*' $ac_mid` +fi +rm -f conftest.err conftest.$ac_objext conftest.$ac_ext + done +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +ac_lo= ac_hi= +fi +rm -f conftest.err conftest.$ac_objext conftest.$ac_ext +fi +rm -f conftest.err conftest.$ac_objext conftest.$ac_ext +# Binary search between lo and hi bounds. +while test "x$ac_lo" != "x$ac_hi"; do + ac_mid=`expr '(' $ac_hi - $ac_lo ')' / 2 + $ac_lo` + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +$ac_includes_default +int +main () +{ +static int test_array [1 - 2 * !(((long) (sizeof (off64_t))) <= $ac_mid)]; +test_array [0] = 0 + + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 + (eval $ac_compile) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest.$ac_objext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_hi=$ac_mid +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +ac_lo=`expr '(' $ac_mid ')' + 1` +fi +rm -f conftest.err conftest.$ac_objext conftest.$ac_ext +done +case $ac_lo in +?*) ac_cv_sizeof_off64_t=$ac_lo;; +'') { { echo "$as_me:$LINENO: error: cannot compute sizeof (off64_t), 77 +See \`config.log' for more details." >&5 +echo "$as_me: error: cannot compute sizeof (off64_t), 77 +See \`config.log' for more details." >&2;} + { (exit 1); exit 1; }; } ;; +esac +else + if test "$cross_compiling" = yes; then + { { echo "$as_me:$LINENO: error: internal error: not reached in cross-compile" >&5 +echo "$as_me: error: internal error: not reached in cross-compile" >&2;} + { (exit 1); exit 1; }; } +else + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +$ac_includes_default +long longval () { return (long) (sizeof (off64_t)); } +unsigned long ulongval () { return (long) (sizeof (off64_t)); } +#include +#include +int +main () +{ + + FILE *f = fopen ("conftest.val", "w"); + if (! f) + exit (1); + if (((long) (sizeof (off64_t))) < 0) + { + long i = longval (); + if (i != ((long) (sizeof (off64_t)))) + exit (1); + fprintf (f, "%ld\n", i); + } + else + { + unsigned long i = ulongval (); + if (i != ((long) (sizeof (off64_t)))) + exit (1); + fprintf (f, "%lu\n", i); + } + exit (ferror (f) || fclose (f) != 0); + + ; + return 0; +} +_ACEOF +rm -f conftest$ac_exeext +if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 + (eval $ac_link) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { ac_try='./conftest$ac_exeext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_cv_sizeof_off64_t=`cat conftest.val` +else + echo "$as_me: program exited with status $ac_status" >&5 +echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +( exit $ac_status ) +{ { echo "$as_me:$LINENO: error: cannot compute sizeof (off64_t), 77 +See \`config.log' for more details." >&5 +echo "$as_me: error: cannot compute sizeof (off64_t), 77 +See \`config.log' for more details." >&2;} + { (exit 1); exit 1; }; } +fi +rm -f core *.core gmon.out bb.out conftest$ac_exeext conftest.$ac_objext conftest.$ac_ext +fi +fi +rm -f conftest.val +else + ac_cv_sizeof_off64_t=0 +fi +fi +echo "$as_me:$LINENO: result: $ac_cv_sizeof_off64_t" >&5 +echo "${ECHO_T}$ac_cv_sizeof_off64_t" >&6 +cat >>confdefs.h <<_ACEOF +#define SIZEOF_OFF64_T $ac_cv_sizeof_off64_t +_ACEOF + + + +echo "$as_me:$LINENO: checking for inline" >&5 +echo $ECHO_N "checking for inline... $ECHO_C" >&6 +if test "${ac_cv_c_inline+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + ac_cv_c_inline=no +for ac_kw in inline __inline__ __inline; do + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#ifndef __cplusplus +typedef int foo_t; +static $ac_kw foo_t static_foo () {return 0; } +$ac_kw foo_t foo () {return 0; } +#endif + +_ACEOF +rm -f conftest.$ac_objext +if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 + (eval $ac_compile) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest.$ac_objext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_cv_c_inline=$ac_kw; break +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +fi +rm -f conftest.err conftest.$ac_objext conftest.$ac_ext +done + +fi +echo "$as_me:$LINENO: result: $ac_cv_c_inline" >&5 +echo "${ECHO_T}$ac_cv_c_inline" >&6 + + +case $ac_cv_c_inline in + inline | yes) ;; + *) + case $ac_cv_c_inline in + no) ac_val=;; + *) ac_val=$ac_cv_c_inline;; + esac + cat >>confdefs.h <<_ACEOF +#ifndef __cplusplus +#define inline $ac_val +#endif +_ACEOF + ;; +esac + +echo "$as_me:$LINENO: checking for working long double with more range or precision than double" >&5 +echo $ECHO_N "checking for working long double with more range or precision than double... $ECHO_C" >&6 +if test "${ac_cv_c_long_double+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#include + long double foo = 0.0; +int +main () +{ +static int test_array [1 - 2 * !(/* Using '|' rather than '||' catches a GCC 2.95.2 x86 bug. */ + (DBL_MAX < LDBL_MAX) | (LDBL_EPSILON < DBL_EPSILON) + | (DBL_MAX_EXP < LDBL_MAX_EXP) | (DBL_MANT_DIG < LDBL_MANT_DIG))]; +test_array [0] = 0 + + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 + (eval $ac_compile) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest.$ac_objext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_cv_c_long_double=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +ac_cv_c_long_double=no +fi +rm -f conftest.err conftest.$ac_objext conftest.$ac_ext +fi +echo "$as_me:$LINENO: result: $ac_cv_c_long_double" >&5 +echo "${ECHO_T}$ac_cv_c_long_double" >&6 +if test $ac_cv_c_long_double = yes; then + +cat >>confdefs.h <<\_ACEOF +#define HAVE_LONG_DOUBLE 1 +_ACEOF + +fi + + +echo "$as_me:$LINENO: checking return type of signal handlers" >&5 +echo $ECHO_N "checking return type of signal handlers... $ECHO_C" >&6 +if test "${ac_cv_type_signal+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#include +#include +#ifdef signal +# undef signal +#endif +#ifdef __cplusplus +extern "C" void (*signal (int, void (*)(int)))(int); +#else +void (*signal ()) (); +#endif + +int +main () +{ +int i; + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 + (eval $ac_compile) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest.$ac_objext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_cv_type_signal=void +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +ac_cv_type_signal=int +fi +rm -f conftest.err conftest.$ac_objext conftest.$ac_ext +fi +echo "$as_me:$LINENO: result: $ac_cv_type_signal" >&5 +echo "${ECHO_T}$ac_cv_type_signal" >&6 + +cat >>confdefs.h <<_ACEOF +#define RETSIGTYPE $ac_cv_type_signal +_ACEOF + + +echo "$as_me:$LINENO: checking for uid_t in sys/types.h" >&5 +echo $ECHO_N "checking for uid_t in sys/types.h... $ECHO_C" >&6 +if test "${ac_cv_type_uid_t+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#include + +_ACEOF +if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | + $EGREP "uid_t" >/dev/null 2>&1; then + ac_cv_type_uid_t=yes +else + ac_cv_type_uid_t=no +fi +rm -f conftest* + +fi +echo "$as_me:$LINENO: result: $ac_cv_type_uid_t" >&5 +echo "${ECHO_T}$ac_cv_type_uid_t" >&6 +if test $ac_cv_type_uid_t = no; then + +cat >>confdefs.h <<\_ACEOF +#define uid_t int +_ACEOF + + +cat >>confdefs.h <<\_ACEOF +#define gid_t int +_ACEOF + +fi + +echo "$as_me:$LINENO: checking for mode_t" >&5 +echo $ECHO_N "checking for mode_t... $ECHO_C" >&6 +if test "${ac_cv_type_mode_t+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +$ac_includes_default +int +main () +{ +if ((mode_t *) 0) + return 0; +if (sizeof (mode_t)) + return 0; + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 + (eval $ac_compile) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest.$ac_objext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_cv_type_mode_t=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +ac_cv_type_mode_t=no +fi +rm -f conftest.err conftest.$ac_objext conftest.$ac_ext +fi +echo "$as_me:$LINENO: result: $ac_cv_type_mode_t" >&5 +echo "${ECHO_T}$ac_cv_type_mode_t" >&6 +if test $ac_cv_type_mode_t = yes; then + : +else + +cat >>confdefs.h <<_ACEOF +#define mode_t int +_ACEOF + +fi + +echo "$as_me:$LINENO: checking for off_t" >&5 +echo $ECHO_N "checking for off_t... $ECHO_C" >&6 +if test "${ac_cv_type_off_t+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +$ac_includes_default +int +main () +{ +if ((off_t *) 0) + return 0; +if (sizeof (off_t)) + return 0; + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 + (eval $ac_compile) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest.$ac_objext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_cv_type_off_t=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +ac_cv_type_off_t=no +fi +rm -f conftest.err conftest.$ac_objext conftest.$ac_ext +fi +echo "$as_me:$LINENO: result: $ac_cv_type_off_t" >&5 +echo "${ECHO_T}$ac_cv_type_off_t" >&6 +if test $ac_cv_type_off_t = yes; then + : +else + +cat >>confdefs.h <<_ACEOF +#define off_t long +_ACEOF + +fi + +echo "$as_me:$LINENO: checking for size_t" >&5 +echo $ECHO_N "checking for size_t... $ECHO_C" >&6 +if test "${ac_cv_type_size_t+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext @@ -6960,71 +8243,6 @@ fi -echo "$as_me:$LINENO: checking for ino_t" >&5 -echo $ECHO_N "checking for ino_t... $ECHO_C" >&6 -if test "${ac_cv_type_ino_t+set}" = set; then - echo $ECHO_N "(cached) $ECHO_C" >&6 -else - cat >conftest.$ac_ext <<_ACEOF -/* confdefs.h. */ -_ACEOF -cat confdefs.h >>conftest.$ac_ext -cat >>conftest.$ac_ext <<_ACEOF -/* end confdefs.h. */ -$ac_includes_default -int -main () -{ -if ((ino_t *) 0) - return 0; -if (sizeof (ino_t)) - return 0; - ; - return 0; -} -_ACEOF -rm -f conftest.$ac_objext -if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 - (eval $ac_compile) 2>conftest.er1 - ac_status=$? - grep -v '^ *+' conftest.er1 >conftest.err - rm -f conftest.er1 - cat conftest.err >&5 - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); } && - { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err' - { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 - (eval $ac_try) 2>&5 - ac_status=$? - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); }; } && - { ac_try='test -s conftest.$ac_objext' - { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 - (eval $ac_try) 2>&5 - ac_status=$? - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); }; }; then - ac_cv_type_ino_t=yes -else - echo "$as_me: failed program was:" >&5 -sed 's/^/| /' conftest.$ac_ext >&5 - -ac_cv_type_ino_t=no -fi -rm -f conftest.err conftest.$ac_objext conftest.$ac_ext -fi -echo "$as_me:$LINENO: result: $ac_cv_type_ino_t" >&5 -echo "${ECHO_T}$ac_cv_type_ino_t" >&6 -if test $ac_cv_type_ino_t = yes; then - : -else - -cat >>confdefs.h <<_ACEOF -#define ino_t unsigned -_ACEOF - -fi - echo "$as_me:$LINENO: checking for socklen_t" >&5 echo $ECHO_N "checking for socklen_t... $ECHO_C" >&6 @@ -8473,8 +9691,126 @@ int main () { -static struct sockaddr_in ac_aggr; -if (sizeof ac_aggr.sin_len) +static struct sockaddr_in ac_aggr; +if (sizeof ac_aggr.sin_len) +return 0; + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 + (eval $ac_compile) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest.$ac_objext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_cv_member_struct_sockaddr_in_sin_len=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +ac_cv_member_struct_sockaddr_in_sin_len=no +fi +rm -f conftest.err conftest.$ac_objext conftest.$ac_ext +fi +rm -f conftest.err conftest.$ac_objext conftest.$ac_ext +fi +echo "$as_me:$LINENO: result: $ac_cv_member_struct_sockaddr_in_sin_len" >&5 +echo "${ECHO_T}$ac_cv_member_struct_sockaddr_in_sin_len" >&6 +if test $ac_cv_member_struct_sockaddr_in_sin_len = yes; then + +cat >>confdefs.h <<\_ACEOF +#define HAVE_SOCKADDR_IN_LEN 1 +_ACEOF + +fi + + +echo "$as_me:$LINENO: checking for struct sockaddr_un.sun_len" >&5 +echo $ECHO_N "checking for struct sockaddr_un.sun_len... $ECHO_C" >&6 +if test "${ac_cv_member_struct_sockaddr_un_sun_len+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ + +#include +#include +#include + + +int +main () +{ +static struct sockaddr_un ac_aggr; +if (ac_aggr.sun_len) +return 0; + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 + (eval $ac_compile) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest.$ac_objext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_cv_member_struct_sockaddr_un_sun_len=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ + +#include +#include +#include + + +int +main () +{ +static struct sockaddr_un ac_aggr; +if (sizeof ac_aggr.sun_len) return 0; ; return 0; @@ -8501,23 +9837,23 @@ ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; }; then - ac_cv_member_struct_sockaddr_in_sin_len=yes + ac_cv_member_struct_sockaddr_un_sun_len=yes else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 -ac_cv_member_struct_sockaddr_in_sin_len=no +ac_cv_member_struct_sockaddr_un_sun_len=no fi rm -f conftest.err conftest.$ac_objext conftest.$ac_ext fi rm -f conftest.err conftest.$ac_objext conftest.$ac_ext fi -echo "$as_me:$LINENO: result: $ac_cv_member_struct_sockaddr_in_sin_len" >&5 -echo "${ECHO_T}$ac_cv_member_struct_sockaddr_in_sin_len" >&6 -if test $ac_cv_member_struct_sockaddr_in_sin_len = yes; then +echo "$as_me:$LINENO: result: $ac_cv_member_struct_sockaddr_un_sun_len" >&5 +echo "${ECHO_T}$ac_cv_member_struct_sockaddr_un_sun_len" >&6 +if test $ac_cv_member_struct_sockaddr_un_sun_len = yes; then cat >>confdefs.h <<\_ACEOF -#define HAVE_SOCKADDR_IN_LEN 1 +#define HAVE_SOCKADDR_UN_LEN 1 _ACEOF fi @@ -8696,6 +10032,75 @@ fi +echo "$as_me:$LINENO: checking struct stat64" >&5 +echo $ECHO_N "checking struct stat64... $ECHO_C" >&6 +cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#include +#if HAVE_SYS_TYPES_H +# include +#endif +#if HAVE_SYS_STAT_H +# include +#endif +#if STDC_HEADERS +# include +# include +#else +# if HAVE_STDLIB_H +# include +# endif +#endif + +int +main () +{ +struct stat64 st; + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 + (eval $ac_compile) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest.$ac_objext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + echo "$as_me:$LINENO: result: yes" >&5 +echo "${ECHO_T}yes" >&6 + +cat >>confdefs.h <<\_ACEOF +#define HAVE_STRUCT_STAT64 1 +_ACEOF + +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6 +fi +rm -f conftest.err conftest.$ac_objext conftest.$ac_ext + # if we can't find strcasecmp, look in -lresolv (for Unixware at least) # @@ -9334,11 +10739,15 @@ + + + + for ac_func in waitpid wait4 getcwd strdup strerror chown chmod mknod mkfifo \ fchmod fstat strchr readlink link utime utimes strftime mtrace ftruncate \ - memmove lchown vsnprintf snprintf asprintf setsid glob strpbrk \ + memmove lchown vsnprintf snprintf vasprintf asprintf setsid glob strpbrk \ strlcat strlcpy strtol mallinfo getgroups setgroups geteuid getegid \ - open64 mkstemp64 + setmode open64 mkstemp64 va_copy __va_copy do as_ac_var=`echo "ac_cv_func_$ac_func" | $as_tr_sh` echo "$as_me:$LINENO: checking for $ac_func" >&5 @@ -9439,14 +10848,15 @@ done -echo "$as_me:$LINENO: checking for working socketpair" >&5 -echo $ECHO_N "checking for working socketpair... $ECHO_C" >&6 -if test "${rsync_cv_HAVE_SOCKETPAIR+set}" = set; then - echo $ECHO_N "(cached) $ECHO_C" >&6 -else -if test "$cross_compiling" = yes; then - rsync_cv_HAVE_SOCKETPAIR=cross + +for ac_func in getpgrp tcgetpgrp +do +as_ac_var=`echo "ac_cv_func_$ac_func" | $as_tr_sh` +echo "$as_me:$LINENO: checking for $ac_func" >&5 +echo $ECHO_N "checking for $ac_func... $ECHO_C" >&6 +if eval "test \"\${$as_ac_var+set}\" = set"; then + echo $ECHO_N "(cached) $ECHO_C" >&6 else cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ @@ -9454,83 +10864,117 @@ cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ +/* Define $ac_func to an innocuous variant, in case declares $ac_func. + For example, HP-UX 11i declares gettimeofday. */ +#define $ac_func innocuous_$ac_func -#include -#include +/* System header to define __stub macros and hopefully few prototypes, + which can conflict with char $ac_func (); below. + Prefer to if __STDC__ is defined, since + exists even on freestanding compilers. */ -main() { - int fd[2]; - exit((socketpair(AF_UNIX, SOCK_STREAM, 0, fd) != -1) ? 0 : 1); +#ifdef __STDC__ +# include +#else +# include +#endif + +#undef $ac_func + +/* Override any gcc2 internal prototype to avoid an error. */ +#ifdef __cplusplus +extern "C" +{ +#endif +/* We use char because int might match the return type of a gcc2 + builtin and then its argument prototype would still apply. */ +char $ac_func (); +/* The GNU C library defines this for functions which it implements + to always fail with ENOSYS. Some functions are actually named + something starting with __ and the normal name is an alias. */ +#if defined (__stub_$ac_func) || defined (__stub___$ac_func) +choke me +#else +char (*f) () = $ac_func; +#endif +#ifdef __cplusplus +} +#endif + +int +main () +{ +return f != $ac_func; + ; + return 0; } _ACEOF -rm -f conftest$ac_exeext +rm -f conftest.$ac_objext conftest$ac_exeext if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 - (eval $ac_link) 2>&5 + (eval $ac_link) 2>conftest.er1 ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); } && { ac_try='./conftest$ac_exeext' + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest$ac_exeext' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; }; then - rsync_cv_HAVE_SOCKETPAIR=yes + eval "$as_ac_var=yes" else - echo "$as_me: program exited with status $ac_status" >&5 -echo "$as_me: failed program was:" >&5 + echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 -( exit $ac_status ) -rsync_cv_HAVE_SOCKETPAIR=no -fi -rm -f core *.core gmon.out bb.out conftest$ac_exeext conftest.$ac_objext conftest.$ac_ext +eval "$as_ac_var=no" fi +rm -f conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext fi -echo "$as_me:$LINENO: result: $rsync_cv_HAVE_SOCKETPAIR" >&5 -echo "${ECHO_T}$rsync_cv_HAVE_SOCKETPAIR" >&6 -if test x"$rsync_cv_HAVE_SOCKETPAIR" = x"yes"; then - -cat >>confdefs.h <<\_ACEOF -#define HAVE_SOCKETPAIR 1 +echo "$as_me:$LINENO: result: `eval echo '${'$as_ac_var'}'`" >&5 +echo "${ECHO_T}`eval echo '${'$as_ac_var'}'`" >&6 +if test `eval echo '${'$as_ac_var'}'` = yes; then + cat >>confdefs.h <<_ACEOF +#define `echo "HAVE_$ac_func" | $as_tr_cpp` 1 _ACEOF fi +done -if test x"$with_included_popt" != x"yes" -then - -echo "$as_me:$LINENO: checking for poptGetContext in -lpopt" >&5 -echo $ECHO_N "checking for poptGetContext in -lpopt... $ECHO_C" >&6 -if test "${ac_cv_lib_popt_poptGetContext+set}" = set; then +if test $ac_cv_func_getpgrp = yes; then + echo "$as_me:$LINENO: checking whether getpgrp requires zero arguments" >&5 +echo $ECHO_N "checking whether getpgrp requires zero arguments... $ECHO_C" >&6 +if test "${ac_cv_func_getpgrp_void+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else - ac_check_lib_save_LIBS=$LIBS -LIBS="-lpopt $LIBS" + # Use it with a single arg. cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ - -/* Override any gcc2 internal prototype to avoid an error. */ -#ifdef __cplusplus -extern "C" -#endif -/* We use char because int might match the return type of a gcc2 - builtin and then its argument prototype would still apply. */ -char poptGetContext (); +$ac_includes_default int main () { -poptGetContext (); +getpgrp (0); ; return 0; } _ACEOF -rm -f conftest.$ac_objext conftest$ac_exeext -if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 - (eval $ac_link) 2>conftest.er1 +rm -f conftest.$ac_objext +if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 + (eval $ac_compile) 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 @@ -9543,66 +10987,43 @@ ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; } && - { ac_try='test -s conftest$ac_exeext' + { ac_try='test -s conftest.$ac_objext' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; }; then - ac_cv_lib_popt_poptGetContext=yes + ac_cv_func_getpgrp_void=no else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 -ac_cv_lib_popt_poptGetContext=no -fi -rm -f conftest.err conftest.$ac_objext \ - conftest$ac_exeext conftest.$ac_ext -LIBS=$ac_check_lib_save_LIBS +ac_cv_func_getpgrp_void=yes fi -echo "$as_me:$LINENO: result: $ac_cv_lib_popt_poptGetContext" >&5 -echo "${ECHO_T}$ac_cv_lib_popt_poptGetContext" >&6 -if test $ac_cv_lib_popt_poptGetContext = yes; then - cat >>confdefs.h <<_ACEOF -#define HAVE_LIBPOPT 1 -_ACEOF - - LIBS="-lpopt $LIBS" +rm -f conftest.err conftest.$ac_objext conftest.$ac_ext -else - with_included_popt=yes fi +echo "$as_me:$LINENO: result: $ac_cv_func_getpgrp_void" >&5 +echo "${ECHO_T}$ac_cv_func_getpgrp_void" >&6 +if test $ac_cv_func_getpgrp_void = yes; then + +cat >>confdefs.h <<\_ACEOF +#define GETPGRP_VOID 1 +_ACEOF fi -echo "$as_me:$LINENO: checking whether to use included libpopt" >&5 -echo $ECHO_N "checking whether to use included libpopt... $ECHO_C" >&6 -if test x"$with_included_popt" = x"yes" -then - echo "$as_me:$LINENO: result: $srcdir/popt" >&5 -echo "${ECHO_T}$srcdir/popt" >&6 - BUILD_POPT='$(popt_OBJS)' - CFLAGS="$CFLAGS -I$srcdir/popt" - if test x"$ALLOCA" != x - then - # this can be removed when/if we add an included alloca.c; - # see autoconf documentation on AC_FUNC_ALLOCA - { echo "$as_me:$LINENO: WARNING: included libpopt will use malloc, not alloca (which wastes a small amount of memory)" >&5 -echo "$as_me: WARNING: included libpopt will use malloc, not alloca (which wastes a small amount of memory)" >&2;} - fi -else - echo "$as_me:$LINENO: result: no" >&5 -echo "${ECHO_T}no" >&6 fi -echo "$as_me:$LINENO: checking for long long" >&5 -echo $ECHO_N "checking for long long... $ECHO_C" >&6 -if test "${rsync_cv_HAVE_LONGLONG+set}" = set; then +# Determine whether chown follows symlinks (it should). +echo "$as_me:$LINENO: checking whether chown() dereferences symlinks" >&5 +echo $ECHO_N "checking whether chown() dereferences symlinks... $ECHO_C" >&6 +if test "${rsync_cv_chown_follows_symlink+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else -if test "$cross_compiling" = yes; then - rsync_cv_HAVE_LONGLONG=cross + if test "$cross_compiling" = yes; then + rsync_cv_chown_follows_symlink=yes else cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ @@ -9610,8 +11031,19 @@ cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ -#include -main() { long long x = 1000000; x *= x; exit(((x/1000000) == 1000000)? 0: 1); } + +#if HAVE_UNISTD_H +# include +#endif +#include +#include + main() { + char const *dangling_symlink = "conftest.dangle"; + unlink(dangling_symlink); + if (symlink("conftest.no-such", dangling_symlink) < 0) abort(); + if (chown(dangling_symlink, getuid(), getgid()) < 0 && errno == ENOENT) exit(0); + exit(1); + } _ACEOF rm -f conftest$ac_exeext if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 @@ -9624,36 +11056,36 @@ ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; }; then - rsync_cv_HAVE_LONGLONG=yes + rsync_cv_chown_follows_symlink=yes else echo "$as_me: program exited with status $ac_status" >&5 echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ( exit $ac_status ) -rsync_cv_HAVE_LONGLONG=no +rsync_cv_chown_follows_symlink=no fi rm -f core *.core gmon.out bb.out conftest$ac_exeext conftest.$ac_objext conftest.$ac_ext fi fi -echo "$as_me:$LINENO: result: $rsync_cv_HAVE_LONGLONG" >&5 -echo "${ECHO_T}$rsync_cv_HAVE_LONGLONG" >&6 -if test x"$rsync_cv_HAVE_LONGLONG" = x"yes"; then +echo "$as_me:$LINENO: result: $rsync_cv_chown_follows_symlink" >&5 +echo "${ECHO_T}$rsync_cv_chown_follows_symlink" >&6 +if test $rsync_cv_chown_follows_symlink = no; then cat >>confdefs.h <<\_ACEOF -#define HAVE_LONGLONG 1 +#define CHOWN_MODIFIES_SYMLINK 1 _ACEOF fi -echo "$as_me:$LINENO: checking for off64_t" >&5 -echo $ECHO_N "checking for off64_t... $ECHO_C" >&6 -if test "${rsync_cv_HAVE_OFF64_T+set}" = set; then +echo "$as_me:$LINENO: checking for working socketpair" >&5 +echo $ECHO_N "checking for working socketpair... $ECHO_C" >&6 +if test "${rsync_cv_HAVE_SOCKETPAIR+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else if test "$cross_compiling" = yes; then - rsync_cv_HAVE_OFF64_T=cross + rsync_cv_HAVE_SOCKETPAIR=cross else cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ @@ -9661,9 +11093,14 @@ cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ -#include -#include -main() { struct stat64 st; off64_t s; if (sizeof(off_t) == sizeof(off64_t)) exit(1); exit((lstat64("/dev/null", &st)==0)?0:1); } + +#include +#include + +main() { + int fd[2]; + exit((socketpair(AF_UNIX, SOCK_STREAM, 0, fd) != -1) ? 0 : 1); +} _ACEOF rm -f conftest$ac_exeext if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 @@ -9676,128 +11113,184 @@ ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; }; then - rsync_cv_HAVE_OFF64_T=yes + rsync_cv_HAVE_SOCKETPAIR=yes else echo "$as_me: program exited with status $ac_status" >&5 echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ( exit $ac_status ) -rsync_cv_HAVE_OFF64_T=no +rsync_cv_HAVE_SOCKETPAIR=no fi rm -f core *.core gmon.out bb.out conftest$ac_exeext conftest.$ac_objext conftest.$ac_ext fi fi -echo "$as_me:$LINENO: result: $rsync_cv_HAVE_OFF64_T" >&5 -echo "${ECHO_T}$rsync_cv_HAVE_OFF64_T" >&6 -if test x"$rsync_cv_HAVE_OFF64_T" = x"yes"; then +echo "$as_me:$LINENO: result: $rsync_cv_HAVE_SOCKETPAIR" >&5 +echo "${ECHO_T}$rsync_cv_HAVE_SOCKETPAIR" >&6 +if test x"$rsync_cv_HAVE_SOCKETPAIR" = x"yes"; then cat >>confdefs.h <<\_ACEOF -#define HAVE_OFF64_T 1 +#define HAVE_SOCKETPAIR 1 _ACEOF fi -echo "$as_me:$LINENO: checking for short ino_t" >&5 -echo $ECHO_N "checking for short ino_t... $ECHO_C" >&6 -if test "${rsync_cv_HAVE_SHORT_INO_T+set}" = set; then - echo $ECHO_N "(cached) $ECHO_C" >&6 -else +if test x"$with_included_popt" != x"yes" +then -if test "$cross_compiling" = yes; then - rsync_cv_HAVE_SHORT_INO_T=cross +echo "$as_me:$LINENO: checking for poptGetContext in -lpopt" >&5 +echo $ECHO_N "checking for poptGetContext in -lpopt... $ECHO_C" >&6 +if test "${ac_cv_lib_popt_poptGetContext+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 else - cat >conftest.$ac_ext <<_ACEOF + ac_check_lib_save_LIBS=$LIBS +LIBS="-lpopt $LIBS" +cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ -#include -#include -#include -main() { if (sizeof(ino_t) < sizeof(unsigned int)) return 0; return 1; } + +/* Override any gcc2 internal prototype to avoid an error. */ +#ifdef __cplusplus +extern "C" +#endif +/* We use char because int might match the return type of a gcc2 + builtin and then its argument prototype would still apply. */ +char poptGetContext (); +int +main () +{ +poptGetContext (); + ; + return 0; +} _ACEOF -rm -f conftest$ac_exeext +rm -f conftest.$ac_objext conftest$ac_exeext if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 - (eval $ac_link) 2>&5 + (eval $ac_link) 2>conftest.er1 ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); } && { ac_try='./conftest$ac_exeext' + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest$ac_exeext' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; }; then - rsync_cv_HAVE_SHORT_INO_T=yes + ac_cv_lib_popt_poptGetContext=yes else - echo "$as_me: program exited with status $ac_status" >&5 -echo "$as_me: failed program was:" >&5 + echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 -( exit $ac_status ) -rsync_cv_HAVE_SHORT_INO_T=no +ac_cv_lib_popt_poptGetContext=no fi -rm -f core *.core gmon.out bb.out conftest$ac_exeext conftest.$ac_objext conftest.$ac_ext +rm -f conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS fi +echo "$as_me:$LINENO: result: $ac_cv_lib_popt_poptGetContext" >&5 +echo "${ECHO_T}$ac_cv_lib_popt_poptGetContext" >&6 +if test $ac_cv_lib_popt_poptGetContext = yes; then + cat >>confdefs.h <<_ACEOF +#define HAVE_LIBPOPT 1 +_ACEOF + + LIBS="-lpopt $LIBS" + +else + with_included_popt=yes fi -echo "$as_me:$LINENO: result: $rsync_cv_HAVE_SHORT_INO_T" >&5 -echo "${ECHO_T}$rsync_cv_HAVE_SHORT_INO_T" >&6 -if test x"$rsync_cv_HAVE_SHORT_INO_T" = x"yes"; then -cat >>confdefs.h <<\_ACEOF -#define HAVE_SHORT_INO_T 1 -_ACEOF +fi +echo "$as_me:$LINENO: checking whether to use included libpopt" >&5 +echo $ECHO_N "checking whether to use included libpopt... $ECHO_C" >&6 +if test x"$with_included_popt" = x"yes" +then + echo "$as_me:$LINENO: result: $srcdir/popt" >&5 +echo "${ECHO_T}$srcdir/popt" >&6 + BUILD_POPT='$(popt_OBJS)' + CFLAGS="$CFLAGS -I$srcdir/popt" + if test x"$ALLOCA" != x + then + # this can be removed when/if we add an included alloca.c; + # see autoconf documentation on AC_FUNC_ALLOCA + { echo "$as_me:$LINENO: WARNING: included libpopt will use malloc, not alloca (which wastes a small amount of memory)" >&5 +echo "$as_me: WARNING: included libpopt will use malloc, not alloca (which wastes a small amount of memory)" >&2;} + fi +else + echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6 fi echo "$as_me:$LINENO: checking for unsigned char" >&5 echo $ECHO_N "checking for unsigned char... $ECHO_C" >&6 -if test "${rsync_cv_HAVE_UNSIGNED_CHAR+set}" = set; then +if test "${rsync_cv_SIGNED_CHAR_OK+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else -if test "$cross_compiling" = yes; then - rsync_cv_HAVE_UNSIGNED_CHAR=cross -else - cat >conftest.$ac_ext <<_ACEOF +cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ -#include -main() { char c; c=250; exit((c > 0)?0:1); } + +int +main () +{ +signed char *s = "" + ; + return 0; +} _ACEOF -rm -f conftest$ac_exeext -if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 - (eval $ac_link) 2>&5 +rm -f conftest.$ac_objext +if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 + (eval $ac_compile) 2>conftest.er1 ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); } && { ac_try='./conftest$ac_exeext' + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest.$ac_objext' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; }; then - rsync_cv_HAVE_UNSIGNED_CHAR=yes + rsync_cv_SIGNED_CHAR_OK=yes else - echo "$as_me: program exited with status $ac_status" >&5 -echo "$as_me: failed program was:" >&5 + echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 -( exit $ac_status ) -rsync_cv_HAVE_UNSIGNED_CHAR=no -fi -rm -f core *.core gmon.out bb.out conftest$ac_exeext conftest.$ac_objext conftest.$ac_ext +rsync_cv_SIGNED_CHAR_OK=no fi +rm -f conftest.err conftest.$ac_objext conftest.$ac_ext fi -echo "$as_me:$LINENO: result: $rsync_cv_HAVE_UNSIGNED_CHAR" >&5 -echo "${ECHO_T}$rsync_cv_HAVE_UNSIGNED_CHAR" >&6 -if test x"$rsync_cv_HAVE_UNSIGNED_CHAR" = x"yes"; then +echo "$as_me:$LINENO: result: $rsync_cv_SIGNED_CHAR_OK" >&5 +echo "${ECHO_T}$rsync_cv_SIGNED_CHAR_OK" >&6 +if test x"$rsync_cv_SIGNED_CHAR_OK" = x"yes"; then cat >>confdefs.h <<\_ACEOF -#define HAVE_UNSIGNED_CHAR 1 +#define SIGNED_CHAR_OK 1 _ACEOF fi @@ -9924,26 +11417,38 @@ echo $ECHO_N "(cached) $ECHO_C" >&6 else -if test "$cross_compiling" = yes; then - rsync_cv_HAVE_GETTIMEOFDAY_TZ=cross -else - cat >conftest.$ac_ext <<_ACEOF +cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ - #include #include -main() { struct timeval tv; exit(gettimeofday(&tv, NULL));} +int +main () +{ +struct timeval tv; exit(gettimeofday(&tv, NULL)); + ; + return 0; +} _ACEOF -rm -f conftest$ac_exeext -if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 - (eval $ac_link) 2>&5 +rm -f conftest.$ac_objext +if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 + (eval $ac_compile) 2>conftest.er1 ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); } && { ac_try='./conftest$ac_exeext' + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest.$ac_objext' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? @@ -9951,15 +11456,12 @@ (exit $ac_status); }; }; then rsync_cv_HAVE_GETTIMEOFDAY_TZ=yes else - echo "$as_me: program exited with status $ac_status" >&5 -echo "$as_me: failed program was:" >&5 + echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 -( exit $ac_status ) rsync_cv_HAVE_GETTIMEOFDAY_TZ=no fi -rm -f core *.core gmon.out bb.out conftest$ac_exeext conftest.$ac_objext conftest.$ac_ext -fi +rm -f conftest.err conftest.$ac_objext conftest.$ac_ext fi echo "$as_me:$LINENO: result: $rsync_cv_HAVE_GETTIMEOFDAY_TZ" >&5 echo "${ECHO_T}$rsync_cv_HAVE_GETTIMEOFDAY_TZ" >&6 @@ -10219,6 +11721,120 @@ fi +echo "$as_me:$LINENO: checking if mknod creates FIFOs" >&5 +echo $ECHO_N "checking if mknod creates FIFOs... $ECHO_C" >&6 +if test "${rsync_cv_MKNOD_CREATES_FIFOS+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + +if test "$cross_compiling" = yes; then + rsync_cv_MKNOD_CREATES_FIFOS=cross +else + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ + +#include +#include +#include +main() { int rc, ec; char *fn = "fifo-test"; +unlink(fn); rc = mknod(fn,S_IFIFO,0600); ec = errno; unlink(fn); +if (rc) {printf("%d %d\n",rc,ec); return ec;} +return 0;} +_ACEOF +rm -f conftest$ac_exeext +if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 + (eval $ac_link) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { ac_try='./conftest$ac_exeext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + rsync_cv_MKNOD_CREATES_FIFOS=yes +else + echo "$as_me: program exited with status $ac_status" >&5 +echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +( exit $ac_status ) +rsync_cv_MKNOD_CREATES_FIFOS=no +fi +rm -f core *.core gmon.out bb.out conftest$ac_exeext conftest.$ac_objext conftest.$ac_ext +fi +fi +echo "$as_me:$LINENO: result: $rsync_cv_MKNOD_CREATES_FIFOS" >&5 +echo "${ECHO_T}$rsync_cv_MKNOD_CREATES_FIFOS" >&6 +if test x"$rsync_cv_MKNOD_CREATES_FIFOS" = x"yes"; then + +cat >>confdefs.h <<\_ACEOF +#define MKNOD_CREATES_FIFOS 1 +_ACEOF + +fi + +echo "$as_me:$LINENO: checking if mknod creates sockets" >&5 +echo $ECHO_N "checking if mknod creates sockets... $ECHO_C" >&6 +if test "${rsync_cv_MKNOD_CREATES_SOCKETS+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + +if test "$cross_compiling" = yes; then + rsync_cv_MKNOD_CREATES_SOCKETS=cross +else + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ + +#include +#include +#include +main() { int rc, ec; char *fn = "sock-test"; +unlink(fn); rc = mknod(fn,S_IFSOCK,0600); ec = errno; unlink(fn); +if (rc) {printf("%d %d\n",rc,ec); return ec;} +return 0;} +_ACEOF +rm -f conftest$ac_exeext +if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 + (eval $ac_link) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { ac_try='./conftest$ac_exeext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + rsync_cv_MKNOD_CREATES_SOCKETS=yes +else + echo "$as_me: program exited with status $ac_status" >&5 +echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +( exit $ac_status ) +rsync_cv_MKNOD_CREATES_SOCKETS=no +fi +rm -f core *.core gmon.out bb.out conftest$ac_exeext conftest.$ac_objext conftest.$ac_ext +fi +fi +echo "$as_me:$LINENO: result: $rsync_cv_MKNOD_CREATES_SOCKETS" >&5 +echo "${ECHO_T}$rsync_cv_MKNOD_CREATES_SOCKETS" >&6 +if test x"$rsync_cv_MKNOD_CREATES_SOCKETS" = x"yes"; then + +cat >>confdefs.h <<\_ACEOF +#define MKNOD_CREATES_SOCKETS 1 +_ACEOF + +fi + # # The following test was mostly taken from the tcl/tk plus patches # diff -urN --exclude=patches rsync-2.6.3/configure.in rsync-2.6.4/configure.in --- rsync-2.6.3/configure.in 2004-09-30 09:35:56.000000000 -0700 +++ rsync-2.6.4/configure.in 2005-03-30 19:14:09.000000000 -0800 @@ -3,9 +3,9 @@ AC_INIT() AC_CONFIG_SRCDIR([byteorder.h]) AC_CONFIG_HEADER(config.h) -AC_PREREQ(2.52) +AC_PREREQ(2.59) -RSYNC_VERSION=2.6.3 +RSYNC_VERSION=2.6.4 AC_SUBST(RSYNC_VERSION) AC_MSG_NOTICE([Configuring rsync $RSYNC_VERSION]) @@ -57,7 +57,7 @@ AC_ARG_ENABLE(profile, - AC_HELP_STRING([--enable-profile], + AC_HELP_STRING([--enable-profile], [turn on CPU profiling (default no)], [], [])) if test x"$enable_profile" = xyes @@ -68,7 +68,7 @@ # Specifically, this turns on panic_action handling. AC_ARG_ENABLE(maintainer-mode, - AC_HELP_STRING([--enable-maintainer-mode], + AC_HELP_STRING([--enable-maintainer-mode], [turn on extra debug features], [], [])) if test x"$enable_maintainer_mode" = xyes @@ -82,7 +82,7 @@ CFLAGS="$CFLAGS -DHAVE_CONFIG_H" # If GCC, turn on warnings. -if test "x$GCC" = "xyes" +if test x"$GCC" = x"yes" then CFLAGS="$CFLAGS -Wall -W" fi @@ -275,7 +275,7 @@ case $host_os in *cygwin* ) AC_MSG_RESULT(yes) AC_DEFINE(SHUTDOWN_ALL_SOCKETS, 1, - [Define if sockets need to be shutdown]) + [Define to 1 if sockets need to be shutdown]) ;; * ) AC_MSG_RESULT(no);; esac @@ -293,9 +293,13 @@ AC_CHECK_SIZEOF(int) AC_CHECK_SIZEOF(long) +AC_CHECK_SIZEOF(long long) AC_CHECK_SIZEOF(short) +AC_CHECK_SIZEOF(off_t) +AC_CHECK_SIZEOF(off64_t) AC_C_INLINE +AC_C_LONG_DOUBLE AC_TYPE_SIGNAL AC_TYPE_UID_T @@ -306,14 +310,13 @@ AC_TYPE_GETGROUPS AC_CHECK_MEMBERS([struct stat.st_rdev]) -AC_CHECK_TYPE([ino_t], [unsigned]) TYPE_SOCKLEN_T AC_CACHE_CHECK([for errno in errno.h],rsync_cv_errno, [ AC_TRY_COMPILE([#include ],[int i = errno], rsync_cv_errno=yes,rsync_cv_have_errno_decl=no)]) if test x"$rsync_cv_errno" = x"yes"; then - AC_DEFINE(HAVE_ERRNO_DECL, 1, [ ]) + AC_DEFINE(HAVE_ERRNO_DECL, 1, [Define to 1 if errno is declared in errno.h]) fi # The following test taken from the cvs sources @@ -348,7 +351,7 @@ test x"$ac_cv_lib_inet_connect" = x"yes"; then # ac_cv_func_connect=yes # don't! it would cause AC_CHECK_FUNC to succeed next time configure is run - AC_DEFINE(HAVE_CONNECT, 1, [ ]) + AC_DEFINE(HAVE_CONNECT, 1, [Define to 1 if you have the "connect" function]) fi fi @@ -383,7 +386,7 @@ #include ],[getaddrinfo(NULL, NULL, NULL, NULL);], [AC_MSG_RESULT([yes]) AC_DEFINE(HAVE_GETADDRINFO, 1, - [Define if you have the `getaddrinfo' function.])], + [Define to 1 if you have the "getaddrinfo" function.])], [AC_MSG_RESULT([no]) AC_LIBOBJ(lib/getaddrinfo)])]) AC_CHECK_FUNCS(getnameinfo, , [AC_LIBOBJ(lib/getnameinfo)]) @@ -409,13 +412,22 @@ #include ]) +AC_CHECK_MEMBER([struct sockaddr_un.sun_len], + [ AC_DEFINE(HAVE_SOCKADDR_UN_LEN, 1, [Do we have sockaddr_un.sun_len?]) ], + [], + [ +#include +#include +#include +]) + AC_MSG_CHECKING(struct sockaddr_storage) AC_TRY_COMPILE([#include #include ], [struct sockaddr_storage x;], AC_MSG_RESULT(yes) AC_DEFINE(HAVE_SOCKADDR_STORAGE, 1, - [Define if you have strct sockaddr_storage.] ), + [Define to 1 if you have struct sockaddr_storage.] ), AC_MSG_RESULT(no)) AC_CHECK_MEMBER([struct sockaddr_in6.sin6_scope_id], @@ -427,6 +439,27 @@ #include ]) +AC_MSG_CHECKING(struct stat64) +AC_TRY_COMPILE([#include +#if HAVE_SYS_TYPES_H +# include +#endif +#if HAVE_SYS_STAT_H +# include +#endif +#if STDC_HEADERS +# include +# include +#else +# if HAVE_STDLIB_H +# include +# endif +#endif +],[struct stat64 st;], + AC_MSG_RESULT(yes) + AC_DEFINE(HAVE_STRUCT_STAT64,1,[Define to 1 if you have struct stat64.]), + AC_MSG_RESULT(no)) + # if we can't find strcasecmp, look in -lresolv (for Unixware at least) # AC_CHECK_FUNCS(strcasecmp) @@ -443,9 +476,34 @@ AC_FUNC_ALLOCA AC_CHECK_FUNCS(waitpid wait4 getcwd strdup strerror chown chmod mknod mkfifo \ fchmod fstat strchr readlink link utime utimes strftime mtrace ftruncate \ - memmove lchown vsnprintf snprintf asprintf setsid glob strpbrk \ + memmove lchown vsnprintf snprintf vasprintf asprintf setsid glob strpbrk \ strlcat strlcpy strtol mallinfo getgroups setgroups geteuid getegid \ - open64 mkstemp64) + setmode open64 mkstemp64 va_copy __va_copy) + +AC_CHECK_FUNCS(getpgrp tcgetpgrp) +if test $ac_cv_func_getpgrp = yes; then + AC_FUNC_GETPGRP +fi + +# Determine whether chown follows symlinks (it should). +AC_CACHE_CHECK([whether chown() dereferences symlinks],rsync_cv_chown_follows_symlink,[ + AC_TRY_RUN([ +#if HAVE_UNISTD_H +# include +#endif +#include +#include + main() { + char const *dangling_symlink = "conftest.dangle"; + unlink(dangling_symlink); + if (symlink("conftest.no-such", dangling_symlink) < 0) abort(); + if (chown(dangling_symlink, getuid(), getgid()) < 0 && errno == ENOENT) exit(0); + exit(1); + }], + rsync_cv_chown_follows_symlink=yes,rsync_cv_chown_follows_symlink=no,rsync_cv_chown_follows_symlink=yes)]) +if test $rsync_cv_chown_follows_symlink = no; then + AC_DEFINE(CHOWN_MODIFIES_SYMLINK, 1, [Define to 1 if chown modifies symlinks.]) +fi AC_CACHE_CHECK([for working socketpair],rsync_cv_HAVE_SOCKETPAIR,[ AC_TRY_RUN([ @@ -458,7 +516,7 @@ }], rsync_cv_HAVE_SOCKETPAIR=yes,rsync_cv_HAVE_SOCKETPAIR=no,rsync_cv_HAVE_SOCKETPAIR=cross)]) if test x"$rsync_cv_HAVE_SOCKETPAIR" = x"yes"; then - AC_DEFINE(HAVE_SOCKETPAIR, 1, [ ]) + AC_DEFINE(HAVE_SOCKETPAIR, 1, [Define to 1 if you have the "socketpair" function]) fi if test x"$with_included_popt" != x"yes" @@ -482,39 +540,11 @@ AC_MSG_RESULT(no) fi -AC_CACHE_CHECK([for long long],rsync_cv_HAVE_LONGLONG,[ -AC_TRY_RUN([#include -main() { long long x = 1000000; x *= x; exit(((x/1000000) == 1000000)? 0: 1); }], -rsync_cv_HAVE_LONGLONG=yes,rsync_cv_HAVE_LONGLONG=no,rsync_cv_HAVE_LONGLONG=cross)]) -if test x"$rsync_cv_HAVE_LONGLONG" = x"yes"; then - AC_DEFINE(HAVE_LONGLONG, 1, [ ]) -fi - -AC_CACHE_CHECK([for off64_t],rsync_cv_HAVE_OFF64_T,[ -AC_TRY_RUN([#include -#include -main() { struct stat64 st; off64_t s; if (sizeof(off_t) == sizeof(off64_t)) exit(1); exit((lstat64("/dev/null", &st)==0)?0:1); }], -rsync_cv_HAVE_OFF64_T=yes,rsync_cv_HAVE_OFF64_T=no,rsync_cv_HAVE_OFF64_T=cross)]) -if test x"$rsync_cv_HAVE_OFF64_T" = x"yes"; then - AC_DEFINE(HAVE_OFF64_T, 1, [ ]) -fi - -AC_CACHE_CHECK([for short ino_t],rsync_cv_HAVE_SHORT_INO_T,[ -AC_TRY_RUN([#include -#include -#include -main() { if (sizeof(ino_t) < sizeof(unsigned int)) return 0; return 1; }], -rsync_cv_HAVE_SHORT_INO_T=yes,rsync_cv_HAVE_SHORT_INO_T=no,rsync_cv_HAVE_SHORT_INO_T=cross)]) -if test x"$rsync_cv_HAVE_SHORT_INO_T" = x"yes"; then - AC_DEFINE(HAVE_SHORT_INO_T, 1, [ ]) -fi - -AC_CACHE_CHECK([for unsigned char],rsync_cv_HAVE_UNSIGNED_CHAR,[ -AC_TRY_RUN([#include -main() { char c; c=250; exit((c > 0)?0:1); }], -rsync_cv_HAVE_UNSIGNED_CHAR=yes,rsync_cv_HAVE_UNSIGNED_CHAR=no,rsync_cv_HAVE_UNSIGNED_CHAR=cross)]) -if test x"$rsync_cv_HAVE_UNSIGNED_CHAR" = x"yes"; then - AC_DEFINE(HAVE_UNSIGNED_CHAR, 1, [ ]) +AC_CACHE_CHECK([for unsigned char],rsync_cv_SIGNED_CHAR_OK,[ +AC_TRY_COMPILE([],[signed char *s = ""], +rsync_cv_SIGNED_CHAR_OK=yes,rsync_cv_SIGNED_CHAR_OK=no)]) +if test x"$rsync_cv_SIGNED_CHAR_OK" = x"yes"; then + AC_DEFINE(SIGNED_CHAR_OK, 1, [Define to 1 if "signed char" is a valid type]) fi AC_CACHE_CHECK([for broken readdir],rsync_cv_HAVE_BROKEN_READDIR,[ @@ -525,26 +555,25 @@ di->d_name[0] == 0) exit(0); exit(1);} ], rsync_cv_HAVE_BROKEN_READDIR=yes,rsync_cv_HAVE_BROKEN_READDIR=no,rsync_cv_HAVE_BROKEN_READDIR=cross)]) if test x"$rsync_cv_HAVE_BROKEN_READDIR" = x"yes"; then - AC_DEFINE(HAVE_BROKEN_READDIR, 1, [ ]) + AC_DEFINE(HAVE_BROKEN_READDIR, 1, [Define to 1 if readdir() is broken]) fi AC_CACHE_CHECK([for utimbuf],rsync_cv_HAVE_UTIMBUF,[ AC_TRY_COMPILE([#include #include ], [struct utimbuf tbuf; tbuf.actime = 0; tbuf.modtime = 1; exit(utime("foo.c",&tbuf));], -rsync_cv_HAVE_UTIMBUF=yes,rsync_cv_HAVE_UTIMBUF=no,rsync_cv_HAVE_UTIMBUF=cross)]) +rsync_cv_HAVE_UTIMBUF=yes,rsync_cv_HAVE_UTIMBUF=no)]) if test x"$rsync_cv_HAVE_UTIMBUF" = x"yes"; then - AC_DEFINE(HAVE_UTIMBUF, 1, [ ]) + AC_DEFINE(HAVE_UTIMBUF, 1, [Define to 1 if you have the "struct utimbuf" type]) fi AC_CACHE_CHECK([if gettimeofday takes tz argument],rsync_cv_HAVE_GETTIMEOFDAY_TZ,[ -AC_TRY_RUN([ -#include -#include -main() { struct timeval tv; exit(gettimeofday(&tv, NULL));}], - rsync_cv_HAVE_GETTIMEOFDAY_TZ=yes,rsync_cv_HAVE_GETTIMEOFDAY_TZ=no,rsync_cv_HAVE_GETTIMEOFDAY_TZ=cross)]) +AC_TRY_COMPILE([#include +#include ], +[struct timeval tv; exit(gettimeofday(&tv, NULL));], +rsync_cv_HAVE_GETTIMEOFDAY_TZ=yes,rsync_cv_HAVE_GETTIMEOFDAY_TZ=no)]) if test x"$rsync_cv_HAVE_GETTIMEOFDAY_TZ" != x"no"; then - AC_DEFINE(HAVE_GETTIMEOFDAY_TZ, 1, [ ]) + AC_DEFINE(HAVE_GETTIMEOFDAY_TZ, 1, [Define to 1 if gettimeofday() takes a time-zone arg]) fi AC_CACHE_CHECK([for C99 vsnprintf],rsync_cv_HAVE_C99_VSNPRINTF,[ @@ -569,7 +598,7 @@ ], rsync_cv_HAVE_C99_VSNPRINTF=yes,rsync_cv_HAVE_C99_VSNPRINTF=no,rsync_cv_HAVE_C99_VSNPRINTF=cross)]) if test x"$rsync_cv_HAVE_C99_VSNPRINTF" = x"yes"; then - AC_DEFINE(HAVE_C99_VSNPRINTF, 1, [ ]) + AC_DEFINE(HAVE_C99_VSNPRINTF, 1, [Define to 1 if vsprintf has a C99-compatible return value]) fi @@ -592,7 +621,7 @@ rsync_cv_HAVE_SECURE_MKSTEMP=no, rsync_cv_HAVE_SECURE_MKSTEMP=cross)]) if test x"$rsync_cv_HAVE_SECURE_MKSTEMP" = x"yes"; then - AC_DEFINE(HAVE_SECURE_MKSTEMP, 1, [ ]) + AC_DEFINE(HAVE_SECURE_MKSTEMP, 1, [Define to 1 if mkstemp() is available and works right]) fi @@ -608,7 +637,7 @@ exit(0);}], rsync_cv_REPLACE_INET_NTOA=no,rsync_cv_REPLACE_INET_NTOA=yes,rsync_cv_REPLACE_INET_NTOA=cross)]) if test x"$rsync_cv_REPLACE_INET_NTOA" = x"yes"; then - AC_DEFINE(REPLACE_INET_NTOA, 1, [ ]) + AC_DEFINE(REPLACE_INET_NTOA, 1, [Define to 1 if inet_ntoa() needs to be replaced]) fi @@ -622,7 +651,35 @@ if (inet_aton("example", &ip) == 0) exit(0); exit(1);}], rsync_cv_REPLACE_INET_ATON=no,rsync_cv_REPLACE_INET_ATON=yes,rsync_cv_REPLACE_INET_ATON=cross)]) if test x"$rsync_cv_REPLACE_INET_ATON" = x"yes"; then - AC_DEFINE(REPLACE_INET_ATON, 1, [ ]) + AC_DEFINE(REPLACE_INET_ATON, 1, [Define to 1 if inet_aton() needs to be replaced]) +fi + +AC_CACHE_CHECK([if mknod creates FIFOs],rsync_cv_MKNOD_CREATES_FIFOS,[ +AC_TRY_RUN([ +#include +#include +#include +main() { int rc, ec; char *fn = "fifo-test"; +unlink(fn); rc = mknod(fn,S_IFIFO,0600); ec = errno; unlink(fn); +if (rc) {printf("%d %d\n",rc,ec); return ec;} +return 0;}], + rsync_cv_MKNOD_CREATES_FIFOS=yes,rsync_cv_MKNOD_CREATES_FIFOS=no,rsync_cv_MKNOD_CREATES_FIFOS=cross)]) +if test x"$rsync_cv_MKNOD_CREATES_FIFOS" = x"yes"; then + AC_DEFINE(MKNOD_CREATES_FIFOS, 1, [Define to 1 if mknod() can create FIFOs.]) +fi + +AC_CACHE_CHECK([if mknod creates sockets],rsync_cv_MKNOD_CREATES_SOCKETS,[ +AC_TRY_RUN([ +#include +#include +#include +main() { int rc, ec; char *fn = "sock-test"; +unlink(fn); rc = mknod(fn,S_IFSOCK,0600); ec = errno; unlink(fn); +if (rc) {printf("%d %d\n",rc,ec); return ec;} +return 0;}], + rsync_cv_MKNOD_CREATES_SOCKETS=yes,rsync_cv_MKNOD_CREATES_SOCKETS=no,rsync_cv_MKNOD_CREATES_SOCKETS=cross)]) +if test x"$rsync_cv_MKNOD_CREATES_SOCKETS" = x"yes"; then + AC_DEFINE(MKNOD_CREATES_SOCKETS, 1, [Define to 1 if mknod() can create sockets.]) fi # diff -urN --exclude=patches rsync-2.6.3/errcode.h rsync-2.6.4/errcode.h --- rsync-2.6.3/errcode.h 2003-12-15 00:04:14.000000000 -0800 +++ rsync-2.6.4/errcode.h 2005-03-15 15:23:39.000000000 -0800 @@ -28,6 +28,7 @@ #define RERR_FILESELECT 3 /* errors selecting input/output files, dirs */ #define RERR_UNSUPPORTED 4 /* requested action not supported */ #define RERR_STARTCLIENT 5 /* error starting client-server protocol */ +#define RERR_LOG_FAILURE 6 /* daemon unable to append to log-file */ #define RERR_SOCKETIO 10 /* error in socket IO */ #define RERR_FILEIO 11 /* error in file IO */ @@ -40,6 +41,7 @@ #define RERR_MALLOC 22 /* error allocating core memory buffers */ #define RERR_PARTIAL 23 /* partial transfer */ #define RERR_VANISHED 24 /* file(s) vanished on sender side */ +#define RERR_DEL_LIMIT 25 /* skipped some deletes due to --max-delete */ #define RERR_TIMEOUT 30 /* timeout in data send/receive */ diff -urN --exclude=patches rsync-2.6.3/exclude.c rsync-2.6.4/exclude.c --- rsync-2.6.3/exclude.c 2004-09-21 21:11:15.000000000 -0700 +++ rsync-2.6.4/exclude.c 2005-02-26 23:34:27.000000000 -0800 @@ -27,42 +27,139 @@ #include "rsync.h" extern int verbose; +extern int am_server; +extern int am_sender; extern int eol_nulls; extern int list_only; extern int recurse; +extern int io_error; +extern int local_server; +extern int delete_mode; +extern int delete_excluded; +extern int cvs_exclude; +extern int sanitize_paths; +extern int protocol_version; +extern int module_id; extern char curr_dir[]; +extern unsigned int curr_dir_len; +extern unsigned int module_dirlen; -struct exclude_list_struct exclude_list = { 0, 0, "" }; -struct exclude_list_struct local_exclude_list = { 0, 0, "per-dir .cvsignore " }; -struct exclude_list_struct server_exclude_list = { 0, 0, "server " }; -char *exclude_path_prefix = NULL; - -/** Build an exclude structure given an exclude pattern. */ -static void make_exclude(struct exclude_list_struct *listp, const char *pat, - unsigned int pat_len, unsigned int mflags) +struct filter_list_struct filter_list = { 0, 0, "" }; +struct filter_list_struct cvs_filter_list = { 0, 0, " [cvsignore]" }; +struct filter_list_struct server_filter_list = { 0, 0, " [server]" }; + +/* Need room enough for ":MODS " prefix plus some room to grow. */ +#define MAX_RULE_PREFIX (16) + +#define MODIFIERS_MERGE_FILE "-+Cenw" +#define MODIFIERS_INCL_EXCL "/!Crs" +#define MODIFIERS_HIDE_PROTECT "/!" + +/* The dirbuf is set by push_local_filters() to the current subdirectory + * relative to curr_dir that is being processed. The path always has a + * trailing slash appended, and the variable dirbuf_len contains the length + * of this path prefix. The path is always absolute. */ +static char dirbuf[MAXPATHLEN+1]; +static unsigned int dirbuf_len = 0; +static int dirbuf_depth; + +/* This is True when we're scanning parent dirs for per-dir merge-files. */ +static BOOL parent_dirscan = False; + +/* This array contains a list of all the currently active per-dir merge + * files. This makes it easier to save the appropriate values when we + * "push" down into each subdirectory. */ +static struct filter_struct **mergelist_parents; +static int mergelist_cnt = 0; +static int mergelist_size = 0; + +/* Each filter_list_struct describes a singly-linked list by keeping track + * of both the head and tail pointers. The list is slightly unusual in that + * a parent-dir's content can be appended to the end of the local list in a + * special way: the last item in the local list has its "next" pointer set + * to point to the inherited list, but the local list's tail pointer points + * at the end of the local list. Thus, if the local list is empty, the head + * will be pointing at the inherited content but the tail will be NULL. To + * help you visualize this, here are the possible list arrangements: + * + * Completely Empty Local Content Only + * ================================== ==================================== + * head -> NULL head -> Local1 -> Local2 -> NULL + * tail -> NULL tail -------------^ + * + * Inherited Content Only Both Local and Inherited Content + * ================================== ==================================== + * head -> Parent1 -> Parent2 -> NULL head -> L1 -> L2 -> P1 -> P2 -> NULL + * tail -> NULL tail ---------^ + * + * This means that anyone wanting to traverse the whole list to use it just + * needs to start at the head and use the "next" pointers until it goes + * NULL. To add new local content, we insert the item after the tail item + * and update the tail (obviously, if "tail" was NULL, we insert it at the + * head). To clear the local list, WE MUST NOT FREE THE INHERITED CONTENT + * because it is shared between the current list and our parent list(s). + * The easiest way to handle this is to simply truncate the list after the + * tail item and then free the local list from the head. When inheriting + * the list for a new local dir, we just save off the filter_list_struct + * values (so we can pop back to them later) and set the tail to NULL. + */ + +static void free_filter(struct filter_struct *ex) { - struct exclude_struct *ret; + if (ex->match_flags & MATCHFLG_PERDIR_MERGE) { + free(ex->u.mergelist->debug_type); + free(ex->u.mergelist); + mergelist_cnt--; + } + free(ex->pattern); + free(ex); +} + +/* Build a filter structure given a filter pattern. The value in "pat" + * is not null-terminated. */ +static void add_rule(struct filter_list_struct *listp, const char *pat, + unsigned int pat_len, uint32 mflags, int xflags) +{ + struct filter_struct *ret; const char *cp; unsigned int ex_len; - ret = new(struct exclude_struct); - if (!ret) - out_of_memory("make_exclude"); + if (verbose > 2) { + rprintf(FINFO, "[%s] add_rule(%s%.*s%s)%s\n", + who_am_i(), get_rule_prefix(mflags, pat, 0, NULL), + (int)pat_len, pat, + (mflags & MATCHFLG_DIRECTORY) ? "/" : "", + listp->debug_type); + } + + /* This flag also indicates that we're reading a list that + * needs to be filtered now, not post-filtered later. */ + if (xflags & XFLG_ANCHORED2ABS) { + uint32 mf = mflags & (MATCHFLG_RECEIVER_SIDE|MATCHFLG_SENDER_SIDE); + if (am_sender) { + if (mf == MATCHFLG_RECEIVER_SIDE) + return; + } else { + if (mf == MATCHFLG_SENDER_SIDE) + return; + } + } + if (!(ret = new(struct filter_struct))) + out_of_memory("add_rule"); memset(ret, 0, sizeof ret[0]); - if (exclude_path_prefix) + if (xflags & XFLG_ANCHORED2ABS && *pat == '/' + && !(mflags & (MATCHFLG_ABS_PATH | MATCHFLG_MERGE_FILE))) { mflags |= MATCHFLG_ABS_PATH; - if (exclude_path_prefix && *pat == '/') - ex_len = strlen(exclude_path_prefix); - else + ex_len = dirbuf_len - module_dirlen - 1; + } else ex_len = 0; - ret->pattern = new_array(char, ex_len + pat_len + 1); - if (!ret->pattern) - out_of_memory("make_exclude"); + if (!(ret->pattern = new_array(char, ex_len + pat_len + 1))) + out_of_memory("add_rule"); if (ex_len) - memcpy(ret->pattern, exclude_path_prefix, ex_len); + memcpy(ret->pattern, dirbuf + module_dirlen, ex_len); strlcpy(ret->pattern + ex_len, pat, pat_len + 1); pat_len += ex_len; @@ -81,42 +178,319 @@ mflags |= MATCHFLG_DIRECTORY; } - for (cp = ret->pattern; (cp = strchr(cp, '/')) != NULL; cp++) - ret->slash_cnt++; + if (mflags & MATCHFLG_PERDIR_MERGE) { + struct filter_list_struct *lp; + unsigned int len; + int i; + + if ((cp = strrchr(ret->pattern, '/')) != NULL) + cp++; + else + cp = ret->pattern; + + /* If the local merge file was already mentioned, don't + * add it again. */ + for (i = 0; i < mergelist_cnt; i++) { + struct filter_struct *ex = mergelist_parents[i]; + const char *s = strrchr(ex->pattern, '/'); + if (s) + s++; + else + s = ex->pattern; + len = strlen(s); + if (len == pat_len - (cp - ret->pattern) + && memcmp(s, cp, len) == 0) { + free_filter(ret); + return; + } + } + + if (!(lp = new_array(struct filter_list_struct, 1))) + out_of_memory("add_rule"); + lp->head = lp->tail = NULL; + if (asprintf(&lp->debug_type, " [per-dir %s]", cp) < 0) + out_of_memory("add_rule"); + ret->u.mergelist = lp; + + if (mergelist_cnt == mergelist_size) { + mergelist_size += 5; + mergelist_parents = realloc_array(mergelist_parents, + struct filter_struct *, + mergelist_size); + if (!mergelist_parents) + out_of_memory("add_rule"); + } + mergelist_parents[mergelist_cnt++] = ret; + } else { + for (cp = ret->pattern; (cp = strchr(cp, '/')) != NULL; cp++) + ret->u.slash_cnt++; + } ret->match_flags = mflags; - if (!listp->tail) + if (!listp->tail) { + ret->next = listp->head; listp->head = listp->tail = ret; - else { + } else { + ret->next = listp->tail->next; listp->tail->next = ret; listp->tail = ret; } } -static void free_exclude(struct exclude_struct *ex) +static void clear_filter_list(struct filter_list_struct *listp) { - free(ex->pattern); - free(ex); + if (listp->tail) { + struct filter_struct *ent, *next; + /* Truncate any inherited items from the local list. */ + listp->tail->next = NULL; + /* Now free everything that is left. */ + for (ent = listp->head; ent; ent = next) { + next = ent->next; + free_filter(ent); + } + } + + listp->head = listp->tail = NULL; } -void clear_exclude_list(struct exclude_list_struct *listp) +/* This returns an expanded (absolute) filename for the merge-file name if + * the name has any slashes in it OR if the parent_dirscan var is True; + * otherwise it returns the original merge_file name. If the len_ptr value + * is non-NULL the merge_file name is limited by the referenced length + * value and will be updated with the length of the resulting name. We + * always return a name that is null terminated, even if the merge_file + * name was not. */ +static char *parse_merge_name(const char *merge_file, unsigned int *len_ptr, + unsigned int prefix_skip) { - struct exclude_struct *ent, *next; + static char buf[MAXPATHLEN]; + char *fn, tmpbuf[MAXPATHLEN]; + unsigned int fn_len; + + if (!parent_dirscan && *merge_file != '/') { + /* Return the name unchanged it doesn't have any slashes. */ + if (len_ptr) { + const char *p = merge_file + *len_ptr; + while (--p > merge_file && *p != '/') {} + if (p == merge_file) { + strlcpy(buf, merge_file, *len_ptr + 1); + return buf; + } + } else if (strchr(merge_file, '/') == NULL) + return (char *)merge_file; + } - for (ent = listp->head; ent; ent = next) { - next = ent->next; - free_exclude(ent); + fn = *merge_file == '/' ? buf : tmpbuf; + if (sanitize_paths) { + const char *r = prefix_skip ? "/" : NULL; + /* null-terminate the name if it isn't already */ + if (len_ptr && merge_file[*len_ptr]) { + char *to = fn == buf ? tmpbuf : buf; + strlcpy(to, merge_file, *len_ptr + 1); + merge_file = to; + } + if (!sanitize_path(fn, merge_file, r, dirbuf_depth)) { + rprintf(FERROR, "merge-file name overflows: %s\n", + safe_fname(merge_file)); + return NULL; + } + } else { + strlcpy(fn, merge_file, len_ptr ? *len_ptr + 1 : MAXPATHLEN); + clean_fname(fn, 1); + } + + fn_len = strlen(fn); + if (fn == buf) + goto done; + + if (dirbuf_len + fn_len >= MAXPATHLEN) { + rprintf(FERROR, "merge-file name overflows: %s\n", + safe_fname(fn)); + return NULL; } + memcpy(buf, dirbuf + prefix_skip, dirbuf_len - prefix_skip); + memcpy(buf + dirbuf_len - prefix_skip, fn, fn_len + 1); + fn_len = clean_fname(buf, 1); + + done: + if (len_ptr) + *len_ptr = fn_len; + return buf; +} - listp->head = listp->tail = NULL; +/* Sets the dirbuf and dirbuf_len values. */ +void set_filter_dir(const char *dir, unsigned int dirlen) +{ + unsigned int len; + if (*dir != '/') { + memcpy(dirbuf, curr_dir, curr_dir_len); + dirbuf[curr_dir_len] = '/'; + len = curr_dir_len + 1; + if (len + dirlen >= MAXPATHLEN) + dirlen = 0; + } else + len = 0; + memcpy(dirbuf + len, dir, dirlen); + dirbuf[dirlen + len] = '\0'; + dirbuf_len = clean_fname(dirbuf, 1); + if (dirbuf_len > 1 && dirbuf[dirbuf_len-1] == '.' + && dirbuf[dirbuf_len-2] == '/') + dirbuf_len -= 2; + if (dirbuf_len != 1) + dirbuf[dirbuf_len++] = '/'; + dirbuf[dirbuf_len] = '\0'; + if (sanitize_paths) + dirbuf_depth = count_dir_elements(dirbuf + module_dirlen); +} + +/* This routine takes a per-dir merge-file entry and finishes its setup. + * If the name has a path portion then we check to see if it refers to a + * parent directory of the first transfer dir. If it does, we scan all the + * dirs from that point through the parent dir of the transfer dir looking + * for the per-dir merge-file in each one. */ +static BOOL setup_merge_file(struct filter_struct *ex, + struct filter_list_struct *lp) +{ + char buf[MAXPATHLEN]; + char *x, *y, *pat = ex->pattern; + unsigned int len; + + if (!(x = parse_merge_name(pat, NULL, 0)) || *x != '/') + return 0; + + y = strrchr(x, '/'); + *y = '\0'; + ex->pattern = strdup(y+1); + if (!*x) + x = "/"; + if (*x == '/') + strlcpy(buf, x, MAXPATHLEN); + else + pathjoin(buf, MAXPATHLEN, dirbuf, x); + + len = clean_fname(buf, 1); + if (len != 1 && len < MAXPATHLEN-1) { + buf[len++] = '/'; + buf[len] = '\0'; + } + /* This ensures that the specified dir is a parent of the transfer. */ + for (x = buf, y = dirbuf; *x && *x == *y; x++, y++) {} + if (*x) + y += strlen(y); /* nope -- skip the scan */ + + parent_dirscan = True; + while (*y) { + char save[MAXPATHLEN]; + strlcpy(save, y, MAXPATHLEN); + *y = '\0'; + dirbuf_len = y - dirbuf; + strlcpy(x, ex->pattern, MAXPATHLEN - (x - buf)); + parse_filter_file(lp, buf, ex->match_flags, XFLG_ANCHORED2ABS); + if (ex->match_flags & MATCHFLG_NO_INHERIT) + lp->head = NULL; + lp->tail = NULL; + strlcpy(y, save, MAXPATHLEN); + while ((*x++ = *y++) != '/') {} + } + parent_dirscan = False; + free(pat); + return 1; } -static int check_one_exclude(char *name, struct exclude_struct *ex, - int name_is_dir) +/* Each time rsync changes to a new directory it call this function to + * handle all the per-dir merge-files. The "dir" value is the current path + * relative to curr_dir (which might not be null-terminated). We copy it + * into dirbuf so that we can easily append a file name on the end. */ +void *push_local_filters(const char *dir, unsigned int dirlen) +{ + struct filter_list_struct *ap, *push; + int i; + + set_filter_dir(dir, dirlen); + + if (!mergelist_cnt) + return NULL; + + push = new_array(struct filter_list_struct, mergelist_cnt); + if (!push) + out_of_memory("push_local_filters"); + + for (i = 0, ap = push; i < mergelist_cnt; i++) { + memcpy(ap++, mergelist_parents[i]->u.mergelist, + sizeof (struct filter_list_struct)); + } + + /* Note: parse_filter_file() might increase mergelist_cnt, so keep + * this loop separate from the above loop. */ + for (i = 0; i < mergelist_cnt; i++) { + struct filter_struct *ex = mergelist_parents[i]; + struct filter_list_struct *lp = ex->u.mergelist; + + if (verbose > 2) { + rprintf(FINFO, "[%s] pushing filter list%s\n", + who_am_i(), lp->debug_type); + } + + lp->tail = NULL; /* Switch any local rules to inherited. */ + if (ex->match_flags & MATCHFLG_NO_INHERIT) + lp->head = NULL; + + if (ex->match_flags & MATCHFLG_FINISH_SETUP) { + ex->match_flags &= ~MATCHFLG_FINISH_SETUP; + if (setup_merge_file(ex, lp)) + set_filter_dir(dir, dirlen); + } + + if (strlcpy(dirbuf + dirbuf_len, ex->pattern, + MAXPATHLEN - dirbuf_len) < MAXPATHLEN - dirbuf_len) { + parse_filter_file(lp, dirbuf, ex->match_flags, + XFLG_ANCHORED2ABS); + } else { + io_error |= IOERR_GENERAL; + rprintf(FINFO, + "cannot add local filter rules in long-named directory: %s\n", + full_fname(dirbuf)); + } + dirbuf[dirbuf_len] = '\0'; + } + + return (void*)push; +} + +void pop_local_filters(void *mem) +{ + struct filter_list_struct *ap, *pop = (struct filter_list_struct*)mem; + int i; + + for (i = mergelist_cnt; i-- > 0; ) { + struct filter_struct *ex = mergelist_parents[i]; + struct filter_list_struct *lp = ex->u.mergelist; + + if (verbose > 2) { + rprintf(FINFO, "[%s] popping filter list%s\n", + who_am_i(), lp->debug_type); + } + + clear_filter_list(lp); + } + + if (!pop) + return; + + for (i = 0, ap = pop; i < mergelist_cnt; i++) { + memcpy(mergelist_parents[i]->u.mergelist, ap++, + sizeof (struct filter_list_struct)); + } + + free(pop); +} + +static int rule_matches(char *name, struct filter_struct *ex, int name_is_dir) { char *p, full_name[MAXPATHLEN]; int match_start = 0; + int ret_match = ex->match_flags & MATCHFLG_NEGATE ? 0 : 1; char *pattern = ex->pattern; if (!*name) @@ -125,18 +499,19 @@ /* If the pattern does not have any slashes AND it does not have * a "**" (which could match a slash), then we just match the * name portion of the path. */ - if (!ex->slash_cnt && !(ex->match_flags & MATCHFLG_WILD2)) { + if (!ex->u.slash_cnt && !(ex->match_flags & MATCHFLG_WILD2)) { if ((p = strrchr(name,'/')) != NULL) name = p+1; } else if (ex->match_flags & MATCHFLG_ABS_PATH && *name != '/' - && curr_dir[1]) { - pathjoin(full_name, sizeof full_name, curr_dir + 1, name); + && curr_dir_len > module_dirlen + 1) { + pathjoin(full_name, sizeof full_name, + curr_dir + module_dirlen + 1, name); name = full_name; } if (ex->match_flags & MATCHFLG_DIRECTORY && !name_is_dir) - return 0; + return !ret_match; if (*pattern == '/') { match_start = 1; @@ -148,9 +523,9 @@ if (ex->match_flags & MATCHFLG_WILD) { /* A non-anchored match with an infix slash and no "**" * needs to match the last slash_cnt+1 name elements. */ - if (!match_start && ex->slash_cnt + if (!match_start && ex->u.slash_cnt && !(ex->match_flags & MATCHFLG_WILD2)) { - int cnt = ex->slash_cnt + 1; + int cnt = ex->u.slash_cnt + 1; for (p = name + strlen(name) - 1; p >= name; p--) { if (*p == '/' && !--cnt) break; @@ -158,13 +533,13 @@ name = p+1; } if (wildmatch(pattern, name)) - return 1; + return ret_match; if (ex->match_flags & MATCHFLG_WILD2_PREFIX) { /* If the **-prefixed pattern has a '/' as the next * character, then try to match the rest of the * pattern at the root. */ if (pattern[2] == '/' && wildmatch(pattern+3, name)) - return 1; + return ret_match; } else if (!match_start && ex->match_flags & MATCHFLG_WILD2) { /* A non-anchored match with an infix or trailing "**" @@ -173,41 +548,40 @@ while ((name = strchr(name, '/')) != NULL) { name++; if (wildmatch(pattern, name)) - return 1; + return ret_match; } } } else if (match_start) { if (strcmp(name,pattern) == 0) - return 1; + return ret_match; } else { int l1 = strlen(name); int l2 = strlen(pattern); if (l2 <= l1 && strcmp(name+(l1-l2),pattern) == 0 && (l1==l2 || name[l1-(l2+1)] == '/')) { - return 1; + return ret_match; } } - return 0; + return !ret_match; } -static void report_exclude_result(char const *name, - struct exclude_struct const *ent, - int name_is_dir, const char *type) +static void report_filter_result(char const *name, + struct filter_struct const *ent, + int name_is_dir, const char *type) { /* If a trailing slash is present to match only directories, - * then it is stripped out by make_exclude. So as a special + * then it is stripped out by add_rule(). So as a special * case we add it back in here. */ if (verbose >= 2) { - rprintf(FINFO, "[%s] %scluding %s %s because of %spattern %s%s\n", + rprintf(FINFO, "[%s] %scluding %s %s because of pattern %s%s%s\n", who_am_i(), ent->match_flags & MATCHFLG_INCLUDE ? "in" : "ex", - name_is_dir ? "directory" : "file", name, type, - ent->pattern, - ent->match_flags & MATCHFLG_DIRECTORY ? "/" : ""); + name_is_dir ? "directory" : "file", name, ent->pattern, + ent->match_flags & MATCHFLG_DIRECTORY ? "/" : "", type); } } @@ -216,13 +590,27 @@ * Return -1 if file "name" is defined to be excluded by the specified * exclude list, 1 if it is included, and 0 if it was not matched. */ -int check_exclude(struct exclude_list_struct *listp, char *name, int name_is_dir) +int check_filter(struct filter_list_struct *listp, char *name, int name_is_dir) { - struct exclude_struct *ent; + struct filter_struct *ent; for (ent = listp->head; ent; ent = ent->next) { - if (check_one_exclude(name, ent, name_is_dir)) { - report_exclude_result(name, ent, name_is_dir, + if (ent->match_flags & MATCHFLG_PERDIR_MERGE) { + int rc = check_filter(ent->u.mergelist, name, + name_is_dir); + if (rc) + return rc; + continue; + } + if (ent->match_flags & MATCHFLG_CVS_IGNORE) { + int rc = check_filter(&cvs_filter_list, name, + name_is_dir); + if (rc) + return rc; + continue; + } + if (rule_matches(name, ent, name_is_dir)) { + report_filter_result(name, ent, name_is_dir, listp->debug_type); return ent->match_flags & MATCHFLG_INCLUDE ? 1 : -1; } @@ -231,119 +619,380 @@ return 0; } +#define RULE_STRCMP(s,r) rule_strcmp((s), (r), sizeof (r) - 1) + +static const uchar *rule_strcmp(const uchar *str, const char *rule, int rule_len) +{ + if (strncmp((char*)str, rule, rule_len) != 0) + return NULL; + if (isspace(str[rule_len]) || str[rule_len] == '_' || !str[rule_len]) + return str + rule_len - 1; + if (str[rule_len] == ',') + return str + rule_len; + return NULL; +} /* Get the next include/exclude arg from the string. The token will not * be '\0' terminated, so use the returned length to limit the string. * Also, be sure to add this length to the returned pointer before passing - * it back to ask for the next token. This routine parses the +/- prefixes - * and the "!" token unless xflags contains XFLG_WORDS_ONLY. The *flag_ptr - * value will also be set to the MATCHFLG_* bits for the current token. - */ -static const char *get_exclude_tok(const char *p, unsigned int *len_ptr, - unsigned int *flag_ptr, int xflags) + * it back to ask for the next token. This routine parses the "!" (list- + * clearing) token and (depending on the mflags) the various prefixes. + * The *mflags_ptr value will be set on exit to the new MATCHFLG_* bits + * for the current token. */ +static const char *parse_rule_tok(const char *p, uint32 mflags, int xflags, + unsigned int *len_ptr, uint32 *mflags_ptr) { - const unsigned char *s = (const unsigned char *)p; - unsigned int len, mflags = 0; + const uchar *s = (const uchar *)p; + uint32 new_mflags; + unsigned int len; - if (xflags & XFLG_WORD_SPLIT) { + if (mflags & MATCHFLG_WORD_SPLIT) { /* Skip over any initial whitespace. */ while (isspace(*s)) s++; - /* Update for "!" check. */ + /* Update to point to real start of rule. */ p = (const char *)s; } + if (!*s) + return NULL; - /* Is this a '+' or '-' followed by a space (not whitespace)? */ - if (!(xflags & XFLG_WORDS_ONLY) - && (*s == '-' || *s == '+') && s[1] == ' ') { - if (*s == '+') - mflags |= MATCHFLG_INCLUDE; - s += 2; - } else if (xflags & XFLG_DEF_INCLUDE) - mflags |= MATCHFLG_INCLUDE; - if (xflags & XFLG_DIRECTORY) - mflags |= MATCHFLG_DIRECTORY; + new_mflags = mflags & MATCHFLGS_FROM_CONTAINER; + + /* Figure out what kind of a filter rule "s" is pointing at. Note + * that if MATCHFLG_NO_PREFIXES is set, the rule is either an include + * or an exclude based on the inheritance of the MATCHFLG_INCLUDE + * flag (above). XFLG_OLD_PREFIXES indicates a compatibility mode + * for old include/exclude patterns where just "+ " and "- " are + * allowed as optional prefixes. */ + if (mflags & MATCHFLG_NO_PREFIXES) { + if (*s == '!' && mflags & MATCHFLG_CVS_IGNORE) + new_mflags |= MATCHFLG_CLEAR_LIST; /* Tentative! */ + } else if (xflags & XFLG_OLD_PREFIXES) { + if (*s == '-' && s[1] == ' ') { + new_mflags &= ~MATCHFLG_INCLUDE; + s += 2; + } else if (*s == '+' && s[1] == ' ') { + new_mflags |= MATCHFLG_INCLUDE; + s += 2; + } + if (*s == '!') + new_mflags |= MATCHFLG_CLEAR_LIST; /* Tentative! */ + } else { + char ch = 0, *mods = ""; + switch (*s) { + case 'c': + if ((s = RULE_STRCMP(s, "clear")) != NULL) + ch = '!'; + break; + case 'd': + if ((s = RULE_STRCMP(s, "dir-merge")) != NULL) + ch = ':'; + break; + case 'e': + if ((s = RULE_STRCMP(s, "exclude")) != NULL) + ch = '-'; + break; + case 'h': + if ((s = RULE_STRCMP(s, "hide")) != NULL) + ch = 'H'; + break; + case 'i': + if ((s = RULE_STRCMP(s, "include")) != NULL) + ch = '+'; + break; + case 'm': + if ((s = RULE_STRCMP(s, "merge")) != NULL) + ch = '.'; + break; + case 'p': + if ((s = RULE_STRCMP(s, "protect")) != NULL) + ch = 'P'; + break; + case 'r': + if ((s = RULE_STRCMP(s, "risk")) != NULL) + ch = 'R'; + break; + case 's': + if ((s = RULE_STRCMP(s, "show")) != NULL) + ch = 'S'; + break; + + default: + ch = *s; + if (s[1] == ',') + s++; + break; + } + switch (ch) { + case ':': + new_mflags |= MATCHFLG_PERDIR_MERGE + | MATCHFLG_FINISH_SETUP; + /* FALL THROUGH */ + case '.': + new_mflags |= MATCHFLG_MERGE_FILE; + mods = MODIFIERS_INCL_EXCL MODIFIERS_MERGE_FILE; + break; + case '+': + new_mflags |= MATCHFLG_INCLUDE; + /* FALL THROUGH */ + case '-': + mods = MODIFIERS_INCL_EXCL; + break; + case 'S': + new_mflags |= MATCHFLG_INCLUDE; + /* FALL THROUGH */ + case 'H': + new_mflags |= MATCHFLG_SENDER_SIDE; + mods = MODIFIERS_HIDE_PROTECT; + break; + case 'R': + new_mflags |= MATCHFLG_INCLUDE; + /* FALL THROUGH */ + case 'P': + new_mflags |= MATCHFLG_RECEIVER_SIDE; + mods = MODIFIERS_HIDE_PROTECT; + break; + case '!': + new_mflags |= MATCHFLG_CLEAR_LIST; + mods = NULL; + break; + default: + rprintf(FERROR, "Unknown filter rule: `%s'\n", p); + exit_cleanup(RERR_SYNTAX); + } + while (mods && *++s && *s != ' ' && *s != '_') { + if (strchr(mods, *s) == NULL) { + if (mflags & MATCHFLG_WORD_SPLIT && isspace(*s)) { + s--; + break; + } + invalid: + rprintf(FERROR, + "invalid modifier sequence at '%c' in filter rule: %s\n", + *s, p); + exit_cleanup(RERR_SYNTAX); + } + switch (*s) { + case '-': + if (new_mflags & MATCHFLG_NO_PREFIXES) + goto invalid; + new_mflags |= MATCHFLG_NO_PREFIXES; + break; + case '+': + if (new_mflags & MATCHFLG_NO_PREFIXES) + goto invalid; + new_mflags |= MATCHFLG_NO_PREFIXES + | MATCHFLG_INCLUDE; + break; + case '/': + new_mflags |= MATCHFLG_ABS_PATH; + break; + case '!': + new_mflags |= MATCHFLG_NEGATE; + break; + case 'C': + if (new_mflags & MATCHFLG_NO_PREFIXES) + goto invalid; + new_mflags |= MATCHFLG_NO_PREFIXES + | MATCHFLG_WORD_SPLIT + | MATCHFLG_NO_INHERIT + | MATCHFLG_CVS_IGNORE; + break; + case 'e': + new_mflags |= MATCHFLG_EXCLUDE_SELF; + break; + case 'n': + new_mflags |= MATCHFLG_NO_INHERIT; + break; + case 'r': + new_mflags |= MATCHFLG_RECEIVER_SIDE; + break; + case 's': + new_mflags |= MATCHFLG_SENDER_SIDE; + break; + case 'w': + new_mflags |= MATCHFLG_WORD_SPLIT; + break; + } + } + if (*s) + s++; + } - if (xflags & XFLG_WORD_SPLIT) { - const unsigned char *cp = s; + if (mflags & MATCHFLG_WORD_SPLIT) { + const uchar *cp = s; /* Token ends at whitespace or the end of the string. */ while (!isspace(*cp) && *cp != '\0') cp++; len = cp - s; } else - len = strlen(s); + len = strlen((char*)s); - if (*p == '!' && len == 1 && !(xflags & XFLG_WORDS_ONLY)) - mflags |= MATCHFLG_CLEAR_LIST; + if (new_mflags & MATCHFLG_CLEAR_LIST) { + if (!(xflags & XFLG_OLD_PREFIXES) && len) { + rprintf(FERROR, + "'!' rule has trailing characters: %s\n", p); + exit_cleanup(RERR_SYNTAX); + } + if (len > 1) + new_mflags &= ~MATCHFLG_CLEAR_LIST; + } else if (!len && !(new_mflags & MATCHFLG_CVS_IGNORE)) { + rprintf(FERROR, "unexpected end of filter rule: %s\n", p); + exit_cleanup(RERR_SYNTAX); + } *len_ptr = len; - *flag_ptr = mflags; + *mflags_ptr = new_mflags; return (const char *)s; } -void add_exclude(struct exclude_list_struct *listp, const char *pattern, - int xflags) +static char default_cvsignore[] = + /* These default ignored items come from the CVS manual. */ + "RCS SCCS CVS CVS.adm RCSLOG cvslog.* tags TAGS" + " .make.state .nse_depinfo *~ #* .#* ,* _$* *$" + " *.old *.bak *.BAK *.orig *.rej .del-*" + " *.a *.olb *.o *.obj *.so *.exe" + " *.Z *.elc *.ln core" + /* The rest we added to suit ourself. */ + " .svn/"; + +static void get_cvs_excludes(uint32 mflags) +{ + char *p, fname[MAXPATHLEN]; + static int initialized = 0; + + if (initialized) + return; + initialized = 1; + + parse_rule(&cvs_filter_list, default_cvsignore, mflags, 0); + + p = module_id >= 0 && lp_use_chroot(module_id) ? "/" : getenv("HOME"); + if (p && pathjoin(fname, MAXPATHLEN, p, ".cvsignore") < MAXPATHLEN) + parse_filter_file(&cvs_filter_list, fname, mflags, 0); + + parse_rule(&cvs_filter_list, getenv("CVSIGNORE"), mflags, 0); +} + + +void parse_rule(struct filter_list_struct *listp, const char *pattern, + uint32 mflags, int xflags) { - unsigned int pat_len, mflags; - const char *cp; + unsigned int pat_len; + uint32 new_mflags; + const char *cp, *p; if (!pattern) return; - cp = pattern; - pat_len = 0; while (1) { - cp = get_exclude_tok(cp + pat_len, &pat_len, &mflags, xflags); - if (!pat_len) + /* Remember that the returned string is NOT '\0' terminated! */ + cp = parse_rule_tok(pattern, mflags, xflags, + &pat_len, &new_mflags); + if (!cp) break; + if (pat_len >= MAXPATHLEN) { + rprintf(FERROR, "discarding over-long filter: %s\n", + cp); + continue; + } + pattern = cp + pat_len; - if (mflags & MATCHFLG_CLEAR_LIST) { + if (new_mflags & MATCHFLG_CLEAR_LIST) { if (verbose > 2) { rprintf(FINFO, - "[%s] clearing %sexclude list\n", + "[%s] clearing filter list%s\n", who_am_i(), listp->debug_type); } - clear_exclude_list(listp); + clear_filter_list(listp); continue; } - make_exclude(listp, cp, pat_len, mflags); - - if (verbose > 2) { - rprintf(FINFO, "[%s] add_exclude(%.*s, %s%sclude)\n", - who_am_i(), (int)pat_len, cp, listp->debug_type, - mflags & MATCHFLG_INCLUDE ? "in" : "ex"); + if (new_mflags & MATCHFLG_MERGE_FILE) { + unsigned int len; + if (!pat_len) { + cp = ".cvsignore"; + pat_len = 10; + } + len = pat_len; + if (new_mflags & MATCHFLG_EXCLUDE_SELF) { + const char *name = strrchr(cp, '/'); + if (name) + len -= ++name - cp; + else + name = cp; + add_rule(listp, name, len, 0, 0); + new_mflags &= ~MATCHFLG_EXCLUDE_SELF; + len = pat_len; + } + if (new_mflags & MATCHFLG_PERDIR_MERGE) { + if (parent_dirscan) { + if (!(p = parse_merge_name(cp, &len, + module_dirlen))) + continue; + add_rule(listp, p, len, new_mflags, 0); + continue; + } + } else { + if (!(p = parse_merge_name(cp, &len, 0))) + continue; + parse_filter_file(listp, p, new_mflags, + XFLG_FATAL_ERRORS); + continue; + } } + + add_rule(listp, cp, pat_len, new_mflags, xflags); + + if (new_mflags & MATCHFLG_CVS_IGNORE + && !(new_mflags & MATCHFLG_MERGE_FILE)) + get_cvs_excludes(new_mflags); } } -void add_exclude_file(struct exclude_list_struct *listp, const char *fname, - int xflags) +void parse_filter_file(struct filter_list_struct *listp, const char *fname, + uint32 mflags, int xflags) { FILE *fp; - char line[MAXPATHLEN+3]; /* Room for "x " prefix and trailing slash. */ + char line[MAXPATHLEN+MAX_RULE_PREFIX+1]; /* +1 for trailing slash. */ char *eob = line + sizeof line - 1; - int word_split = xflags & XFLG_WORD_SPLIT; + int word_split = mflags & MATCHFLG_WORD_SPLIT; if (!fname || !*fname) return; - if (*fname != '-' || fname[1]) - fp = fopen(fname, "rb"); - else + if (*fname != '-' || fname[1] || am_server) { + if (server_filter_list.head) { + strlcpy(line, fname, sizeof line); + clean_fname(line, 1); + if (check_filter(&server_filter_list, line, 0) < 0) + fp = NULL; + else + fp = fopen(line, "rb"); + } else + fp = fopen(fname, "rb"); + } else fp = stdin; + + if (verbose > 2) { + rprintf(FINFO, "[%s] parse_filter_file(%s,%x,%x)%s\n", + who_am_i(), safe_fname(fname), mflags, xflags, + fp ? "" : " [not found]"); + } + if (!fp) { if (xflags & XFLG_FATAL_ERRORS) { rsyserr(FERROR, errno, - "failed to open %s file %s", - xflags & XFLG_DEF_INCLUDE ? "include" : "exclude", - fname); + "failed to open %sclude file %s", + mflags & MATCHFLG_INCLUDE ? "in" : "ex", + safe_fname(fname)); exit_cleanup(RERR_FILEIO); } return; } + dirbuf[dirbuf_len] = '\0'; while (1) { char *s = line; @@ -364,96 +1013,184 @@ overflow = 1; } if (overflow) { - rprintf(FERROR, "discarding over-long exclude: %s...\n", line); + rprintf(FERROR, "discarding over-long filter: %s...\n", line); s = line; } *s = '\0'; /* Skip an empty token and (when line parsing) comments. */ if (*line && (word_split || (*line != ';' && *line != '#'))) - add_exclude(listp, line, xflags); + parse_rule(listp, line, mflags, xflags); if (ch == EOF) break; } fclose(fp); } - -void send_exclude_list(int f) +/* If the "for_xfer" flag is set, the prefix is made compatible with the + * current protocol_version (if possible) or a NULL is returned (if not + * possible). */ +char *get_rule_prefix(int match_flags, const char *pat, int for_xfer, + unsigned int *plen_ptr) { - struct exclude_struct *ent; - - /* This is a complete hack - blame Rusty. - * - * FIXME: This pattern shows up in the output of - * report_exclude_result(), which is not ideal. */ - if (list_only && !recurse) - add_exclude(&exclude_list, "/*/*", 0); - - for (ent = exclude_list.head; ent; ent = ent->next) { - unsigned int l; - char p[MAXPATHLEN+1]; + static char buf[MAX_RULE_PREFIX+1]; + char *op = buf; + int legal_len = for_xfer && protocol_version < 29 ? 1 : MAX_RULE_PREFIX-1; + + if (match_flags & MATCHFLG_PERDIR_MERGE) { + if (legal_len == 1) + return NULL; + *op++ = ':'; + } else if (match_flags & MATCHFLG_INCLUDE) + *op++ = '+'; + else if (legal_len != 1 + || ((*pat == '-' || *pat == '+') && pat[1] == ' ')) + *op++ = '-'; + else + legal_len = 0; - l = strlcpy(p, ent->pattern, sizeof p); - if (l == 0 || l >= MAXPATHLEN) - continue; - if (ent->match_flags & MATCHFLG_DIRECTORY) { - p[l++] = '/'; - p[l] = '\0'; + if (match_flags & MATCHFLG_CVS_IGNORE) + *op++ = 'C'; + else { + if (match_flags & MATCHFLG_NO_INHERIT) + *op++ = 'n'; + if (match_flags & MATCHFLG_WORD_SPLIT) + *op++ = 'w'; + if (match_flags & MATCHFLG_NO_PREFIXES) { + if (match_flags & MATCHFLG_INCLUDE) + *op++ = '+'; + else + *op++ = '-'; } - - if (ent->match_flags & MATCHFLG_INCLUDE) { - write_int(f, l + 2); - write_buf(f, "+ ", 2); - } else if ((*p == '-' || *p == '+') && p[1] == ' ') { - write_int(f, l + 2); - write_buf(f, "- ", 2); - } else - write_int(f, l); - write_buf(f, p, l); } - - write_int(f, 0); + if (match_flags & MATCHFLG_EXCLUDE_SELF) + *op++ = 'e'; + if (match_flags & MATCHFLG_SENDER_SIDE + && (!for_xfer || protocol_version >= 29)) + *op++ = 's'; + if (match_flags & MATCHFLG_RECEIVER_SIDE + && (!for_xfer || protocol_version >= 29 + || (delete_excluded && am_sender))) + *op++ = 'r'; + if (op - buf > legal_len) + return NULL; + if (legal_len) + *op++ = ' '; + *op = '\0'; + if (plen_ptr) + *plen_ptr = op - buf; + return buf; } - -void recv_exclude_list(int f) +static void send_rules(int f_out, struct filter_list_struct *flp) { - char line[MAXPATHLEN+3]; /* Room for "x " prefix and trailing slash. */ - unsigned int l; + struct filter_struct *ent, *prev = NULL; - while ((l = read_int(f)) != 0) { - if (l >= sizeof line) - overflow("recv_exclude_list"); - read_sbuf(f, line, l); - add_exclude(&exclude_list, line, 0); + for (ent = flp->head; ent; ent = ent->next) { + unsigned int len, plen, dlen; + int elide = 0; + char *p; + + if (ent->match_flags & MATCHFLG_SENDER_SIDE) + elide = am_sender ? 1 : -1; + if (ent->match_flags & MATCHFLG_RECEIVER_SIDE) + elide = elide ? 0 : am_sender ? -1 : 1; + else if (delete_excluded && !elide) + elide = am_sender ? 1 : -1; + if (elide < 0) { + if (prev) + prev->next = ent->next; + else + flp->head = ent->next; + } else + prev = ent; + if (elide > 0) + continue; + if (ent->match_flags & MATCHFLG_CVS_IGNORE + && !(ent->match_flags & MATCHFLG_MERGE_FILE)) { + int f = am_sender || protocol_version < 29 ? f_out : -1; + send_rules(f, &cvs_filter_list); + if (f >= 0) + continue; + } + p = get_rule_prefix(ent->match_flags, ent->pattern, 1, &plen); + if (!p) { + rprintf(FERROR, + "filter rules are too modern for remote rsync.\n"); + exit_cleanup(RERR_SYNTAX); + } + if (f_out < 0) + continue; + len = strlen(ent->pattern); + dlen = ent->match_flags & MATCHFLG_DIRECTORY ? 1 : 0; + if (!(plen + len + dlen)) + continue; + write_int(f_out, plen + len + dlen); + if (plen) + write_buf(f_out, p, plen); + write_buf(f_out, ent->pattern, len); + if (dlen) + write_byte(f_out, '/'); } + flp->tail = prev; } +/* This is only called by the client. */ +void send_filter_list(int f_out) +{ + int receiver_wants_list = delete_mode + && (!delete_excluded || protocol_version >= 29); -static char default_cvsignore[] = - /* These default ignored items come from the CVS manual. */ - "RCS SCCS CVS CVS.adm RCSLOG cvslog.* tags TAGS" - " .make.state .nse_depinfo *~ #* .#* ,* _$* *$" - " *.old *.bak *.BAK *.orig *.rej .del-*" - " *.a *.olb *.o *.obj *.so *.exe" - " *.Z *.elc *.ln core" - /* The rest we added to suit ourself. */ - " .svn/"; + if (local_server || (am_sender && !receiver_wants_list)) + f_out = -1; + if (cvs_exclude && am_sender) { + if (protocol_version >= 29) + parse_rule(&filter_list, ":C", 0, 0); + parse_rule(&filter_list, "-C", 0, 0); + } -void add_cvs_excludes(void) -{ - char fname[MAXPATHLEN]; - char *p; + /* This is a complete hack - blame Rusty. FIXME! + * Remove this hack when older rsyncs (below 2.6.4) are gone. */ + if (list_only == 1 && !recurse) + parse_rule(&filter_list, "/*/*", MATCHFLG_NO_PREFIXES, 0); + + send_rules(f_out, &filter_list); + + if (f_out >= 0) + write_int(f_out, 0); + + if (cvs_exclude) { + if (!am_sender || protocol_version < 29) + parse_rule(&filter_list, ":C", 0, 0); + if (!am_sender) + parse_rule(&filter_list, "-C", 0, 0); + } +} - add_exclude(&exclude_list, default_cvsignore, - XFLG_WORD_SPLIT | XFLG_WORDS_ONLY); +/* This is only called by the server. */ +void recv_filter_list(int f_in) +{ + char line[MAXPATHLEN+MAX_RULE_PREFIX+1]; /* +1 for trailing slash. */ + int xflags = protocol_version >= 29 ? 0 : XFLG_OLD_PREFIXES; + int receiver_wants_list = delete_mode + && (!delete_excluded || protocol_version >= 29); + unsigned int len; + + if (!local_server && (am_sender || receiver_wants_list)) { + while ((len = read_int(f_in)) != 0) { + if (len >= sizeof line) + overflow("recv_rules"); + read_sbuf(f_in, line, len); + parse_rule(&filter_list, line, 0, xflags); + } + } - if ((p = getenv("HOME")) - && pathjoin(fname, sizeof fname, p, ".cvsignore") < sizeof fname) { - add_exclude_file(&exclude_list, fname, - XFLG_WORD_SPLIT | XFLG_WORDS_ONLY); + if (cvs_exclude) { + if (local_server || am_sender || protocol_version < 29) + parse_rule(&filter_list, ":C", 0, 0); + if (local_server || am_sender) + parse_rule(&filter_list, "-C", 0, 0); } - add_exclude(&exclude_list, getenv("CVSIGNORE"), - XFLG_WORD_SPLIT | XFLG_WORDS_ONLY); + if (local_server) /* filter out any rules that aren't for us. */ + send_rules(-1, &filter_list); } diff -urN --exclude=patches rsync-2.6.3/fileio.c rsync-2.6.4/fileio.c --- rsync-2.6.3/fileio.c 2004-08-03 01:05:29.000000000 -0700 +++ rsync-2.6.4/fileio.c 2005-02-27 13:12:13.000000000 -0800 @@ -143,56 +143,52 @@ * It gives sliding window access to a file. mmap() is not used because of * the possibility of another program (such as a mailer) truncating the * file thus giving us a SIGBUS. */ -struct map_struct *map_file(int fd, OFF_T len, OFF_T map_size, - size_t block_size) +struct map_struct *map_file(int fd, OFF_T len, int32 read_size, + int32 blk_size) { struct map_struct *map; if (!(map = new(struct map_struct))) out_of_memory("map_file"); - if (block_size && (map_size % block_size)) - map_size += block_size - (map_size % block_size); + if (blk_size && (read_size % blk_size)) + read_size += blk_size - (read_size % blk_size); memset(map, 0, sizeof map[0]); map->fd = fd; map->file_size = len; - map->def_window_size = map_size; + map->def_window_size = read_size; return map; } /* slide the read window in the file */ -char *map_ptr(struct map_struct *map,OFF_T offset,int len) +char *map_ptr(struct map_struct *map, OFF_T offset, int32 len) { - int nread; + int32 nread; OFF_T window_start, read_start; - int window_size, read_size, read_offset; + int32 window_size, read_size, read_offset; if (len == 0) return NULL; - - /* can't go beyond the end of file */ - if (len > (map->file_size - offset)) { - len = map->file_size - offset; + if (len < 0) { + rprintf(FERROR, "invalid len passed to map_ptr: %ld\n", + (long)len); + exit_cleanup(RERR_FILEIO); } /* in most cases the region will already be available */ - if (offset >= map->p_offset && - offset+len <= map->p_offset+map->p_len) { - return (map->p + (offset - map->p_offset)); - } + if (offset >= map->p_offset && offset+len <= map->p_offset+map->p_len) + return map->p + (offset - map->p_offset); /* nope, we are going to have to do a read. Work out our desired window */ window_start = offset; window_size = map->def_window_size; - if (window_start + window_size > map->file_size) { + if (window_start + window_size > map->file_size) window_size = map->file_size - window_start; - } - if (offset + len > window_start + window_size) { - window_size = (offset+len) - window_start; - } + if (len > window_size) + window_size = len; /* make sure we have allocated enough memory for the window */ if (window_size > map->p_size) { @@ -202,8 +198,8 @@ map->p_size = window_size; } - /* now try to avoid re-reading any bytes by reusing any bytes from the previous - buffer. */ + /* Now try to avoid re-reading any bytes by reusing any bytes + * from the previous buffer. */ if (window_start >= map->p_offset && window_start < map->p_offset + map->p_len && window_start + window_size >= map->p_offset + map->p_len) { @@ -218,11 +214,16 @@ } if (read_size <= 0) { - rprintf(FINFO,"Warning: unexpected read size of %d in map_ptr\n", read_size); + rprintf(FERROR, "invalid read_size of %ld in map_ptr\n", + (long)read_size); + exit_cleanup(RERR_FILEIO); } else { if (map->p_fd_offset != read_start) { - if (do_lseek(map->fd,read_start,SEEK_SET) != read_start) { - rprintf(FERROR,"lseek failed in map_ptr\n"); + OFF_T ret = do_lseek(map->fd, read_start, SEEK_SET); + if (ret != read_start) { + rsyserr(FERROR, errno, + "lseek returned %.0f, not %.0f", + (double)ret, (double)read_start); exit_cleanup(RERR_FILEIO); } map->p_fd_offset = read_start; @@ -244,7 +245,7 @@ map->p_offset = window_start; map->p_len = window_size; - return map->p + (offset - map->p_offset); + return map->p; } diff -urN --exclude=patches rsync-2.6.3/flist.c rsync-2.6.4/flist.c --- rsync-2.6.3/flist.c 2004-09-21 02:24:02.000000000 -0700 +++ rsync-2.6.4/flist.c 2005-03-30 09:31:35.000000000 -0800 @@ -27,26 +27,21 @@ #include "rsync.h" -extern struct stats stats; - extern int verbose; -extern int do_progress; +extern int dry_run; +extern int list_only; extern int am_root; extern int am_server; extern int am_daemon; extern int am_sender; +extern int do_progress; extern int always_checksum; extern int module_id; extern int ignore_errors; extern int numeric_ids; - -extern int cvs_exclude; - extern int recurse; -extern char curr_dir[MAXPATHLEN]; -extern char *files_from; +extern int xfer_dirs; extern int filesfrom_fd; - extern int one_file_system; extern int keep_dirlinks; extern int preserve_links; @@ -61,19 +56,22 @@ extern int copy_unsafe_links; extern int protocol_version; extern int sanitize_paths; -extern int delete_excluded; extern int orig_umask; -extern int list_only; +extern struct stats stats; +extern struct file_list *the_file_list; + +extern char curr_dir[MAXPATHLEN]; -extern struct exclude_list_struct exclude_list; -extern struct exclude_list_struct server_exclude_list; -extern struct exclude_list_struct local_exclude_list; +extern struct filter_list_struct filter_list; +extern struct filter_list_struct server_filter_list; int io_error; +dev_t filesystem_dev; /* used to implement -x */ static char empty_sum[MD4_SUM_LENGTH]; +static int flist_count_offset; static unsigned int file_struct_len; -static struct file_list *received_flist; +static struct file_list *sorting_flist; static void clean_flist(struct file_list *flist, int strip_root, int no_dups); static void output_flist(struct file_list *flist); @@ -89,7 +87,7 @@ static int show_filelist_p(void) { - return verbose && (recurse || files_from) && !am_server; + return verbose && xfer_dirs && !am_server; } static void start_filelist_progress(char *kind) @@ -101,16 +99,16 @@ } -static void emit_filelist_progress(const struct file_list *flist) +static void emit_filelist_progress(int count) { - rprintf(FINFO, " %d files...\r", flist->count); + rprintf(FINFO, " %d files...\r", count); } -static void maybe_emit_filelist_progress(const struct file_list *flist) +static void maybe_emit_filelist_progress(int count) { - if (do_progress && show_filelist_p() && (flist->count % 100) == 0) - emit_filelist_progress(flist); + if (do_progress && show_filelist_p() && (count % 100) == 0) + emit_filelist_progress(count); } @@ -141,19 +139,19 @@ permstring(perms, f->mode); -#if SUPPORT_LINKS +#ifdef SUPPORT_LINKS if (preserve_links && S_ISLNK(f->mode)) { rprintf(FINFO, "%s %11.0f %s %s -> %s\n", perms, (double)f->length, timestring(f->modtime), - f_name(f), f->u.link); + safe_fname(f_name(f)), safe_fname(f->u.link)); } else #endif { rprintf(FINFO, "%s %11.0f %s %s\n", perms, (double)f->length, timestring(f->modtime), - f_name(f)); + safe_fname(f_name(f))); } } @@ -174,7 +172,7 @@ **/ static int readlink_stat(const char *path, STRUCT_STAT *buffer, char *linkbuf) { -#if SUPPORT_LINKS +#ifdef SUPPORT_LINKS if (copy_links) return do_stat(path, buffer); if (link_stat(path, buffer, 0) < 0) @@ -187,7 +185,7 @@ if (copy_unsafe_links && unsafe_symlink(linkbuf, path)) { if (verbose > 1) { rprintf(FINFO,"copying unsafe symlink \"%s\" -> \"%s\"\n", - path, linkbuf); + safe_fname(path), safe_fname(linkbuf)); } return do_stat(path, buffer); } @@ -200,7 +198,7 @@ int link_stat(const char *path, STRUCT_STAT *buffer, int follow_dirlinks) { -#if SUPPORT_LINKS +#ifdef SUPPORT_LINKS if (copy_links) return do_stat(path, buffer); if (do_lstat(path, buffer) < 0) @@ -216,17 +214,13 @@ #endif } -/* - * This function is used to check if a file should be included/excluded +/* This function is used to check if a file should be included/excluded * from the list of files based on its name and type etc. The value of - * exclude_level is set to either SERVER_EXCLUDES or ALL_EXCLUDES. - */ -static int check_exclude_file(char *fname, int is_dir, int exclude_level) + * filter_level is set to either SERVER_FILTERS or ALL_FILTERS. */ +static int is_excluded(char *fname, int is_dir, int filter_level) { - int rc; - #if 0 /* This currently never happens, so avoid a useless compare. */ - if (exclude_level == NO_EXCLUDES) + if (filter_level == NO_FILTERS) return 0; #endif if (fname) { @@ -240,35 +234,20 @@ return 0; } } - if (server_exclude_list.head - && check_exclude(&server_exclude_list, fname, is_dir) < 0) + if (server_filter_list.head + && check_filter(&server_filter_list, fname, is_dir) < 0) return 1; - if (exclude_level != ALL_EXCLUDES) + if (filter_level != ALL_FILTERS) return 0; - if (exclude_list.head - && (rc = check_exclude(&exclude_list, fname, is_dir)) != 0) - return rc < 0; - if (local_exclude_list.head - && check_exclude(&local_exclude_list, fname, is_dir) < 0) + if (filter_list.head + && check_filter(&filter_list, fname, is_dir) < 0) return 1; return 0; } -/* used by the one_file_system code */ -static dev_t filesystem_dev; - -static void set_filesystem(char *fname) -{ - STRUCT_STAT st; - if (do_stat(fname, &st) != 0) - return; - filesystem_dev = st.st_dev; -} - - static int to_wire_mode(mode_t mode) { -#if SUPPORT_LINKS +#ifdef SUPPORT_LINKS if (S_ISLNK(mode) && (_S_IFLNK != 0120000)) return (mode & ~(_S_IFMT)) | 0120000; #endif @@ -283,7 +262,8 @@ } -static void send_directory(int f, struct file_list *flist, char *dir); +static void send_directory(int f, struct file_list *flist, + char *fbuf, int len); static char *flist_dir; static int flist_dir_len; @@ -317,7 +297,7 @@ new_ptr = realloc_array(flist->files, struct file_struct *, flist->malloced); - if (verbose >= 2) { + if (verbose >= 2 && flist->malloced != FLIST_START) { rprintf(FINFO, "[%s] expand file_list to %.0f bytes, did%s move\n", who_am_i(), (double)sizeof flist->files[0] * flist->malloced, @@ -335,7 +315,7 @@ unsigned short flags; static time_t modtime; static mode_t mode; - static uint64 dev; + static int64 dev; static dev_t rdev; static uint32 rdev_major; static uid_t uid; @@ -344,7 +324,7 @@ char fname[MAXPATHLEN]; int l1, l2; - if (f == -1) + if (f < 0) return; if (!file) { @@ -399,7 +379,7 @@ else modtime = file->modtime; -#if SUPPORT_HARD_LINKS +#ifdef SUPPORT_HARD_LINKS if (file->link_u.idev) { if (file->F_DEV == dev) { if (protocol_version >= 28) @@ -477,7 +457,7 @@ } } -#if SUPPORT_LINKS +#ifdef SUPPORT_LINKS if (preserve_links && S_ISLNK(mode)) { int len = strlen(file->u.link); write_int(f, len); @@ -485,7 +465,7 @@ } #endif -#if SUPPORT_HARD_LINKS +#ifdef SUPPORT_HARD_LINKS if (flags & XMIT_HAS_IDEV_DATA) { if (protocol_version < 26) { /* 32-bit dev_t and ino_t */ @@ -522,18 +502,20 @@ -void receive_file_entry(struct file_struct **fptr, unsigned short flags, - struct file_list *flist, int f) +static struct file_struct *receive_file_entry(struct file_list *flist, + unsigned short flags, int f) { static time_t modtime; static mode_t mode; - static uint64 dev; + static int64 dev; static dev_t rdev; static uint32 rdev_major; static uid_t uid; static gid_t gid; static char lastname[MAXPATHLEN], *lastdir; static int lastdir_depth, lastdir_len = -1; + static unsigned int del_hier_name_len = 0; + static int in_del_hier = 0; char thisname[MAXPATHLEN]; unsigned int l1 = 0, l2 = 0; int alloc_len, basename_len, dirname_len, linkname_len, sum_len; @@ -541,14 +523,15 @@ char *basename, *dirname, *bp; struct file_struct *file; - if (!fptr) { + if (!flist) { modtime = 0, mode = 0; dev = 0, rdev = makedev(0, 0); rdev_major = 0; uid = 0, gid = 0; *lastname = '\0'; lastdir_len = -1; - return; + in_del_hier = 0; + return NULL; } if (flags & XMIT_SAME_NAME) @@ -562,7 +545,7 @@ if (l2 >= MAXPATHLEN - l1) { rprintf(FERROR, "overflow: flags=0x%x l1=%d l2=%d lastname=%s\n", - flags, l1, l2, lastname); + flags, l1, l2, safe_fname(lastname)); overflow("receive_file_entry"); } @@ -622,7 +605,7 @@ } } -#if SUPPORT_LINKS +#ifdef SUPPORT_LINKS if (preserve_links && S_ISLNK(mode)) { linkname_len = read_int(f) + 1; /* count the '\0' */ if (linkname_len <= 0 || linkname_len > MAXPATHLEN) { @@ -641,11 +624,11 @@ + linkname_len + sum_len; bp = pool_alloc(flist->file_pool, alloc_len, "receive_file_entry"); - file = *fptr = (struct file_struct *)bp; + file = (struct file_struct *)bp; memset(bp, 0, file_struct_len); bp += file_struct_len; - file->flags = flags & XMIT_TOP_DIR ? FLAG_TOP_DIR : 0; + file->flags = 0; file->modtime = modtime; file->length = file_length; file->mode = mode; @@ -658,10 +641,30 @@ memcpy(bp, dirname, dirname_len - 1); bp += dirname_len; bp[-1] = '\0'; - if (sanitize_paths) - lastdir_depth = count_dir_elements(lastdir); - } else if (dirname) - file->dirname = dirname; + lastdir_depth = count_dir_elements(lastdir); + file->dir.depth = lastdir_depth + 1; + } else if (dirname) { + file->dirname = dirname; /* we're reusing lastname */ + file->dir.depth = lastdir_depth + 1; + } else + file->dir.depth = 1; + + if (S_ISDIR(mode)) { + if (basename_len == 1+1 && *basename == '.') /* +1 for '\0' */ + file->dir.depth--; + if (flags & XMIT_TOP_DIR) { + in_del_hier = 1; + del_hier_name_len = file->dir.depth == 0 ? 0 : l1 + l2; + file->flags |= FLAG_TOP_DIR | FLAG_DEL_HERE; + } else if (in_del_hier) { + if (!relative_paths || !del_hier_name_len + || (l1 >= del_hier_name_len + && thisname[del_hier_name_len] == '/')) + file->flags |= FLAG_DEL_HERE; + else + in_del_hier = 0; + } + } file->basename = bp; memcpy(bp, basename, basename_len); @@ -670,7 +673,7 @@ if (preserve_devices && IS_DEVICE(mode)) file->u.rdev = rdev; -#if SUPPORT_LINKS +#ifdef SUPPORT_LINKS if (linkname_len) { file->u.link = bp; read_sbuf(f, bp, linkname_len - 1); @@ -680,11 +683,11 @@ } #endif -#if SUPPORT_HARD_LINKS +#ifdef SUPPORT_HARD_LINKS if (preserve_hard_links && protocol_version < 28 && S_ISREG(mode)) flags |= XMIT_HAS_IDEV_DATA; if (flags & XMIT_HAS_IDEV_DATA) { - uint64 inode; + int64 inode; if (protocol_version < 26) { dev = read_int(f); inode = read_int(f); @@ -723,6 +726,8 @@ * permissions and umask. This emulates what GNU cp does */ file->mode &= ~orig_umask; } + + return file; } @@ -742,7 +747,7 @@ * important case. Some systems may not have d_type. **/ struct file_struct *make_file(char *fname, struct file_list *flist, - int exclude_level) + int filter_level) { static char *lastdir; static int lastdir_len = -1; @@ -760,7 +765,8 @@ if (strlcpy(thisname, fname, sizeof thisname) >= sizeof thisname - flist_dir_len) { - rprintf(FINFO, "skipping overly long name: %s\n", fname); + rprintf(FINFO, "skipping overly long name: %s\n", + safe_fname(fname)); return NULL; } clean_fname(thisname, 0); @@ -772,11 +778,11 @@ if (readlink_stat(thisname, &st, linkname) != 0) { int save_errno = errno; /* See if file is excluded before reporting an error. */ - if (exclude_level != NO_EXCLUDES - && check_exclude_file(thisname, 0, exclude_level)) + if (filter_level != NO_FILTERS + && is_excluded(thisname, 0, filter_level)) return NULL; if (save_errno == ENOENT) { -#if SUPPORT_LINKS +#ifdef SUPPORT_LINKS /* Avoid "vanished" error if symlink points nowhere. */ if (copy_links && do_lstat(thisname, &st) == 0 && S_ISLNK(st.st_mode)) { @@ -800,12 +806,12 @@ return NULL; } - /* backup.c calls us with exclude_level set to NO_EXCLUDES. */ - if (exclude_level == NO_EXCLUDES) - goto skip_excludes; + /* backup.c calls us with filter_level set to NO_FILTERS. */ + if (filter_level == NO_FILTERS) + goto skip_filters; - if (S_ISDIR(st.st_mode) && !recurse && !files_from) { - rprintf(FINFO, "skipping directory %s\n", thisname); + if (S_ISDIR(st.st_mode) && !xfer_dirs) { + rprintf(FINFO, "skipping directory %s\n", safe_fname(thisname)); return NULL; } @@ -816,17 +822,22 @@ && S_ISDIR(st.st_mode)) flags |= FLAG_MOUNT_POINT; - if (check_exclude_file(thisname, S_ISDIR(st.st_mode) != 0, exclude_level)) + if (is_excluded(thisname, S_ISDIR(st.st_mode) != 0, filter_level)) return NULL; - if (lp_ignore_nonreadable(module_id) && access(thisname, R_OK) != 0) - return NULL; + if (lp_ignore_nonreadable(module_id)) { +#ifdef SUPPORT_LINKS + if (!S_ISLNK(st.st_mode)) +#endif + if (access(thisname, R_OK) != 0) + return NULL; + } -skip_excludes: +skip_filters: if (verbose > 2) { rprintf(FINFO, "[%s] make_file(%s,*,%d)\n", - who_am_i(), thisname, exclude_level); + who_am_i(), safe_fname(thisname), filter_level); } if ((basename = strrchr(thisname, '/')) != NULL) { @@ -844,7 +855,7 @@ } basename_len = strlen(basename) + 1; /* count the '\0' */ -#if SUPPORT_LINKS +#ifdef SUPPORT_LINKS linkname_len = S_ISLNK(st.st_mode) ? strlen(linkname) + 1 : 0; #else linkname_len = 0; @@ -873,7 +884,7 @@ file->uid = st.st_uid; file->gid = st.st_gid; -#if SUPPORT_HARD_LINKS +#ifdef SUPPORT_HARD_LINKS if (flist && flist->hlink_pool) { if (protocol_version < 28) { if (S_ISREG(st.st_mode)) @@ -911,7 +922,7 @@ file->u.rdev = st.st_rdev; #endif -#if SUPPORT_LINKS +#ifdef SUPPORT_LINKS if (linkname_len) { file->u.link = bp; memcpy(bp, linkname, linkname_len); @@ -925,14 +936,15 @@ /*bp += sum_len;*/ } - file->basedir = flist_dir; + file->dir.root = flist_dir; /* This code is only used by the receiver when it is building * a list of files for a delete pass. */ if (keep_dirlinks && linkname_len && flist) { STRUCT_STAT st2; - int i = flist_find(received_flist, file); - if (i >= 0 && S_ISDIR(received_flist->files[i]->mode) + int save_mode = file->mode; + file->mode = S_IFDIR; /* find a directory w/our name */ + if (flist_find(the_file_list, file) >= 0 && do_stat(thisname, &st2) == 0 && S_ISDIR(st2.st_mode)) { file->modtime = st2.st_mtime; file->length = st2.st_size; @@ -940,34 +952,27 @@ file->uid = st2.st_uid; file->gid = st2.st_gid; file->u.link = NULL; - if (file->link_u.idev) { - pool_free(flist->hlink_pool, 0, file->link_u.idev); - file->link_u.idev = NULL; - } - } + } else + file->mode = save_mode; } - if (!S_ISDIR(st.st_mode)) + if (S_ISREG(st.st_mode) || S_ISLNK(st.st_mode)) stats.total_size += st.st_size; return file; } -void send_file_name(int f, struct file_list *flist, char *fname, - int recursive, unsigned short base_flags) +static struct file_struct *send_file_name(int f, struct file_list *flist, + char *fname, unsigned short base_flags) { struct file_struct *file; - char fbuf[MAXPATHLEN]; - - /* f is set to -1 when calculating deletion file list */ - file = make_file(fname, flist, - f == -1 && delete_excluded? SERVER_EXCLUDES : ALL_EXCLUDES); + file = make_file(fname, flist, f == -2 ? SERVER_FILTERS : ALL_FILTERS); if (!file) - return; + return NULL; - maybe_emit_filelist_progress(flist); + maybe_emit_filelist_progress(flist->count + flist_count_offset); flist_expand(flist); @@ -975,95 +980,91 @@ flist->files[flist->count++] = file; send_file_entry(file, f, base_flags); } + return file; +} - if (recursive && S_ISDIR(file->mode) - && !(file->flags & FLAG_MOUNT_POINT)) { - struct exclude_list_struct last_list = local_exclude_list; - local_exclude_list.head = local_exclude_list.tail = NULL; - send_directory(f, flist, f_name_to(file, fbuf)); - if (verbose > 2) { - rprintf(FINFO, "[%s] popping %sexclude list\n", - who_am_i(), local_exclude_list.debug_type); +static void send_if_directory(int f, struct file_list *flist, + struct file_struct *file) +{ + char fbuf[MAXPATHLEN]; + + if (S_ISDIR(file->mode) + && !(file->flags & FLAG_MOUNT_POINT) && f_name_to(file, fbuf)) { + void *save_filters; + unsigned int len = strlen(fbuf); + if (len > 1 && fbuf[len-1] == '/') + fbuf[--len] = '\0'; + if (len >= MAXPATHLEN - 1) { + io_error |= IOERR_GENERAL; + rprintf(FERROR, "skipping long-named directory: %s\n", + full_fname(fbuf)); + return; } - clear_exclude_list(&local_exclude_list); - local_exclude_list = last_list; + save_filters = push_local_filters(fbuf, len); + send_directory(f, flist, fbuf, len); + pop_local_filters(save_filters); } } -static void send_directory(int f, struct file_list *flist, char *dir) +/* This function is normally called by the sender, but the receiving side also + * calls it from get_dirlist() with f set to -1 so that we just construct the + * file list in memory without sending it over the wire. Also, get_dirlist() + * might call this with f set to -2, which also indicates that local filter + * rules should be ignored. */ +static void send_directory(int f, struct file_list *flist, + char *fbuf, int len) { - DIR *d; struct dirent *di; - char fname[MAXPATHLEN]; - unsigned int offset; + unsigned remainder; char *p; + DIR *d; + int start = flist->count; - d = opendir(dir); - if (!d) { + if (!(d = opendir(fbuf))) { io_error |= IOERR_GENERAL; - rsyserr(FERROR, errno, "opendir %s failed", full_fname(dir)); + rsyserr(FERROR, errno, "opendir %s failed", full_fname(fbuf)); return; } - offset = strlcpy(fname, dir, MAXPATHLEN); - p = fname + offset; - if (offset >= MAXPATHLEN || p[-1] != '/') { - if (offset >= MAXPATHLEN - 1) { - io_error |= IOERR_GENERAL; - rprintf(FERROR, "skipping long-named directory: %s\n", - full_fname(fname)); - closedir(d); - return; - } + p = fbuf + len; + if (len != 1 || *fbuf != '/') *p++ = '/'; - offset++; - } - - if (cvs_exclude) { - if (strlcpy(p, ".cvsignore", MAXPATHLEN - offset) - < MAXPATHLEN - offset) { - add_exclude_file(&local_exclude_list, fname, - XFLG_WORD_SPLIT | XFLG_WORDS_ONLY); - } else { - io_error |= IOERR_GENERAL; - rprintf(FINFO, - "cannot cvs-exclude in long-named directory %s\n", - full_fname(fname)); - } - } + *p = '\0'; + remainder = MAXPATHLEN - (p - fbuf); for (errno = 0, di = readdir(d); di; errno = 0, di = readdir(d)) { char *dname = d_name(di); if (dname[0] == '.' && (dname[1] == '\0' || (dname[1] == '.' && dname[2] == '\0'))) continue; - if (strlcpy(p, dname, MAXPATHLEN - offset) < MAXPATHLEN - offset) - send_file_name(f, flist, fname, recurse, 0); + if (strlcpy(p, dname, remainder) < remainder) + send_file_name(f, flist, fbuf, 0); else { io_error |= IOERR_GENERAL; rprintf(FINFO, "cannot send long-named file %s\n", - full_fname(fname)); + full_fname(fbuf)); } } + + fbuf[len] = '\0'; + if (errno) { io_error |= IOERR_GENERAL; - rsyserr(FERROR, errno, "readdir(%s)", dir); + rsyserr(FERROR, errno, "readdir(%s)", full_fname(fbuf)); } closedir(d); + + if (recurse) { + int i, end = flist->count - 1; + for (i = start; i <= end; i++) + send_if_directory(f, flist, flist->files[i]); + } } -/** - * This function is normally called by the sender, but the receiver also - * uses it to construct its own file list if --delete has been specified. - * The delete_files() function in receiver.c sets f to -1 so that we just - * construct the file list in memory without sending it over the wire. It - * also has the side-effect of ignoring user-excludes if delete_excluded - * is set (so that the delete list includes user-excluded files). - **/ struct file_list *send_file_list(int f, int argc, char *argv[]) { int l; @@ -1071,32 +1072,33 @@ char *p, *dir, olddir[sizeof curr_dir]; char lastpath[MAXPATHLEN] = ""; struct file_list *flist; + struct timeval start_tv, end_tv; int64 start_write; int use_ff_fd = 0; - if (show_filelist_p() && f != -1) + if (show_filelist_p()) start_filelist_progress("building file list"); start_write = stats.total_written; + gettimeofday(&start_tv, NULL); - flist = flist_new(f == -1 ? WITHOUT_HLINK : WITH_HLINK, - "send_file_list"); + flist = flist_new(WITH_HLINK, "send_file_list"); - if (f != -1) { - io_start_buffering_out(); - if (filesfrom_fd >= 0) { - if (argv[0] && !push_dir(argv[0])) { - rsyserr(FERROR, errno, "push_dir %s failed", - full_fname(argv[0])); - exit_cleanup(RERR_FILESELECT); - } - use_ff_fd = 1; + io_start_buffering_out(); + if (filesfrom_fd >= 0) { + if (argv[0] && !push_dir(argv[0])) { + rsyserr(FERROR, errno, "push_dir %s failed", + full_fname(argv[0])); + exit_cleanup(RERR_FILESELECT); } + use_ff_fd = 1; } while (1) { + struct file_struct *file; char fname2[MAXPATHLEN]; char *fname = fname2; + int is_dot_dir; if (use_ff_fd) { if (read_filesfrom_line(filesfrom_fd, fname) == 0) @@ -1111,7 +1113,7 @@ } l = strlen(fname); - if (fname[l - 1] == '/') { + if (!l || fname[l - 1] == '/') { if (l == 2 && fname[0] == '.') { /* Turn "./" into just "." rather than "./." */ fname[1] = '\0'; @@ -1119,19 +1121,22 @@ fname[l++] = '.'; fname[l] = '\0'; } + is_dot_dir = 1; + } else { + is_dot_dir = fname[l-1] == '.' + && (l == 1 || fname[l-2] == '/'); } if (link_stat(fname, &st, keep_dirlinks) != 0) { - if (f != -1) { - io_error |= IOERR_GENERAL; - rsyserr(FERROR, errno, "link_stat %s failed", - full_fname(fname)); - } + io_error |= IOERR_GENERAL; + rsyserr(FERROR, errno, "link_stat %s failed", + full_fname(fname)); continue; } - if (S_ISDIR(st.st_mode) && !recurse && !files_from) { - rprintf(FINFO, "skipping directory %s\n", fname); + if (S_ISDIR(st.st_mode) && !xfer_dirs) { + rprintf(FINFO, "skipping directory %s\n", + safe_fname(fname)); continue; } @@ -1148,7 +1153,7 @@ dir = fname; fname = p + 1; } - } else if (f != -1 && implied_dirs && (p=strrchr(fname,'/')) && p != fname) { + } else if (implied_dirs && (p=strrchr(fname,'/')) && p != fname) { /* this ensures we send the intermediate directories, thus getting their permissions right */ char *lp = lastpath, *fn = fname, *slash = fname; @@ -1162,21 +1167,17 @@ } *p = '/'; if (fn != p || (*lp && *lp != '/')) { - int copy_links_saved = copy_links; - int recurse_saved = recurse; + int save_copy_links = copy_links; + int save_xfer_dirs = xfer_dirs; copy_links = copy_unsafe_links; - /* set recurse to 1 to prevent make_file - * from ignoring directory, but still - * turn off the recursive parameter to - * send_file_name */ - recurse = 1; + xfer_dirs = 1; while ((slash = strchr(slash+1, '/')) != 0) { *slash = 0; - send_file_name(f, flist, fname, 0, 0); + send_file_name(f, flist, fname, 0); *slash = '/'; } - copy_links = copy_links_saved; - recurse = recurse_saved; + copy_links = save_copy_links; + xfer_dirs = save_xfer_dirs; *p = 0; strlcpy(lastpath, fname, sizeof lastpath); *p = '/'; @@ -1209,9 +1210,12 @@ } if (one_file_system) - set_filesystem(fname); + filesystem_dev = st.st_dev; - send_file_name(f, flist, fname, recurse, XMIT_TOP_DIR); + if ((file = send_file_name(f, flist, fname, XMIT_TOP_DIR))) { + if (recurse || (xfer_dirs && is_dot_dir)) + send_if_directory(f, flist, file); + } if (olddir[0]) { flist_dir = NULL; @@ -1224,32 +1228,43 @@ } } - if (f != -1) { - send_file_entry(NULL, f, 0); + gettimeofday(&end_tv, NULL); + stats.flist_buildtime = (int64)(end_tv.tv_sec - start_tv.tv_sec) * 1000 + + (end_tv.tv_usec - start_tv.tv_usec) / 1000; + if (stats.flist_buildtime == 0) + stats.flist_buildtime = 1; + start_tv = end_tv; - if (show_filelist_p()) - finish_filelist_progress(flist); - } + send_file_entry(NULL, f, 0); + + if (show_filelist_p()) + finish_filelist_progress(flist); + + gettimeofday(&end_tv, NULL); + stats.flist_xfertime = (int64)(end_tv.tv_sec - start_tv.tv_sec) * 1000 + + (end_tv.tv_usec - start_tv.tv_usec) / 1000; if (flist->hlink_pool) { pool_destroy(flist->hlink_pool); flist->hlink_pool = NULL; } + /* Sort the list without removing any duplicates. This allows the + * receiving side to ask for any name they like, which gives us the + * flexibility to change the way we unduplicate names in the future + * without causing a compatibility problem with older versions. */ clean_flist(flist, 0, 0); - if (f != -1) { - /* Now send the uid/gid list. This was introduced in - * protocol version 15 */ - send_uid_list(f); + /* Now send the uid/gid list. This was introduced in + * protocol version 15 */ + send_uid_list(f); - /* send the io_error flag */ - write_int(f, lp_ignore_errors(module_id) ? 0 : io_error); + /* send the io_error flag */ + write_int(f, lp_ignore_errors(module_id) ? 0 : io_error); - io_end_buffering(); - stats.flist_size = stats.total_written - start_write; - stats.num_files = flist->count; - } + io_end_buffering(); + stats.flist_size = stats.total_written - start_write; + stats.num_files = flist->count; if (verbose > 3) output_flist(flist); @@ -1273,7 +1288,6 @@ start_read = stats.total_read; flist = flist_new(WITH_HLINK, "recv_file_list"); - received_flist = flist; flist->count = 0; flist->malloced = 1000; @@ -1283,27 +1297,27 @@ while ((flags = read_byte(f)) != 0) { - int i = flist->count; + struct file_struct *file; flist_expand(flist); if (protocol_version >= 28 && (flags & XMIT_EXTENDED_FLAGS)) flags |= read_byte(f) << 8; - receive_file_entry(&flist->files[i], flags, flist, f); + file = receive_file_entry(flist, flags, f); - if (S_ISREG(flist->files[i]->mode)) - stats.total_size += flist->files[i]->length; + if (S_ISREG(file->mode)) + stats.total_size += file->length; - flist->count++; + flist->files[flist->count++] = file; - maybe_emit_filelist_progress(flist); + maybe_emit_filelist_progress(flist->count); if (verbose > 2) { rprintf(FINFO, "recv_file_name(%s)\n", - f_name(flist->files[i])); + safe_fname(f_name(file))); } } - receive_file_entry(NULL, 0, NULL, 0); /* Signal that we're done. */ + receive_file_entry(NULL, 0, 0); /* Signal that we're done. */ if (verbose > 2) rprintf(FINFO, "received %d names\n", flist->count); @@ -1313,7 +1327,7 @@ clean_flist(flist, relative_paths, 1); - if (f != -1) { + if (f >= 0) { /* Now send the uid/gid list. This was introduced in * protocol version 15 */ recv_uid_list(f, flist); @@ -1348,48 +1362,42 @@ } -int file_compare(struct file_struct **file1, struct file_struct **file2) +static int file_compare(struct file_struct **file1, struct file_struct **file2) { - struct file_struct *f1 = *file1; - struct file_struct *f2 = *file2; - - if (!f1->basename && !f2->basename) - return 0; - if (!f1->basename) - return -1; - if (!f2->basename) - return 1; - if (f1->dirname == f2->dirname) - return u_strcmp(f1->basename, f2->basename); - return f_name_cmp(f1, f2); + return f_name_cmp(*file1, *file2); } +/* Search for an identically-named item in the file list. Note that the + * items must agree in their directory-ness, or no match is returned. */ int flist_find(struct file_list *flist, struct file_struct *f) { - int low = 0, high = flist->count - 1; - - while (high >= 0 && !flist->files[high]->basename) high--; + int low = flist->low, high = flist->high; + int ret, mid, mid_up; - if (high < 0) - return -1; - - while (low != high) { - int mid = (low + high) / 2; - int ret = file_compare(&flist->files[flist_up(flist, mid)],&f); - if (ret == 0) - return flist_up(flist, mid); + while (low <= high) { + mid = (low + high) / 2; + for (mid_up = mid; !flist->files[mid_up]->basename; mid_up++) {} + if (mid_up <= high) + ret = f_name_cmp(flist->files[mid_up], f); + else + ret = 1; + if (ret == 0) { + if (protocol_version < 29 + && S_ISDIR(flist->files[mid_up]->mode) + != S_ISDIR(f->mode)) + return -1; + return mid_up; + } if (ret > 0) - high = mid; + high = mid - 1; else - low = mid + 1; + low = mid_up + 1; } - - if (file_compare(&flist->files[flist_up(flist, low)], &f) == 0) - return flist_up(flist, low); return -1; } + /* * Free up any resources a file_struct has allocated * and clear the file. @@ -1419,7 +1427,7 @@ out_of_memory, POOL_INTERN))) out_of_memory(msg); -#if SUPPORT_HARD_LINKS +#ifdef SUPPORT_HARD_LINKS if (with_hlink && preserve_hard_links) { if (!(flist->hlink_pool = pool_create(HLINK_EXTENT, sizeof (struct idev), out_of_memory, POOL_INTERN))) @@ -1453,8 +1461,10 @@ if (!flist || flist->count == 0) return; + sorting_flist = flist; qsort(flist->files, flist->count, sizeof flist->files[0], (int (*)())file_compare); + sorting_flist = NULL; for (i = no_dups? 0 : flist->count; i < flist->count; i++) { if (flist->files[i]->basename) { @@ -1462,50 +1472,90 @@ break; } } + flist->low = prev_i; while (++i < flist->count) { - if (!flist->files[i]->basename) + int j; + struct file_struct *file = flist->files[i]; + + if (!file->basename) continue; - if (f_name_cmp(flist->files[i], flist->files[prev_i]) == 0) { + if (f_name_cmp(file, flist->files[prev_i]) == 0) + j = prev_i; + else if (protocol_version >= 29 && S_ISDIR(file->mode)) { + int save_mode = file->mode; + /* Make sure that this directory doesn't duplicate a + * non-directory earlier in the list. */ + flist->high = prev_i; + file->mode = S_IFREG; + j = flist_find(flist, file); + file->mode = save_mode; + } else + j = -1; + if (j >= 0) { + struct file_struct *fp = flist->files[j]; + int keep, drop; + /* If one is a dir and the other is not, we want to + * keep the dir because it might have contents in the + * list. */ + if (S_ISDIR(file->mode) != S_ISDIR(fp->mode)) { + if (S_ISDIR(file->mode)) + keep = i, drop = j; + else + keep = j, drop = i; + } else + keep = j, drop = i; if (verbose > 1 && !am_server) { rprintf(FINFO, - "removing duplicate name %s from file list %d\n", - f_name(flist->files[i]), i); + "removing duplicate name %s from file list (%d)\n", + safe_fname(f_name(file)), drop); } /* Make sure that if we unduplicate '.', that we don't - * lose track of a user-specified starting point (or - * else deletions will mysteriously fail with -R). */ - if (flist->files[i]->flags & FLAG_TOP_DIR) - flist->files[prev_i]->flags |= FLAG_TOP_DIR; - - clear_file(i, flist); + * lose track of a user-specified top directory. */ + if (flist->files[drop]->flags & FLAG_TOP_DIR) + flist->files[keep]->flags |= FLAG_TOP_DIR; + + clear_file(drop, flist); + + if (keep == i) { + if (flist->low == drop) { + for (j = drop + 1; + j < i && !flist->files[j]->basename; + j++) {} + flist->low = j; + } + prev_i = i; + } } else prev_i = i; } + flist->high = no_dups ? prev_i : flist->count - 1; if (strip_root) { - /* we need to strip off the root directory in the case - of relative paths, but this must be done _after_ - the sorting phase */ - for (i = 0; i < flist->count; i++) { - if (flist->files[i]->dirname && - flist->files[i]->dirname[0] == '/') { - memmove(&flist->files[i]->dirname[0], - &flist->files[i]->dirname[1], - strlen(flist->files[i]->dirname)); - } + /* We need to strip off the leading slashes for relative + * paths, but this must be done _after_ the sorting phase. */ + for (i = flist->low; i <= flist->high; i++) { + struct file_struct *file = flist->files[i]; - if (flist->files[i]->dirname && - !flist->files[i]->dirname[0]) { - flist->files[i]->dirname = NULL; + if (!file->dirname) + continue; + if (*file->dirname == '/') { + char *s = file->dirname + 1; + while (*s == '/') s++; + memmove(file->dirname, s, strlen(s) + 1); } + + if (!*file->dirname) + file->dirname = NULL; } } } + static void output_flist(struct file_list *flist) { - char uidbuf[16], gidbuf[16]; + char uidbuf[16], gidbuf[16], depthbuf[16]; struct file_struct *file; + const char *who = who_am_i(); int i; for (i = 0; i < flist->count; i++) { @@ -1518,25 +1568,43 @@ sprintf(gidbuf, " gid=%ld", (long)file->gid); else *gidbuf = '\0'; - rprintf(FINFO, "[%s] i=%d %s %s %s mode=0%o len=%.0f%s%s\n", - who_am_i(), i, NS(file->basedir), NS(file->dirname), - NS(file->basename), (int)file->mode, - (double)file->length, uidbuf, gidbuf); + if (!am_sender) + sprintf(depthbuf, "%d", file->dir.depth); + rprintf(FINFO, "[%s] i=%d %s %s%s%s%s mode=0%o len=%.0f%s%s flags=%x\n", + who, i, am_sender ? NS(file->dir.root) : depthbuf, + file->dirname ? safe_fname(file->dirname) : "", + file->dirname ? "/" : "", NS(file->basename), + S_ISDIR(file->mode) ? "/" : "", (int)file->mode, + (double)file->length, uidbuf, gidbuf, file->flags); } } -enum fnc_state { fnc_DIR, fnc_SLASH, fnc_BASE }; +enum fnc_state { s_DIR, s_SLASH, s_BASE, s_TRAILING }; +enum fnc_type { t_PATH, t_ITEM }; -/* Compare the names of two file_struct entities, just like strcmp() - * would do if it were operating on the joined strings. We assume - * that there are no 0-length strings. - */ +/* Compare the names of two file_struct entities, similar to how strcmp() + * would do if it were operating on the joined strings. + * + * Some differences beginning with protocol_version 29: (1) directory names + * are compared with an assumed trailing slash so that they compare in a + * way that would cause them to sort immediately prior to any content they + * may have; (2) a directory of any name compares after a non-directory of + * any name at the same depth; (3) a directory with name "." compares prior + * to anything else. These changes mean that a directory and a non-dir + * with the same name will not compare as equal (protocol_version >= 29). + * + * The dirname component can be an empty string, but the basename component + * cannot (and never is in the current codebase). The basename component + * may be NULL (for a removed item), in which case it is considered to be + * after any existing item. */ int f_name_cmp(struct file_struct *f1, struct file_struct *f2) { int dif; const uchar *c1, *c2; enum fnc_state state1, state2; + enum fnc_type type1, type2; + enum fnc_type t_path = protocol_version >= 29 ? t_PATH : t_ITEM; if (!f1 || !f1->basename) { if (!f2 || !f2->basename) @@ -1546,55 +1614,102 @@ if (!f2 || !f2->basename) return 1; - if (!(c1 = (uchar*)f1->dirname)) { - state1 = fnc_BASE; + c1 = (uchar*)f1->dirname; + c2 = (uchar*)f2->dirname; + if (c1 == c2) + c1 = c2 = NULL; + if (!c1) { + type1 = S_ISDIR(f1->mode) ? t_path : t_ITEM; c1 = (uchar*)f1->basename; + if (type1 == t_PATH && *c1 == '.' && !c1[1]) { + type1 = t_ITEM; + state1 = s_TRAILING; + c1 = (uchar*)""; + } else + state1 = s_BASE; } else if (!*c1) { - state1 = fnc_SLASH; + type1 = t_path; + state1 = s_SLASH; c1 = (uchar*)"/"; - } else - state1 = fnc_DIR; - if (!(c2 = (uchar*)f2->dirname)) { - state2 = fnc_BASE; + } else { + type1 = t_path; + state1 = s_DIR; + } + if (!c2) { + type2 = S_ISDIR(f2->mode) ? t_path : t_ITEM; c2 = (uchar*)f2->basename; + if (type2 == t_PATH && *c2 == '.' && !c2[1]) { + type2 = t_ITEM; + state2 = s_TRAILING; + c2 = (uchar*)""; + } else + state2 = s_BASE; } else if (!*c2) { - state2 = fnc_SLASH; + type2 = t_path; + state2 = s_SLASH; c2 = (uchar*)"/"; - } else - state2 = fnc_DIR; + } else { + type2 = t_path; + state2 = s_DIR; + } + + if (type1 != type2) + return type1 == t_PATH ? 1 : -1; while (1) { - if ((dif = (int)*c1 - (int)*c2) != 0) + if ((dif = (int)*c1++ - (int)*c2++) != 0) break; - if (!*++c1) { + if (!*c1) { switch (state1) { - case fnc_DIR: - state1 = fnc_SLASH; + case s_DIR: + state1 = s_SLASH; c1 = (uchar*)"/"; break; - case fnc_SLASH: - state1 = fnc_BASE; + case s_SLASH: + type1 = S_ISDIR(f1->mode) ? t_path : t_ITEM; + state1 = s_BASE; c1 = (uchar*)f1->basename; break; - case fnc_BASE: + case s_BASE: + state1 = s_TRAILING; + if (type1 == t_PATH) { + c1 = (uchar*)"/"; + break; + } + /* FALL THROUGH */ + case s_TRAILING: + type1 = t_ITEM; break; } + if (*c2 && type1 != type2) + return type1 == t_PATH ? 1 : -1; } - if (!*++c2) { + if (!*c2) { switch (state2) { - case fnc_DIR: - state2 = fnc_SLASH; + case s_DIR: + state2 = s_SLASH; c2 = (uchar*)"/"; break; - case fnc_SLASH: - state2 = fnc_BASE; + case s_SLASH: + type2 = S_ISDIR(f2->mode) ? t_path : t_ITEM; + state2 = s_BASE; c2 = (uchar*)f2->basename; break; - case fnc_BASE: + case s_BASE: + state2 = s_TRAILING; + if (type2 == t_PATH) { + c2 = (uchar*)"/"; + break; + } + /* FALL THROUGH */ + case s_TRAILING: if (!*c1) return 0; + type2 = t_ITEM; break; } + if (type1 != type2) + return type1 == t_PATH ? 1 : -1; } } @@ -1622,8 +1737,7 @@ } -/* Like f_name_to(), but we rotate through 5 static buffers of our own. - */ +/* Like f_name_to(), but we rotate through 5 static buffers of our own. */ char *f_name(struct file_struct *f) { static char names[5][MAXPATHLEN]; @@ -1633,3 +1747,39 @@ return f_name_to(f, names[n]); } + + +/* Do a non-recursive scan of the named directory, possibly ignoring all + * exclude rules except for the daemon's. If "dlen" is >=0, it is the length + * of the dirname string, and also indicates that "dirname" is a MAXPATHLEN + * buffer (the functions we call will append names onto the end, but the old + * dir value will be restored on exit). */ +struct file_list *get_dirlist(char *dirname, int dlen, + int ignore_filter_rules) +{ + struct file_list *dirlist; + char dirbuf[MAXPATHLEN]; + int save_recurse = recurse; + + if (dlen < 0) { + dlen = strlcpy(dirbuf, dirname, MAXPATHLEN); + if (dlen >= MAXPATHLEN) + return NULL; + dirname = dirbuf; + } + + dirlist = flist_new(WITHOUT_HLINK, "get_dirlist"); + + recurse = 0; + send_directory(ignore_filter_rules ? -2 : -1, dirlist, dirname, dlen); + recurse = save_recurse; + if (do_progress) + flist_count_offset += dirlist->count; + + clean_flist(dirlist, 0, 0); + + if (verbose > 3) + output_flist(dirlist); + + return dirlist; +} diff -urN --exclude=patches rsync-2.6.3/generator.c rsync-2.6.4/generator.c --- rsync-2.6.3/generator.c 2004-09-20 12:47:59.000000000 -0700 +++ rsync-2.6.4/generator.c 2005-03-30 08:33:41.000000000 -0800 @@ -25,15 +25,31 @@ extern int verbose; extern int dry_run; +extern int log_format_has_i; +extern int log_format_has_o_or_i; +extern int daemon_log_format_has_i; +extern int am_root; +extern int am_server; +extern int am_daemon; +extern int do_progress; +extern int recurse; extern int relative_paths; extern int keep_dirlinks; extern int preserve_links; -extern int am_root; extern int preserve_devices; extern int preserve_hard_links; extern int preserve_perms; extern int preserve_uid; extern int preserve_gid; +extern int preserve_times; +extern int omit_dir_times; +extern int delete_before; +extern int delete_during; +extern int delete_after; +extern int module_id; +extern int ignore_errors; +extern int remove_sent_files; +extern int delay_updates; extern int update_only; extern int opt_ignore_existing; extern int inplace; @@ -41,47 +57,311 @@ extern int csum_length; extern int ignore_times; extern int size_only; +extern OFF_T max_size; extern int io_timeout; +extern int io_error; +extern int sock_f_out; +extern int ignore_timeout; extern int protocol_version; +extern int fuzzy_basis; extern int always_checksum; extern char *partial_dir; -extern char *compare_dest; +extern char *basis_dir[]; +extern int compare_dest; +extern int copy_dest; extern int link_dest; extern int whole_file; -extern int local_server; extern int list_only; extern int read_batch; extern int only_existing; extern int orig_umask; extern int safe_symlinks; -extern unsigned int block_size; +extern long block_size; /* "long" because popt can't set an int32. */ +extern int max_delete; +extern int force_delete; +extern int one_file_system; +extern struct stats stats; +extern dev_t filesystem_dev; +extern char *backup_dir; +extern char *backup_suffix; +extern int backup_suffix_len; +extern struct file_list *the_file_list; +extern struct filter_list_struct server_filter_list; + +int allowed_lull = 0; -extern struct exclude_list_struct server_exclude_list; +static int deletion_count = 0; /* used to implement --max-delete */ -/* choose whether to skip a particular file */ -static int skip_file(char *fname, struct file_struct *file, STRUCT_STAT *st) +static int is_backup_file(char *fn) { - if (st->st_size != file->length) - return 0; - if (link_dest) { - if (preserve_perms - && (st->st_mode & CHMOD_BITS) != (file->mode & CHMOD_BITS)) - return 0; + int k = strlen(fn) - backup_suffix_len; + return k > 0 && strcmp(fn+k, backup_suffix) == 0; +} - if (am_root && preserve_uid && st->st_uid != file->uid) - return 0; - if (preserve_gid && file->gid != GID_NONE - && st->st_gid != file->gid) +/* Delete a file or directory. If DEL_FORCE_RECURSE is set in the flags, or if + * force_delete is set, this will delete recursively as long as DEL_NO_RECURSE + * is not set in the flags. */ +static int delete_item(char *fname, int mode, int flags) +{ + struct file_list *dirlist; + char buf[MAXPATHLEN]; + int j, dlen, zap_dir, ok; + void *save_filters; + + if (!S_ISDIR(mode)) { + if (max_delete && ++deletion_count > max_delete) + return 0; + if (make_backups && (backup_dir || !is_backup_file(fname))) + ok = make_backup(fname); + else + ok = robust_unlink(fname) == 0; + if (ok) { + if (!(flags & DEL_TERSE)) + log_delete(fname, mode); return 0; + } + if (errno == ENOENT) { + deletion_count--; + return 0; + } + rsyserr(FERROR, errno, "delete_file: unlink %s failed", + full_fname(fname)); + return -1; + } + + zap_dir = (flags & DEL_FORCE_RECURSE || (force_delete && recurse)) + && !(flags & DEL_NO_RECURSE); + if ((max_delete && ++deletion_count > max_delete) + || (dry_run && zap_dir)) { + ok = 0; + errno = ENOTEMPTY; + } else if (make_backups && !backup_dir && !is_backup_file(fname) + && !(flags & DEL_FORCE_RECURSE)) + ok = make_backup(fname); + else + ok = do_rmdir(fname) == 0; + if (ok) { + if (!(flags & DEL_TERSE)) + log_delete(fname, mode); + return 0; } + if (errno == ENOENT) { + deletion_count--; + return 0; + } + if (!zap_dir || (errno != ENOTEMPTY && errno != EEXIST)) { + rsyserr(FERROR, errno, "delete_file: rmdir %s failed", + full_fname(fname)); + return -1; + } + flags |= DEL_FORCE_RECURSE; /* mark subdir dels as not "in the way" */ + deletion_count--; + + dlen = strlcpy(buf, fname, MAXPATHLEN); + save_filters = push_local_filters(buf, dlen); + + dirlist = get_dirlist(buf, dlen, 0); + for (j = dirlist->count; j--; ) { + struct file_struct *fp = dirlist->files[j]; + + if (fp->flags & FLAG_MOUNT_POINT) + continue; + + f_name_to(fp, buf); + if (delete_item(buf, fp->mode, flags & ~DEL_TERSE) != 0) { + flist_free(dirlist); + return -1; + } + } + flist_free(dirlist); + + pop_local_filters(save_filters); + + if (max_delete && ++deletion_count > max_delete) + return 0; + + if (do_rmdir(fname) == 0) { + if (!(flags & DEL_TERSE)) + log_delete(fname, mode); + } else if (errno != ENOTEMPTY && errno != ENOENT) { + rsyserr(FERROR, errno, "delete_file: rmdir %s failed", + full_fname(fname)); + return -1; + } + + return 0; +} + + +/* This function is used to implement per-directory deletion, and is used by + * all the --delete-WHEN options. Note that the fbuf pointer must point to a + * MAXPATHLEN buffer with the name of the directory in it (the functions we + * call will append names onto the end, but the old dir value will be restored + * on exit). */ +static void delete_in_dir(struct file_list *flist, char *fbuf, + struct file_struct *file) +{ + static int min_depth = MAXPATHLEN, cur_depth = -1; + static void *filt_array[MAXPATHLEN/2+1]; + static int already_warned = 0; + struct file_list *dirlist; + char delbuf[MAXPATHLEN]; + STRUCT_STAT st; + int dlen, i; + + if (!flist) { + while (cur_depth >= min_depth) + pop_local_filters(filt_array[cur_depth--]); + min_depth = MAXPATHLEN; + cur_depth = -1; + return; + } + + if (verbose > 2) + rprintf(FINFO, "delete_in_dir(%s)\n", safe_fname(fbuf)); + + if (allowed_lull) + maybe_send_keepalive(); + + if (file->dir.depth >= MAXPATHLEN/2+1) + return; /* Impossible... */ + + if (io_error && !(lp_ignore_errors(module_id) || ignore_errors)) { + if (already_warned) + return; + rprintf(FINFO, + "IO error encountered -- skipping file deletion\n"); + already_warned = 1; + return; + } + + while (cur_depth >= file->dir.depth && cur_depth >= min_depth) + pop_local_filters(filt_array[cur_depth--]); + cur_depth = file->dir.depth; + if (min_depth > cur_depth) + min_depth = cur_depth; + dlen = strlen(fbuf); + filt_array[cur_depth] = push_local_filters(fbuf, dlen); + + if (link_stat(fbuf, &st, keep_dirlinks) < 0) + return; + + if (one_file_system && file->flags & FLAG_TOP_DIR) + filesystem_dev = st.st_dev; + + dirlist = get_dirlist(fbuf, dlen, 0); + + /* If an item in dirlist is not found in flist, delete it + * from the filesystem. */ + for (i = dirlist->count; i--; ) { + if (!dirlist->files[i]->basename) + continue; + if (flist_find(flist, dirlist->files[i]) < 0) { + int mode = dirlist->files[i]->mode; + f_name_to(dirlist->files[i], delbuf); + if (delete_item(delbuf, mode, DEL_FORCE_RECURSE) < 0) + break; + } + } + + flist_free(dirlist); +} + +/* This deletes any files on the receiving side that are not present on the + * sending side. This is used by --delete-before and --delete-after. */ +static void do_delete_pass(struct file_list *flist) +{ + char fbuf[MAXPATHLEN]; + int j; + + if (dry_run > 1) /* destination doesn't exist yet */ + return; + + for (j = 0; j < flist->count; j++) { + struct file_struct *file = flist->files[j]; + + if (!(file->flags & FLAG_DEL_HERE)) + continue; + + 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); + } +} + +static int unchanged_attrs(struct file_struct *file, STRUCT_STAT *st) +{ + if (preserve_perms + && (st->st_mode & CHMOD_BITS) != (file->mode & CHMOD_BITS)) + return 0; + + if (am_root && preserve_uid && st->st_uid != file->uid) + return 0; + + if (preserve_gid && file->gid != GID_NONE && st->st_gid != file->gid) + return 0; + + return 1; +} + + +void itemize(struct file_struct *file, int ndx, int statret, STRUCT_STAT *st, + int32 iflags, uchar fnamecmp_type, char *xname) +{ + if (statret == 0) { + if (S_ISREG(file->mode) && file->length != st->st_size) + iflags |= ITEM_REPORT_SIZE; + if (!(iflags & ITEM_NO_DEST_AND_NO_UPDATE)) { + int keep_time = !preserve_times ? 0 + : S_ISDIR(file->mode) ? !omit_dir_times + : !S_ISLNK(file->mode); + + if ((iflags & (ITEM_TRANSFER|ITEM_LOCAL_CHANGE) && !keep_time) + || (keep_time && file->modtime != st->st_mtime)) + iflags |= ITEM_REPORT_TIME; + if (preserve_perms && file->mode != st->st_mode) + iflags |= ITEM_REPORT_PERMS; + if (preserve_uid && am_root && file->uid != st->st_uid) + iflags |= ITEM_REPORT_OWNER; + if (preserve_gid && file->gid != GID_NONE + && st->st_gid != file->gid) + iflags |= ITEM_REPORT_GROUP; + } + } else + iflags |= ITEM_IS_NEW; + + iflags &= 0xffff; + if ((iflags & SIGNIFICANT_ITEM_FLAGS || verbose > 1 + || (xname && *xname)) && !read_batch) { + if (protocol_version >= 29) { + if (ndx >= 0) + write_int(sock_f_out, ndx); + write_shortint(sock_f_out, iflags); + if (iflags & ITEM_BASIS_TYPE_FOLLOWS) + write_byte(sock_f_out, fnamecmp_type); + if (iflags & ITEM_XNAME_FOLLOWS) + write_vstring(sock_f_out, xname, strlen(xname)); + } else if (ndx >= 0) + log_item(file, &stats, iflags, xname); + } +} + + +/* Perform our quick-check heuristic for determining if a file is unchanged. */ +static int unchanged_file(char *fn, struct file_struct *file, STRUCT_STAT *st) +{ + if (st->st_size != file->length) + return 0; /* if always checksum is set then we use the checksum instead of the file time to determine whether to sync */ if (always_checksum && S_ISREG(st->st_mode)) { char sum[MD4_SUM_LENGTH]; - file_checksum(fname,sum,st->st_size); + file_checksum(fn, sum, st->st_size); return memcmp(sum, file->u.sum, protocol_version < 21 ? 2 : MD4_SUM_LENGTH) == 0; } @@ -97,23 +377,6 @@ /* - * NULL sum_struct means we have no checksums - */ -void write_sum_head(int f, struct sum_struct *sum) -{ - static struct sum_struct null_sum; - - if (sum == NULL) - sum = &null_sum; - - write_int(f, sum->count); - write_int(f, sum->blength); - if (protocol_version >= 27) - write_int(f, sum->s2length); - write_int(f, sum->remainder); -} - -/* * set (initialize) the size entries in the per-file sum_struct * calculating dynamic block and checksum sizes. * @@ -123,39 +386,39 @@ * The block size is a rounded square root of file length. * * The checksum size is determined according to: - * blocksum_bits = BLOCKSUM_EXP + 2*log2(file_len) - log2(block_len) + * blocksum_bits = BLOCKSUM_BIAS + 2*log2(file_len) - log2(block_len) * provided by Donovan Baarda which gives a probability of rsync * algorithm corrupting data and falling back using the whole md4 * checksums. * * This might be made one of several selectable heuristics. */ - -static void sum_sizes_sqroot(struct sum_struct *sum, uint64 len) +static void sum_sizes_sqroot(struct sum_struct *sum, int64 len) { - unsigned int blength; + int32 blength; int s2length; - uint32 c; - uint64 l; - if (block_size) { + if (block_size) blength = block_size; - } else if (len <= BLOCK_SIZE * BLOCK_SIZE) { + else if (len <= BLOCK_SIZE * BLOCK_SIZE) blength = BLOCK_SIZE; - } else { - l = len; - c = 1; - while (l >>= 2) { - c <<= 1; + else { + int32 c; + int64 l; + int cnt; + for (c = 1, l = len, cnt = 0; l >>= 2; c <<= 1, cnt++) {} + if (cnt >= 31 || c >= MAX_BLOCK_SIZE) + blength = MAX_BLOCK_SIZE; + else { + blength = 0; + do { + blength |= c; + if (len < (int64)blength * blength) + blength &= ~c; + c >>= 1; + } while (c >= 8); /* round to multiple of 8 */ + blength = MAX(blength, BLOCK_SIZE); } - blength = 0; - do { - blength |= c; - if (len < (uint64)blength * blength) - blength &= ~c; - c >>= 1; - } while (c >= 8); /* round to multiple of 8 */ - blength = MAX(blength, BLOCK_SIZE); } if (protocol_version < 27) { @@ -163,20 +426,13 @@ } else if (csum_length == SUM_LENGTH) { s2length = SUM_LENGTH; } else { + int32 c; + int64 l; int b = BLOCKSUM_BIAS; - l = len; - while (l >>= 1) { - b += 2; - } - c = blength; - while (c >>= 1 && b) { - b--; - } - s2length = (b + 1 - 32 + 7) / 8; /* add a bit, - * subtract rollsum, - * round up - * --optimize in compiler-- - */ + for (l = len; l >>= 1; b += 2) {} + for (c = blength; c >>= 1 && b; b--) {} + /* add a bit, subtract rollsum, round up. */ + s2length = (b + 1 - 32 + 7) / 8; /* --optimize in compiler-- */ s2length = MAX(s2length, csum_length); s2length = MIN(s2length, SUM_LENGTH); } @@ -188,8 +444,9 @@ sum->remainder = (len % blength); if (sum->count && verbose > 2) { - rprintf(FINFO, "count=%.0f rem=%u blength=%u s2length=%d flength=%.0f\n", - (double)sum->count, sum->remainder, sum->blength, + rprintf(FINFO, + "count=%.0f rem=%ld blength=%ld s2length=%d flength=%.0f\n", + (double)sum->count, (long)sum->remainder, (long)sum->blength, sum->s2length, (double)sum->flength); } } @@ -202,7 +459,7 @@ */ static void generate_and_send_sums(int fd, OFF_T len, int f_out, int f_copy) { - size_t i; + int32 i; struct map_struct *mapbuf; struct sum_struct sum; OFF_T offset = 0; @@ -217,7 +474,7 @@ write_sum_head(f_out, &sum); for (i = 0; i < sum.count; i++) { - unsigned int n1 = MIN(len, sum.blength); + int32 n1 = (int32)MIN(len, (OFF_T)sum.blength); char *map = map_ptr(mapbuf, offset, n1); uint32 sum1 = get_checksum1(map, n1); char sum2[SUM_LENGTH]; @@ -229,8 +486,8 @@ if (verbose > 3) { rprintf(FINFO, - "chunk[%.0f] offset=%.0f len=%u sum1=%08lx\n", - (double)i, (double)offset, n1, + "chunk[%.0f] offset=%.0f len=%ld sum1=%08lx\n", + (double)i, (double)offset, (long)n1, (unsigned long)sum1); } write_int(f_out, sum1); @@ -244,45 +501,162 @@ } +/* Try to find a filename in the same dir as "fname" with a similar name. */ +static int find_fuzzy(struct file_struct *file, struct file_list *dirlist) +{ + int fname_len, fname_suf_len; + const char *fname_suf, *fname = file->basename; + uint32 lowest_dist = 25 << 16; /* ignore a distance greater than 25 */ + int j, lowest_j = -1; + + fname_len = strlen(fname); + fname_suf = find_filename_suffix(fname, fname_len, &fname_suf_len); + + for (j = 0; j < dirlist->count; j++) { + struct file_struct *fp = dirlist->files[j]; + const char *suf, *name; + int len, suf_len; + uint32 dist; + + if (!S_ISREG(fp->mode) || !fp->length + || fp->flags & FLAG_NO_FUZZY) + continue; + + name = fp->basename; + + if (fp->length == file->length + && fp->modtime == file->modtime) { + if (verbose > 4) { + rprintf(FINFO, + "fuzzy size/modtime match for %s\n", + name); + } + return j; + } + + len = strlen(name); + suf = find_filename_suffix(name, len, &suf_len); + + dist = fuzzy_distance(name, len, fname, fname_len); + /* Add some extra weight to how well the suffixes match. */ + dist += fuzzy_distance(suf, suf_len, fname_suf, fname_suf_len) + * 10; + if (verbose > 4) { + rprintf(FINFO, "fuzzy distance for %s = %d.%05d\n", + name, (int)(dist>>16), (int)(dist&0xFFFF)); + } + if (dist <= lowest_dist) { + lowest_dist = dist; + lowest_j = j; + } + } + + return lowest_j; +} + +void check_for_finished_hlinks(int itemizing, enum logcode code) +{ + struct file_struct *file; + int ndx; + + while ((ndx = get_hlink_num()) != -1) { + if (ndx < 0 || ndx >= the_file_list->count) + continue; + + file = the_file_list->files[ndx]; + if (!file->link_u.links) + continue; -/* - * Acts on file number @p i from @p flist, whose name is @p fname. - * - * First fixes up permissions, then generates checksums for the file. + hard_link_cluster(file, ndx, itemizing, code); + } +} + +static int phase = 0; + +/* Acts on the_file_list->file's ndx'th item, whose name is fname. If a dir, + * make sure it exists, and has the right permissions/timestamp info. For + * all other non-regular files (symlinks, etc.) we create them here. For + * regular files that have changed, we try to find a basis file and then + * start sending checksums. * - * @note This comment was added later by mbp who was trying to work it - * out. It might be wrong. - */ -static void recv_generator(char *fname, struct file_struct *file, int i, - int f_out) + * Note that f_out is set to -1 when doing final directory-permission and + * modification-time repair. */ +static void recv_generator(char *fname, struct file_struct *file, int ndx, + int itemizing, int maybe_PERMS_REPORT, + enum logcode code, int f_out) { - int fd, f_copy; - STRUCT_STAT st, partial_st; - struct file_struct *back_file; - int statret, stat_errno; - char *fnamecmp, *partialptr, *backupptr; + static int missing_below = -1, excluded_below = -1; + static char *fuzzy_dirname = ""; + static struct file_list *fuzzy_dirlist = NULL; + struct file_struct *fuzzy_file = NULL; + int fd = -1, f_copy = -1; + STRUCT_STAT st, real_st, partial_st; + struct file_struct *back_file = NULL; + int statret, real_ret, stat_errno; + char *fnamecmp, *partialptr, *backupptr = NULL; char fnamecmpbuf[MAXPATHLEN]; + uchar fnamecmp_type; if (list_only) return; - if (verbose > 2) - rprintf(FINFO, "recv_generator(%s,%d)\n", safe_fname(fname), i); - - if (server_exclude_list.head - && check_exclude(&server_exclude_list, fname, - S_ISDIR(file->mode)) < 0) { - if (verbose) { - rprintf(FINFO, "skipping server-excluded file \"%s\"\n", - safe_fname(fname)); + if (!fname) { + if (fuzzy_dirlist) { + flist_free(fuzzy_dirlist); + fuzzy_dirlist = NULL; + fuzzy_dirname = ""; + } + if (missing_below >= 0) { + dry_run--; + missing_below = -1; } return; } + if (verbose > 2) { + rprintf(FINFO, "recv_generator(%s,%d)\n", + safe_fname(fname), ndx); + } + + if (server_filter_list.head) { + if (excluded_below >= 0) { + if (file->dir.depth > excluded_below) + goto skipping; + excluded_below = -1; + } + if (check_filter(&server_filter_list, fname, + S_ISDIR(file->mode)) < 0) { + if (S_ISDIR(file->mode)) + excluded_below = file->dir.depth; + skipping: + if (verbose) { + rprintf(FINFO, + "skipping server-excluded file \"%s\"\n", + safe_fname(fname)); + } + return; + } + } + + if (missing_below >= 0 && file->dir.depth <= missing_below) { + dry_run--; + missing_below = -1; + } if (dry_run > 1) { statret = -1; stat_errno = ENOENT; } else { + if (fuzzy_basis && S_ISREG(file->mode)) { + char *dn = file->dirname ? file->dirname : "."; + if (fuzzy_dirname != dn + && strcmp(fuzzy_dirname, dn) != 0) { + if (fuzzy_dirlist) + flist_free(fuzzy_dirlist); + fuzzy_dirlist = get_dirlist(dn, -1, 1); + } + fuzzy_dirname = dn; + } + statret = link_stat(fname, &st, keep_dirlinks && S_ISDIR(file->mode)); stat_errno = errno; @@ -311,86 +685,115 @@ * to prepare appropriately. If there is already a * file of that name and it is *not* a directory, then * we need to delete it. If it doesn't exist, then - * recursively create it. */ - - if (dry_run) - return; /* TODO: causes inaccuracies -- fix */ + * (perhaps recursively) create it. */ if (statret == 0 && !S_ISDIR(st.st_mode)) { - if (robust_unlink(fname) != 0) { - rsyserr(FERROR, errno, - "recv_generator: unlink %s to make room for directory", - full_fname(fname)); + if (delete_item(fname, st.st_mode, DEL_TERSE) < 0) return; - } statret = -1; } + if (dry_run && statret != 0 && missing_below < 0) { + missing_below = file->dir.depth; + dry_run++; + } + if (itemizing && f_out != -1) { + itemize(file, ndx, statret, &st, + statret ? ITEM_LOCAL_CHANGE : 0, 0, NULL); + } if (statret != 0 && do_mkdir(fname,file->mode) != 0 && errno != EEXIST) { - if (!(relative_paths && errno == ENOENT - && create_directory_path(fname, orig_umask) == 0 - && do_mkdir(fname, file->mode) == 0)) { + if (!relative_paths || errno != ENOENT + || create_directory_path(fname, orig_umask) < 0 + || do_mkdir(fname, file->mode) < 0) { rsyserr(FERROR, errno, "recv_generator: mkdir %s failed", full_fname(fname)); } } - /* f_out is set to -1 when doing final directory-permission - * and modification-time repair. */ if (set_perms(fname, file, statret ? NULL : &st, 0) - && verbose && f_out != -1) - rprintf(FINFO, "%s/\n", safe_fname(fname)); + && verbose && code && f_out != -1) + rprintf(code, "%s/\n", safe_fname(fname)); + if (delete_during && f_out != -1 && !phase && dry_run < 2 + && (file->flags & FLAG_DEL_HERE)) + delete_in_dir(the_file_list, fname, file); return; } - if (preserve_links && S_ISLNK(file->mode)) { -#if SUPPORT_LINKS - char lnk[MAXPATHLEN]; - int l; + if (max_size && file->length > max_size) { + if (verbose > 1) { + rprintf(FINFO, "%s is over max-size\n", + safe_fname(fname)); + } + return; + } + if (preserve_links && S_ISLNK(file->mode)) { +#ifdef SUPPORT_LINKS if (safe_symlinks && unsafe_symlink(file->u.link, fname)) { if (verbose) { - rprintf(FINFO, "ignoring unsafe symlink %s -> \"%s\"\n", - full_fname(fname), file->u.link); + rprintf(FINFO, + "ignoring unsafe symlink %s -> \"%s\"\n", + full_fname(fname), + safe_fname(file->u.link)); } return; } if (statret == 0) { - l = readlink(fname,lnk,MAXPATHLEN-1); - if (l > 0) { - lnk[l] = 0; + char lnk[MAXPATHLEN]; + int len; + + if (!S_ISDIR(st.st_mode) + && (len = readlink(fname, lnk, MAXPATHLEN-1)) > 0) { + lnk[len] = 0; /* A link already pointing to the * right place -- no further action * required. */ - if (strcmp(lnk,file->u.link) == 0) { + if (strcmp(lnk, file->u.link) == 0) { + if (itemizing) { + itemize(file, ndx, 0, &st, 0, + 0, NULL); + } set_perms(fname, file, &st, - PERMS_REPORT); + maybe_PERMS_REPORT); return; } } - /* Not a symlink, so delete whatever's - * already there and put a new symlink - * in place. */ - delete_file(fname); + /* Not the right symlink (or not a symlink), so + * delete it. */ + if (delete_item(fname, st.st_mode, DEL_TERSE) < 0) + return; + if (!S_ISLNK(st.st_mode)) + statret = -1; } if (do_symlink(file->u.link,fname) != 0) { rsyserr(FERROR, errno, "symlink %s -> \"%s\" failed", full_fname(fname), safe_fname(file->u.link)); } else { set_perms(fname,file,NULL,0); - if (verbose) { - rprintf(FINFO, "%s -> %s\n", safe_fname(fname), + if (itemizing) { + itemize(file, ndx, statret, &st, + ITEM_LOCAL_CHANGE, 0, NULL); + } + if (code && verbose) { + rprintf(code, "%s -> %s\n", safe_fname(fname), safe_fname(file->u.link)); } + if (remove_sent_files && !dry_run) { + char numbuf[4]; + SIVAL(numbuf, 0, ndx); + send_msg(MSG_SUCCESS, numbuf, 4); + } } #endif return; } -#ifdef HAVE_MKNOD if (am_root && preserve_devices && IS_DEVICE(file->mode)) { if (statret != 0 || st.st_mode != file->mode || st.st_rdev != file->u.rdev) { - delete_file(fname); + if (delete_item(fname, st.st_mode, DEL_TERSE) < 0) + return; + if (!IS_DEVICE(st.st_mode)) + statret = -1; if (verbose > 2) { rprintf(FINFO,"mknod(%s,0%o,0x%x)\n", safe_fname(fname), @@ -401,19 +804,24 @@ full_fname(fname)); } else { set_perms(fname,file,NULL,0); - if (verbose) { - rprintf(FINFO, "%s\n", + if (itemizing) { + itemize(file, ndx, statret, &st, + ITEM_LOCAL_CHANGE, 0, NULL); + } + if (code && verbose) { + rprintf(code, "%s\n", safe_fname(fname)); } } } else { - set_perms(fname, file, &st, PERMS_REPORT); + if (itemizing) + itemize(file, ndx, statret, &st, 0, 0, NULL); + set_perms(fname, file, &st, maybe_PERMS_REPORT); } return; } -#endif - if (preserve_hard_links && hard_link_check(file, HL_CHECK_MASTER)) + if (preserve_hard_links && hard_link_check(file, ndx, HL_CHECK_MASTER)) return; if (!S_ISREG(file->mode)) { @@ -422,54 +830,141 @@ return; } + if (opt_ignore_existing && statret == 0) { + if (verbose > 1) + rprintf(FINFO, "%s exists\n", safe_fname(fname)); + return; + } + + if (update_only && statret == 0 + && cmp_modtime(st.st_mtime, file->modtime) > 0) { + if (verbose > 1) + rprintf(FINFO, "%s is newer\n", safe_fname(fname)); + return; + } + fnamecmp = fname; + fnamecmp_type = FNAMECMP_FNAME; + + if (statret == 0 && !S_ISREG(st.st_mode)) { + if (delete_item(fname, st.st_mode, DEL_TERSE) != 0) + return; + statret = -1; + stat_errno = ENOENT; + } - if (statret == -1 && compare_dest != NULL) { - /* try the file at compare_dest instead */ - pathjoin(fnamecmpbuf, sizeof fnamecmpbuf, compare_dest, fname); - if (link_stat(fnamecmpbuf, &st, 0) == 0 - && S_ISREG(st.st_mode)) { -#if HAVE_LINK - if (link_dest && !dry_run) { - if (do_link(fnamecmpbuf, fname) < 0) { + if (statret != 0 && basis_dir[0] != NULL) { + int best_match = -1; + int match_level = 0; + int i = 0; + do { + pathjoin(fnamecmpbuf, sizeof fnamecmpbuf, + basis_dir[i], fname); + if (link_stat(fnamecmpbuf, &st, 0) < 0 + || !S_ISREG(st.st_mode)) + continue; + switch (match_level) { + case 0: + best_match = i; + match_level = 1; + /* FALL THROUGH */ + case 1: + if (!unchanged_file(fnamecmpbuf, file, &st)) + continue; + best_match = i; + match_level = 2; + if (copy_dest) + break; + /* FALL THROUGH */ + case 2: + if (!unchanged_attrs(file, &st)) + continue; + best_match = i; + match_level = 3; + break; + } + break; + } while (basis_dir[++i] != NULL); + if (match_level) { + statret = 0; + if (i != best_match) { + i = best_match; + pathjoin(fnamecmpbuf, sizeof fnamecmpbuf, + basis_dir[i], fname); + if (link_stat(fnamecmpbuf, &st, 0) < 0) { + match_level = 0; + statret = -1; + stat_errno = errno; + } + } +#ifdef HAVE_LINK + if (link_dest && match_level == 3) { + if (hard_link_one(file, ndx, fname, -1, &st, + fnamecmpbuf, 1, + itemizing && verbose > 1, + code) == 0) + return; + if (verbose) { + rsyserr(FINFO, errno, "link %s => %s", + full_fname(fnamecmpbuf), + safe_fname(fname)); + } + match_level = 2; + } +#endif + if (match_level == 2) { + /* Copy the file locally. */ + if (copy_file(fnamecmpbuf, fname, file->mode) < 0) { if (verbose) { rsyserr(FINFO, errno, - "link %s => %s", - fnamecmpbuf, + "copy_file %s => %s", + full_fname(fnamecmpbuf), safe_fname(fname)); } - fnamecmp = fnamecmpbuf; - } - } else -#endif + match_level = 0; + statret = -1; + } else + set_perms(fname, file, NULL, 0); + } else if (compare_dest || match_level == 1) { fnamecmp = fnamecmpbuf; - statret = 0; + fnamecmp_type = i; + } } } - if (statret == 0 && !S_ISREG(st.st_mode)) { - if (delete_file(fname) != 0) - return; - statret = -1; - stat_errno = ENOENT; - } + real_ret = statret; + real_st = st; - if (partial_dir && (partialptr = partial_dir_fname(fname)) + if (partial_dir && (partialptr = partial_dir_fname(fname)) != NULL && link_stat(partialptr, &partial_st, 0) == 0 && S_ISREG(partial_st.st_mode)) { - if (statret == -1) + if (statret != 0) goto prepare_to_open; } else partialptr = NULL; - if (statret == -1) { - if (preserve_hard_links && hard_link_check(file, HL_SKIP)) + if (statret != 0 && fuzzy_basis && dry_run <= 1) { + int j = find_fuzzy(file, fuzzy_dirlist); + if (j >= 0) { + fuzzy_file = fuzzy_dirlist->files[j]; + f_name_to(fuzzy_file, fnamecmpbuf); + if (verbose > 2) { + rprintf(FINFO, "fuzzy basis selected for %s: %s\n", + safe_fname(fname), safe_fname(fnamecmpbuf)); + } + st.st_size = fuzzy_file->length; + statret = 0; + fnamecmp = fnamecmpbuf; + fnamecmp_type = FNAMECMP_FUZZY; + } + } + + if (statret != 0) { + if (preserve_hard_links && hard_link_check(file, ndx, HL_SKIP)) return; - if (stat_errno == ENOENT) { - write_int(f_out,i); - if (!dry_run && !read_batch) - write_sum_head(f_out, NULL); - } else if (verbose > 1) { + if (stat_errno == ENOENT) + goto notify_others; + if (verbose > 1) { rsyserr(FERROR, stat_errno, "recv_generator: failed to stat %s", full_fname(fname)); @@ -477,40 +972,42 @@ return; } - if (opt_ignore_existing && fnamecmp == fname) { - if (verbose > 1) - rprintf(FINFO, "%s exists\n", safe_fname(fname)); - return; - } - - if (update_only && fnamecmp == fname - && cmp_modtime(st.st_mtime, file->modtime) > 0) { - if (verbose > 1) - rprintf(FINFO, "%s is newer\n", safe_fname(fname)); - return; - } - - if (skip_file(fnamecmp, file, &st)) { - if (fnamecmp == fname) - set_perms(fname, file, &st, PERMS_REPORT); + if (!compare_dest && fnamecmp_type <= FNAMECMP_BASIS_DIR_HIGH) + ; + else if (fnamecmp_type == FNAMECMP_FUZZY) + ; + else if (unchanged_file(fnamecmp, file, &st)) { + if (fnamecmp_type == FNAMECMP_FNAME) { + if (itemizing) { + itemize(file, ndx, real_ret, &real_st, + 0, 0, NULL); + } + set_perms(fname, file, &st, maybe_PERMS_REPORT); + if (preserve_hard_links && file->link_u.links) + hard_link_cluster(file, ndx, itemizing, code); + return; + } + /* Only --compare-dest gets here. */ + itemize(file, ndx, real_ret, &real_st, + ITEM_NO_DEST_AND_NO_UPDATE, 0, NULL); return; } prepare_to_open: - if (dry_run || read_batch) { - write_int(f_out,i); - return; - } - - if (whole_file > 0) { - write_int(f_out,i); - write_sum_head(f_out, NULL); - return; - } - if (partialptr) { st = partial_st; fnamecmp = partialptr; + fnamecmp_type = FNAMECMP_PARTIAL_DIR; + statret = 0; + } + + if (dry_run || read_batch || whole_file) + goto notify_others; + + if (fuzzy_basis) { + int j = flist_find(fuzzy_dirlist, file); + if (j >= 0) /* don't use changing file as future fuzzy basis */ + fuzzy_dirlist->files[j]->flags |= FLAG_NO_FUZZY; } /* open the file */ @@ -521,19 +1018,18 @@ full_fname(fnamecmp)); pretend_missing: /* pretend the file didn't exist */ - if (preserve_hard_links && hard_link_check(file, HL_SKIP)) + if (preserve_hard_links && hard_link_check(file, ndx, HL_SKIP)) return; - write_int(f_out,i); - write_sum_head(f_out, NULL); - return; + statret = real_ret = -1; + goto notify_others; } - if (inplace && make_backups) { + if (inplace && make_backups && fnamecmp_type == FNAMECMP_FNAME) { if (!(backupptr = get_backup_name(fname))) { close(fd); return; } - if (!(back_file = make_file(fname, NULL, NO_EXCLUDES))) { + if (!(back_file = make_file(fname, NULL, NO_FILTERS))) { close(fd); goto pretend_missing; } @@ -552,10 +1048,7 @@ close(fd); return; } - } else { - backupptr = NULL; - back_file = NULL; - f_copy = -1; + fnamecmp_type = FNAMECMP_BACKUP; } if (verbose > 3) { @@ -564,16 +1057,44 @@ } if (verbose > 2) - rprintf(FINFO, "generating and sending sums for %d\n", i); + rprintf(FINFO, "generating and sending sums for %d\n", ndx); + +notify_others: + write_int(f_out, ndx); + if (itemizing) { + int iflags = ITEM_TRANSFER; + if (always_checksum) + iflags |= ITEM_REPORT_CHECKSUM; + if (fnamecmp_type != FNAMECMP_FNAME) + iflags |= ITEM_BASIS_TYPE_FOLLOWS; + if (fnamecmp_type == FNAMECMP_FUZZY) + iflags |= ITEM_XNAME_FOLLOWS; + itemize(file, -1, real_ret, &real_st, iflags, fnamecmp_type, + fuzzy_file ? fuzzy_file->basename : NULL); + } + + if (dry_run) { + if (preserve_hard_links && file->link_u.links) + hard_link_cluster(file, ndx, itemizing, code); + return; + } + if (read_batch) + return; + + if (statret != 0 || whole_file) { + write_sum_head(f_out, NULL); + return; + } - write_int(f_out,i); generate_and_send_sums(fd, st.st_size, f_out, f_copy); if (f_copy >= 0) { close(f_copy); set_perms(backupptr, back_file, NULL, 0); - if (verbose > 1) - rprintf(FINFO, "backed up %s to %s\n", fname, backupptr); + if (verbose > 1) { + rprintf(FINFO, "backed up %s to %s\n", + safe_fname(fname), safe_fname(backupptr)); + } free(back_file); } @@ -583,51 +1104,102 @@ void generate_files(int f_out, struct file_list *flist, char *local_name) { - int i; - int phase = 0; + int i, lull_mod; char fbuf[MAXPATHLEN]; + int itemizing, maybe_PERMS_REPORT; + enum logcode code; + int need_retouch_dir_times = preserve_times && !omit_dir_times; + int need_retouch_dir_perms = 0; + int save_only_existing = only_existing; + int save_opt_ignore_existing = opt_ignore_existing; + int save_do_progress = do_progress; + + allowed_lull = read_batch ? 0 : (io_timeout + 1) / 2; + lull_mod = allowed_lull * 5; + + if (protocol_version >= 29) { + itemizing = 1; + maybe_PERMS_REPORT = log_format_has_i ? 0 : PERMS_REPORT; + code = daemon_log_format_has_i ? 0 : FLOG; + } else if (am_daemon) { + itemizing = daemon_log_format_has_i && !dry_run; + maybe_PERMS_REPORT = PERMS_REPORT; + code = itemizing || dry_run ? FCLIENT : FINFO; + } else if (!am_server) { + itemizing = log_format_has_i; + maybe_PERMS_REPORT = log_format_has_i ? 0 : PERMS_REPORT; + code = itemizing ? 0 : FINFO; + } else { + itemizing = 0; + maybe_PERMS_REPORT = PERMS_REPORT; + code = FINFO; + } if (verbose > 2) { rprintf(FINFO, "generator starting pid=%ld count=%d\n", (long)getpid(), flist->count); } + if (delete_before && !local_name && flist->count > 0) + do_delete_pass(flist); + do_progress = 0; + + if (whole_file < 0) + whole_file = 0; if (verbose >= 2) { - rprintf(FINFO, - whole_file > 0 - ? "delta-transmission disabled for local transfer or --whole-file\n" - : "delta transmission enabled\n"); + rprintf(FINFO, "delta-transmission %s\n", + whole_file + ? "disabled for local transfer or --whole-file" + : "enabled"); } - /* we expect to just sit around now, so don't exit on a - timeout. If we really get a timeout then the other process should - exit */ - io_timeout = 0; + if (protocol_version < 29) + ignore_timeout = 1; for (i = 0; i < flist->count; i++) { struct file_struct *file = flist->files[i]; - struct file_struct copy; if (!file->basename) continue; - /* we need to ensure that any directories we create have writeable - permissions initially so that we can create the files within - them. This is then fixed after the files are transferred */ + + recv_generator(local_name ? local_name : f_name_to(file, fbuf), + file, i, itemizing, maybe_PERMS_REPORT, code, + f_out); + + /* We need to ensure that any dirs we create have writeable + * permissions during the time we are putting files within + * them. This is then fixed after the transfer is done. */ if (!am_root && S_ISDIR(file->mode) && !(file->mode & S_IWUSR)) { - copy = *file; - /* XXX: Could this be causing a problem on SCO? Perhaps their - * handling of permissions is strange? */ - copy.mode |= S_IWUSR; /* user write */ - file = © + int mode = file->mode | S_IWUSR; /* user write */ + char *fname = local_name ? local_name : fbuf; + if (do_chmod(fname, mode & CHMOD_BITS) < 0) { + rsyserr(FERROR, errno, + "failed to modify permissions on %s", + full_fname(fname)); + } + need_retouch_dir_perms = 1; } - recv_generator(local_name ? local_name : f_name_to(file, fbuf), - file, i, f_out); + if (preserve_hard_links) + check_for_finished_hlinks(itemizing, code); + + if (allowed_lull && !(i % lull_mod)) + maybe_send_keepalive(); } + recv_generator(NULL, NULL, 0, 0, 0, code, -1); + if (delete_during) + delete_in_dir(NULL, NULL, NULL); phase++; csum_length = SUM_LENGTH; + only_existing = max_size = opt_ignore_existing = 0; + update_only = always_checksum = size_only = 0; ignore_times = 1; + make_backups = 0; /* avoid a duplicate backup for inplace processing */ + + /* We expect to just sit around now, so don't exit on a timeout. + * If we really get a timeout then the other process should exit. */ + ignore_timeout = 1; if (verbose > 2) rprintf(FINFO,"generate_files phase=%d\n",phase); @@ -636,29 +1208,67 @@ /* files can cycle through the system more than once * to catch initial checksum errors */ - while ((i = get_redo_num()) != -1) { + while ((i = get_redo_num(itemizing, code)) != -1) { struct file_struct *file = flist->files[i]; recv_generator(local_name ? local_name : f_name_to(file, fbuf), - file, i, f_out); + file, i, itemizing, maybe_PERMS_REPORT, code, + f_out); } phase++; + only_existing = save_only_existing; + opt_ignore_existing = save_opt_ignore_existing; + if (verbose > 2) rprintf(FINFO,"generate_files phase=%d\n",phase); write_int(f_out, -1); + /* Reduce round-trip lag-time for a useless delay-updates phase. */ + if (protocol_version >= 29 && !delay_updates) + write_int(f_out, -1); + + /* Read MSG_DONE for the redo phase (and any prior messages). */ + get_redo_num(itemizing, code); + + if (protocol_version >= 29) { + phase++; + if (verbose > 2) + rprintf(FINFO, "generate_files phase=%d\n", phase); + if (delay_updates) + write_int(f_out, -1); + /* Read MSG_DONE for delay-updates phase & prior messages. */ + get_redo_num(itemizing, code); + } + + do_progress = save_do_progress; + if (delete_after && !local_name && flist->count > 0) + do_delete_pass(flist); + + if ((need_retouch_dir_perms || need_retouch_dir_times) + && !list_only && !local_name && !dry_run) { + int j = 0; + /* Now we need to fix any directory permissions that were + * modified during the transfer and/or re-set any tweaked + * modified-time values. */ + for (i = 0; i < flist->count; i++) { + struct file_struct *file = flist->files[i]; + if (!file->basename || !S_ISDIR(file->mode)) + continue; + if (!need_retouch_dir_times && file->mode & S_IWUSR) + continue; + recv_generator(f_name(file), file, i, itemizing, + maybe_PERMS_REPORT, code, -1); + if (allowed_lull && !(j++ % lull_mod)) + maybe_send_keepalive(); + } + } + recv_generator(NULL, NULL, 0, 0, 0, code, -1); - if (preserve_hard_links) - do_hard_links(); - - /* now we need to fix any directory permissions that were - * modified during the transfer */ - for (i = 0; i < flist->count; i++) { - struct file_struct *file = flist->files[i]; - if (!file->basename || !S_ISDIR(file->mode)) - continue; - recv_generator(local_name ? local_name : f_name(file), - file, i, -1); + if (max_delete > 0 && deletion_count > max_delete) { + rprintf(FINFO, + "Deletions stopped due to --max-delete limit (%d skipped)\n", + deletion_count - max_delete); + io_error |= IOERR_DEL_LIMIT; } if (verbose > 2) diff -urN --exclude=patches rsync-2.6.3/getfsdev.c rsync-2.6.4/getfsdev.c --- rsync-2.6.3/getfsdev.c 2004-08-09 13:46:54.000000000 -0700 +++ rsync-2.6.4/getfsdev.c 2005-02-13 16:53:43.000000000 -0800 @@ -3,9 +3,15 @@ int main(int argc, char *argv[]) { STRUCT_STAT st; + int ret; while (--argc > 0) { - if (stat(*++argv, &st) < 0) { +#ifdef USE_STAT64_FUNCS + ret = stat64(*++argv, &st); +#else + ret = stat(*++argv, &st); +#endif + if (ret < 0) { fprintf(stderr, "Unable to stat `%s'\n", *argv); exit(1); } diff -urN --exclude=patches rsync-2.6.3/hlink.c rsync-2.6.4/hlink.c --- rsync-2.6.3/hlink.c 2004-07-12 00:03:28.000000000 -0700 +++ rsync-2.6.4/hlink.c 2005-03-09 10:54:06.000000000 -0800 @@ -23,12 +23,18 @@ extern int dry_run; extern int verbose; extern int make_backups; +extern struct file_list *the_file_list; -#if SUPPORT_HARD_LINKS -static int hlink_compare(struct file_struct **file1, struct file_struct **file2) +#ifdef SUPPORT_HARD_LINKS + +#define FPTR(i) (the_file_list->files[i]) +#define LINKED(p1,p2) (FPTR(p1)->F_DEV == FPTR(p2)->F_DEV \ + && FPTR(p1)->F_INODE == FPTR(p2)->F_INODE) + +static int hlink_compare(int *int1, int *int2) { - struct file_struct *f1 = *file1; - struct file_struct *f2 = *file2; + struct file_struct *f1 = FPTR(*int1); + struct file_struct *f2 = FPTR(*int2); if (f1->F_DEV != f2->F_DEV) return (int) (f1->F_DEV > f2->F_DEV ? 1 : -1); @@ -36,24 +42,20 @@ if (f1->F_INODE != f2->F_INODE) return (int) (f1->F_INODE > f2->F_INODE ? 1 : -1); - return file_compare(file1, file2); + return f_name_cmp(f1, f2); } -static struct file_struct **hlink_list; +static int *hlink_list; static int hlink_count; -#define LINKED(p1,p2) ((p1)->F_DEV == (p2)->F_DEV \ - && (p1)->F_INODE == (p2)->F_INODE) - /* Analyze the data in the hlink_list[], remove items that aren't multiply * linked, and replace the dev+inode data with the hlindex+next linked list. */ -static void link_idev_data(struct file_list *flist) +static void link_idev_data(void) { - struct file_struct *head; - int from, to, start; + int head, from, to, start; alloc_pool_t hlink_pool; - alloc_pool_t idev_pool = flist->hlink_pool; + alloc_pool_t idev_pool = the_file_list->hlink_pool; hlink_pool = pool_create(128 * 1024, sizeof (struct hlink), out_of_memory, POOL_INTERN); @@ -63,26 +65,27 @@ head = hlink_list[start]; while (from < hlink_count-1 && LINKED(hlink_list[from], hlink_list[from+1])) { - pool_free(idev_pool, 0, hlink_list[from]->link_u.idev); - hlink_list[from]->link_u.links = pool_talloc(hlink_pool, + pool_free(idev_pool, 0, FPTR(hlink_list[from])->link_u.idev); + FPTR(hlink_list[from])->link_u.links = pool_talloc(hlink_pool, struct hlink, 1, "hlink_list"); - hlink_list[from]->F_HLINDEX = to; - hlink_list[from]->F_NEXT = hlink_list[from+1]; + FPTR(hlink_list[from])->F_HLINDEX = to; + FPTR(hlink_list[from])->F_NEXT = hlink_list[from+1]; from++; } if (from > start) { - pool_free(idev_pool, 0, hlink_list[from]->link_u.idev); - hlink_list[from]->link_u.links = pool_talloc(hlink_pool, + pool_free(idev_pool, 0, FPTR(hlink_list[from])->link_u.idev); + FPTR(hlink_list[from])->link_u.links = pool_talloc(hlink_pool, struct hlink, 1, "hlink_list"); - hlink_list[from]->F_HLINDEX = to; - hlink_list[from]->F_NEXT = head; - hlink_list[from]->flags |= FLAG_HLINK_EOL; + FPTR(head)->flags |= FLAG_HLINK_TOL; + FPTR(hlink_list[from])->F_HLINDEX = to; + FPTR(hlink_list[from])->F_NEXT = head; + FPTR(hlink_list[from])->flags |= FLAG_HLINK_EOL; hlink_list[to++] = head; } else { - pool_free(idev_pool, 0, head->link_u.idev); - head->link_u.idev = NULL; + pool_free(idev_pool, 0, FPTR(head)->link_u.idev); + FPTR(head)->link_u.idev = NULL; } } @@ -93,33 +96,33 @@ hlink_pool = NULL; } else { hlink_count = to; - if (!(hlink_list = realloc_array(hlink_list, - struct file_struct *, hlink_count))) + hlink_list = realloc_array(hlink_list, int, hlink_count); + if (!hlink_list) out_of_memory("init_hard_links"); } - flist->hlink_pool = hlink_pool; + the_file_list->hlink_pool = hlink_pool; pool_destroy(idev_pool); } #endif -void init_hard_links(struct file_list *flist) +void init_hard_links(void) { -#if SUPPORT_HARD_LINKS +#ifdef SUPPORT_HARD_LINKS int i; - if (flist->count < 2) + if (the_file_list->count < 2) return; if (hlink_list) free(hlink_list); - if (!(hlink_list = new_array(struct file_struct *, flist->count))) + if (!(hlink_list = new_array(int, the_file_list->count))) out_of_memory("init_hard_links"); hlink_count = 0; - for (i = 0; i < flist->count; i++) { - if (flist->files[i]->link_u.idev) - hlink_list[hlink_count++] = flist->files[i]; + for (i = 0; i < the_file_list->count; i++) { + if (FPTR(i)->link_u.idev) + hlink_list[hlink_count++] = i; } qsort(hlink_list, hlink_count, @@ -129,21 +132,21 @@ free(hlink_list); hlink_list = NULL; } else - link_idev_data(flist); + link_idev_data(); #endif } -int hard_link_check(struct file_struct *file, int skip) +int hard_link_check(struct file_struct *file, int ndx, int skip) { -#if SUPPORT_HARD_LINKS +#ifdef SUPPORT_HARD_LINKS if (!hlink_list || !file->link_u.links) return 0; if (skip && !(file->flags & FLAG_HLINK_EOL)) hlink_list[file->F_HLINDEX] = file->F_NEXT; - if (hlink_list[file->F_HLINDEX] != file) { - if (verbose > 1) { + if (hlink_list[file->F_HLINDEX] != ndx) { + if (verbose > 2) { rprintf(FINFO, "\"%s\" is a hard link\n", - f_name(file)); + safe_fname(f_name(file))); } return 1; } @@ -151,62 +154,80 @@ return 0; } -#if SUPPORT_HARD_LINKS -static void hard_link_one(char *hlink1, char *hlink2) +#ifdef SUPPORT_HARD_LINKS +int hard_link_one(struct file_struct *file, int ndx, char *fname, + int statret, STRUCT_STAT *st, char *toname, int terse, + int itemizing, enum logcode code) { - if (do_link(hlink1, hlink2)) { + if (do_link(toname, fname)) { if (verbose) { - rsyserr(FINFO, errno, "link %s => %s failed", - hlink2, hlink1); + rsyserr(FERROR, errno, "link %s => %s failed", + full_fname(fname), safe_fname(toname)); } + return -1; + } + + if (itemizing) { + itemize(file, ndx, statret, st, + ITEM_LOCAL_CHANGE | ITEM_XNAME_FOLLOWS, 0, + terse ? "" : toname); + } + if (code && verbose && !terse) { + rprintf(code, "%s => %s\n", + safe_fname(fname), safe_fname(toname)); } - else if (verbose) - rprintf(FINFO, "%s => %s\n", hlink2, hlink1); + return 0; } #endif - -/** - * Create any hard links in the global hlink_list. They were put - * there by running init_hard_links on the filelist. - **/ -void do_hard_links(void) +void hard_link_cluster(struct file_struct *file, int master, int itemizing, + enum logcode code) { -#if SUPPORT_HARD_LINKS - struct file_struct *file, *first; +#ifdef SUPPORT_HARD_LINKS char hlink1[MAXPATHLEN]; char *hlink2; STRUCT_STAT st1, st2; - int i; + int statret, ndx = master; - if (!hlink_list) + if (link_stat(f_name_to(file, hlink1), &st1, 0) < 0) return; - - for (i = 0; i < hlink_count; i++) { - first = file = hlink_list[i]; - if (link_stat(f_name_to(first, hlink1), &st1, 0) < 0) + if (!(file->flags & FLAG_HLINK_TOL)) { + while (!(file->flags & FLAG_HLINK_EOL)) { + ndx = file->F_NEXT; + file = FPTR(ndx); + } + } + do { + ndx = file->F_NEXT; + file = FPTR(ndx); + if (ndx == master) continue; - while ((file = file->F_NEXT) != first) { - hlink2 = f_name(file); - if (link_stat(hlink2, &st2, 0) == 0) { - if (st2.st_dev == st1.st_dev - && st2.st_ino == st1.st_ino) - continue; - if (make_backups) { - if (!make_backup(hlink2)) - continue; - } else if (robust_unlink(hlink2)) { - if (verbose > 0) { - rsyserr(FINFO, errno, - "unlink %s failed", - full_fname(hlink2)); - } + hlink2 = f_name(file); + if ((statret = link_stat(hlink2, &st2, 0)) == 0) { + if (st2.st_dev == st1.st_dev + && st2.st_ino == st1.st_ino) { + if (itemizing) { + itemize(file, ndx, statret, &st2, + ITEM_LOCAL_CHANGE | ITEM_XNAME_FOLLOWS, + 0, ""); + } + continue; + } + if (make_backups) { + if (!make_backup(hlink2)) continue; + } else if (robust_unlink(hlink2)) { + if (verbose > 0) { + rsyserr(FINFO, errno, + "unlink %s failed", + full_fname(hlink2)); } + continue; } - hard_link_one(hlink1, hlink2); } - } + hard_link_one(file, ndx, hlink2, statret, + &st2, hlink1, 0, itemizing, code); + } while (!(file->flags & FLAG_HLINK_EOL)); #endif } diff -urN --exclude=patches rsync-2.6.3/io.c rsync-2.6.4/io.c --- rsync-2.6.3/io.c 2004-08-01 19:43:54.000000000 -0700 +++ rsync-2.6.4/io.c 2005-03-09 10:54:02.000000000 -0800 @@ -43,17 +43,24 @@ extern size_t bwlimit_writemax; extern int verbose; extern int io_timeout; +extern int allowed_lull; extern int am_server; extern int am_daemon; extern int am_sender; +extern int am_generator; extern int eol_nulls; +extern int csum_length; extern int checksum_seed; extern int protocol_version; -extern char *remote_filesfrom_file; +extern int remove_sent_files; +extern int preserve_hard_links; +extern char *filesfrom_host; extern struct stats stats; +extern struct file_list *the_file_list; const char phase_unknown[] = "unknown"; int select_timeout = SELECT_TIMEOUT; +int ignore_timeout = 0; int batch_fd = -1; int batch_gen_fd = -1; @@ -73,17 +80,16 @@ const char *io_write_phase = phase_unknown; const char *io_read_phase = phase_unknown; -/** Ignore EOF errors while reading a module listing if the remote - version is 24 or less. */ -int kludge_around_eof = False; +/* Ignore an EOF error if non-zero. See whine_about_eof(). */ +int kluge_around_eof = 0; int msg_fd_in = -1; int msg_fd_out = -1; +int sock_f_in = -1; +int sock_f_out = -1; static int io_multiplexing_out; static int io_multiplexing_in; -static int sock_f_in = -1; -static int sock_f_out = -1; static time_t last_io; static int no_flush; @@ -96,16 +102,20 @@ static char *io_filesfrom_bp; static char io_filesfrom_lastchar; static int io_filesfrom_buflen; +static size_t contiguous_write_len = 0; static void read_loop(int fd, char *buf, size_t len); -struct redo_list { - struct redo_list *next; - int num; +struct flist_ndx_item { + struct flist_ndx_item *next; + int ndx; }; -static struct redo_list *redo_list_head; -static struct redo_list *redo_list_tail; +struct flist_ndx_list { + struct flist_ndx_item *head, *tail; +}; + +static struct flist_ndx_list redo_list, hlink_list; struct msg_list { struct msg_list *next; @@ -116,26 +126,44 @@ static struct msg_list *msg_list_head; static struct msg_list *msg_list_tail; -static void redo_list_add(int num) +static void flist_ndx_push(struct flist_ndx_list *lp, int ndx) { - struct redo_list *rl; + struct flist_ndx_item *item; - if (!(rl = new(struct redo_list))) - exit_cleanup(RERR_MALLOC); - rl->next = NULL; - rl->num = num; - if (redo_list_tail) - redo_list_tail->next = rl; + if (!(item = new(struct flist_ndx_item))) + out_of_memory("flist_ndx_push"); + item->next = NULL; + item->ndx = ndx; + if (lp->tail) + lp->tail->next = item; else - redo_list_head = rl; - redo_list_tail = rl; + lp->head = item; + lp->tail = item; +} + +static int flist_ndx_pop(struct flist_ndx_list *lp) +{ + struct flist_ndx_item *next; + int ndx; + + if (!lp->head) + return -1; + + ndx = lp->head->ndx; + next = lp->head->next; + free(lp->head); + lp->head = next; + if (!next) + lp->tail = NULL; + + return ndx; } static void check_timeout(void) { time_t t; - if (!io_timeout) + if (!io_timeout || ignore_timeout) return; if (!last_io) { @@ -147,7 +175,7 @@ if (t - last_io >= io_timeout) { if (!am_server && !am_daemon) { - rprintf(FERROR, "io timeout after %d seconds - exiting\n", + rprintf(FERROR, "io timeout after %d seconds -- exiting\n", (int)(t-last_io)); } exit_cleanup(RERR_TIMEOUT); @@ -162,17 +190,17 @@ sock_f_out = f_out; } -/** Setup the fd used to receive MSG_* messages. Only needed when - * we're the generator because the sender and receiver both use the - * multiplexed I/O setup. */ +/* Setup the fd used to receive MSG_* messages. Only needed during the + * early stages of being a local sender (up through the sending of the + * file list) or when we're the generator (to fetch the messages from + * the receiver). */ void set_msg_fd_in(int fd) { msg_fd_in = fd; } -/** Setup the fd used to send our MSG_* messages. Only needed when - * we're the receiver because the generator and the sender both use - * the multiplexed I/O setup. */ +/* Setup the fd used to send our MSG_* messages. Only needed when + * we're the receiver (to send our messages to the generator). */ void set_msg_fd_out(int fd) { msg_fd_out = fd; @@ -185,10 +213,10 @@ struct msg_list *ml; if (!(ml = new(struct msg_list))) - exit_cleanup(RERR_MALLOC); + out_of_memory("msg_list_add"); ml->next = NULL; if (!(ml->buf = new_array(char, len+4))) - exit_cleanup(RERR_MALLOC); + out_of_memory("msg_list_add"); SIVAL(ml->buf, 0, ((code+MPLEX_BASE)<<24) | len); memcpy(ml->buf+4, buf, len); ml->len = len+4; @@ -201,12 +229,18 @@ void send_msg(enum msgcode code, char *buf, int len) { + if (msg_fd_out < 0) { + io_multiplex_write(code, buf, len); + return; + } msg_list_add(code, buf, len); msg_list_push(NORMAL_FLUSH); } -/** Read a message from the MSG_* fd and dispatch it. This is only - * called by the generator. */ +/* Read a message from the MSG_* fd and handle it. This is called either + * during the early stages of being a local sender (up through the sending + * of the file list) or when we're the generator (to fetch the messages + * from the receiver). */ static void read_msg_fd(void) { char buf[2048]; @@ -215,7 +249,7 @@ int tag, len; /* Temporarily disable msg_fd_in. This is needed to avoid looping back - * to this routine from read_timeout() and writefd_unbuffered(). */ + * to this routine from writefd_unbuffered(). */ msg_fd_in = -1; read_loop(fd, buf, 4); @@ -226,19 +260,38 @@ switch (tag) { case MSG_DONE: - if (len != 0) { + if (len != 0 || !am_generator) { rprintf(FERROR, "invalid message %d:%d\n", tag, len); exit_cleanup(RERR_STREAMIO); } - redo_list_add(-1); + flist_ndx_push(&redo_list, -1); break; case MSG_REDO: - if (len != 4) { + if (len != 4 || !am_generator) { rprintf(FERROR, "invalid message %d:%d\n", tag, len); exit_cleanup(RERR_STREAMIO); } read_loop(fd, buf, 4); - redo_list_add(IVAL(buf,0)); + flist_ndx_push(&redo_list, IVAL(buf,0)); + break; + case MSG_DELETED: + if (len >= (int)sizeof buf || !am_generator) { + rprintf(FERROR, "invalid message %d:%d\n", tag, len); + exit_cleanup(RERR_STREAMIO); + } + read_loop(fd, buf, len); + io_multiplex_write(MSG_DELETED, buf, len); + break; + case MSG_SUCCESS: + if (len != 4 || !am_generator) { + rprintf(FERROR, "invalid message %d:%d\n", tag, len); + exit_cleanup(RERR_STREAMIO); + } + read_loop(fd, buf, len); + if (remove_sent_files) + io_multiplex_write(MSG_SUCCESS, buf, len); + if (preserve_hard_links) + flist_ndx_push(&hlink_list, IVAL(buf,0)); break; case MSG_INFO: case MSG_ERROR: @@ -300,22 +353,22 @@ return 1; } -int get_redo_num(void) +int get_redo_num(int itemizing, enum logcode code) { - struct redo_list *next; - int num; - - while (!redo_list_head) + while (1) { + if (hlink_list.head) + check_for_finished_hlinks(itemizing, code); + if (redo_list.head) + break; read_msg_fd(); + } - num = redo_list_head->num; - next = redo_list_head->next; - free(redo_list_head); - redo_list_head = next; - if (!next) - redo_list_tail = NULL; + return flist_ndx_pop(&redo_list); +} - return num; +int get_hlink_num(void) +{ + return flist_ndx_pop(&hlink_list); } /** @@ -337,20 +390,28 @@ io_filesfrom_buflen = 0; } -/** - * It's almost always an error to get an EOF when we're trying to read - * from the network, because the protocol is self-terminating. +/* It's almost always an error to get an EOF when we're trying to read from the + * network, because the protocol is (for the most part) self-terminating. * - * However, there is one unfortunate cases where it is not, which is - * rsync <2.4.6 sending a list of modules on a server, since the list - * is terminated by closing the socket. So, for the section of the - * program where that is a problem (start_socket_client), - * kludge_around_eof is True and we just exit. - */ + * There is one case for the receiver when it is at the end of the transfer + * (hanging around reading any keep-alive packets that might come its way): if + * the sender dies before the generator's kill-signal comes through, we can end + * up here needing to loop until the kill-signal arrives. In this situation, + * kluge_around_eof will be < 0. + * + * There is another case for older protocol versions (< 24) where the module + * listing was not terminated, so we must ignore an EOF error in that case and + * exit. In this situation, kluge_around_eof will be > 0. */ static void whine_about_eof(int fd) { - if (kludge_around_eof && fd == sock_f_in) - exit_cleanup(0); + if (kluge_around_eof && fd == sock_f_in) { + int i; + if (kluge_around_eof > 0) + exit_cleanup(0); + /* If we're still here after 10 seconds, exit with an error. */ + for (i = 10*1000/20; i--; ) + msleep(20); + } rprintf(FERROR, RSYNC_NAME ": connection unexpectedly closed " "(%.0f bytes received so far) [%s]\n", @@ -387,11 +448,7 @@ FD_ZERO(&r_fds); FD_ZERO(&w_fds); FD_SET(fd, &r_fds); - if (msg_fd_in >= 0) { - FD_SET(msg_fd_in, &r_fds); - if (msg_fd_in > maxfd) - maxfd = msg_fd_in; - } else if (msg_list_head) { + if (msg_list_head) { FD_SET(msg_fd_out, &w_fds); if (msg_fd_out > maxfd) maxfd = msg_fd_out; @@ -428,9 +485,7 @@ continue; } - if (msg_fd_in >= 0 && FD_ISSET(msg_fd_in, &r_fds)) - read_msg_fd(); - else if (msg_list_head && FD_ISSET(msg_fd_out, &w_fds)) + if (msg_list_head && FD_ISSET(msg_fd_out, &w_fds)) msg_list_push(NORMAL_FLUSH); if (io_filesfrom_f_out >= 0) { @@ -534,7 +589,7 @@ { char ch, *s, *eob = fname + MAXPATHLEN - 1; int cnt; - int reading_remotely = remote_filesfrom_file != NULL; + int reading_remotely = filesfrom_host != NULL; int nulls = eol_nulls || reading_remotely; start: @@ -610,6 +665,21 @@ } +void maybe_send_keepalive(void) +{ + if (time(NULL) - last_io >= allowed_lull) { + if (!iobuf_out || !iobuf_out_cnt) { + if (protocol_version < 29) + return; /* there's nothing we can do */ + write_int(sock_f_out, the_file_list->count); + write_shortint(sock_f_out, ITEM_IS_NEW); + } + if (iobuf_out) + io_flush(NORMAL_FLUSH); + } +} + + /** * Continue trying to read len bytes - don't return until len has been * read. @@ -636,7 +706,7 @@ static size_t remaining; static size_t iobuf_in_ndx; int tag, ret = 0; - char line[1024]; + char line[MAXPATHLEN+1]; if (!iobuf_in || fd != sock_f_in) return read_timeout(fd, buf, len); @@ -673,11 +743,37 @@ read_loop(fd, iobuf_in, remaining); iobuf_in_ndx = 0; break; + case MSG_DELETED: + if (remaining >= sizeof line) { + rprintf(FERROR, "invalid multi-message %d:%ld\n", + tag, (long)remaining); + exit_cleanup(RERR_STREAMIO); + } + read_loop(fd, line, remaining); + line[remaining] = '\0'; + /* A directory name was sent with the trailing null */ + if (remaining > 0 && !line[remaining-1]) + log_delete(line, S_IFDIR); + else + log_delete(line, S_IFREG); + remaining = 0; + break; + case MSG_SUCCESS: + if (remaining != 4) { + rprintf(FERROR, "invalid multi-message %d:%ld [%s]\n", + tag, (long)remaining, who_am_i()); + 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) { - rprintf(FERROR, "multiplexing overflow %d:%ld\n\n", - tag, (long)remaining); + rprintf(FERROR, + "multiplexing overflow %d:%ld [%s]\n", + tag, (long)remaining, who_am_i()); exit_cleanup(RERR_STREAMIO); } read_loop(fd, line, remaining); @@ -685,7 +781,8 @@ remaining = 0; break; default: - rprintf(FERROR, "unexpected tag %d\n", tag); + rprintf(FERROR, "unexpected tag %d [%s]\n", + tag, who_am_i()); exit_cleanup(RERR_STREAMIO); } } @@ -723,6 +820,14 @@ } +int read_shortint(int f) +{ + uchar b[2]; + readfd(f, (char *)b, 2); + return (b[1] << 8) + b[0]; +} + + int32 read_int(int f) { char b[4]; @@ -744,14 +849,13 @@ if ((int32)ret != (int32)0xffffffff) return ret; -#ifdef INT64_IS_OFF_T - if (sizeof (int64) < 8) { - rprintf(FERROR, "Integer overflow: attempted 64-bit offset\n"); - exit_cleanup(RERR_UNSUPPORTED); - } -#endif +#if SIZEOF_INT64 < 8 + rprintf(FERROR, "Integer overflow: attempted 64-bit offset\n"); + exit_cleanup(RERR_UNSUPPORTED); +#else readfd(f,b,8); ret = IVAL(b,0) | (((int64)IVAL(b,4))<<32); +#endif return ret; } @@ -764,16 +868,77 @@ void read_sbuf(int f,char *buf,size_t len) { readfd(f, buf, len); - buf[len] = 0; + buf[len] = '\0'; } -unsigned char read_byte(int f) +uchar read_byte(int f) { - unsigned char c; + uchar c; readfd(f, (char *)&c, 1); return c; } +int read_vstring(int f, char *buf, int bufsize) +{ + int len = read_byte(f); + + if (len & 0x80) + len = (len & ~0x80) * 0x100 + read_byte(f); + + if (len >= bufsize) { + rprintf(FERROR, "over-long vstring received (%d > %d)\n", + len, bufsize - 1); + return -1; + } + + if (len) + readfd(f, buf, len); + buf[len] = '\0'; + return len; +} + +/* Populate a sum_struct with values from the socket. This is + * called by both the sender and the receiver. */ +void read_sum_head(int f, struct sum_struct *sum) +{ + sum->count = read_int(f); + sum->blength = read_int(f); + if (sum->blength < 0 || sum->blength > MAX_BLOCK_SIZE) { + rprintf(FERROR, "Invalid block length %ld [%s]\n", + (long)sum->blength, who_am_i()); + exit_cleanup(RERR_PROTOCOL); + } + sum->s2length = protocol_version < 27 ? csum_length : (int)read_int(f); + if (sum->s2length < 0 || sum->s2length > MD4_SUM_LENGTH) { + rprintf(FERROR, "Invalid checksum length %d [%s]\n", + sum->s2length, who_am_i()); + exit_cleanup(RERR_PROTOCOL); + } + sum->remainder = read_int(f); + if (sum->remainder < 0 || sum->remainder > sum->blength) { + rprintf(FERROR, "Invalid remainder length %ld [%s]\n", + (long)sum->remainder, who_am_i()); + exit_cleanup(RERR_PROTOCOL); + } +} + +/* Send the values from a sum_struct over the socket. Set sum to + * NULL if there are no checksums to send. This is called by both + * the generator and the sender. */ +void write_sum_head(int f, struct sum_struct *sum) +{ + static struct sum_struct null_sum; + + if (sum == NULL) + sum = &null_sum; + + write_int(f, sum->count); + write_int(f, sum->blength); + if (protocol_version >= 27) + write_int(f, sum->s2length); + write_int(f, sum->remainder); +} + /** * Sleep after writing to limit I/O bandwidth usage. @@ -832,8 +997,8 @@ /* Write len bytes to the file descriptor fd, looping as necessary to get - * the job done and also (in the generator) reading any data on msg_fd_in - * (to avoid deadlock). + * the job done and also (in certain circumstnces) reading any data on + * msg_fd_in to avoid deadlock. * * This function underlies the multiplexing system. The body of the * application never calls this function directly. */ @@ -851,12 +1016,17 @@ FD_SET(fd,&w_fds); maxfd = fd; - if (msg_fd_in >= 0) { + if (msg_fd_in >= 0 && len-total >= contiguous_write_len) { FD_ZERO(&r_fds); FD_SET(msg_fd_in,&r_fds); if (msg_fd_in > maxfd) maxfd = msg_fd_in; } + if (fd != sock_f_out && iobuf_out_cnt && no_flush == 1) { + FD_SET(sock_f_out, &w_fds); + if (sock_f_out > maxfd) + maxfd = sock_f_out; + } tv.tv_sec = select_timeout; tv.tv_usec = 0; @@ -902,7 +1072,8 @@ /* If the other side is sending us error messages, try * to grab any messages they sent before they died. */ while (fd == sock_f_out && io_multiplexing_in) { - io_timeout = 30; + io_timeout = select_timeout = 30; + ignore_timeout = 0; readfd_unbuffered(sock_f_in, io_filesfrom_buf, sizeof io_filesfrom_buf); } @@ -933,6 +1104,13 @@ SIVAL(buffer, 0, ((MPLEX_BASE + (int)code)<<24) + len); + /* When the generator reads messages from the msg_fd_in pipe, it can + * cause output to occur down the socket. Setting contiguous_write_len + * prevents the reading of msg_fd_in once we actually start to write + * this sequence of data (though we might read it before the start). */ + if (am_generator && msg_fd_in >= 0) + contiguous_write_len = len + 4; + if (n > sizeof buffer - 4) n = sizeof buffer - 4; @@ -944,6 +1122,9 @@ if (len) writefd_unbuffered(sock_f_out, buf, len); + + if (am_generator && msg_fd_in >= 0) + contiguous_write_len = 0; } @@ -997,6 +1178,15 @@ } +void write_shortint(int f, int x) +{ + uchar b[2]; + b[0] = x; + b[1] = x >> 8; + writefd(f, (char *)b, 2); +} + + void write_int(int f,int32 x) { char b[4]; @@ -1026,18 +1216,16 @@ return; } -#ifdef INT64_IS_OFF_T - if (sizeof (int64) < 8) { - rprintf(FERROR, "Integer overflow: attempted 64-bit offset\n"); - exit_cleanup(RERR_UNSUPPORTED); - } -#endif - +#if SIZEOF_INT64 < 8 + rprintf(FERROR, "Integer overflow: attempted 64-bit offset\n"); + exit_cleanup(RERR_UNSUPPORTED); +#else write_int(f, (int32)0xFFFFFFFF); SIVAL(b,0,(x&0xFFFFFFFF)); SIVAL(b,4,((x>>32)&0xFFFFFFFF)); writefd(f,b,8); +#endif } void write_buf(int f,char *buf,size_t len) @@ -1051,11 +1239,30 @@ writefd(f, buf, strlen(buf)); } -void write_byte(int f,unsigned char c) +void write_byte(int f, uchar c) { writefd(f, (char *)&c, 1); } +void write_vstring(int f, char *str, int len) +{ + uchar lenbuf[3], *lb = lenbuf; + + if (len > 0x7F) { + if (len > 0x7FFF) { + rprintf(FERROR, + "attempting to send over-long vstring (%d > %d)\n", + len, 0x7FFF); + exit_cleanup(RERR_PROTOCOL); + } + *lb++ = len / 0x100 + 0x80; + } + *lb = len; + + writefd(f, (char*)lenbuf, lb - lenbuf + 1); + if (len) + writefd(f, str, len); +} /** diff -urN --exclude=patches rsync-2.6.3/lib/compat.c rsync-2.6.4/lib/compat.c --- rsync-2.6.3/lib/compat.c 2004-01-19 16:59:26.000000000 -0800 +++ rsync-2.6.4/lib/compat.c 2005-02-13 16:53:44.000000000 -0800 @@ -155,7 +155,7 @@ { unsigned char *p = (unsigned char *)&ip.s_addr; static char buf[18]; -#if WORDS_BIGENDIAN +#ifdef WORDS_BIGENDIAN snprintf(buf, 18, "%d.%d.%d.%d", (int)p[0], (int)p[1], (int)p[2], (int)p[3]); #else @@ -196,7 +196,7 @@ /* some systems don't take the 2nd argument */ int sys_gettimeofday(struct timeval *tv) { -#if HAVE_GETTIMEOFDAY_TZ +#ifdef HAVE_GETTIMEOFDAY_TZ return gettimeofday(tv, NULL); #else return gettimeofday(tv); diff -urN --exclude=patches rsync-2.6.3/lib/getaddrinfo.c rsync-2.6.4/lib/getaddrinfo.c --- rsync-2.6.3/lib/getaddrinfo.c 2004-03-15 17:26:36.000000000 -0800 +++ rsync-2.6.4/lib/getaddrinfo.c 2005-02-13 16:53:44.000000000 -0800 @@ -161,7 +161,7 @@ (*to_ai)->ai_addr = (struct sockaddr *)((*to_ai) + 1); memset((*to_ai)->ai_addr, 0, (afd)->a_socklen); (*to_ai)->ai_addrlen = (afd)->a_socklen; -#if HAVE_SOCKADDR_LEN +#ifdef HAVE_SOCKADDR_LEN (*to_ai)->ai_addr->sa_len = (afd)->a_socklen; #endif (*to_ai)->ai_addr->sa_family = (*to_ai)->ai_family = (afd)->a_af; diff -urN --exclude=patches rsync-2.6.3/lib/getnameinfo.c rsync-2.6.4/lib/getnameinfo.c --- rsync-2.6.3/lib/getnameinfo.c 2004-03-15 17:26:36.000000000 -0800 +++ rsync-2.6.4/lib/getnameinfo.c 2005-02-13 16:53:44.000000000 -0800 @@ -99,7 +99,7 @@ if (sa == NULL) return ENI_NOSOCKET; -#if HAVE_SOCKADDR_LEN +#ifdef HAVE_SOCKADDR_LEN if (sa->sa_len != salen) return ENI_SALEN; #endif diff -urN --exclude=patches rsync-2.6.3/lib/mdfour.c rsync-2.6.4/lib/mdfour.c --- rsync-2.6.3/lib/mdfour.c 2003-09-09 08:58:48.000000000 -0700 +++ rsync-2.6.4/lib/mdfour.c 2005-01-10 12:52:08.000000000 -0800 @@ -206,9 +206,11 @@ } #ifdef TEST_MDFOUR +int protocol_version = 28; + static void file_checksum1(char *fname) { - int fd, i; + int fd, i, was_multiple_of_64 = 1; struct mdfour md; unsigned char buf[64*1024], sum[16]; @@ -222,9 +224,13 @@ while (1) { int n = read(fd, buf, sizeof(buf)); - if (n <= 0) break; + if (n <= 0) + break; + was_multiple_of_64 = !(n % 64); mdfour_update(&md, buf, n); } + if (was_multiple_of_64 && protocol_version >= 27) + mdfour_update(&md, buf, 0); close(fd); diff -urN --exclude=patches rsync-2.6.3/lib/pool_alloc.c rsync-2.6.4/lib/pool_alloc.c --- rsync-2.6.3/lib/pool_alloc.c 2004-04-09 13:17:01.000000000 -0700 +++ rsync-2.6.4/lib/pool_alloc.c 2005-01-20 14:37:38.000000000 -0800 @@ -17,10 +17,10 @@ /* statistical data */ unsigned long e_created; /* extents created */ unsigned long e_freed; /* extents detroyed */ - uint64 n_allocated; /* calls to alloc */ - uint64 n_freed; /* calls to free */ - uint64 b_allocated; /* cum. bytes allocated */ - uint64 b_freed; /* cum. bytes freed */ + int64 n_allocated; /* calls to alloc */ + int64 n_freed; /* calls to free */ + int64 b_allocated; /* cum. bytes allocated */ + int64 b_freed; /* cum. bytes freed */ }; struct pool_extent @@ -34,7 +34,7 @@ struct align_test { void *foo; - uint64 bar; + int64 bar; }; #define MINALIGN offsetof(struct align_test, bar) diff -urN --exclude=patches rsync-2.6.3/lib/snprintf.c rsync-2.6.4/lib/snprintf.c --- rsync-2.6.3/lib/snprintf.c 2003-07-04 08:36:39.000000000 -0700 +++ rsync-2.6.4/lib/snprintf.c 2005-02-21 09:02:53.000000000 -0800 @@ -1,4 +1,8 @@ /* + * NOTE: If you change this file, please merge it into rsync, samba, etc. + */ + +/* * Copyright Patrick Powell 1995 * This code is based on code written by Patrick Powell (papowell@astart.com) * It may be used for any purpose as long as this notice remains intact @@ -53,14 +57,57 @@ * got rid of fcvt code (twas buggy and made testing harder) * added C99 semantics * - * Paul Green (paulg@samba.org) April 9, 2003 - * fixed handling of %f when converting fractions with leading zeros. - * (e.g., 0.025). + * date: 2002/12/19 19:56:31; author: herb; state: Exp; lines: +2 -0 + * actually print args for %g and %e + * + * date: 2002/06/03 13:37:52; author: jmcd; state: Exp; lines: +8 -0 + * Since includes.h isn't included here, VA_COPY has to be defined here. I don't + * see any include file that is guaranteed to be here, so I'm defining it + * locally. Fixes AIX and Solaris builds. + * + * date: 2002/06/03 03:07:24; author: tridge; state: Exp; lines: +5 -13 + * put the ifdef for HAVE_VA_COPY in one place rather than in lots of + * functions + * + * date: 2002/05/17 14:51:22; author: jmcd; state: Exp; lines: +21 -4 + * Fix usage of va_list passed as an arg. Use __va_copy before using it + * when it exists. + * + * date: 2002/04/16 22:38:04; author: idra; state: Exp; lines: +20 -14 + * Fix incorrect zpadlen handling in fmtfp. + * Thanks to Ollie Oldham for spotting it. + * few mods to make it easier to compile the tests. + * addedd the "Ollie" test to the floating point ones. + * + * Martin Pool (mbp@samba.org) April 2003 + * Remove NO_CONFIG_H so that the test case can be built within a source + * tree with less trouble. + * Remove unnecessary SAFE_FREE() definition. + * + * Martin Pool (mbp@samba.org) May 2003 + * Put in a prototype for dummy_snprintf() to quiet compiler warnings. + * + * Move #endif to make sure VA_COPY, LDOUBLE, etc are defined even + * if the C library has some snprintf functions already. **************************************************************/ -#ifndef NO_CONFIG_H /* for some tests */ +#ifndef NO_CONFIG_H #include "config.h" -#endif +#else +#define NULL 0 +#endif + +#ifdef TEST_SNPRINTF /* need math library headers for testing */ + +/* In test mode, we pretend that this system doesn't have any snprintf + * functions, regardless of what config.h says. */ +# undef HAVE_SNPRINTF +# undef HAVE_VSNPRINTF +# undef HAVE_C99_VSNPRINTF +# undef HAVE_ASPRINTF +# undef HAVE_VASPRINTF +# include +#endif /* TEST_SNPRINTF */ #ifdef HAVE_STRING_H #include @@ -82,8 +129,9 @@ /* only include stdio.h if we are not re-defining snprintf or vsnprintf */ #include /* make the compiler happy with an empty file */ + void dummy_snprintf(void); void dummy_snprintf(void) {} -#else +#endif /* HAVE_SNPRINTF, etc */ #ifdef HAVE_LONG_DOUBLE #define LDOUBLE long double @@ -91,21 +139,22 @@ #define LDOUBLE double #endif -#ifdef HAVE_LONG_LONG +#if SIZEOF_LONG_LONG #define LLONG long long #else #define LLONG long #endif -static size_t dopr(char *buffer, size_t maxlen, const char *format, - va_list args); -static void fmtstr(char *buffer, size_t *currlen, size_t maxlen, - char *value, int flags, int min, int max); -static void fmtint(char *buffer, size_t *currlen, size_t maxlen, - long value, int base, int min, int max, int flags); -static void fmtfp(char *buffer, size_t *currlen, size_t maxlen, - LDOUBLE fvalue, int min, int max, int flags); -static void dopr_outch(char *buffer, size_t *currlen, size_t maxlen, char c); +#ifndef VA_COPY +#ifdef HAVE_VA_COPY +#define VA_COPY(dest, src) va_copy(dest, src) +#else +#ifdef HAVE___VA_COPY +#define VA_COPY(dest, src) __va_copy(dest, src) +#else +#define VA_COPY(dest, src) (dest) = (src) +#endif +#endif /* * dopr(): poor man's version of doprintf @@ -141,7 +190,20 @@ #define MAX(p,q) (((p) >= (q)) ? (p) : (q)) #endif -static size_t dopr(char *buffer, size_t maxlen, const char *format, va_list args) +/* yes this really must be a ||. Don't muck with this (tridge) */ +#if !defined(HAVE_VSNPRINTF) || !defined(HAVE_C99_VSNPRINTF) + +static size_t dopr(char *buffer, size_t maxlen, const char *format, + va_list args_in); +static void fmtstr(char *buffer, size_t *currlen, size_t maxlen, + char *value, int flags, int min, int max); +static void fmtint(char *buffer, size_t *currlen, size_t maxlen, + long value, int base, int min, int max, int flags); +static void fmtfp(char *buffer, size_t *currlen, size_t maxlen, + LDOUBLE fvalue, int min, int max, int flags); +static void dopr_outch(char *buffer, size_t *currlen, size_t maxlen, char c); + +static size_t dopr(char *buffer, size_t maxlen, const char *format, va_list args_in) { char ch; LLONG value; @@ -153,6 +215,9 @@ int flags; int cflags; size_t currlen; + va_list args; + + VA_COPY(args, args_in); state = DP_S_DEFAULT; currlen = flags = cflags = min = 0; @@ -322,6 +387,7 @@ fvalue = va_arg (args, LDOUBLE); else fvalue = va_arg (args, double); + fmtfp (buffer, &currlen, maxlen, fvalue, min, max, flags); break; case 'G': flags |= DP_F_UP; @@ -330,12 +396,14 @@ fvalue = va_arg (args, LDOUBLE); else fvalue = va_arg (args, double); + fmtfp (buffer, &currlen, maxlen, fvalue, min, max, flags); break; case 'c': dopr_outch (buffer, &currlen, maxlen, va_arg (args, int)); break; case 's': strvalue = va_arg (args, char *); + if (!strvalue) strvalue = "(NULL)"; if (max == -1) { max = strlen(strvalue); } @@ -564,28 +632,26 @@ for (i=0;i<100;i++) { l = (long)x; - if (l <= (x+1) && l >= (x-1)) break; + if (l <= (x+1) && l >= (x-1)) { + if (i != 0) { + double i2; + double ret; + + ret = my_modf(x0-l*f, &i2); + (*iptr) = l*f + i2; + return ret; + } + + (*iptr) = l; + return x - (*iptr); + } x *= 0.1; f *= 10.0; } - if (i == 100) { - /* yikes! the number is beyond what we can handle. What do we do? */ - (*iptr) = 0; - return 0; - } - - if (i != 0) { - double i2; - double ret; - - ret = my_modf(x0-l*f, &i2); - (*iptr) = l*f + i2; - return ret; - } - - (*iptr) = l; - return x - (*iptr); + /* yikes! the number is beyond what we can handle. What do we do? */ + (*iptr) = 0; + return 0; } @@ -601,7 +667,7 @@ int padlen = 0; /* amount to pad */ int zpadlen = 0; int caps = 0; - int index; + int idx; double intpart; double fracpart; double temp; @@ -658,14 +724,13 @@ /* Convert integer part */ do { - temp = intpart; - my_modf(intpart*0.1, &intpart); - temp = temp*0.1; - index = (int) ((temp -intpart +0.05)* 10.0); - /* index = (int) (((double)(temp*0.1) -intpart +0.05) *10.0); */ - /* printf ("%llf, %f, %x\n", temp, intpart, index); */ + temp = intpart*0.1; + my_modf(temp, &intpart); + idx = (int) ((temp -intpart +0.05)* 10.0); + /* idx = (int) (((double)(temp*0.1) -intpart +0.05) *10.0); */ + /* printf ("%llf, %f, %x\n", temp, intpart, idx); */ iconvert[iplace++] = - (caps? "0123456789ABCDEF":"0123456789abcdef")[index]; + (caps? "0123456789ABCDEF":"0123456789abcdef")[idx]; } while (intpart && (iplace < 311)); if (iplace == 311) iplace--; iconvert[iplace] = 0; @@ -674,14 +739,13 @@ if (fracpart) { do { - temp = fracpart; - my_modf(fracpart*0.1, &fracpart); - temp = temp*0.1; - index = (int) ((temp -fracpart +0.05)* 10.0); - /* index = (int) ((((temp/10) -fracpart) +0.05) *10); */ - /* printf ("%lf, %lf, %ld\n", temp, fracpart, index); */ + temp = fracpart*0.1; + my_modf(temp, &fracpart); + idx = (int) ((temp -fracpart +0.05)* 10.0); + /* idx = (int) ((((temp/10) -fracpart) +0.05) *10); */ + /* printf ("%lf, %lf, %ld\n", temp, fracpart, idx ); */ fconvert[fplace++] = - (caps? "0123456789ABCDEF":"0123456789abcdef")[index]; + (caps? "0123456789ABCDEF":"0123456789abcdef")[idx]; } while(fracpart && (fplace < 311)); if (fplace == 311) fplace--; } @@ -729,14 +793,14 @@ dopr_outch (buffer, currlen, maxlen, '.'); while (zpadlen > 0) { - dopr_outch (buffer, currlen, maxlen, '0'); - --zpadlen; + dopr_outch (buffer, currlen, maxlen, '0'); + --zpadlen; } while (fplace > 0) dopr_outch (buffer, currlen, maxlen, fconvert[--fplace]); } - + while (padlen < 0) { dopr_outch (buffer, currlen, maxlen, ' '); ++padlen; @@ -751,17 +815,21 @@ (*currlen)++; } -#if !defined(HAVE_VSNPRINTF) || !defined(HAVE_C99_VSNPRINTF) -#define vsnprintf rsync_vsnprintf - int vsnprintf(char *str, size_t count, const char *fmt, va_list args) + int rsync_vsnprintf (char *str, size_t count, const char *fmt, va_list args) { return dopr(str, count, fmt, args); } +#define vsnprintf rsync_vsnprintf #endif +/* yes this really must be a ||. Don't muck with this (tridge) + * + * The logic for these two is that we need our own definition if the + * OS *either* has no definition of *sprintf, or if it does have one + * that doesn't work properly according to the autoconf test. + */ #if !defined(HAVE_SNPRINTF) || !defined(HAVE_C99_VSNPRINTF) -#define snprintf rsync_snprintf - int snprintf(char *str,size_t count,const char *fmt,...) +int rsync_snprintf(char *str,size_t count,const char *fmt,...) { size_t ret; va_list ap; @@ -771,6 +839,7 @@ va_end(ap); return ret; } +#define snprintf rsync_snprintf #endif #endif @@ -779,13 +848,19 @@ int vasprintf(char **ptr, const char *format, va_list ap) { int ret; + va_list ap2; + + VA_COPY(ap2, ap); - ret = vsnprintf(NULL, 0, format, ap); + ret = vsnprintf(NULL, 0, format, ap2); if (ret <= 0) return ret; (*ptr) = (char *)malloc(ret+1); if (!*ptr) return -1; - ret = vsnprintf(*ptr, ret+1, format, ap); + + VA_COPY(ap2, ap); + + ret = vsnprintf(*ptr, ret+1, format, ap2); return ret; } @@ -798,6 +873,7 @@ va_list ap; int ret; + *ptr = NULL; va_start(ap, format); ret = vasprintf(ptr, format, ap); va_end(ap); @@ -832,8 +908,9 @@ "-16.16f", NULL }; - double fp_nums[] = { 6442452944.1234, -1.5, 134.21, 91340.2, 341.1234, 0203.9, 0.96, 0.996, - 0.9996, 1.996, 4.136, 0}; + double fp_nums[] = { 6442452944.1234, -1.5, 134.21, 91340.2, 341.1234, 203.9, 0.96, 0.996, + 0.9996, 1.996, 4.136, 5.030201, 0.00205, + /* END LIST */ 0}; char *int_fmt[] = { "%-1.5d", "%1.5d", @@ -928,8 +1005,10 @@ { double v0 = 0.12345678901234567890123456789012345678901; for (x=0; x<100; x++) { - snprintf(buf1, sizeof(buf1), "%1.1f", v0*pow(10, x)); - sprintf(buf2, "%1.1f", v0*pow(10, x)); + double p = pow(10, x); + double r = v0*p; + snprintf(buf1, sizeof(buf1), "%1.1f", r); + sprintf(buf2, "%1.1f", r); if (strcmp(buf1, buf2)) { printf("we seem to support %d digits\n", x-1); break; @@ -939,4 +1018,4 @@ return 0; } -#endif /* SNPRINTF_TEST */ +#endif /* TEST_SNPRINTF */ diff -urN --exclude=patches rsync-2.6.3/lib/wildmatch.c rsync-2.6.4/lib/wildmatch.c --- rsync-2.6.3/lib/wildmatch.c 2003-07-14 08:12:59.000000000 -0700 +++ rsync-2.6.4/lib/wildmatch.c 2005-01-28 13:01:21.000000000 -0800 @@ -57,10 +57,10 @@ int wildmatch_iteration_count; #endif -static int domatch(const unsigned char *p, const unsigned char *text) +static int domatch(const uchar *p, const uchar *text) { int matched, special; - unsigned char ch, prev; + uchar ch, prev; #ifdef WILD_TEST_ITERATIONS wildmatch_iteration_count++; @@ -141,9 +141,9 @@ ch = 0; /* This makes "prev" get set to 0. */ } else if (ch == '[' && p[1] == ':') { - const unsigned char *s = p += 2; + const uchar *s; int i; - while ((ch = *p) && ch != ']') p++; + for (s = p += 2; (ch = *p) && ch != ']'; p++) {} if (!ch) return ABORT_ALL; i = p - s - 1; @@ -225,5 +225,5 @@ #ifdef WILD_TEST_ITERATIONS wildmatch_iteration_count = 0; #endif - return domatch((const unsigned char*)p, (const unsigned char*)t) == TRUE; + return domatch((const uchar*)p, (const uchar*)t) == TRUE; } diff -urN --exclude=patches rsync-2.6.3/loadparm.c rsync-2.6.4/loadparm.c --- rsync-2.6.3/loadparm.c 2004-07-30 13:05:37.000000000 -0700 +++ rsync-2.6.4/loadparm.c 2005-02-19 09:38:51.000000000 -0800 @@ -102,8 +102,10 @@ char *log_file; char *pid_file; char *socket_options; + char *bind_address; int syslog_facility; int max_verbosity; + int rsync_port; } global; static global Globals; @@ -131,6 +133,7 @@ char *auth_users; char *secrets_file; BOOL strict_modes; + char *filter; char *exclude; char *exclude_from; char *include; @@ -173,6 +176,7 @@ NULL, /* auth users */ NULL, /* secrets file */ True, /* strict modes */ + NULL, /* filter */ NULL, /* exclude */ NULL, /* exclude from */ NULL, /* include */ @@ -271,6 +275,8 @@ {"log file", P_STRING, P_GLOBAL, &Globals.log_file, NULL, 0}, {"pid file", P_STRING, P_GLOBAL, &Globals.pid_file, NULL, 0}, {"max verbosity", P_INTEGER, P_GLOBAL, &Globals.max_verbosity, NULL, 0}, + {"port", P_INTEGER, P_GLOBAL, &Globals.rsync_port, NULL, 0}, + {"address", P_STRING, P_GLOBAL, &Globals.bind_address, NULL, 0}, {"timeout", P_INTEGER, P_LOCAL, &sDefault.timeout, NULL, 0}, {"max connections", P_INTEGER, P_LOCAL, &sDefault.max_connections,NULL, 0}, @@ -290,6 +296,7 @@ {"auth users", P_STRING, P_LOCAL, &sDefault.auth_users, NULL, 0}, {"secrets file", P_STRING, P_LOCAL, &sDefault.secrets_file,NULL, 0}, {"strict modes", P_BOOL, P_LOCAL, &sDefault.strict_modes,NULL, 0}, + {"filter", P_STRING, P_LOCAL, &sDefault.filter, NULL, 0}, {"exclude", P_STRING, P_LOCAL, &sDefault.exclude, NULL, 0}, {"exclude from", P_STRING, P_LOCAL, &sDefault.exclude_from,NULL, 0}, {"include", P_STRING, P_LOCAL, &sDefault.include, NULL, 0}, @@ -353,6 +360,8 @@ FN_GLOBAL_STRING(lp_socket_options, &Globals.socket_options) FN_GLOBAL_INTEGER(lp_syslog_facility, &Globals.syslog_facility) FN_GLOBAL_INTEGER(lp_max_verbosity, &Globals.max_verbosity) +FN_GLOBAL_INTEGER(lp_rsync_port, &Globals.rsync_port) +FN_GLOBAL_STRING(lp_bind_address, &Globals.bind_address) FN_LOCAL_STRING(lp_name, name) FN_LOCAL_STRING(lp_comment, comment) @@ -372,6 +381,7 @@ FN_LOCAL_STRING(lp_auth_users, auth_users) FN_LOCAL_STRING(lp_secrets_file, secrets_file) FN_LOCAL_BOOL(lp_strict_modes, strict_modes) +FN_LOCAL_STRING(lp_filter, filter) FN_LOCAL_STRING(lp_exclude, exclude) FN_LOCAL_STRING(lp_exclude_from, exclude_from) FN_LOCAL_STRING(lp_include, include) diff -urN --exclude=patches rsync-2.6.3/log.c rsync-2.6.4/log.c --- rsync-2.6.3/log.c 2004-09-05 14:30:00.000000000 -0700 +++ rsync-2.6.4/log.c 2005-03-30 19:01:26.000000000 -0800 @@ -27,12 +27,19 @@ */ #include "rsync.h" +extern int verbose; +extern int dry_run; extern int am_daemon; extern int am_server; extern int am_sender; +extern int local_server; extern int quiet; extern int module_id; extern int msg_fd_out; +extern int protocol_version; +extern int preserve_times; +extern int log_format_has_o_or_i; +extern int daemon_log_format_has_o_or_i; extern char *auth_user; extern char *log_format; @@ -52,6 +59,7 @@ { RERR_FILESELECT , "errors selecting input/output files, dirs" }, { RERR_UNSUPPORTED, "requested action not supported" }, { RERR_STARTCLIENT, "error starting client-server protocol" }, + { RERR_LOG_FAILURE, "daemon unable to append to log-file" }, { RERR_SOCKETIO , "error in socket IO" }, { RERR_FILEIO , "error in file IO" }, { RERR_STREAMIO , "error in rsync protocol data stream" }, @@ -65,8 +73,9 @@ { RERR_TIMEOUT , "timeout in data send/receive" }, { RERR_CMD_FAILED , "remote shell failed" }, { RERR_CMD_KILLED , "remote shell killed" }, - { RERR_CMD_RUN, "remote command could not be run" }, - { RERR_CMD_NOTFOUND, "remote command not found" }, + { RERR_CMD_RUN , "remote command could not be run" }, + { RERR_CMD_NOTFOUND,"remote command not found" }, + { RERR_DEL_LIMIT , "the --max-delete limit stopped deletions" }, { 0, NULL } }; @@ -146,6 +155,11 @@ int old_umask = umask(022 | orig_umask); logfile = fopen(logfname, "a"); umask(old_umask); + if (!logfile) { + am_daemon = 0; /* avoid trying to log again */ + rsyserr(FERROR, errno, "fopen() of log-file failed"); + exit_cleanup(RERR_LOG_FAILURE); + } } } @@ -178,7 +192,9 @@ return; } - if (am_daemon) { + if (code == FCLIENT) + code = FINFO; + else if (am_daemon) { static int in_block; char msg[2048]; int priority = code == FERROR ? LOG_WARNING : LOG_INFO; @@ -224,7 +240,7 @@ if (buf[len-1] == '\r' || buf[len-1] == '\n') fflush(f); } - + /* This is the rsync debugging function. Call it with FINFO, FERROR or * FLOG. */ @@ -235,7 +251,7 @@ size_t len; va_start(ap, format); - len = vsnprintf(buf, sizeof(buf), format, ap); + len = vsnprintf(buf, sizeof buf, format, ap); va_end(ap); /* Deal with buffer overruns. Instead of panicking, just @@ -245,20 +261,20 @@ const char ellipsis[] = "[...]"; /* Reset length, and zero-terminate the end of our buffer */ - len = sizeof(buf)-1; + len = sizeof buf - 1; buf[len] = '\0'; /* Copy the ellipsis to the end of the string, but give * us one extra character: * - * v--- null byte at buf[sizeof(buf)-1] + * v--- null byte at buf[sizeof buf - 1] * abcdefghij0 * -> abcd[...]00 <-- now two null bytes at end * * If the input format string has a trailing newline, * we copy it into that extra null; if it doesn't, well, * all we lose is one byte. */ - strncpy(buf+len-sizeof(ellipsis), ellipsis, sizeof(ellipsis)); + strncpy(buf+len-sizeof ellipsis, ellipsis, sizeof ellipsis); if (format[strlen(format)-1] == '\n') { buf[len-1] = '\n'; } @@ -304,7 +320,7 @@ void rflush(enum logcode code) { FILE *f = NULL; - + if (am_daemon) { return; } @@ -332,50 +348,96 @@ /* a generic logging routine for send/recv, with parameter * substitiution */ -static void log_formatted(enum logcode code, - char *format, char *op, struct file_struct *file, - struct stats *initial_stats) +static void log_formatted(enum logcode code, char *format, char *op, + struct file_struct *file, struct stats *initial_stats, + int iflags, char *hlink) { - char buf[1024]; - char buf2[1024]; + char buf[MAXPATHLEN+1024], buf2[MAXPATHLEN], fmt[32]; char *p, *s, *n; - size_t l; + size_t len, total; int64 b; + *fmt = '%'; + /* We expand % codes one by one in place in buf. We don't - * copy in the terminating nul of the inserted strings, but - * rather keep going until we reach the nul of the format. - * Just to make sure we don't clobber that nul and therefore - * accidentally keep going, we zero the buffer now. */ - l = strlcpy(buf, format, sizeof buf); - if (l < sizeof buf) - memset(buf + l, 0, sizeof buf - l); - - for (s = &buf[0]; s && (p = strchr(s,'%')); ) { + * copy in the terminating null of the inserted strings, but + * rather keep going until we reach the null of the format. */ + total = strlcpy(buf, format, sizeof buf); + if (total > MAXPATHLEN) { + rprintf(FERROR, "log-format string is WAY too long!\n"); + exit_cleanup(RERR_MESSAGEIO); + } + buf[total++] = '\n'; + buf[total] = '\0'; + + for (p = buf; (p = strchr(p, '%')) != NULL; ) { + s = p++; + n = fmt + 1; + if (*p == '-') + *n++ = *p++; + while (isdigit(*(uchar*)p) && n - fmt < (int)(sizeof fmt) - 8) + *n++ = *p++; + if (!*p) + break; + *n = '\0'; n = NULL; - s = p + 1; - switch (p[1]) { + switch (*p) { case 'h': if (am_daemon) n = client_name(0); break; case 'a': if (am_daemon) n = client_addr(0); break; case 'l': - snprintf(buf2,sizeof(buf2),"%.0f", + strlcat(fmt, ".0f", sizeof fmt); + snprintf(buf2, sizeof buf2, fmt, (double)file->length); n = buf2; break; case 'p': - snprintf(buf2,sizeof(buf2),"%d", - (int)getpid()); + strlcat(fmt, "ld", sizeof fmt); + snprintf(buf2, sizeof buf2, fmt, + (long)getpid()); n = buf2; break; case 'o': n = op; break; case 'f': - pathjoin(buf2, sizeof buf2, - file->basedir ? file->basedir : "", - f_name(file)); - clean_fname(buf2, 0); + n = safe_fname(f_name(file)); + if (am_sender && file->dir.root) { + pathjoin(buf2, sizeof buf2, + file->dir.root, n); + /* The buffer from safe_fname() has more + * room than MAXPATHLEN, so this is safe. */ + if (fmt[1]) + strcpy(n, buf2); + else + n = buf2; + } + clean_fname(n, 0); + if (*n == '/') + n++; + break; + case 'n': + n = safe_fname(f_name(file)); + if (S_ISDIR(file->mode)) { + /* The buffer from safe_fname() has more + * room than MAXPATHLEN, so this is safe. */ + strcat(n, "/"); + } + break; + case 'L': + if (hlink && *hlink) { + n = safe_fname(hlink); + strcpy(buf2, " => "); + } else if (S_ISLNK(file->mode) && file->u.link) { + n = safe_fname(file->u.link); + strcpy(buf2, " -> "); + } else { + n = ""; + if (!fmt[1]) + break; + strcpy(buf2, " "); + } + strlcat(fmt, "s", sizeof fmt); + snprintf(buf2 + 4, sizeof buf2 - 4, fmt, n); n = buf2; - if (*n == '/') n++; break; case 'm': n = lp_name(module_id); break; case 't': n = timestring(time(NULL)); break; @@ -389,7 +451,8 @@ b = stats.total_read - initial_stats->total_read; } - snprintf(buf2,sizeof(buf2),"%.0f", (double)b); + strlcat(fmt, ".0f", sizeof fmt); + snprintf(buf2, sizeof buf2, fmt, (double)b); n = buf2; break; case 'c': @@ -400,62 +463,165 @@ b = stats.total_read - initial_stats->total_read; } - snprintf(buf2,sizeof(buf2),"%.0f", (double)b); + strlcat(fmt, ".0f", sizeof fmt); + snprintf(buf2, sizeof buf2, fmt, (double)b); n = buf2; break; + case 'i': + if (iflags & ITEM_DELETED) { + n = "*deleting"; + break; + } + n = buf2 + MAXPATHLEN - 32; + n[0] = iflags & ITEM_LOCAL_CHANGE + ? iflags & ITEM_XNAME_FOLLOWS ? 'h' : 'c' + : !(iflags & ITEM_TRANSFER) ? '.' + : !local_server && *op == 's' ? '<' : '>'; + n[1] = S_ISDIR(file->mode) ? 'd' + : IS_DEVICE(file->mode) ? 'D' + : S_ISLNK(file->mode) ? 'L' : 'f'; + n[2] = !(iflags & ITEM_REPORT_CHECKSUM) ? '.' : 'c'; + n[3] = !(iflags & ITEM_REPORT_SIZE) ? '.' : 's'; + n[4] = !(iflags & ITEM_REPORT_TIME) ? '.' + : !preserve_times || IS_DEVICE(file->mode) + || S_ISLNK(file->mode) ? 'T' : 't'; + n[5] = !(iflags & ITEM_REPORT_PERMS) ? '.' : 'p'; + n[6] = !(iflags & ITEM_REPORT_OWNER) ? '.' : 'o'; + n[7] = !(iflags & ITEM_REPORT_GROUP) ? '.' : 'g'; + n[8] = !(iflags & ITEM_REPORT_XATTRS) ? '.' : 'a'; + n[9] = '\0'; + + if (iflags & (ITEM_IS_NEW|ITEM_MISSING_DATA)) { + char ch = iflags & ITEM_IS_NEW ? '+' : '?'; + int i; + for (i = 2; n[i]; i++) + n[i] = ch; + } else if (!(iflags & (ITEM_TRANSFER|ITEM_LOCAL_CHANGE))) { + int i; + for (i = 2; n[i]; i++) { + if (n[i] != '.') + break; + } + if (!n[i]) { + for (i = 2; n[i]; i++) + n[i] = ' '; + } + } + break; } - /* n is the string to be inserted in place of this % - * code; l is its length not including the trailing - * NUL */ + /* "n" is the string to be inserted in place of this % code. */ if (!n) continue; + if (n != buf2 && fmt[1]) { + strlcat(fmt, "s", sizeof fmt); + snprintf(buf2, sizeof buf2, fmt, n); + n = buf2; + } + len = strlen(n); - l = strlen(n); + /* Subtract the length of the escape from the string's size. */ + total -= p - s + 1; - if (l + ((int)(s - &buf[0])) >= sizeof(buf)) { - rprintf(FERROR,"buffer overflow expanding %%%c - exiting\n", + if (len + total >= (size_t)sizeof buf) { + rprintf(FERROR, + "buffer overflow expanding %%%c -- exiting\n", p[0]); exit_cleanup(RERR_MESSAGEIO); } /* Shuffle the rest of the string along to make space for n */ - if (l != 2) { - memmove(s+(l-1), s+1, strlen(s+1)+1); - } - - /* Copy in n but NOT its nul, because the format sting - * probably continues after this. */ - memcpy(p, n, l); + if (len != (size_t)(p - s + 1)) + memmove(s + len, p + 1, total - (s - buf) + 1); + total += len; + + /* Insert the contents of string "n", but NOT its null. */ + if (len) + memcpy(s, n, len); /* Skip over inserted string; continue looking */ - s = p+l; + p = s + len; } - rprintf(code,"%s\n", buf); + rwrite(code, buf, total); } -/* log the outgoing transfer of a file */ -void log_send(struct file_struct *file, struct stats *initial_stats) +/* Return 1 if the format escape is in the log-format string (e.g. look for + * the 'b' in the "%9b" format escape). */ +int log_format_has(const char *format, char esc) { - if (lp_transfer_logging(module_id)) { - log_formatted(FLOG, lp_log_format(module_id), "send", file, initial_stats); - } else if (log_format && !am_server) { - log_formatted(FINFO, log_format, "send", file, initial_stats); + const char *p; + + if (!format) + return 0; + + for (p = format; (p = strchr(p, '%')) != NULL; ) { + if (*++p == '-') + p++; + while (isdigit(*(uchar*)p)) + p++; + if (!*p) + break; + if (*p == esc) + return 1; } + return 0; } -/* log the incoming transfer of a file */ -void log_recv(struct file_struct *file, struct stats *initial_stats) +/* log the transfer of a file */ +void log_item(struct file_struct *file, struct stats *initial_stats, + int iflags, char *hlink) { + char *s_or_r = am_sender ? "send" : "recv"; + if (lp_transfer_logging(module_id)) { - log_formatted(FLOG, lp_log_format(module_id), "recv", file, initial_stats); + log_formatted(FLOG, lp_log_format(module_id), s_or_r, + file, initial_stats, iflags, hlink); } else if (log_format && !am_server) { - log_formatted(FINFO, log_format, "recv", file, initial_stats); + log_formatted(FINFO, log_format, s_or_r, + file, initial_stats, iflags, hlink); } } +void maybe_log_item(struct file_struct *file, int iflags, int itemizing, + char *buf) +{ + int see_item = itemizing && (iflags || verbose > 1); + if (am_server) { + if (am_daemon && !dry_run && see_item) + log_item(file, &stats, iflags, buf); + } else if (see_item || iflags & ITEM_LOCAL_CHANGE || *buf + || (S_ISDIR(file->mode) && iflags & SIGNIFICANT_ITEM_FLAGS)) + log_item(file, &stats, iflags, buf); +} + +void log_delete(char *fname, int mode) +{ + static struct file_struct file; + int len = strlen(fname); + char *fmt; + + file.mode = mode; + file.basename = fname; + + if (!verbose && !log_format) + ; + else if (am_server && protocol_version >= 29 && len < MAXPATHLEN) { + if (S_ISDIR(mode)) + len++; /* directories include trailing null */ + send_msg(MSG_DELETED, fname, len); + } else { + fmt = log_format_has_o_or_i ? log_format : "deleting %n"; + log_formatted(FCLIENT, fmt, "del.", &file, &stats, + ITEM_DELETED, NULL); + } + + if (!am_daemon || dry_run || !lp_transfer_logging(module_id)) + return; + fmt = daemon_log_format_has_o_or_i ? lp_log_format(module_id) : "deleting %n"; + log_formatted(FLOG, fmt, "del.", &file, &stats, ITEM_DELETED, NULL); +} /* @@ -467,7 +633,7 @@ void log_exit(int code, const char *file, int line) { if (code == 0) { - rprintf(FLOG,"wrote %.0f bytes read %.0f bytes total size %.0f\n", + rprintf(FLOG,"sent %.0f bytes received %.0f bytes total size %.0f\n", (double)stats.total_written, (double)stats.total_read, (double)stats.total_size); diff -urN --exclude=patches rsync-2.6.3/main.c rsync-2.6.4/main.c --- rsync-2.6.3/main.c 2004-09-29 10:58:07.000000000 -0700 +++ rsync-2.6.4/main.c 2005-03-30 08:55:11.000000000 -0800 @@ -21,25 +21,20 @@ #include "rsync.h" -time_t starttime = 0; - -extern struct stats stats; +extern int verbose; +extern int dry_run; +extern int list_only; extern int am_root; extern int am_server; extern int am_sender; extern int am_generator; extern int am_daemon; -extern int verbose; extern int blocking_io; -extern int cvs_exclude; -extern int delete_mode; -extern int delete_excluded; -extern int delete_after; +extern int remove_sent_files; extern int daemon_over_rsh; +extern int need_messages_from_generator; +extern int kluge_around_eof; extern int do_stats; -extern int dry_run; -extern int list_only; -extern int local_server; extern int log_got_error; extern int module_id; extern int orig_umask; @@ -48,8 +43,11 @@ extern int preserve_hard_links; extern int protocol_version; extern int recurse; +extern int fuzzy_basis; extern int relative_paths; extern int rsync_port; +extern int inplace; +extern int make_backups; extern int whole_file; extern int read_batch; extern int write_batch; @@ -57,16 +55,19 @@ extern int batch_gen_fd; extern int filesfrom_fd; extern pid_t cleanup_child_pid; -extern char *files_from; -extern char *remote_filesfrom_file; +extern struct stats stats; +extern char *filesfrom_host; +extern char *partial_dir; +extern char *basis_dir[]; extern char *rsync_path; extern char *shell_cmd; extern char *batch_name; +int local_server = 0; +struct file_list *the_file_list; -/* there's probably never more than at most 2 outstanding child processes, - * but set it higher just in case. - */ +/* There's probably never more than at most 2 outstanding child processes, + * but set it higher, just in case. */ #define MAXCHILDPROCS 5 struct pid_status { @@ -74,6 +75,9 @@ int status; } pid_stat_table[MAXCHILDPROCS]; +static time_t starttime, endtime; +static int64 total_read, total_written; + static void show_malloc_stats(void); /**************************************************************************** @@ -118,12 +122,13 @@ * the report. All processes might also generate a set of debug stats, if * the verbose level is high enough (this is the only thing that the * generator process and the server receiver ever do here). */ -static void report(int f) +static void handle_stats(int f) { + endtime = time(NULL); + /* Cache two stats because the read/write code can change it. */ - int64 total_read = stats.total_read; - int64 total_written = stats.total_written; - time_t t = time(NULL); + total_read = stats.total_read; + total_written = stats.total_written; if (do_stats && verbose > 1) { /* These come out from every process */ @@ -145,6 +150,10 @@ write_longint(f, total_read); write_longint(f, total_written); write_longint(f, stats.total_size); + if (protocol_version >= 29) { + write_longint(f, stats.flist_buildtime); + write_longint(f, stats.flist_xfertime); + } } return; } @@ -157,12 +166,20 @@ total_written = read_longint(f); total_read = read_longint(f); stats.total_size = read_longint(f); + if (protocol_version >= 29) { + stats.flist_buildtime = read_longint(f); + stats.flist_xfertime = read_longint(f); + } } else if (write_batch) { /* The --read-batch process is going to be a client * receiver, so we need to give it the stats. */ write_longint(batch_fd, total_read); write_longint(batch_fd, total_written); write_longint(batch_fd, stats.total_size); + if (protocol_version >= 29) { + write_longint(batch_fd, stats.flist_buildtime); + write_longint(batch_fd, stats.flist_xfertime); + } } if (do_stats) { @@ -178,17 +195,31 @@ rprintf(FINFO,"Matched data: %.0f bytes\n", (double)stats.matched_data); rprintf(FINFO,"File list size: %d\n", stats.flist_size); + if (stats.flist_buildtime) { + rprintf(FINFO, + "File list generation time: %.3f seconds\n", + (double)stats.flist_buildtime / 1000); + rprintf(FINFO, + "File list transfer time: %.3f seconds\n", + (double)stats.flist_xfertime / 1000); + } rprintf(FINFO,"Total bytes sent: %.0f\n", (double)total_written); rprintf(FINFO,"Total bytes received: %.0f\n", (double)total_read); } + fflush(stdout); + fflush(stderr); +} + +static void output_summary(void) +{ if (verbose || do_stats) { rprintf(FINFO, "\nsent %.0f bytes received %.0f bytes %.2f bytes/sec\n", (double)total_written, (double)total_read, - (total_written + total_read)/(0.5 + (t - starttime))); + (total_written + total_read)/(0.5 + (endtime - starttime))); rprintf(FINFO, "total size is %.0f speedup is %.2f\n", (double)stats.total_size, (double)stats.total_size / (total_written+total_read)); @@ -210,22 +241,30 @@ mi = mallinfo(); rprintf(FINFO, "\n" RSYNC_NAME "[%d] (%s%s%s) heap statistics:\n", - getpid(), - am_server ? "server " : "", - am_daemon ? "daemon " : "", - who_am_i()); - rprintf(FINFO, " arena: %10d (bytes from sbrk)\n", mi.arena); - rprintf(FINFO, " ordblks: %10d (chunks not in use)\n", mi.ordblks); - rprintf(FINFO, " smblks: %10d\n", mi.smblks); - rprintf(FINFO, " hblks: %10d (chunks from mmap)\n", mi.hblks); - rprintf(FINFO, " hblkhd: %10d (bytes from mmap)\n", mi.hblkhd); - rprintf(FINFO, " allmem: %10d (bytes from sbrk + mmap)\n", - mi.arena + mi.hblkhd); - rprintf(FINFO, " usmblks: %10d\n", mi.usmblks); - rprintf(FINFO, " fsmblks: %10d\n", mi.fsmblks); - rprintf(FINFO, " uordblks: %10d (bytes used)\n", mi.uordblks); - rprintf(FINFO, " fordblks: %10d (bytes free)\n", mi.fordblks); - rprintf(FINFO, " keepcost: %10d (bytes in releasable chunk)\n", mi.keepcost); + getpid(), am_server ? "server " : "", + am_daemon ? "daemon " : "", who_am_i()); + rprintf(FINFO, " arena: %10ld (bytes from sbrk)\n", + (long)mi.arena); + rprintf(FINFO, " ordblks: %10ld (chunks not in use)\n", + (long)mi.ordblks); + rprintf(FINFO, " smblks: %10ld\n", + (long)mi.smblks); + rprintf(FINFO, " hblks: %10ld (chunks from mmap)\n", + (long)mi.hblks); + rprintf(FINFO, " hblkhd: %10ld (bytes from mmap)\n", + (long)mi.hblkhd); + rprintf(FINFO, " allmem: %10ld (bytes from sbrk + mmap)\n", + (long)mi.arena + mi.hblkhd); + rprintf(FINFO, " usmblks: %10ld\n", + (long)mi.usmblks); + rprintf(FINFO, " fsmblks: %10ld\n", + (long)mi.fsmblks); + rprintf(FINFO, " uordblks: %10ld (bytes used)\n", + (long)mi.uordblks); + rprintf(FINFO, " fordblks: %10ld (bytes free)\n", + (long)mi.fordblks); + rprintf(FINFO, " keepcost: %10ld (bytes in releasable chunk)\n", + (long)mi.keepcost); #endif /* HAVE_MALLINFO */ } @@ -266,7 +305,7 @@ dash_l_set = 1; } -#if HAVE_REMSH +#ifdef HAVE_REMSH /* remsh (on HPUX) takes the arguments the other way around */ args[argc++] = machine; if (user && !(daemon_over_rsh && dash_l_set)) { @@ -311,7 +350,7 @@ if (verbose > 3) { rprintf(FINFO,"cmd="); for (i = 0; i < argc; i++) - rprintf(FINFO,"%s ",args[i]); + rprintf(FINFO, "%s ", safe_fname(args[i])); rprintf(FINFO,"\n"); } @@ -381,7 +420,7 @@ exit_cleanup(RERR_FILEIO); } if (verbose > 0) - rprintf(FINFO, "created directory %s\n", name); + rprintf(FINFO, "created directory %s\n", safe_fname(name)); if (dry_run) { dry_run++; @@ -398,6 +437,30 @@ } +/* This is only called by the sender. */ +static void read_final_goodbye(int f_in, int f_out) +{ + int i; + + if (protocol_version < 29) + i = read_int(f_in); + else { + while ((i = read_int(f_in)) == the_file_list->count + && read_shortint(f_in) == ITEM_IS_NEW) { + /* Forward the keep-alive (no-op) to the receiver. */ + write_int(f_out, the_file_list->count); + write_shortint(f_out, ITEM_IS_NEW); + } + } + + if (i != -1) { + rprintf(FERROR, "Invalid packet at end of run (%d) [%s]\n", + i, who_am_i()); + exit_cleanup(RERR_PROTOCOL); + } +} + + static void do_server_sender(int f_in, int f_out, int argc,char *argv[]) { int i; @@ -414,6 +477,12 @@ 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", @@ -431,7 +500,7 @@ argv[i] += l+1; } - if (argc == 0 && recurse) { + if (argc == 0 && (recurse || list_only)) { argc = 1; argv--; argv[0] = "."; @@ -441,17 +510,16 @@ if (!flist || flist->count == 0) { exit_cleanup(0); } + the_file_list = flist; io_start_buffering_in(); io_start_buffering_out(); send_files(flist,f_out,f_in); io_flush(FULL_FLUSH); - report(f_out); - if (protocol_version >= 24) { - /* final goodbye message */ - read_int(f_in); - } + handle_stats(f_out); + if (protocol_version >= 24) + read_final_goodbye(f_in, f_out); io_flush(FULL_FLUSH); exit_cleanup(0); } @@ -468,22 +536,21 @@ copy_links = 0; if (preserve_hard_links) - init_hard_links(flist); - - if (!delete_after) { - /* I moved this here from recv_files() to prevent a race condition */ - if (recurse && delete_mode && !local_name && flist->count > 0) - delete_files(flist); - } + init_hard_links(); if (fd_pair(error_pipe) < 0) { - rprintf(FERROR,"error pipe failed in do_recv\n"); - exit_cleanup(RERR_SOCKETIO); + rsyserr(FERROR, errno, "pipe failed in do_recv"); + exit_cleanup(RERR_IPC); } io_flush(NORMAL_FLUSH); - if ((pid = do_fork()) == 0) { + if ((pid = do_fork()) == -1) { + rsyserr(FERROR, errno, "fork failed in do_recv"); + exit_cleanup(RERR_IPC); + } + + if (pid == 0) { close(error_pipe[0]); if (f_in != f_out) close(f_out); @@ -494,15 +561,30 @@ /* set place to send errors */ set_msg_fd_out(error_pipe[1]); - recv_files(f_in,flist,local_name); + recv_files(f_in, flist, local_name); io_flush(FULL_FLUSH); - report(f_in); + handle_stats(f_in); send_msg(MSG_DONE, "", 0); io_flush(FULL_FLUSH); - /* finally we go to sleep until our parent kills us - * with a USR2 signal. We sleep for a short time as on - * some OSes a signal won't interrupt a sleep! */ + + /* Handle any keep-alive packets from the post-processing work + * that the generator does. */ + if (protocol_version >= 29) { + kluge_around_eof = -1; + + /* This should only get stopped via a USR2 signal. */ + while (read_int(f_in) == flist->count + && read_shortint(f_in) == ITEM_IS_NEW) {} + + rprintf(FERROR, "Invalid packet at end of run [%s]\n", + who_am_i()); + exit_cleanup(RERR_PROTOCOL); + } + + /* Finally, we go to sleep until our parent kills us with a + * USR2 signal. We sleep for a short time, as on some OSes + * a signal won't interrupt a sleep! */ while (1) msleep(20); } @@ -522,8 +604,7 @@ generate_files(f_out, flist, local_name); - get_redo_num(); /* Read final MSG_DONE and any prior messages. */ - report(-1); + handle_stats(-1); io_flush(FULL_FLUSH); if (protocol_version >= 24) { /* send a final goodbye message */ @@ -544,6 +625,13 @@ struct file_list *flist; char *local_name = NULL; char *dir = NULL; + int save_verbose = verbose; + + if (filesfrom_fd >= 0) { + /* We can't mix messages with files-from data on the socket, + * so temporarily turn off verbose messages. */ + verbose = 0; + } if (verbose > 2) { rprintf(FINFO, "server_recv(%d) starting pid=%ld\n", @@ -569,23 +657,25 @@ } io_start_buffering_in(); - if (delete_mode && !delete_excluded) - recv_exclude_list(f_in); + recv_filter_list(f_in); if (filesfrom_fd >= 0) { - /* We're receiving the file info from the sender, so we need - * the IO routines to automatically write out the names onto - * our f_out socket as we read the list info from the sender. - * This avoids both deadlock and extra delays/buffers. */ + /* We need to send the files-from names to the sender at the + * same time that we receive the file-list from them, so we + * need the IO routines to automatically write out the names + * onto our f_out socket as we read the file-list. This + * avoids both deadlock and extra delays/buffers. */ io_set_filesfrom_fds(filesfrom_fd, f_out); filesfrom_fd = -1; } flist = recv_file_list(f_in); + verbose = save_verbose; if (!flist) { rprintf(FERROR,"server_recv: recv_file_list error\n"); exit_cleanup(RERR_FILESELECT); } + the_file_list = flist; if (argc > 0) { if (strcmp(dir,".")) { @@ -621,10 +711,10 @@ if (am_sender) { keep_dirlinks = 0; /* Must be disabled on the sender. */ + if (need_messages_from_generator) + io_start_multiplex_in(); - recv_exclude_list(f_in); - if (cvs_exclude) - add_cvs_excludes(); + recv_filter_list(f_in); do_server_sender(f_in, f_out, argc, argv); } else { do_server_recv(f_in, f_out, argc, argv); @@ -644,9 +734,7 @@ char *local_name = NULL; cleanup_child_pid = pid; - if (read_batch) { - assert(am_sender == 0); - } else { + if (!read_batch) { set_nonblocking(f_in); set_nonblocking(f_out); } @@ -670,43 +758,44 @@ if (am_sender) { keep_dirlinks = 0; /* Must be disabled on the sender. */ io_start_buffering_out(); - if (cvs_exclude) - add_cvs_excludes(); - if (delete_mode && !delete_excluded) - send_exclude_list(f_out); - if (remote_filesfrom_file) + if (!filesfrom_host) + set_msg_fd_in(f_in); + send_filter_list(f_out); + if (filesfrom_host) filesfrom_fd = f_in; if (write_batch) start_write_batch(f_out); - if (!read_batch) /* don't write to pipe */ - flist = send_file_list(f_out,argc,argv); + flist = send_file_list(f_out, argc, argv); + set_msg_fd_in(-1); if (verbose > 3) rprintf(FINFO,"file list sent\n"); + the_file_list = flist; io_flush(NORMAL_FLUSH); send_files(flist,f_out,f_in); io_flush(FULL_FLUSH); - if (protocol_version >= 24) { - /* final goodbye message */ - read_int(f_in); - } + handle_stats(-1); + if (protocol_version >= 24) + read_final_goodbye(f_in, f_out); if (pid != -1) { if (verbose > 3) rprintf(FINFO,"client_run waiting on %d\n", (int) pid); io_flush(FULL_FLUSH); wait_process(pid, &status); } - report(-1); + output_summary(); io_flush(FULL_FLUSH); exit_cleanup(status); } + if (need_messages_from_generator && !read_batch) + io_start_multiplex_out(); + if (argc == 0) - list_only = 1; + list_only |= 1; - if (!read_batch) - send_exclude_list(f_out); + send_filter_list(read_batch ? -1 : f_out); if (filesfrom_fd >= 0) { io_set_filesfrom_fds(filesfrom_fd, f_out); @@ -722,6 +811,7 @@ "the --recursive option?\n"); exit_cleanup(0); } + the_file_list = flist; local_name = get_local_name(flist,argv[0]); @@ -777,134 +867,64 @@ if ((rc = copy_argv(argv))) return rc; - /* rsync:// always uses rsync server over direct socket connection */ - if (strncasecmp(URL_PREFIX, argv[0], strlen(URL_PREFIX)) == 0 - && !read_batch) { - char *host, *path; - - host = argv[0] + strlen(URL_PREFIX); - p = strchr(host,'/'); - if (p) { - *p = '\0'; - path = p+1; - } else - path = ""; - if (*host == '[' && (p = strchr(host, ']')) != NULL) { - host++; - *p++ = '\0'; - if (*p != ':') - p = NULL; - } else - p = strchr(host, ':'); - if (p) { - rsync_port = atoi(p+1); - *p = '\0'; - } - return start_socket_client(host, path, argc-1, argv+1); - } - if (!read_batch) { /* for read_batch, NO source is specified */ - p = find_colon(argv[0]); - if (p) { /* source is remote */ - if (remote_filesfrom_file - && remote_filesfrom_file != files_from + 1 - && strncmp(files_from, argv[0], p-argv[0]+1) != 0) { + argc--; + shell_path = check_for_hostspec(argv[0], &shell_machine, &rsync_port); + if (shell_path) { /* source is remote */ + argv++; + if (filesfrom_host && *filesfrom_host + && strcmp(filesfrom_host, shell_machine) != 0) { rprintf(FERROR, "--files-from hostname is not the same as the transfer hostname\n"); exit_cleanup(RERR_SYNTAX); } - if (p[1] == ':') { /* double colon */ - *p = 0; + if (rsync_port) { if (!shell_cmd) { - return start_socket_client(argv[0], p+2, - argc-1, argv+1); + return start_socket_client(shell_machine, + shell_path, + argc, argv); } - p++; daemon_over_rsh = 1; } - if (argc < 1) { /* destination required */ - usage(FERROR); - exit_cleanup(RERR_SYNTAX); - } - am_sender = 0; - *p = 0; - shell_machine = argv[0]; - shell_path = p+1; - argv++; - } else { /* source is local */ + } else { /* source is local, check dest arg */ am_sender = 1; - /* rsync:// destination uses rsync server over direct socket */ - if (strncasecmp(URL_PREFIX, argv[argc-1], strlen(URL_PREFIX)) == 0) { - char *host, *path; - - host = argv[argc-1] + strlen(URL_PREFIX); - p = strchr(host,'/'); - if (p) { - *p = '\0'; - path = p+1; - } else - path = ""; - if (*host == '[' && (p = strchr(host, ']')) != NULL) { - host++; - *p++ = '\0'; - if (*p != ':') - p = NULL; - } else - p = strchr(host, ':'); - if (p) { - rsync_port = atoi(p+1); - *p = '\0'; - } - return start_socket_client(host, path, argc-1, argv); + if (argc < 1) { /* destination required */ + usage(FERROR); + exit_cleanup(RERR_SYNTAX); } - p = find_colon(argv[argc-1]); /* look in dest arg */ - if (p && remote_filesfrom_file - && remote_filesfrom_file != files_from + 1 - && strncmp(files_from, argv[argc-1], p-argv[argc-1]+1) != 0) { + shell_path = check_for_hostspec(argv[argc], &shell_machine, &rsync_port); + if (shell_path && filesfrom_host && *filesfrom_host + && strcmp(filesfrom_host, shell_machine) != 0) { rprintf(FERROR, "--files-from hostname is not the same as the transfer hostname\n"); exit_cleanup(RERR_SYNTAX); } - if (!p) { /* no colon found, so src & dest are local */ + if (!shell_path) { /* no hostspec found, so src & dest are local */ local_server = 1; - if (remote_filesfrom_file) { + if (filesfrom_host) { rprintf(FERROR, "--files-from cannot be remote when the transfer is local\n"); exit_cleanup(RERR_SYNTAX); } - } else if (p[1] == ':') { /* double colon */ - *p = 0; + shell_machine = NULL; + shell_path = argv[argc]; + } else if (rsync_port) { if (!shell_cmd) { - return start_socket_client(argv[argc-1], p+2, - argc-1, argv); + return start_socket_client(shell_machine, + shell_path, + argc, argv); } - p++; daemon_over_rsh = 1; } - - if (argc < 2) { - usage(FERROR); - exit_cleanup(RERR_SYNTAX); - } - - if (local_server) { - shell_machine = NULL; - shell_path = argv[argc-1]; - } else { - *p = 0; - shell_machine = argv[argc-1]; - shell_path = p+1; - } } - argc--; } else { /* read_batch */ local_server = 1; shell_path = argv[argc-1]; - if (find_colon(shell_path)) { + if (check_for_hostspec(shell_path, &shell_machine, &rsync_port)) { rprintf(FERROR, "remote destination is not allowed with --read-batch\n"); exit_cleanup(RERR_SYNTAX); } @@ -921,10 +941,10 @@ if (verbose > 3) { rprintf(FINFO,"cmd=%s machine=%s user=%s path=%s\n", - shell_cmd?shell_cmd:"", - shell_machine?shell_machine:"", - shell_user?shell_user:"", - shell_path?shell_path:""); + shell_cmd ? safe_fname(shell_cmd) : "", + shell_machine ? safe_fname(shell_machine) : "", + shell_user ? safe_fname(shell_user) : "", + shell_path ? safe_fname(shell_path) : ""); } /* for remote source, only single dest arg can remain ... */ @@ -934,9 +954,8 @@ } /* ... or no dest at all */ - if (!am_sender && argc == 0) { - list_only = 1; - } + if (!am_sender && argc == 0) + list_only |= 1; pid = do_cmd(shell_cmd,shell_machine,shell_user,shell_path, &f_in,&f_out); @@ -967,7 +986,11 @@ static RETSIGTYPE sigusr2_handler(UNUSED(int val)) { - if (log_got_error) _exit(RERR_PARTIAL); + if (!am_server) + output_summary(); + close_all(); + if (log_got_error) + _exit(RERR_PARTIAL); _exit(0); } @@ -1113,7 +1136,7 @@ } if (batch_fd < 0) { rsyserr(FERROR, errno, "Batch file %s open error", - batch_name); + full_fname(batch_name)); exit_cleanup(RERR_FILEIO); } if (read_batch) @@ -1128,9 +1151,6 @@ exit_cleanup(RERR_SYNTAX); } - if (dry_run) - verbose = MAX(verbose,1); - if (am_server) { set_nonblocking(STDIN_FILENO); set_nonblocking(STDOUT_FILENO); diff -urN --exclude=patches rsync-2.6.3/match.c rsync-2.6.4/match.c --- rsync-2.6.3/match.c 2004-09-07 14:45:19.000000000 -0700 +++ rsync-2.6.4/match.c 2005-03-05 09:51:23.000000000 -0800 @@ -23,13 +23,13 @@ extern int am_server; extern int do_progress; extern int checksum_seed; -extern int inplace; -extern int make_backups; + +int updating_basis_file; typedef unsigned short tag; #define TABLESIZE (1<<16) -#define NULL_TAG ((size_t)-1) +#define NULL_TAG (-1) static int false_alarms; static int tag_hits; @@ -44,12 +44,12 @@ struct target { tag t; - size_t i; + int32 i; }; static struct target *targets; -static size_t *tag_table; +static int32 *tag_table; #define gettag2(s1,s2) (((s1) + (s2)) & 0xFFFF) #define gettag(sum) gettag2((sum)&0xFFFF,(sum)>>16) @@ -62,10 +62,10 @@ static void build_hash_table(struct sum_struct *s) { - size_t i; + int32 i; if (!tag_table) - tag_table = new_array(size_t, TABLESIZE); + tag_table = new_array(int32, TABLESIZE); targets = new_array(struct target, s->count); if (!tag_table || !targets) @@ -101,17 +101,20 @@ * @param i If >0, the number of a matched token. If 0, indicates we * have only literal data. **/ -static void matched(int f,struct sum_struct *s,struct map_struct *buf, - OFF_T offset,int i) +static void matched(int f, struct sum_struct *s, struct map_struct *buf, + OFF_T offset, int32 i) { - OFF_T n = offset - last_match; - OFF_T j; + int32 n = offset - last_match; /* max value: block_size (int32) */ + int32 j; - if (verbose > 2 && i >= 0) - rprintf(FINFO,"match at %.0f last_match=%.0f j=%d len=%u n=%.0f\n", - (double)offset,(double)last_match,i,s->sums[i].len,(double)n); + if (verbose > 2 && i >= 0) { + rprintf(FINFO, + "match at %.0f last_match=%.0f j=%d len=%ld n=%ld\n", + (double)offset, (double)last_match, i, + (long)s->sums[i].len, (long)n); + } - send_token(f,i,buf,last_match,n,i<0?0:s->sums[i].len); + send_token(f, i, buf, last_match, n, i < 0 ? 0 : s->sums[i].len); data_transfer += n; if (i >= 0) { @@ -120,8 +123,8 @@ } for (j = 0; j < n; j += CHUNK_SIZE) { - int n1 = MIN(CHUNK_SIZE,n-j); - sum_update(map_ptr(buf,last_match+j,n1),n1); + int32 n1 = MIN(CHUNK_SIZE, n - j); + sum_update(map_ptr(buf, last_match + j, n1), n1); } @@ -130,12 +133,8 @@ else last_match = offset; - if (buf && do_progress) { + if (buf && do_progress) show_progress(last_match, buf->file_size); - - if (i == -1) - end_progress(buf->file_size); - } } @@ -143,8 +142,7 @@ struct map_struct *buf, OFF_T len) { OFF_T offset, end, backup; - unsigned int k; - size_t want_i; + int32 k, want_i; char sum2[SUM_LENGTH]; uint32 s1, s2, sum; int more; @@ -155,11 +153,11 @@ want_i = 0; if (verbose > 2) { - rprintf(FINFO,"hash search b=%u len=%.0f\n", - s->blength, (double)len); + rprintf(FINFO, "hash search b=%ld len=%.0f\n", + (long)s->blength, (double)len); } - k = MIN(len, s->blength); + k = (int32)MIN(len, (OFF_T)s->blength); map = (schar *)map_ptr(buf, 0, k); @@ -167,21 +165,21 @@ s1 = sum & 0xFFFF; s2 = sum >> 16; if (verbose > 3) - rprintf(FINFO, "sum=%.8x k=%u\n", sum, k); + rprintf(FINFO, "sum=%.8x k=%ld\n", sum, (long)k); offset = 0; end = len + 1 - s->sums[s->count-1].len; if (verbose > 3) { - rprintf(FINFO, "hash search s->blength=%u len=%.0f count=%.0f\n", - s->blength, (double)len, (double)s->count); + rprintf(FINFO, "hash search s->blength=%ld len=%.0f count=%.0f\n", + (long)s->blength, (double)len, (double)s->count); } do { tag t = gettag2(s1,s2); int done_csum2 = 0; - size_t j = tag_table[t]; + int32 j = tag_table[t]; if (verbose > 4) rprintf(FINFO,"offset=%.0f sum=%08x\n",(double)offset,sum); @@ -192,20 +190,19 @@ sum = (s1 & 0xffff) | (s2 << 16); tag_hits++; do { - unsigned int l; - size_t i = targets[j].i; + int32 l, i = targets[j].i; if (sum != s->sums[i].sum1) continue; /* also make sure the two blocks are the same length */ - l = MIN((OFF_T)s->blength, len-offset); + l = (int32)MIN((OFF_T)s->blength, len-offset); if (l != s->sums[i].len) continue; - /* inplace: ensure chunk's offset is either >= our + /* in-place: ensure chunk's offset is either >= our * offset or that the data didn't move. */ - if (inplace && !make_backups && s->sums[i].offset < offset + if (updating_basis_file && s->sums[i].offset < offset && !(s->sums[i].flags & SUMFLG_SAME_OFFSET)) continue; @@ -224,12 +221,12 @@ continue; } - /* If inplace is enabled, the best possible match is + /* When updating in-place, the best possible match is * one with an identical offset, so we prefer that over * the following want_i optimization. */ - if (inplace && !make_backups) { + if (updating_basis_file) { do { - size_t i2 = targets[j].i; + int32 i2 = targets[j].i; if (s->sums[i2].offset != offset) continue; if (i2 != i) { @@ -250,7 +247,7 @@ /* we've found a match, but now check to see * if want_i can hint at a better match. */ if (i != want_i && want_i < s->count - && (!inplace || make_backups || s->sums[want_i].offset >= offset + && (!updating_basis_file || s->sums[want_i].offset >= offset || s->sums[want_i].flags & SUMFLG_SAME_OFFSET) && sum == s->sums[want_i].sum1 && memcmp(sum2, s->sums[want_i].sum2, s->s2length) == 0) { @@ -263,7 +260,7 @@ matched(f,s,buf,offset,i); offset += s->sums[i].len - 1; - k = MIN(s->blength, len-offset); + k = (int32)MIN((OFF_T)s->blength, len-offset); map = (schar *)map_ptr(buf, offset, k); sum = get_checksum1((char *)map, k); s1 = sum & 0xFFFF; @@ -298,14 +295,12 @@ match. The 3 reads are caused by the running match, the checksum update and the literal send. */ - if (backup >= CHUNK_SIZE + s->blength - && end - offset > CHUNK_SIZE) { - matched(f,s,buf,offset - s->blength, -2); - } + if (backup >= s->blength+CHUNK_SIZE && end-offset > CHUNK_SIZE) + matched(f, s, buf, offset - s->blength, -2); } while (++offset < end); - matched(f,s,buf,len,-1); - map_ptr(buf,len-1,1); + matched(f, s, buf, len, -1); + map_ptr(buf, len-1, 1); } @@ -335,7 +330,7 @@ sum_init(checksum_seed); - if (len > 0 && s->count>0) { + if (len > 0 && s->count > 0) { build_hash_table(s); if (verbose > 2) @@ -348,11 +343,9 @@ } else { OFF_T j; /* by doing this in pieces we avoid too many seeks */ - for (j = 0; j < len-CHUNK_SIZE; j += CHUNK_SIZE) { - int n1 = MIN(CHUNK_SIZE,(len-CHUNK_SIZE)-j); - matched(f,s,buf,j+n1,-2); - } - matched(f,s,buf,len,-1); + for (j = CHUNK_SIZE; j < len; j += CHUNK_SIZE) + matched(f, s, buf, j, -2); + matched(f, s, buf, len, -1); } sum_end(file_sum); diff -urN --exclude=patches rsync-2.6.3/mkproto.awk rsync-2.6.4/mkproto.awk --- rsync-2.6.3/mkproto.awk 2004-01-01 13:10:50.000000000 -0800 +++ rsync-2.6.4/mkproto.awk 2005-02-18 12:16:59.000000000 -0800 @@ -58,7 +58,7 @@ next; } -!/^OFF_T|^size_t|^off_t|^pid_t|^unsigned|^mode_t|^DIR|^user|^int|^char|^uint|^struct|^BOOL|^void|^time|^const/ { +!/^OFF_T|^size_t|^off_t|^pid_t|^unsigned|^mode_t|^DIR|^user|^int|^char|^uint|^uchar|^short|^struct|^BOOL|^void|^time|^const/ { next; } diff -urN --exclude=patches rsync-2.6.3/options.c rsync-2.6.4/options.c --- rsync-2.6.3/options.c 2004-09-23 10:39:05.000000000 -0700 +++ rsync-2.6.4/options.c 2005-03-30 16:21:15.000000000 -0800 @@ -21,10 +21,11 @@ #include "rsync.h" #include "popt.h" +extern int module_id; extern int sanitize_paths; extern int select_timeout; -extern struct exclude_list_struct exclude_list; -extern struct exclude_list_struct server_exclude_list; +extern struct filter_list_struct filter_list; +extern struct filter_list_struct server_filter_list; int make_backups = 0; @@ -48,34 +49,38 @@ int preserve_uid = 0; int preserve_gid = 0; int preserve_times = 0; +int omit_dir_times = 0; int update_only = 0; int cvs_exclude = 0; int dry_run = 0; -int local_server = 0; int ignore_times = 0; int delete_mode = 0; +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; int do_compression = 0; int am_root = 0; +int am_server = 0; +int am_sender = 0; +int am_generator = 0; +int am_starting_up = 1; int orig_umask = 0; int relative_paths = -1; int implied_dirs = 1; int numeric_ids = 0; int force_delete = 0; int io_timeout = 0; -int read_only = 0; -int module_id = -1; -int am_server = 0; -int am_sender = 0; -int am_generator = 0; char *files_from = NULL; int filesfrom_fd = -1; -char *remote_filesfrom_file = NULL; +char *filesfrom_host = NULL; int eol_nulls = 0; int recurse = 0; +int xfer_dirs = 0; int am_daemon = 0; int daemon_over_rsh = 0; int do_stats = 0; @@ -84,18 +89,22 @@ int safe_symlinks = 0; int copy_unsafe_links = 0; int size_only = 0; +int daemon_bwlimit = 0; int bwlimit = 0; +int fuzzy_basis = 0; size_t bwlimit_writemax = 0; -int delete_after = 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; int modify_window = 0; int blocking_io = -1; int checksum_seed = 0; int inplace = 0; -unsigned int block_size = 0; +int delay_updates = 0; +long block_size = 0; /* "long" because popt can't set an int32. */ /** Network address family. **/ @@ -108,7 +117,12 @@ /** Do not go into the background when run as --daemon. Good * for debugging and required for running as a service on W32, * or under Unix process-monitors. **/ -int no_detach = 0; +int no_detach +#if defined _WIN32 || defined __WIN32__ + = 1; +#else + = 0; +#endif int write_batch = 0; int read_batch = 0; @@ -119,7 +133,7 @@ char *backup_suffix = NULL; char *tmpdir = NULL; char *partial_dir = NULL; -char *compare_dest = NULL; +char *basis_dir[MAX_BASIS_DIRS+1]; char *config_file = NULL; char *shell_cmd = NULL; char *log_format = NULL; @@ -127,11 +141,18 @@ char *rsync_path = RSYNC_PATH; char *backup_dir = NULL; char backup_dir_buf[MAXPATHLEN]; -int rsync_port = RSYNC_PORT; +int rsync_port = 0; +int compare_dest = 0; +int copy_dest = 0; int link_dest = 0; +int basis_dir_cnt = 0; +char *dest_option = NULL; int verbose = 0; int quiet = 0; +int log_before_transfer = 0; +int log_format_has_i = 0; +int log_format_has_o_or_i = 0; int always_checksum = 0; int list_only = 0; @@ -139,7 +160,13 @@ char *batch_name = NULL; static int daemon_opt; /* sets am_daemon after option error-reporting */ +static int F_option_cnt = 0; static int modify_window_set; +static int itemize_changes = 0; +static int refused_delete, refused_archive_part; +static int refused_partial, refused_progress, refused_delete_before; +static char *max_size_arg; +static char partialdir_for_delayupdate[] = ".~tmp~"; /** Local address to bind. As a character string because it's * interpreted by the IPv6 layer: should be a numeric IP4 or IP6 @@ -160,26 +187,26 @@ got_socketpair = ""; #endif -#if HAVE_FTRUNCATE +#ifdef HAVE_FTRUNCATE have_inplace = ""; #endif -#if SUPPORT_HARD_LINKS +#ifdef SUPPORT_HARD_LINKS hardlinks = ""; #endif -#if SUPPORT_LINKS +#ifdef SUPPORT_LINKS links = ""; #endif -#if INET6 +#ifdef INET6 ipv6 = ""; #endif rprintf(f, "%s version %s protocol version %d\n", RSYNC_NAME, RSYNC_VERSION, PROTOCOL_VERSION); rprintf(f, - "Copyright (C) 1996-2004 by Andrew Tridgell and others\n"); + "Copyright (C) 1996-2005 by Andrew Tridgell and others\n"); rprintf(f, "\n"); rprintf(f, "Capabilities: %d-bit files, %ssocketpairs, " "%shard links, %ssymlinks, batchfiles, \n", @@ -192,16 +219,20 @@ rprintf(f, " %sinplace, %sIPv6, %d-bit system inums, %d-bit internal inums\n", have_inplace, ipv6, (int) (sizeof dumstat->st_ino * 8), - (int) (sizeof (uint64) * 8)); + (int) (sizeof (int64) * 8)); #ifdef MAINTAINER_MODE rprintf(f, " panic action: \"%s\"\n", get_panic_action()); #endif -#ifdef INT64_IS_OFF_T - if (sizeof (int64) < 8) - rprintf(f, "WARNING: no 64-bit integers on this platform!\n"); +#if SIZEOF_INT64 < 8 + rprintf(f, "WARNING: no 64-bit integers on this platform!\n"); #endif + if (sizeof (int64) != SIZEOF_INT64) { + rprintf(f, + "WARNING: size mismatch in SIZEOF_INT64 define (%d != %d)\n", + (int) SIZEOF_INT64, (int) sizeof (int64)); + } rprintf(f, "\n" @@ -230,101 +261,111 @@ rprintf(F," sources separated by space as long as they have same top-level\n"); rprintf(F,"\nOptions\n"); rprintf(F," -v, --verbose increase verbosity\n"); - rprintf(F," -q, --quiet decrease verbosity\n"); - rprintf(F," -c, --checksum always checksum\n"); - rprintf(F," -a, --archive archive mode, equivalent to -rlptgoD\n"); + rprintf(F," -q, --quiet suppress non-error messages\n"); + rprintf(F," -c, --checksum skip based on checksum, not mod-time & size\n"); + rprintf(F," -a, --archive archive mode; same as -rlptgoD (no -H)\n"); rprintf(F," -r, --recursive recurse into directories\n"); rprintf(F," -R, --relative use relative path names\n"); rprintf(F," --no-relative turn off --relative\n"); rprintf(F," --no-implied-dirs don't send implied dirs with -R\n"); rprintf(F," -b, --backup make backups (see --suffix & --backup-dir)\n"); - rprintf(F," --backup-dir make backups into this directory\n"); - rprintf(F," --suffix=SUFFIX backup suffix (default %s w/o --backup-dir)\n",BACKUP_SUFFIX); - rprintf(F," -u, --update update only (don't overwrite newer files)\n"); - rprintf(F," --inplace update destination files inplace (SEE MAN PAGE)\n"); - rprintf(F," -K, --keep-dirlinks treat symlinked dir on receiver as dir\n"); + rprintf(F," --backup-dir=DIR make backups into hierarchy based in DIR\n"); + rprintf(F," --suffix=SUFFIX set backup suffix (default %s w/o --backup-dir)\n",BACKUP_SUFFIX); + rprintf(F," -u, --update skip files that are newer on the receiver\n"); + rprintf(F," --inplace update destination files in-place (SEE MAN PAGE)\n"); + rprintf(F," -d, --dirs transfer directories without recursing\n"); rprintf(F," -l, --links copy symlinks as symlinks\n"); - rprintf(F," -L, --copy-links copy the referent of all symlinks\n"); - rprintf(F," --copy-unsafe-links copy the referent of \"unsafe\" symlinks\n"); - rprintf(F," --safe-links ignore \"unsafe\" symlinks\n"); + rprintf(F," -L, --copy-links transform symlink into referent file/dir\n"); + rprintf(F," --copy-unsafe-links only \"unsafe\" symlinks are transformed\n"); + rprintf(F," --safe-links ignore symlinks that point outside the source tree\n"); rprintf(F," -H, --hard-links preserve hard links\n"); + rprintf(F," -K, --keep-dirlinks treat symlinked dir on receiver as dir\n"); rprintf(F," -p, --perms preserve permissions\n"); rprintf(F," -o, --owner preserve owner (root only)\n"); rprintf(F," -g, --group preserve group\n"); rprintf(F," -D, --devices preserve devices (root only)\n"); rprintf(F," -t, --times preserve times\n"); + rprintf(F," -O, --omit-dir-times omit directories when preserving times\n"); rprintf(F," -S, --sparse handle sparse files efficiently\n"); rprintf(F," -n, --dry-run show what would have been transferred\n"); - rprintf(F," -W, --whole-file copy whole files, no incremental checks\n"); - rprintf(F," --no-whole-file turn off --whole-file\n"); + rprintf(F," -W, --whole-file copy files whole (without rsync algorithm)\n"); + rprintf(F," --no-whole-file always use incremental rsync algorithm\n"); rprintf(F," -x, --one-file-system don't cross filesystem boundaries\n"); rprintf(F," -B, --block-size=SIZE force a fixed checksum block-size\n"); - rprintf(F," -e, --rsh=COMMAND specify the remote shell\n"); - rprintf(F," --rsync-path=PATH specify path to rsync on the remote machine\n"); - rprintf(F," --existing only update files that already exist\n"); + rprintf(F," -e, --rsh=COMMAND specify the remote shell to use\n"); + rprintf(F," --rsync-path=PROGRAM specify the rsync to run 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 sent files/symlinks 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"); + rprintf(F," --delete-during receiver deletes during transfer, not before\n"); + rprintf(F," --delete-after receiver deletes after transfer, not before\n"); rprintf(F," --delete-excluded also delete excluded files on the receiving side\n"); - rprintf(F," --delete-after receiver deletes after transferring, not before\n"); rprintf(F," --ignore-errors delete even if there are I/O errors\n"); + rprintf(F," --force force deletion of directories even if not empty\n"); rprintf(F," --max-delete=NUM don't delete more than NUM files\n"); + rprintf(F," --max-size=SIZE don't transfer any file larger than SIZE\n"); rprintf(F," --partial keep partially transferred files\n"); rprintf(F," --partial-dir=DIR put a partially transferred file into DIR\n"); - rprintf(F," --force force deletion of directories even if not empty\n"); + rprintf(F," --delay-updates put all updated files into place at transfer's end\n"); rprintf(F," --numeric-ids don't map uid/gid values by user/group name\n"); rprintf(F," --timeout=TIME set I/O timeout in seconds\n"); - rprintf(F," -I, --ignore-times turn off mod time & file size quick check\n"); - rprintf(F," --size-only ignore mod time for quick check (use size)\n"); - rprintf(F," --modify-window=NUM compare mod times with reduced accuracy\n"); + rprintf(F," -I, --ignore-times don't skip files that match in size and mod-time\n"); + rprintf(F," --size-only skip files that match in size\n"); + rprintf(F," --modify-window=NUM compare mod-times with reduced accuracy\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"); rprintf(F," --compare-dest=DIR also compare destination files relative to DIR\n"); - rprintf(F," --link-dest=DIR create hardlinks to DIR for unchanged files\n"); - rprintf(F," -P equivalent to --partial --progress\n"); - rprintf(F," -z, --compress compress file data\n"); - rprintf(F," -C, --cvs-exclude auto ignore files in the same way CVS does\n"); + rprintf(F," --copy-dest=DIR ... and include copies of unchanged files\n"); + rprintf(F," --link-dest=DIR hardlink to files in DIR when unchanged\n"); + rprintf(F," -z, --compress compress file data during the transfer\n"); + rprintf(F," -C, --cvs-exclude auto-ignore files the same way CVS does\n"); + rprintf(F," -f, --filter=RULE add a file-filtering RULE\n"); + rprintf(F," -F same as --filter='dir-merge /.rsync-filter'\n"); + rprintf(F," repeated: --filter='- .rsync-filter'\n"); rprintf(F," --exclude=PATTERN exclude files matching PATTERN\n"); - rprintf(F," --exclude-from=FILE exclude patterns listed in FILE\n"); + rprintf(F," --exclude-from=FILE read exclude patterns from FILE\n"); rprintf(F," --include=PATTERN don't exclude files matching PATTERN\n"); - rprintf(F," --include-from=FILE don't exclude patterns listed in FILE\n"); - rprintf(F," --files-from=FILE read FILE for list of source-file names\n"); + rprintf(F," --include-from=FILE read include patterns from FILE\n"); + rprintf(F," --files-from=FILE read list of source-file names from FILE\n"); rprintf(F," -0, --from0 all *-from file lists are delimited by nulls\n"); rprintf(F," --version print version number\n"); - rprintf(F," --daemon run as an rsync daemon\n"); - rprintf(F," --no-detach do not detach from the parent\n"); - rprintf(F," --address=ADDRESS bind to the specified address\n"); - rprintf(F," --config=FILE specify alternate rsyncd.conf file\n"); - rprintf(F," --port=PORT specify alternate rsyncd port number\n"); + rprintf(F," --port=PORT specify double-colon alternate port number\n"); rprintf(F," --blocking-io use blocking I/O for the remote shell\n"); - rprintf(F," --no-blocking-io turn off --blocking-io\n"); - rprintf(F," --stats give some file transfer stats\n"); + rprintf(F," --no-blocking-io turn off blocking I/O when it is the default\n"); + rprintf(F," --stats give some file-transfer stats\n"); rprintf(F," --progress show progress during transfer\n"); - rprintf(F," --log-format=FORMAT log file transfers using specified format\n"); - rprintf(F," --password-file=FILE get password from FILE\n"); - rprintf(F," --bwlimit=KBPS limit I/O bandwidth, KBytes per second\n"); - rprintf(F," --write-batch=FILE write a batch to FILE\n"); - rprintf(F," --read-batch=FILE read a batch from FILE\n"); - rprintf(F," --checksum-seed=NUM set block/file checksum seed\n"); + rprintf(F," -P same as --partial --progress\n"); + rprintf(F," -i, --itemize-changes output a change-summary for all updates\n"); + rprintf(F," --log-format=FORMAT log file-transfers using specified format\n"); + rprintf(F," --password-file=FILE read password from FILE\n"); + rprintf(F," --list-only list the files instead of copying them\n"); + rprintf(F," --bwlimit=KBPS limit I/O bandwidth; KBytes per second\n"); + rprintf(F," --write-batch=FILE write a batched update to FILE\n"); + rprintf(F," --read-batch=FILE read a batched update from FILE\n"); + rprintf(F," --protocol=NUM force an older protocol version to be used\n"); #ifdef INET6 rprintf(F," -4, --ipv4 prefer IPv4\n"); rprintf(F," -6, --ipv6 prefer IPv6\n"); #endif rprintf(F," -h, --help show this help screen\n"); - rprintf(F,"\n"); - - rprintf(F,"\nPlease see the rsync(1) and rsyncd.conf(5) man pages for full documentation\n"); + rprintf(F,"\nUse \"rsync --daemon --help\" to see the daemon-mode command-line options.\n"); + rprintf(F,"Please see the rsync(1) and rsyncd.conf(5) man pages for full documentation.\n"); rprintf(F,"See http://rsync.samba.org/ for updates, bug reports, and answers\n"); } -enum {OPT_VERSION = 1000, OPT_SENDER, OPT_EXCLUDE, OPT_EXCLUDE_FROM, - OPT_DELETE_AFTER, OPT_DELETE_EXCLUDED, OPT_LINK_DEST, +enum {OPT_VERSION = 1000, OPT_DAEMON, OPT_SENDER, OPT_EXCLUDE, OPT_EXCLUDE_FROM, + OPT_FILTER, OPT_COMPARE_DEST, OPT_COPY_DEST, OPT_LINK_DEST, OPT_INCLUDE, OPT_INCLUDE_FROM, OPT_MODIFY_WINDOW, - OPT_READ_BATCH, OPT_WRITE_BATCH, OPT_TIMEOUT, + OPT_READ_BATCH, OPT_WRITE_BATCH, OPT_TIMEOUT, OPT_MAX_SIZE, OPT_REFUSED_BASE = 9000}; static struct poptOption long_options[] = { /* longName, shortName, argInfo, argPtr, value, descrip, argDesc */ - {"version", 0, POPT_ARG_NONE, 0, OPT_VERSION, 0, 0}, + {"version", 0, POPT_ARG_NONE, 0, OPT_VERSION, 0, 0}, {"suffix", 0, POPT_ARG_STRING, &backup_suffix, 0, 0, 0 }, {"rsync-path", 0, POPT_ARG_STRING, &rsync_path, 0, 0, 0 }, {"password-file", 0, POPT_ARG_STRING, &password_file, 0, 0, 0 }, @@ -332,73 +373,83 @@ {"size-only", 0, POPT_ARG_NONE, &size_only, 0, 0, 0 }, {"modify-window", 0, POPT_ARG_INT, &modify_window, OPT_MODIFY_WINDOW, 0, 0 }, {"one-file-system", 'x', POPT_ARG_NONE, &one_file_system, 0, 0, 0 }, - {"delete", 0, POPT_ARG_NONE, &delete_mode, 0, 0, 0 }, {"existing", 0, POPT_ARG_NONE, &only_existing, 0, 0, 0 }, {"ignore-existing", 0, POPT_ARG_NONE, &opt_ignore_existing, 0, 0, 0 }, - {"delete-after", 0, POPT_ARG_NONE, 0, OPT_DELETE_AFTER, 0, 0 }, - {"delete-excluded", 0, POPT_ARG_NONE, 0, OPT_DELETE_EXCLUDED, 0, 0 }, + {"del", 0, POPT_ARG_NONE, &delete_during, 0, 0, 0 }, + {"delete", 0, POPT_ARG_NONE, &delete_mode, 0, 0, 0 }, + {"delete-before", 0, POPT_ARG_VAL, &delete_before, 2, 0, 0 }, + {"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 }, - {"exclude", 0, POPT_ARG_STRING, 0, OPT_EXCLUDE, 0, 0 }, - {"include", 0, POPT_ARG_STRING, 0, OPT_INCLUDE, 0, 0 }, - {"exclude-from", 0, POPT_ARG_STRING, 0, OPT_EXCLUDE_FROM, 0, 0 }, - {"include-from", 0, POPT_ARG_STRING, 0, OPT_INCLUDE_FROM, 0, 0 }, + {"filter", 'f', POPT_ARG_STRING, 0, OPT_FILTER, 0, 0 }, + {"exclude", 0, POPT_ARG_STRING, 0, OPT_EXCLUDE, 0, 0 }, + {"include", 0, POPT_ARG_STRING, 0, OPT_INCLUDE, 0, 0 }, + {"exclude-from", 0, POPT_ARG_STRING, 0, OPT_EXCLUDE_FROM, 0, 0 }, + {"include-from", 0, POPT_ARG_STRING, 0, OPT_INCLUDE_FROM, 0, 0 }, {"safe-links", 0, POPT_ARG_NONE, &safe_symlinks, 0, 0, 0 }, - {"help", 'h', POPT_ARG_NONE, 0, 'h', 0, 0 }, + {"help", 'h', POPT_ARG_NONE, 0, 'h', 0, 0 }, {"backup", 'b', POPT_ARG_NONE, &make_backups, 0, 0, 0 }, {"dry-run", 'n', POPT_ARG_NONE, &dry_run, 0, 0, 0 }, {"sparse", 'S', POPT_ARG_NONE, &sparse_files, 0, 0, 0 }, {"cvs-exclude", 'C', POPT_ARG_NONE, &cvs_exclude, 0, 0, 0 }, {"update", 'u', POPT_ARG_NONE, &update_only, 0, 0, 0 }, {"inplace", 0, POPT_ARG_NONE, &inplace, 0, 0, 0 }, - {"keep-dirlinks", 'K', POPT_ARG_NONE, &keep_dirlinks, 0, 0, 0 }, + {"dirs", 'd', POPT_ARG_VAL, &xfer_dirs, 2, 0, 0 }, {"links", 'l', POPT_ARG_NONE, &preserve_links, 0, 0, 0 }, {"copy-links", 'L', POPT_ARG_NONE, ©_links, 0, 0, 0 }, + {"keep-dirlinks", 'K', POPT_ARG_NONE, &keep_dirlinks, 0, 0, 0 }, {"whole-file", 'W', POPT_ARG_VAL, &whole_file, 1, 0, 0 }, {"no-whole-file", 0, POPT_ARG_VAL, &whole_file, 0, 0, 0 }, - {"copy-unsafe-links", 0, POPT_ARG_NONE, ©_unsafe_links, 0, 0, 0 }, + {"copy-unsafe-links",0, POPT_ARG_NONE, ©_unsafe_links, 0, 0, 0 }, {"perms", 'p', POPT_ARG_NONE, &preserve_perms, 0, 0, 0 }, {"owner", 'o', POPT_ARG_NONE, &preserve_uid, 0, 0, 0 }, {"group", 'g', POPT_ARG_NONE, &preserve_gid, 0, 0, 0 }, {"devices", 'D', POPT_ARG_NONE, &preserve_devices, 0, 0, 0 }, {"times", 't', POPT_ARG_NONE, &preserve_times, 0, 0, 0 }, + {"omit-dir-times", 'O', POPT_ARG_VAL, &omit_dir_times, 2, 0, 0 }, {"checksum", 'c', POPT_ARG_NONE, &always_checksum, 0, 0, 0 }, - {"verbose", 'v', POPT_ARG_NONE, 0, 'v', 0, 0 }, - {"quiet", 'q', POPT_ARG_NONE, 0, 'q', 0, 0 }, + {"verbose", 'v', POPT_ARG_NONE, 0, 'v', 0, 0 }, + {"quiet", 'q', POPT_ARG_NONE, 0, 'q', 0, 0 }, {"archive", 'a', POPT_ARG_NONE, &archive_mode, 0, 0, 0 }, {"server", 0, POPT_ARG_NONE, &am_server, 0, 0, 0 }, - {"sender", 0, POPT_ARG_NONE, 0, OPT_SENDER, 0, 0 }, + {"sender", 0, POPT_ARG_NONE, 0, OPT_SENDER, 0, 0 }, {"recursive", 'r', POPT_ARG_NONE, &recurse, 0, 0, 0 }, + {"list-only", 0, POPT_ARG_VAL, &list_only, 2, 0, 0 }, {"relative", 'R', POPT_ARG_VAL, &relative_paths, 1, 0, 0 }, {"no-relative", 0, POPT_ARG_VAL, &relative_paths, 0, 0, 0 }, {"rsh", 'e', POPT_ARG_STRING, &shell_cmd, 0, 0, 0 }, - {"block-size", 'B', POPT_ARG_INT, &block_size, 0, 0, 0 }, + {"block-size", 'B', POPT_ARG_LONG, &block_size, 0, 0, 0 }, {"max-delete", 0, POPT_ARG_INT, &max_delete, 0, 0, 0 }, + {"max-size", 0, POPT_ARG_STRING, &max_size_arg, OPT_MAX_SIZE, 0, 0 }, {"timeout", 0, POPT_ARG_INT, &io_timeout, OPT_TIMEOUT, 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, &compare_dest, OPT_LINK_DEST, 0, 0 }, + {"compare-dest", 0, POPT_ARG_STRING, 0, OPT_COMPARE_DEST, 0, 0 }, + {"copy-dest", 0, POPT_ARG_STRING, 0, OPT_COPY_DEST, 0, 0 }, + {"link-dest", 0, POPT_ARG_STRING, 0, OPT_LINK_DEST, 0, 0 }, + {"fuzzy", 'y', POPT_ARG_NONE, &fuzzy_basis, 0, 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, &daemon_opt, 0, 0, 0 }, - {"no-detach", 0, POPT_ARG_NONE, &no_detach, 0, 0, 0 }, {"stats", 0, POPT_ARG_NONE, &do_stats, 0, 0, 0 }, {"progress", 0, POPT_ARG_NONE, &do_progress, 0, 0, 0 }, {"partial", 0, POPT_ARG_NONE, &keep_partial, 0, 0, 0 }, {"partial-dir", 0, POPT_ARG_STRING, &partial_dir, 0, 0, 0 }, + {"delay-updates", 0, POPT_ARG_NONE, &delay_updates, 0, 0, 0 }, {"ignore-errors", 0, POPT_ARG_NONE, &ignore_errors, 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 }, - {0, 'P', POPT_ARG_NONE, 0, 'P', 0, 0 }, - {"config", 0, POPT_ARG_STRING, &config_file, 0, 0, 0 }, + {0, 'F', POPT_ARG_NONE, 0, 'F', 0, 0 }, + {0, 'P', POPT_ARG_NONE, 0, 'P', 0, 0 }, {"port", 0, POPT_ARG_INT, &rsync_port, 0, 0, 0 }, {"log-format", 0, POPT_ARG_STRING, &log_format, 0, 0, 0 }, + {"itemize-changes", 'i', POPT_ARG_NONE, &itemize_changes, 0, 0, 0 }, {"bwlimit", 0, POPT_ARG_INT, &bwlimit, 0, 0, 0 }, - {"address", 0, POPT_ARG_STRING, &bind_address, 0, 0, 0 }, {"backup-dir", 0, POPT_ARG_STRING, &backup_dir, 0, 0, 0 }, {"hard-links", 'H', POPT_ARG_NONE, &preserve_hard_links, 0, 0, 0 }, - {"read-batch", 0, POPT_ARG_STRING, &batch_name, OPT_READ_BATCH, 0, 0 }, - {"write-batch", 0, POPT_ARG_STRING, &batch_name, OPT_WRITE_BATCH, 0, 0 }, + {"read-batch", 0, POPT_ARG_STRING, &batch_name, OPT_READ_BATCH, 0, 0 }, + {"write-batch", 0, POPT_ARG_STRING, &batch_name, OPT_WRITE_BATCH, 0, 0 }, {"files-from", 0, POPT_ARG_STRING, &files_from, 0, 0, 0 }, {"from0", '0', POPT_ARG_NONE, &eol_nulls, 0, 0, 0}, {"no-implied-dirs", 0, POPT_ARG_VAL, &implied_dirs, 0, 0, 0 }, @@ -408,6 +459,53 @@ {"ipv4", '4', POPT_ARG_VAL, &default_af_hint, AF_INET, 0, 0 }, {"ipv6", '6', POPT_ARG_VAL, &default_af_hint, AF_INET6, 0, 0 }, #endif + /* All these options switch us into daemon-mode option-parsing. */ + {"address", 0, POPT_ARG_STRING, 0, OPT_DAEMON, 0, 0 }, + {"config", 0, POPT_ARG_STRING, 0, OPT_DAEMON, 0, 0 }, + {"daemon", 0, POPT_ARG_NONE, 0, OPT_DAEMON, 0, 0 }, + {"detach", 0, POPT_ARG_NONE, 0, OPT_DAEMON, 0, 0 }, + {"no-detach", 0, POPT_ARG_NONE, 0, OPT_DAEMON, 0, 0 }, + {0,0,0,0, 0, 0, 0} +}; + +static void daemon_usage(enum logcode F) +{ + print_rsync_version(F); + + rprintf(F,"\nUsage: rsync --daemon [OPTION]...\n"); + rprintf(F," --address=ADDRESS bind to the specified address\n"); + rprintf(F," --bwlimit=KBPS limit I/O bandwidth; KBytes per second\n"); + rprintf(F," --config=FILE specify alternate rsyncd.conf file\n"); + rprintf(F," --no-detach do not detach from the parent\n"); + rprintf(F," --port=PORT listen on alternate port number\n"); + rprintf(F," -v, --verbose increase verbosity\n"); +#ifdef INET6 + rprintf(F," -4, --ipv4 prefer IPv4\n"); + rprintf(F," -6, --ipv6 prefer IPv6\n"); +#endif + rprintf(F," -h, --help show this help screen\n"); + + rprintf(F,"\nIf you were not trying to invoke rsync as a daemon, avoid using any of the\n"); + rprintf(F,"daemon-specific rsync options. See also the rsyncd.conf(5) man page.\n"); +} + +static struct poptOption long_daemon_options[] = { + /* longName, shortName, argInfo, argPtr, value, descrip, argDesc */ + {"address", 0, POPT_ARG_STRING, &bind_address, 0, 0, 0 }, + {"bwlimit", 0, POPT_ARG_INT, &daemon_bwlimit, 0, 0, 0 }, + {"config", 0, POPT_ARG_STRING, &config_file, 0, 0, 0 }, + {"daemon", 0, POPT_ARG_NONE, &daemon_opt, 0, 0, 0 }, +#ifdef INET6 + {"ipv4", '4', POPT_ARG_VAL, &default_af_hint, AF_INET, 0, 0 }, + {"ipv6", '6', POPT_ARG_VAL, &default_af_hint, AF_INET6, 0, 0 }, +#endif + {"detach", 0, POPT_ARG_VAL, &no_detach, 0, 0, 0 }, + {"no-detach", 0, POPT_ARG_VAL, &no_detach, 1, 0, 0 }, + {"port", 0, POPT_ARG_INT, &rsync_port, 0, 0, 0 }, + {"protocol", 0, POPT_ARG_INT, &protocol_version, 0, 0, 0 }, + {"server", 0, POPT_ARG_NONE, &am_server, 0, 0, 0 }, + {"verbose", 'v', POPT_ARG_NONE, 0, 'v', 0, 0 }, + {"help", 'h', POPT_ARG_NONE, 0, 'h', 0, 0 }, {0,0,0,0, 0, 0, 0} }; @@ -449,9 +547,6 @@ break; if ((cp = strchr(bp, ' ')) != NULL) *cp= '\0'; - /* If they specify "delete", reject all delete options. */ - if (strcmp(bp, "delete") == 0) - bp = "delete*"; is_wild = strpbrk(bp, "*?[") != NULL; found_match = 0; for (op = long_options; ; op++) { @@ -460,8 +555,28 @@ break; if ((op->longName && wildmatch(bp, op->longName)) || (*shortname && wildmatch(bp, shortname))) { + if (op->argInfo == POPT_ARG_VAL) + op->argInfo = POPT_ARG_NONE; op->val = (op - long_options) + OPT_REFUSED_BASE; found_match = 1; + /* These flags are set to let us easily check + * an implied option later in the code. */ + switch (*shortname) { + case 'r': case 'd': case 'l': case 'p': + case 't': case 'g': case 'o': case 'D': + refused_archive_part = op->val; + break; + case '\0': + if (wildmatch("delete", op->longName)) + refused_delete = op->val; + else if (wildmatch("delete-before", op->longName)) + refused_delete_before = op->val; + else if (wildmatch("partial", op->longName)) + refused_partial = op->val; + else if (wildmatch("progress", op->longName)) + refused_progress = op->val; + break; + } if (!is_wild) break; } @@ -475,20 +590,47 @@ *cp = ' '; bp = cp + 1; } + + for (op = long_options; ; op++) { + *shortname = op->shortName; + if (!op->longName && !*shortname) + break; + if (op->val == OPT_DAEMON) { + if (op->argInfo == POPT_ARG_VAL) + op->argInfo = POPT_ARG_NONE; + op->val = (op - long_options) + OPT_REFUSED_BASE; + } + } } -static int count_args(char const **argv) +static int count_args(const char **argv) { int i = 0; - while (argv[i] != NULL) - i++; + if (argv) { + while (argv[i] != NULL) + i++; + } return i; } +static void create_refuse_error(int which) +{ + /* The "which" value is the index + OPT_REFUSED_BASE. */ + struct poptOption *op = &long_options[which - OPT_REFUSED_BASE]; + int n = snprintf(err_buf, sizeof err_buf, + "The server is configured to refuse --%s\n", + op->longName) - 1; + if (op->shortName) { + snprintf(err_buf + n, sizeof err_buf - n, + " (-%c)\n", op->shortName); + } +} + + /** * Process command line arguments. Called on both local and remote. * @@ -512,6 +654,7 @@ /* The context leaks in case of an error, but if there's a * problem we always exit anyhow. */ pc = poptGetContext(RSYNC_NAME, *argc, *argv, long_options, 0); + poptReadDefaultConfig(pc, 0); while ((opt = poptGetNextOpt(pc)) != -1) { /* most options are handled automatically by popt; @@ -522,6 +665,46 @@ print_rsync_version(FINFO); exit_cleanup(0); + case OPT_DAEMON: + if (am_daemon) { + strcpy(err_buf, "Attempt to hack rsync thwarted!\n"); + return 0; + } + poptFreeContext(pc); + pc = poptGetContext(RSYNC_NAME, *argc, *argv, + long_daemon_options, 0); + while ((opt = poptGetNextOpt(pc)) != -1) { + switch (opt) { + case 'h': + daemon_usage(FINFO); + exit_cleanup(0); + + case 'v': + verbose++; + break; + + default: + rprintf(FERROR, + "rsync: %s: %s (in daemon mode)\n", + poptBadOption(pc, POPT_BADOPTION_NOALIAS), + poptStrerror(opt)); + goto daemon_error; + } + } + if (!daemon_opt) { + rprintf(FERROR, "Daemon option(s) used without --daemon.\n"); + daemon_error: + rprintf(FERROR, + "(Type \"rsync --daemon --help\" for assistance with daemon mode.)\n"); + exit_cleanup(RERR_SYNTAX); + } + *argv = poptGetArgs(pc); + *argc = count_args(*argv); + am_starting_up = 0; + daemon_opt = 0; + am_daemon = 1; + return 1; + case OPT_MODIFY_WINDOW: /* The value has already been set by popt, but * we need to remember that we're using a @@ -529,23 +712,18 @@ modify_window_set = 1; break; - case OPT_DELETE_AFTER: - delete_after = 1; - delete_mode = 1; - break; - - case OPT_DELETE_EXCLUDED: - delete_excluded = 1; - delete_mode = 1; + case OPT_FILTER: + parse_rule(&filter_list, poptGetOptArg(pc), 0, 0); break; case OPT_EXCLUDE: - add_exclude(&exclude_list, poptGetOptArg(pc), 0); + parse_rule(&filter_list, poptGetOptArg(pc), + 0, XFLG_OLD_PREFIXES); break; case OPT_INCLUDE: - add_exclude(&exclude_list, poptGetOptArg(pc), - XFLG_DEF_INCLUDE); + parse_rule(&filter_list, poptGetOptArg(pc), + MATCHFLG_INCLUDE, XFLG_OLD_PREFIXES); break; case OPT_EXCLUDE_FROM: @@ -553,15 +731,17 @@ arg = poptGetOptArg(pc); if (sanitize_paths) arg = sanitize_path(NULL, arg, NULL, 0); - if (server_exclude_list.head) { + if (server_filter_list.head) { char *cp = (char *)arg; + if (!*cp) + goto options_rejected; clean_fname(cp, 1); - if (check_exclude(&server_exclude_list, cp, 0) < 0) + if (check_filter(&server_filter_list, cp, 0) < 0) goto options_rejected; } - add_exclude_file(&exclude_list, arg, XFLG_FATAL_ERRORS - | (opt == OPT_INCLUDE_FROM - ? XFLG_DEF_INCLUDE : 0)); + parse_filter_file(&filter_list, arg, + opt == OPT_INCLUDE_FROM ? MATCHFLG_INCLUDE : 0, + XFLG_FATAL_ERRORS | XFLG_OLD_PREFIXES); break; case 'h': @@ -585,7 +765,23 @@ am_sender = 1; break; + case 'F': + switch (++F_option_cnt) { + case 1: + parse_rule(&filter_list,": /.rsync-filter",0,0); + break; + case 2: + parse_rule(&filter_list,"- .rsync-filter",0,0); + break; + } + break; + case 'P': + if (refused_partial || refused_progress) { + create_refuse_error(refused_partial + ? refused_partial : refused_progress); + return 0; + } do_progress = 1; keep_partial = 1; break; @@ -600,15 +796,45 @@ read_batch = 1; break; + case OPT_MAX_SIZE: + for (arg = max_size_arg; isdigit(*(uchar*)arg); arg++) {} + if (*arg == '.') + for (arg++; isdigit(*(uchar*)arg); arg++) {} + switch (*arg) { + case 'k': case 'K': + max_size = atof(max_size_arg) * 1024; + break; + case 'm': case 'M': + max_size = atof(max_size_arg) * 1024*1024; + break; + case 'g': case 'G': + max_size = atof(max_size_arg) * 1024*1024*1024; + break; + case '\0': + max_size = atof(max_size_arg); + break; + default: + max_size = 0; + break; + } + if (max_size <= 0) { + snprintf(err_buf, sizeof err_buf, + "--max-size value is invalid: %s\n", + max_size_arg); + return 0; + } + break; + case OPT_TIMEOUT: if (io_timeout && io_timeout < select_timeout) select_timeout = io_timeout; break; case OPT_LINK_DEST: -#if HAVE_LINK +#ifdef HAVE_LINK link_dest = 1; - break; + dest_option = "--link-dest"; + goto set_dest_dir; #else snprintf(err_buf, sizeof err_buf, "hard links are not supported on this %s\n", @@ -616,31 +842,43 @@ return 0; #endif + case OPT_COPY_DEST: + copy_dest = 1; + dest_option = "--copy-dest"; + goto set_dest_dir; + + case OPT_COMPARE_DEST: + compare_dest = 1; + dest_option = "--compare-dest"; + set_dest_dir: + if (basis_dir_cnt >= MAX_BASIS_DIRS) { + snprintf(err_buf, sizeof err_buf, + "ERROR: at most %d %s args may be specified\n", + MAX_BASIS_DIRS, dest_option); + return 0; + } + arg = poptGetOptArg(pc); + if (sanitize_paths) + arg = sanitize_path(NULL, arg, NULL, 0); + basis_dir[basis_dir_cnt++] = (char *)arg; + break; + default: /* A large opt value means that set_refuse_options() - * turned this option off (opt-BASE is its index). */ + * turned this option off. */ if (opt >= OPT_REFUSED_BASE) { - struct poptOption *op = - &long_options[opt-OPT_REFUSED_BASE]; - int n = snprintf(err_buf, sizeof err_buf, - "The server is configured to refuse --%s\n", - op->longName) - 1; - if (op->shortName) { - snprintf(err_buf+n, sizeof err_buf-n, - " (-%c)\n", op->shortName); - } - } else { - snprintf(err_buf, sizeof err_buf, - "%s%s: %s\n", - am_server ? "on remote machine: " : "", - poptBadOption(pc, POPT_BADOPTION_NOALIAS), - poptStrerror(opt)); + create_refuse_error(opt); + return 0; } + snprintf(err_buf, sizeof err_buf, "%s%s: %s\n", + am_server ? "on remote machine: " : "", + poptBadOption(pc, POPT_BADOPTION_NOALIAS), + poptStrerror(opt)); return 0; } } -#if !SUPPORT_LINKS +#ifndef SUPPORT_LINKS if (preserve_links && !am_sender) { snprintf(err_buf, sizeof err_buf, "symlinks are not supported on this %s\n", @@ -649,7 +887,7 @@ } #endif -#if !SUPPORT_HARD_LINKS +#ifndef SUPPORT_HARD_LINKS if (preserve_hard_links) { snprintf(err_buf, sizeof err_buf, "hard links are not supported on this %s\n", @@ -664,12 +902,6 @@ return 0; } if (write_batch || read_batch) { - if (dry_run) { - snprintf(err_buf, sizeof err_buf, - "--%s-batch cannot be used with --dry_run (-n)\n", - write_batch ? "write" : "read"); - return 0; - } if (am_server) { rprintf(FINFO, "ignoring --%s-batch option sent to server\n", @@ -679,7 +911,8 @@ * batch args to server. */ read_batch = write_batch = 0; batch_name = NULL; - } + } else if (dry_run) + write_batch = 0; } if (read_batch && files_from) { snprintf(err_buf, sizeof err_buf, @@ -699,10 +932,20 @@ return 0; } + if (compare_dest + copy_dest + link_dest > 1) { + snprintf(err_buf, sizeof err_buf, + "You may not mix --compare-dest, --copy-dest, and --link-dest.\n"); + return 0; + } + if (archive_mode) { + if (refused_archive_part) { + create_refuse_error(refused_archive_part); + return 0; + } if (!files_from) recurse = 1; -#if SUPPORT_LINKS +#ifdef SUPPORT_LINKS preserve_links = 1; #endif preserve_perms = 1; @@ -712,14 +955,48 @@ preserve_devices = 1; } + if (recurse || list_only || files_from) + xfer_dirs |= 1; + if (relative_paths < 0) relative_paths = files_from? 1 : 0; + if (!!delete_before + delete_during + delete_after > 1) { + snprintf(err_buf, sizeof err_buf, + "You may not combine multiple --delete-WHEN options.\n"); + return 0; + } + if (!recurse) { + delete_before = delete_during = delete_after = 0; + delete_mode = delete_excluded = 0; + } else if (delete_before || delete_during || delete_after) + delete_mode = 1; + else if (delete_mode || delete_excluded) { + if (refused_delete_before) { + create_refuse_error(refused_delete_before); + return 0; + } + delete_mode = delete_before = 1; + } + + if (delete_mode && refused_delete) { + create_refuse_error(refused_delete); + return 0; + } + + if (remove_sent_files) { + /* We only want to infer this refusal of --remove-sent-files + * via the refusal of "delete", not any of the "delete-FOO" + * options. */ + if (refused_delete && am_sender) { + create_refuse_error(refused_delete); + return 0; + } + need_messages_from_generator = 1; + } + *argv = poptGetArgs(pc); - if (*argv) - *argc = count_args(*argv); - else - *argc = 0; + *argc = count_args(*argv); if (sanitize_paths) { int i; @@ -729,51 +1006,43 @@ tmpdir = sanitize_path(NULL, tmpdir, NULL, 0); if (partial_dir) partial_dir = sanitize_path(NULL, partial_dir, NULL, 0); - if (compare_dest) - compare_dest = sanitize_path(NULL, compare_dest, NULL, 0); if (backup_dir) backup_dir = sanitize_path(NULL, backup_dir, NULL, 0); - if (files_from) - files_from = sanitize_path(NULL, files_from, NULL, 0); } - if (server_exclude_list.head && !am_sender) { - struct exclude_list_struct *elp = &server_exclude_list; + if (server_filter_list.head && !am_sender) { + struct filter_list_struct *elp = &server_filter_list; + int i; if (tmpdir) { + if (!*tmpdir) + goto options_rejected; clean_fname(tmpdir, 1); - if (check_exclude(elp, tmpdir, 1) < 0) + if (check_filter(elp, tmpdir, 1) < 0) goto options_rejected; } - if (partial_dir) { + if (partial_dir && *partial_dir) { clean_fname(partial_dir, 1); - if (check_exclude(elp, partial_dir, 1) < 0) + if (check_filter(elp, partial_dir, 1) < 0) goto options_rejected; } - if (compare_dest) { - clean_fname(compare_dest, 1); - if (check_exclude(elp, compare_dest, 1) < 0) + for (i = 0; i < basis_dir_cnt; i++) { + if (!*basis_dir[i]) + goto options_rejected; + clean_fname(basis_dir[i], 1); + if (check_filter(elp, basis_dir[i], 1) < 0) goto options_rejected; } if (backup_dir) { - clean_fname(backup_dir, 1); - if (check_exclude(elp, backup_dir, 1) < 0) + if (!*backup_dir) goto options_rejected; + clean_fname(backup_dir, 1); + if (check_filter(elp, backup_dir, 1) < 0) { + options_rejected: + snprintf(err_buf, sizeof err_buf, + "Your options have been rejected by the server.\n"); + return 0; + } } } - if (server_exclude_list.head && files_from) { - clean_fname(files_from, 1); - if (check_exclude(&server_exclude_list, files_from, 0) < 0) { - options_rejected: - snprintf(err_buf, sizeof err_buf, - "Your options have been rejected by the server.\n"); - return 0; - } - } - - if (daemon_opt) { - daemon_opt = 0; - am_daemon = 1; - return 1; - } if (!backup_suffix) backup_suffix = backup_dir ? "" : BACKUP_SUFFIX; @@ -796,28 +1065,64 @@ backup_dir_buf[backup_dir_len++] = '/'; backup_dir_buf[backup_dir_len] = '\0'; } - if (verbose > 1 && !am_sender) - rprintf(FINFO, "backup_dir is %s\n", backup_dir_buf); + if (verbose > 1 && !am_sender) { + rprintf(FINFO, "backup_dir is %s\n", + safe_fname(backup_dir_buf)); + } } else if (!backup_suffix_len && (!am_server || !am_sender)) { snprintf(err_buf, sizeof err_buf, "--suffix cannot be a null string without --backup-dir\n"); return 0; } + if (make_backups && !backup_dir) + omit_dir_times = 1; - if (do_progress && !verbose) + if (log_format) { + if (log_format_has(log_format, 'i')) + log_format_has_i = 1; + if (!log_format_has(log_format, 'b') + && !log_format_has(log_format, 'c')) + log_before_transfer = !am_server; + } else if (itemize_changes) { + log_format = "%i %n%L"; + log_format_has_i = 1; + log_before_transfer = !am_server; + } + + if ((do_progress || dry_run) && !verbose && !log_before_transfer + && !am_server) verbose = 1; + if (verbose && !log_format) { + log_format = "%n%L"; + log_before_transfer = !am_server; + } + if (log_format_has_i || log_format_has(log_format, 'o')) + log_format_has_o_or_i = 1; + + if (daemon_bwlimit && (!bwlimit || bwlimit > daemon_bwlimit)) + bwlimit = daemon_bwlimit; if (bwlimit) { bwlimit_writemax = (size_t)bwlimit * 128; if (bwlimit_writemax < 512) bwlimit_writemax = 512; } + if (delay_updates && !partial_dir) + partial_dir = partialdir_for_delayupdate; + if (inplace) { -#if HAVE_FTRUNCATE +#ifdef HAVE_FTRUNCATE if (partial_dir) { snprintf(err_buf, sizeof err_buf, - "--inplace cannot be used with --partial-dir\n"); + "--inplace cannot be used with --%s\n", + delay_updates ? "delay-updates" : "partial-dir"); + return 0; + } + /* --inplace implies --partial for refusal purposes, but we + * clear the keep_partial flag for internal logic purposes. */ + if (refused_partial) { + create_refuse_error(refused_partial); return 0; } keep_partial = 0; @@ -827,28 +1132,31 @@ am_server ? "server" : "client"); return 0; #endif - if (compare_dest) { - snprintf(err_buf, sizeof err_buf, - "--inplace does not yet work with %s\n", - link_dest ? "--link-dest" : "--compare-dest"); - return 0; - } } else { - if (keep_partial && !partial_dir) - partial_dir = getenv("RSYNC_PARTIAL_DIR"); + if (keep_partial && !partial_dir) { + if ((arg = getenv("RSYNC_PARTIAL_DIR")) != NULL && *arg) + partial_dir = strdup(arg); + } if (partial_dir) { + if (*partial_dir) + clean_fname(partial_dir, 1); if (!*partial_dir || strcmp(partial_dir, ".") == 0) partial_dir = NULL; else if (*partial_dir != '/') { - add_exclude(&exclude_list, partial_dir, - XFLG_DIRECTORY); + parse_rule(&filter_list, partial_dir, + MATCHFLG_NO_PREFIXES|MATCHFLG_DIRECTORY, 0); + } + if (!partial_dir && refused_partial) { + create_refuse_error(refused_partial); + return 0; } keep_partial = 1; } } if (files_from) { - char *colon; + char *h, *p; + int q; if (*argc > 2 || (!am_daemon && *argc == 1)) { usage(FERROR); exit_cleanup(RERR_SYNTAX); @@ -856,20 +1164,30 @@ if (strcmp(files_from, "-") == 0) { filesfrom_fd = 0; if (am_server) - remote_filesfrom_file = "-"; - } - else if ((colon = find_colon(files_from)) != 0) { + filesfrom_host = ""; /* reading from socket */ + } else if ((p = check_for_hostspec(files_from, &h, &q)) != 0) { if (am_server) { - usage(FERROR); - exit_cleanup(RERR_SYNTAX); + snprintf(err_buf, sizeof err_buf, + "The --files-from sent to the server cannot specify a host.\n"); + return 0; } - remote_filesfrom_file = colon+1 + (colon[1] == ':'); - if (strcmp(remote_filesfrom_file, "-") == 0) { + files_from = p; + filesfrom_host = h; + if (strcmp(files_from, "-") == 0) { snprintf(err_buf, sizeof err_buf, "Invalid --files-from remote filename\n"); return 0; } } else { + if (sanitize_paths) + files_from = sanitize_path(NULL, files_from, NULL, 0); + if (server_filter_list.head) { + if (!*files_from) + goto options_rejected; + clean_fname(files_from, 1); + if (check_filter(&server_filter_list, files_from, 0) < 0) + goto options_rejected; + } filesfrom_fd = open(files_from, O_RDONLY|O_BINARY); if (filesfrom_fd < 0) { snprintf(err_buf, sizeof err_buf, @@ -880,6 +1198,8 @@ } } + am_starting_up = 0; + return 1; } @@ -894,8 +1214,8 @@ **/ void server_options(char **args,int *argc) { + static char argstr[50+MAX_BASIS_DIRS*2]; int ac = *argc; - static char argstr[50]; char *arg; int i, x; @@ -931,6 +1251,8 @@ argstr[x++] = 'l'; if (copy_links) argstr[x++] = 'L'; + if (xfer_dirs > 1) + argstr[x++] = 'd'; if (keep_dirlinks && am_sender) argstr[x++] = 'K'; @@ -950,6 +1272,8 @@ argstr[x++] = 'D'; if (preserve_times) argstr[x++] = 't'; + if (omit_dir_times == 2 && am_sender) + argstr[x++] = 'O'; if (preserve_perms) argstr[x++] = 'p'; if (recurse) @@ -969,11 +1293,10 @@ if (do_compression) argstr[x++] = 'z'; - /* this is a complete hack - blame Rusty - - this is a hack to make the list_only (remote file list) - more useful */ - if (list_only && !recurse) + /* This is a complete hack - blame Rusty. FIXME! + * This hack is only needed for older rsync versions that + * don't understand the --list-only option. */ + if (list_only == 1 && !recurse) argstr[x++] = 'r'; argstr[x] = 0; @@ -981,8 +1304,22 @@ if (x != 1) args[ac++] = argstr; + if (list_only > 1) + args[ac++] = "--list-only"; + + /* The server side doesn't use our log-format, but in certain + * circumstances they need to know a little about the option. */ + if (log_format && am_sender) { + if (log_format_has_i) + args[ac++] = "--log-format=%i"; + else if (log_format_has_o_or_i) + args[ac++] = "--log-format=%o"; + else if (!verbose) + args[ac++] = "--log-format=X"; + } + if (block_size) { - if (asprintf(&arg, "-B%u", block_size) < 0) + if (asprintf(&arg, "-B%lu", block_size) < 0) goto oom; args[ac++] = arg; } @@ -993,6 +1330,11 @@ args[ac++] = arg; } + if (max_size && am_sender) { + args[ac++] = "--max-size"; + args[ac++] = max_size_arg; + } + if (io_timeout) { if (asprintf(&arg, "--timeout=%d", io_timeout) < 0) goto oom; @@ -1021,12 +1363,14 @@ if (am_sender) { if (delete_excluded) args[ac++] = "--delete-excluded"; - else if (delete_mode) + else if (delete_before == 1 || delete_after) args[ac++] = "--delete"; - + if (delete_before > 1) + args[ac++] = "--delete-before"; + if (delete_during) + args[ac++] = "--delete-during"; if (delete_after) args[ac++] = "--delete-after"; - if (force_delete) args[ac++] = "--force"; } @@ -1047,8 +1391,12 @@ } if (partial_dir && am_sender) { - args[ac++] = "--partial-dir"; - args[ac++] = partial_dir; + if (partial_dir != partialdir_for_delayupdate) { + args[ac++] = "--partial-dir"; + args[ac++] = partial_dir; + } + if (delay_updates) + args[ac++] = "--delay-updates"; } else if (keep_partial) args[ac++] = "--partial"; @@ -1078,26 +1426,39 @@ args[ac++] = tmpdir; } - if (compare_dest && am_sender) { + if (basis_dir[0] && am_sender) { /* the server only needs this option if it is not the sender, * 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++] = link_dest ? "--link-dest" : "--compare-dest"; - args[ac++] = compare_dest; + int i; + for (i = 0; i < basis_dir_cnt; i++) { + args[ac++] = dest_option; + args[ac++] = basis_dir[i]; + } } - if (files_from && (!am_sender || remote_filesfrom_file)) { - if (remote_filesfrom_file) { + if (files_from && (!am_sender || filesfrom_host)) { + if (filesfrom_host) { args[ac++] = "--files-from"; - args[ac++] = remote_filesfrom_file; + args[ac++] = files_from; if (eol_nulls) args[ac++] = "--from0"; } else { args[ac++] = "--files-from=-"; args[ac++] = "--from0"; } + if (!relative_paths) + args[ac++] = "--no-relative"; } + if (!implied_dirs && !am_sender) + args[ac++] = "--no-implied-dirs"; + + if (fuzzy_basis && am_sender) + args[ac++] = "--fuzzy"; + + if (remove_sent_files) + args[ac++] = "--remove-sent-files"; *argc = ac; return; @@ -1106,23 +1467,75 @@ out_of_memory("server_options"); } -/** - * Return the position of a ':' IF it is not part of a filename (i.e. as - * long as it doesn't occur after a slash. - */ -char *find_colon(char *s) +/* Look for a HOST specfication of the form "HOST:PATH", "HOST::PATH", or + * "rsync://HOST:PORT/PATH". If found, *host_ptr will be set to some allocated + * memory with the HOST. If a daemon-accessing spec was specified, the value + * of *port_ptr will contain a non-0 port number, otherwise it will be set to + * 0. The return value is a pointer to the PATH. Note that the HOST spec can + * be an IPv6 literal address enclosed in '[' and ']' (such as "[::1]" or + * "[::ffff:127.0.0.1]") which is returned without the '[' and ']'. */ +char *check_for_hostspec(char *s, char **host_ptr, int *port_ptr) { - char *p, *p2; + char *p; + int not_host; + + if (port_ptr && strncasecmp(URL_PREFIX, s, strlen(URL_PREFIX)) == 0) { + char *path; + int hostlen; + s += strlen(URL_PREFIX); + if ((p = strchr(s, '/')) != NULL) { + hostlen = p - s; + path = p + 1; + } else { + hostlen = strlen(s); + path = ""; + } + if (*s == '[' && (p = strchr(s, ']')) != NULL) { + s++; + hostlen = p - s; + if (p[1] == ':') + *port_ptr = atoi(p+2); + } else { + if ((p = strchr(s, ':')) != NULL) { + hostlen = p - s; + *port_ptr = atoi(p+1); + } + } + if (!*port_ptr) + *port_ptr = RSYNC_PORT; + *host_ptr = new_array(char, hostlen + 1); + strlcpy(*host_ptr, s, hostlen + 1); + return path; + } - p = strchr(s,':'); - if (!p) - return NULL; - - /* now check to see if there is a / in the string before the : - if there is then - discard the colon on the assumption that the : is part of a filename */ - p2 = strchr(s,'/'); - if (p2 && p2 < p) - return NULL; + if (*s == '[' && (p = strchr(s, ']')) != NULL && p[1] == ':') { + s++; + *p = '\0'; + not_host = strchr(s, '/') || !strchr(s, ':'); + *p = ']'; + if (not_host) + return NULL; + p++; + } else { + if (!(p = strchr(s, ':'))) + return NULL; + *p = '\0'; + not_host = strchr(s, '/') != NULL; + *p = ':'; + if (not_host) + return NULL; + } + + *host_ptr = new_array(char, p - s + 1); + strlcpy(*host_ptr, s, p - s + 1); + + if (p[1] == ':') { + if (port_ptr && !*port_ptr) + *port_ptr = RSYNC_PORT; + return p + 2; + } + if (port_ptr) + *port_ptr = 0; - return p; + return p + 1; } diff -urN --exclude=patches rsync-2.6.3/packaging/lsb/rsync.spec rsync-2.6.4/packaging/lsb/rsync.spec --- rsync-2.6.3/packaging/lsb/rsync.spec 2004-09-30 09:35:56.000000000 -0700 +++ rsync-2.6.4/packaging/lsb/rsync.spec 2005-03-30 19:14:09.000000000 -0800 @@ -1,24 +1,46 @@ -Summary: Program for efficient remote updates of files. +Summary: A program for synchronizing files over a network. Name: rsync -Version: 2.6.3 +Version: 2.6.4 Release: 1 -Copyright: GPL -Group: Applications/Networking -Source: ftp://samba.anu.edu.au/pub/rsync/rsync-%{version}.tar.gz -URL: http://samba.anu.edu.au/rsync/ -Packager: Andrew Tridgell -BuildRoot: /tmp/rsync +Group: Applications/Internet +Source: ftp://rsync.samba.org/pub/rsync/rsync-%{version}.tar.gz +URL: http://rsync.samba.org/ + +Prefix: %{_prefix} +BuildRoot: /var/tmp/%{name}-root +License: GPL %description -rsync is a replacement for rcp that has many more features. +Rsync uses a reliable algorithm to bring remote and host files into +sync very quickly. Rsync is fast because it just sends the differences +in the files over the network instead of sending the complete +files. Rsync is often used as a very powerful mirroring process or +just as a more capable replacement for the rcp command. A technical +report which describes the rsync algorithm is included in this +package. -rsync uses the "rsync algorithm" which provides a very fast method for -bringing remote files into sync. It does this by sending just the -differences in the files across the link, without requiring that both -sets of files are present at one of the ends of the link beforehand. +%prep +%setup -q + +%build +%configure + +make + +%install +rm -rf $RPM_BUILD_ROOT + +%makeinstall + +%clean +rm -rf $RPM_BUILD_ROOT -A technical report describing the rsync algorithm is included with -this package. +%files +%defattr(-,root,root) +%doc COPYING README tech_report.tex +%{_prefix}/bin/rsync +%{_mandir}/man1/rsync.1* +%{_mandir}/man5/rsyncd.conf.5* %changelog * Thu Jan 30 2003 Horst von Brand @@ -64,30 +86,3 @@ rsync-1.6.2-1 packaged. (This entry by jam to credit Michael for the previous package(s).) - -%prep -%setup - -%build -./configure --prefix=/usr --mandir=%{_mandir} -make CFLAGS="$RPM_OPT_FLAGS" -strip rsync - -%install -mkdir -p $RPM_BUILD_ROOT/usr/bin -mkdir -p $RPM_BUILD_ROOT/%{_mandir}/man{1,5} -install -m755 rsync $RPM_BUILD_ROOT/usr/bin -install -m644 rsync.1 $RPM_BUILD_ROOT/%{_mandir}/man1 -install -m644 rsyncd.conf.5 $RPM_BUILD_ROOT/%{_mandir}/man5 - -%clean -rm -rf $RPM_BUILD_ROOT - -%files -%attr(-,root,root) /usr/bin/rsync -%attr(-,root,root) %{_mandir}/man1/rsync.1* -%attr(-,root,root) %{_mandir}/man5/rsyncd.conf.5* -%attr(-,root,root) %doc tech_report.tex -%attr(-,root,root) %doc README -%attr(-,root,root) %doc COPYING -%attr(-,root,root) %doc doc/README-SGML doc/rsync.sgml diff -urN --exclude=patches rsync-2.6.3/params.c rsync-2.6.4/params.c --- rsync-2.6.3/params.c 2004-05-15 12:31:10.000000000 -0700 +++ rsync-2.6.4/params.c 2005-02-07 12:36:43.000000000 -0800 @@ -492,7 +492,7 @@ if( NULL == OpenedFile ) { rsyserr(FERROR, errno, "rsync: unable to open configuration file \"%s\"", - FileName); + safe_fname(FileName)); } return( OpenedFile ); diff -urN --exclude=patches rsync-2.6.3/pipe.c rsync-2.6.4/pipe.c --- rsync-2.6.3/pipe.c 2004-08-11 17:52:58.000000000 -0700 +++ rsync-2.6.4/pipe.c 2005-02-07 12:36:43.000000000 -0800 @@ -79,7 +79,8 @@ if (blocking_io > 0) set_blocking(STDOUT_FILENO); execvp(command[0], command); - rsyserr(FERROR, errno, "Failed to exec %s", command[0]); + rsyserr(FERROR, errno, "Failed to exec %s", + safe_fname(command[0])); exit_cleanup(RERR_IPC); } diff -urN --exclude=patches rsync-2.6.3/popt/popt.c rsync-2.6.4/popt/popt.c --- rsync-2.6.3/popt/popt.c 2004-06-09 14:41:21.000000000 -0700 +++ rsync-2.6.4/popt/popt.c 2005-02-20 09:21:13.000000000 -0800 @@ -1128,7 +1128,7 @@ /*@=nullderef@*/ } -const char *const poptStrerror(const int error) +const char * poptStrerror(const int error) { switch (error) { case POPT_ERROR_NOARG: diff -urN --exclude=patches rsync-2.6.3/popt/popt.h rsync-2.6.4/popt/popt.h --- rsync-2.6.3/popt/popt.h 2004-01-27 08:27:05.000000000 -0800 +++ rsync-2.6.4/popt/popt.h 2005-02-20 09:21:13.000000000 -0800 @@ -373,7 +373,7 @@ * @return error string */ /*@-redecl@*/ -/*@observer@*/ const char *const poptStrerror(const int error) +/*@observer@*/ const char * poptStrerror(const int error) /*@*/; /*@=redecl@*/ diff -urN --exclude=patches rsync-2.6.3/popt/popthelp.c rsync-2.6.4/popt/popthelp.c --- rsync-2.6.3/popt/popthelp.c 2004-06-09 14:41:21.000000000 -0700 +++ rsync-2.6.4/popt/popthelp.c 2005-02-20 09:20:14.000000000 -0800 @@ -84,7 +84,7 @@ /*@observer@*/ /*@null@*/ static const char * getArgDescrip(const struct poptOption * opt, /*@-paramuse@*/ /* FIX: wazzup? */ - /*@null@*/ const char * translation_domain) + /*@null@*/ UNUSED(const char * translation_domain)) /*@=paramuse@*/ /*@*/ { @@ -115,7 +115,7 @@ singleOptionDefaultValue(int lineLength, const struct poptOption * opt, /*@-paramuse@*/ /* FIX: i18n macros disable with lclint */ - /*@null@*/ const char * translation_domain) + /*@null@*/ UNUSED(const char * translation_domain)) /*@=paramuse@*/ /*@*/ { diff -urN --exclude=patches rsync-2.6.3/progress.c rsync-2.6.4/progress.c --- rsync-2.6.3/progress.c 2004-02-27 18:00:57.000000000 -0800 +++ rsync-2.6.4/progress.c 2005-03-05 09:49:46.000000000 -0800 @@ -26,6 +26,12 @@ #define PROGRESS_HISTORY_SECS 5 +#ifdef GETPGRP_VOID +#define GETPGRP_ARG +#else +#define GETPGRP_ARG 0 +#endif + struct progress_history { struct timeval time; OFF_T ofs; @@ -61,17 +67,18 @@ if (is_last) { /* Compute stats based on the starting info. */ - diff = msdiff(&ph_start.time, now); - if (!diff) + if (!ph_start.time.tv_sec + || !(diff = msdiff(&ph_start.time, now))) diff = 1; rate = (double) (ofs - ph_start.ofs) * 1000.0 / diff / 1024.0; /* Switch to total time taken for our last update. */ remain = (double) diff / 1000.0; } else { /* Compute stats based on recent progress. */ - diff = msdiff(&ph_list[oldest_hpos].time, now); - rate = diff ? (double) (ofs - ph_list[oldest_hpos].ofs) * 1000.0 - / diff / 1024.0 : 0; + if (!(diff = msdiff(&ph_list[oldest_hpos].time, now))) + diff = 1; + rate = (double) (ofs - ph_list[oldest_hpos].ofs) * 1000.0 + / diff / 1024.0; remain = rate ? (double) (size - ofs) / rate / 1000.0 : 0.0; } @@ -115,10 +122,19 @@ void show_progress(OFF_T ofs, OFF_T size) { struct timeval now; +#if defined HAVE_GETPGRP && defined HAVE_TCGETPGRP + static pid_t pgrp = -1; + pid_t tc_pgrp; +#endif if (am_server) return; +#if defined HAVE_GETPGRP && defined HAVE_TCGETPGRP + if (pgrp == -1) + pgrp = getpgrp(GETPGRP_ARG); +#endif + gettimeofday(&now, NULL); if (!ph_start.time.tv_sec) { @@ -150,5 +166,11 @@ ph_list[newest_hpos].ofs = ofs; } +#if defined HAVE_GETPGRP && defined HAVE_TCGETPGRP + tc_pgrp = tcgetpgrp(STDOUT_FILENO); + if (tc_pgrp != pgrp && tc_pgrp != -1) + return; +#endif + rprint_progress(ofs, size, &now, False); } diff -urN --exclude=patches rsync-2.6.3/proto.h rsync-2.6.4/proto.h --- rsync-2.6.3/proto.h 2004-09-21 02:15:56.000000000 -0700 +++ rsync-2.6.4/proto.h 2005-03-30 16:19:27.000000000 -0800 @@ -11,11 +11,11 @@ void write_batch_shell_file(int argc, char *argv[], int file_arg_cnt); void show_flist(int index, struct file_struct **fptr); void show_argvs(int argc, char *argv[]); -uint32 get_checksum1(char *buf1,int len); -void get_checksum2(char *buf,int len,char *sum); +uint32 get_checksum1(char *buf1, int32 len); +void get_checksum2(char *buf, int32 len, char *sum); void file_checksum(char *fname,char *sum,OFF_T size); void sum_init(int seed); -void sum_update(char *p, int len); +void sum_update(char *p, int32 len); void sum_end(char *sum); void close_all(void); void _exit_cleanup(int code, const char *file, int line); @@ -44,36 +44,34 @@ int daemon_main(void); void setup_protocol(int f_out,int f_in); int claim_connection(char *fname,int max_connections); -void clear_exclude_list(struct exclude_list_struct *listp); -int check_exclude(struct exclude_list_struct *listp, char *name, int name_is_dir); -void add_exclude(struct exclude_list_struct *listp, const char *pattern, - int xflags); -void add_exclude_file(struct exclude_list_struct *listp, const char *fname, - int xflags); -void send_exclude_list(int f); -void recv_exclude_list(int f); -void add_cvs_excludes(void); +void set_filter_dir(const char *dir, unsigned int dirlen); +void *push_local_filters(const char *dir, unsigned int dirlen); +void pop_local_filters(void *mem); +int check_filter(struct filter_list_struct *listp, char *name, int name_is_dir); +void parse_rule(struct filter_list_struct *listp, const char *pattern, + uint32 mflags, int xflags); +void parse_filter_file(struct filter_list_struct *listp, const char *fname, + uint32 mflags, int xflags); +char *get_rule_prefix(int match_flags, const char *pat, int for_xfer, + unsigned int *plen_ptr); +void send_filter_list(int f_out); +void recv_filter_list(int f_in); int sparse_end(int f); int flush_write_file(int f); int write_file(int f,char *buf,size_t len); -struct map_struct *map_file(int fd, OFF_T len, OFF_T map_size, - size_t block_size); -char *map_ptr(struct map_struct *map,OFF_T offset,int len); +struct map_struct *map_file(int fd, OFF_T len, int32 read_size, + int32 blk_size); +char *map_ptr(struct map_struct *map, OFF_T offset, int32 len); int unmap_file(struct map_struct *map); void init_flist(void); void show_flist_stats(void); int link_stat(const char *path, STRUCT_STAT *buffer, int follow_dirlinks); void flist_expand(struct file_list *flist); void send_file_entry(struct file_struct *file, int f, unsigned short base_flags); -void receive_file_entry(struct file_struct **fptr, unsigned short flags, - struct file_list *flist, int f); struct file_struct *make_file(char *fname, struct file_list *flist, - int exclude_level); -void send_file_name(int f, struct file_list *flist, char *fname, - int recursive, unsigned short base_flags); + int filter_level); struct file_list *send_file_list(int f, int argc, char *argv[]); struct file_list *recv_file_list(int f); -int file_compare(struct file_struct **file1, struct file_struct **file2); int flist_find(struct file_list *flist, struct file_struct *f); void clear_file(int i, struct file_list *flist); struct file_list *flist_new(int with_hlink, char *msg); @@ -81,34 +79,50 @@ int f_name_cmp(struct file_struct *f1, struct file_struct *f2); char *f_name_to(struct file_struct *f, char *fbuf); char *f_name(struct file_struct *f); -void write_sum_head(int f, struct sum_struct *sum); +struct file_list *get_dirlist(char *dirname, int dlen, + int ignore_filter_rules); +void itemize(struct file_struct *file, int ndx, int statret, STRUCT_STAT *st, + int32 iflags, uchar fnamecmp_type, char *xname); +void check_for_finished_hlinks(int itemizing, enum logcode code); void generate_files(int f_out, struct file_list *flist, char *local_name); -void init_hard_links(struct file_list *flist); -int hard_link_check(struct file_struct *file, int skip); -void do_hard_links(void); +void init_hard_links(void); +int hard_link_check(struct file_struct *file, int ndx, int skip); +int hard_link_one(struct file_struct *file, int ndx, char *fname, + int statret, STRUCT_STAT *st, char *toname, int terse, + int itemizing, enum logcode code); +void hard_link_cluster(struct file_struct *file, int master, int itemizing, + enum logcode code); void io_set_sock_fds(int f_in, int f_out); void set_msg_fd_in(int fd); void set_msg_fd_out(int fd); void send_msg(enum msgcode code, char *buf, int len); int msg_list_push(int flush_it_all); -int get_redo_num(void); +int get_redo_num(int itemizing, enum logcode code); +int get_hlink_num(void); void io_set_filesfrom_fds(int f_in, int f_out); int read_filesfrom_line(int fd, char *fname); void io_start_buffering_out(void); void io_start_buffering_in(void); void io_end_buffering(void); +void maybe_send_keepalive(void); +int read_shortint(int f); int32 read_int(int f); int64 read_longint(int f); void read_buf(int f,char *buf,size_t len); void read_sbuf(int f,char *buf,size_t len); -unsigned char read_byte(int f); +uchar read_byte(int f); +int read_vstring(int f, char *buf, int bufsize); +void read_sum_head(int f, struct sum_struct *sum); +void write_sum_head(int f, struct sum_struct *sum); void io_flush(int flush_it_all); +void write_shortint(int f, int x); void write_int(int f,int32 x); void write_int_named(int f, int32 x, const char *phase); void write_longint(int f, int64 x); void write_buf(int f,char *buf,size_t len); void write_sbuf(int f, char *buf); -void write_byte(int f,unsigned char c); +void write_byte(int f, uchar c); +void write_vstring(int f, char *str, int len); int read_line(int f, char *buf, size_t maxlen); void io_printf(int fd, const char *format, ...); void io_start_multiplex_out(void); @@ -124,6 +138,8 @@ char *lp_socket_options(void); int lp_syslog_facility(void); int lp_max_verbosity(void); +int lp_rsync_port(void); +char *lp_bind_address(void); char *lp_name(int ); char *lp_comment(int ); char *lp_path(int ); @@ -142,6 +158,7 @@ char *lp_auth_users(int ); char *lp_secrets_file(int ); BOOL lp_strict_modes(int ); +char *lp_filter(int ); char *lp_exclude(int ); char *lp_exclude_from(int ); char *lp_include(int ); @@ -161,8 +178,12 @@ void rprintf(enum logcode code, const char *format, ...); void rsyserr(enum logcode code, int errcode, const char *format, ...); void rflush(enum logcode code); -void log_send(struct file_struct *file, struct stats *initial_stats); -void log_recv(struct file_struct *file, struct stats *initial_stats); +int log_format_has(const char *format, char esc); +void log_item(struct file_struct *file, struct stats *initial_stats, + int iflags, char *hlink); +void maybe_log_item(struct file_struct *file, int iflags, int itemizing, + char *buf); +void log_delete(char *fname, int mode); void log_exit(int code, const char *file, int line); void wait_process(pid_t pid, int *status); int child_main(int argc, char *argv[]); @@ -176,7 +197,7 @@ void option_error(void); int parse_arguments(int *argc, const char ***argv, int frommain); void server_options(char **args,int *argc); -char *find_colon(char *s); +char *check_for_hostspec(char *s, char **host_ptr, int *port_ptr); BOOL pm_process( char *FileName, BOOL (*sfunc)(char *), BOOL (*pfunc)(char *, char *) ); @@ -185,17 +206,17 @@ int (*child_main)(int, char*[])); void end_progress(OFF_T size); void show_progress(OFF_T ofs, OFF_T size); -void delete_files(struct file_list *flist); int recv_files(int f_in, struct file_list *flist, char *local_name); void free_sums(struct sum_struct *s); -int delete_file(char *fname); int set_perms(char *fname,struct file_struct *file,STRUCT_STAT *st, int flags); void sig_int(void); void finish_transfer(char *fname, char *fnametmp, struct file_struct *file, - int ok_to_set_time); + int ok_to_set_time, int overwriting_basis); const char *who_am_i(void); -void read_sum_head(int f, struct sum_struct *sum); +void successful_send(int ndx); +int read_item_attrs(int f_in, int f_out, int ndx, uchar *type_ptr, + char *buf, int *len_ptr); void send_files(struct file_list *flist, int f_out, int f_in); int try_bind_local(int s, int ai_family, int ai_socktype, const char *bind_address); @@ -224,13 +245,12 @@ int do_lstat(const char *fname, STRUCT_STAT *st); int do_fstat(int fd, STRUCT_STAT *st); OFF_T do_lseek(int fd, OFF_T offset, int whence); -void *do_mmap(void *start, int len, int prot, int flags, int fd, OFF_T offset); char *d_name(struct dirent *di); void set_compression(char *fname); -void send_token(int f,int token,struct map_struct *buf,OFF_T offset, - int n,int toklen); -int recv_token(int f,char **data); -void see_token(char *data, int toklen); +void send_token(int f, int32 token, struct map_struct *buf, OFF_T offset, + int32 n, int32 toklen); +int32 recv_token(int f, char **data); +void see_token(char *data, int32 toklen); void add_uid(uid_t uid); void add_gid(gid_t gid); void send_uid_list(int f); @@ -261,7 +281,7 @@ char *sanitize_path(char *dest, const char *p, const char *rootdir, int depth); int push_dir(char *dir); int pop_dir(char *dir); -const char *safe_fname(const char *fname); +char *safe_fname(const char *fname); char *full_fname(const char *fn); char *partial_dir_fname(const char *fname); int handle_partial_dir(const char *fname, int create); @@ -273,4 +293,6 @@ int _Insure_trap_error(int a1, int a2, int a3, int a4, int a5, int a6); void *_new_array(unsigned int size, unsigned long num); void *_realloc_array(void *ptr, unsigned int size, unsigned long num); +const char *find_filename_suffix(const char *fn, int fn_len, int *len_ptr); +uint32 fuzzy_distance(const char *s1, int len1, const char *s2, int len2); int sys_gettimeofday(struct timeval *tv); diff -urN --exclude=patches rsync-2.6.3/receiver.c rsync-2.6.4/receiver.c --- rsync-2.6.3/receiver.c 2004-09-21 02:24:06.000000000 -0700 +++ rsync-2.6.4/receiver.c 2005-03-29 14:05:33.000000000 -0800 @@ -21,122 +21,103 @@ #include "rsync.h" extern int verbose; -extern int recurse; -extern int delete_after; -extern int max_delete; -extern int csum_length; -extern struct stats stats; extern int dry_run; +extern int am_daemon; +extern int am_server; +extern int do_progress; +extern int log_before_transfer; +extern int log_format_has_i; +extern int daemon_log_format_has_i; +extern int csum_length; 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; extern int preserve_perms; -extern int cvs_exclude; extern int io_error; -extern char *tmpdir; -extern char *partial_dir; -extern char *compare_dest; +extern int basis_dir_cnt; extern int make_backups; -extern int do_progress; -extern char *backup_dir; -extern char *backup_suffix; -extern int backup_suffix_len; extern int cleanup_got_literal; +extern int remove_sent_files; extern int module_id; extern int ignore_errors; extern int orig_umask; extern int keep_partial; extern int checksum_seed; extern int inplace; +extern int delay_updates; +extern struct stats stats; +extern char *log_format; +extern char *tmpdir; +extern char *partial_dir; +extern char *basis_dir[]; +extern struct file_list *the_file_list; +extern struct filter_list_struct server_filter_list; + +#define SLOT_SIZE (16*1024) /* Desired size in bytes */ +#define PER_SLOT_BITS (SLOT_SIZE * 8) /* Number of bits per slot */ +#define PER_SLOT_INTS (SLOT_SIZE / 4) /* Number of int32s per slot */ + +static uint32 **delayed_bits = NULL; +static int delayed_slot_cnt = 0; +static int phase = 0; -extern struct exclude_list_struct server_exclude_list; - - -static void delete_one(char *fn, int is_dir) +static void init_delayed_bits(int max_ndx) { - if (!is_dir) { - if (robust_unlink(fn) != 0) { - rsyserr(FERROR, errno, "delete_one: unlink %s failed", - full_fname(fn)); - } else if (verbose) - rprintf(FINFO, "deleting %s\n", safe_fname(fn)); - } else { - if (do_rmdir(fn) != 0) { - if (errno != ENOTEMPTY && errno != EEXIST) { - rsyserr(FERROR, errno, - "delete_one: rmdir %s failed", - full_fname(fn)); - } - } else if (verbose) { - rprintf(FINFO, "deleting directory %s\n", - safe_fname(fn)); - } - } -} - + delayed_slot_cnt = (max_ndx + PER_SLOT_BITS - 1) / PER_SLOT_BITS; -static int is_backup_file(char *fn) -{ - int k = strlen(fn) - backup_suffix_len; - return k > 0 && strcmp(fn+k, backup_suffix) == 0; + if (!(delayed_bits = (uint32**)calloc(delayed_slot_cnt, sizeof (uint32*)))) + out_of_memory("set_delayed_bit"); } - -/* This deletes any files on the receiving side that are not present - * on the sending side. */ -void delete_files(struct file_list *flist) +static void set_delayed_bit(int ndx) { - struct file_list *local_file_list; - int i, j; - char *argv[1], fbuf[MAXPATHLEN]; - static int deletion_count; - - if (cvs_exclude) - add_cvs_excludes(); - - if (io_error && !(lp_ignore_errors(module_id) || ignore_errors)) { - rprintf(FINFO,"IO error encountered - skipping file deletion\n"); - return; - } + int slot = ndx / PER_SLOT_BITS; + ndx %= PER_SLOT_BITS; - for (j = 0; j < flist->count; j++) { - if (!(flist->files[j]->flags & FLAG_TOP_DIR) - || !S_ISDIR(flist->files[j]->mode)) - continue; + if (!delayed_bits[slot]) { + if (!(delayed_bits[slot] = (uint32*)calloc(PER_SLOT_INTS, 4))) + out_of_memory("set_delayed_bit"); + } - argv[0] = f_name_to(flist->files[j], fbuf); + delayed_bits[slot][ndx/32] |= 1u << (ndx % 32); +} - if (!(local_file_list = send_file_list(-1, 1, argv))) +/* Call this with -1 to start checking from 0. Returns -1 at the end. */ +static int next_delayed_bit(int after) +{ + uint32 bits, mask; + int i, ndx = after + 1; + int slot = ndx / PER_SLOT_BITS; + ndx %= PER_SLOT_BITS; + + mask = (1u << (ndx % 32)) - 1; + for (i = ndx / 32; slot < delayed_slot_cnt; slot++, i = mask = 0) { + if (!delayed_bits[slot]) continue; - - if (verbose > 1) - 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) - break; - if (!local_file_list->files[i]->basename) + for ( ; i < PER_SLOT_INTS; i++, mask = 0) { + if (!(bits = delayed_bits[slot][i] & ~mask)) 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))) { - make_backup(f); - if (verbose) { - rprintf(FINFO, "deleting %s\n", - safe_fname(f)); - } - } else { - int mode = local_file_list->files[i]->mode; - delete_one(f, S_ISDIR(mode) != 0); - } - deletion_count++; + /* The xor magic figures out the lowest enabled bit in + * bits, and the switch quickly computes log2(bit). */ + switch (bits ^ (bits & (bits-1))) { +#define LOG2(n) case 1u << n: return slot*PER_SLOT_BITS + i*32 + n + LOG2(0); LOG2(1); LOG2(2); LOG2(3); + LOG2(4); LOG2(5); LOG2(6); LOG2(7); + LOG2(8); LOG2(9); LOG2(10); LOG2(11); + LOG2(12); LOG2(13); LOG2(14); LOG2(15); + LOG2(16); LOG2(17); LOG2(18); LOG2(19); + LOG2(20); LOG2(21); LOG2(22); LOG2(23); + LOG2(24); LOG2(25); LOG2(26); LOG2(27); + LOG2(28); LOG2(29); LOG2(30); LOG2(31); } + return -1; /* impossible... */ } - flist_free(local_file_list); } + + return -1; } @@ -189,7 +170,8 @@ 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; } @@ -208,18 +190,18 @@ 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; char *data; - int i; + int32 i; char *map = NULL; read_sum_head(f_in, &sum); if (fd_r >= 0 && size_r > 0) { - OFF_T map_size = MAX(sum.blength * 2, 16*1024); - mapbuf = map_file(fd_r, size_r, map_size, sum.blength); + int32 read_size = MAX(sum.blength * 2, 16*1024); + mapbuf = map_file(fd_r, size_r, read_size, sum.blength); if (verbose > 2) { rprintf(FINFO, "recv mapped %s of size %.0f\n", safe_fname(fname_r), (double)size_r); @@ -242,7 +224,7 @@ 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) goto report_write_error; @@ -251,22 +233,24 @@ } 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) { @@ -283,12 +267,13 @@ continue; } } - if (fd != -1 && write_file(fd, map, len) != (int)len) + if (fd != -1 && map && 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) @@ -324,6 +309,57 @@ receive_data(f_in, NULL, -1, 0, NULL, -1, length); } +static void handle_delayed_updates(struct file_list *flist, char *local_name) +{ + char *fname, *partialptr, numbuf[4]; + int i; + + for (i = -1; (i = next_delayed_bit(i)) >= 0; ) { + struct file_struct *file = flist->files[i]; + fname = local_name ? local_name : f_name(file); + if ((partialptr = partial_dir_fname(fname)) != NULL) { + 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 { + if (remove_sent_files + || (preserve_hard_links + && file->link_u.links)) { + SIVAL(numbuf, 0, i); + send_msg(MSG_SUCCESS,numbuf,4); + } + handle_partial_dir(partialptr, + PDIR_DELETE); + } + } + } +} + +static int get_next_gen_i(int batch_gen_fd, int next_gen_i, int desired_i) +{ + while (next_gen_i < desired_i) { + if (next_gen_i >= 0) { + rprintf(FINFO, + "(No batched update for%s \"%s\")\n", + phase ? " resend of" : "", + safe_fname(f_name(the_file_list->files[next_gen_i]))); + } + next_gen_i = read_int(batch_gen_fd); + if (next_gen_i == -1) + next_gen_i = the_file_list->count; + } + return next_gen_i; +} + /** * main routine for receiver process. @@ -334,15 +370,20 @@ int next_gen_i = -1; int fd1,fd2; STRUCT_STAT st; + int iflags, xlen; char *fname, fbuf[MAXPATHLEN]; - char template[MAXPATHLEN]; + char xname[MAXPATHLEN]; char fnametmp[MAXPATHLEN]; - char *fnamecmp, *partialptr; + char *fnamecmp, *partialptr, numbuf[4]; char fnamecmpbuf[MAXPATHLEN]; + uchar fnamecmp_type; struct file_struct *file; struct stats initial_stats; int save_make_backups = make_backups; - int i, recv_ok, phase = 0; + int itemizing = am_daemon ? daemon_log_format_has_i + : !am_server && log_format_has_i; + int max_phase = protocol_version >= 29 ? 2 : 1; + int i, recv_ok; if (verbose > 2) rprintf(FINFO,"recv_files(%d) starting\n",flist->count); @@ -352,107 +393,150 @@ flist->hlink_pool = NULL; } + if (delay_updates) + init_delayed_bits(flist->count); + while (1) { cleanup_disable(); i = read_int(f_in); if (i == -1) { if (read_batch) { - if (next_gen_i != flist->count) - while (read_int(batch_gen_fd) != -1) {} + get_next_gen_i(batch_gen_fd, next_gen_i, + flist->count); next_gen_i = -1; } - - if (phase) + if (++phase > max_phase) break; - - phase = 1; csum_length = SUM_LENGTH; if (verbose > 2) rprintf(FINFO, "recv_files phase=%d\n", phase); + if (phase == 2 && delay_updates) + handle_delayed_updates(flist, local_name); send_msg(MSG_DONE, "", 0); - if (keep_partial) + if (keep_partial && !partial_dir) make_backups = 0; /* prevents double backup */ continue; } - if (i < 0 || i >= flist->count) { - rprintf(FERROR,"Invalid file index %d in recv_files (count=%d)\n", - i, flist->count); - exit_cleanup(RERR_PROTOCOL); - } + iflags = read_item_attrs(f_in, -1, i, &fnamecmp_type, + xname, &xlen); + if (iflags == ITEM_IS_NEW) /* no-op packet */ + continue; file = flist->files[i]; + fname = local_name ? local_name : f_name_to(file, fbuf); + + if (verbose > 2) + rprintf(FINFO, "recv_files(%s)\n", safe_fname(fname)); + + if (!(iflags & ITEM_TRANSFER)) { + maybe_log_item(file, iflags, itemizing, xname); + continue; + } + if (phase == 2) { + rprintf(FERROR, + "got transfer request in phase 2 [%s]\n", + who_am_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); - - if (dry_run) { - if (!am_server && verbose) /* log the transfer */ - rprintf(FINFO, "%s\n", safe_fname(fname)); - continue; + 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); } - initial_stats = stats; - - if (verbose > 2) - rprintf(FINFO, "recv_files(%s)\n", safe_fname(fname)); + if (dry_run) { /* log the transfer */ + if (!am_server && log_format) + log_item(file, &stats, iflags, NULL); + if (read_batch) + discard_receive_data(f_in, file->length); + continue; + } if (read_batch) { - while (i > next_gen_i) { - next_gen_i = read_int(batch_gen_fd); - if (next_gen_i == -1) - next_gen_i = flist->count; - } + next_gen_i = get_next_gen_i(batch_gen_fd, next_gen_i, i); if (i < next_gen_i) { - rprintf(FINFO, "skipping update for \"%s\"\n", + rprintf(FINFO, "(Skipping batched update for \"%s\")\n", safe_fname(fname)); 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) { - rprintf(FERROR, "attempt to hack rsync failed.\n"); - exit_cleanup(RERR_PROTOCOL); - } + partialptr = partial_dir ? partial_dir_fname(fname) : fname; - if (partial_dir) { - if ((partialptr = partial_dir_fname(fname)) != NULL) + if (protocol_version >= 29) { + switch (fnamecmp_type) { + case FNAMECMP_FNAME: + fnamecmp = fname; + break; + case FNAMECMP_PARTIAL_DIR: fnamecmp = partialptr; - else + break; + case FNAMECMP_BACKUP: + fnamecmp = get_backup_name(fname); + break; + case FNAMECMP_FUZZY: + if (file->dirname) { + pathjoin(fnamecmpbuf, MAXPATHLEN, + file->dirname, xname); + fnamecmp = fnamecmpbuf; + } else + fnamecmp = xname; + break; + default: + if (fnamecmp_type >= basis_dir_cnt) { + rprintf(FERROR, + "invalid basis_dir index: %d.\n", + fnamecmp_type); + exit_cleanup(RERR_PROTOCOL); + } + pathjoin(fnamecmpbuf, sizeof fnamecmpbuf, + basis_dir[fnamecmp_type], fname); + fnamecmp = fnamecmpbuf; + break; + } + if (!fnamecmp || (server_filter_list.head + && check_filter(&server_filter_list, fname, 0) < 0)) fnamecmp = fname; - } else - fnamecmp = partialptr = fname; - - if (inplace && make_backups) { - if (!(fnamecmp = get_backup_name(fname))) + } else { + /* Reminder: --inplace && --partial-dir are never + * enabled at the same time. */ + if (inplace && make_backups) { + if (!(fnamecmp = get_backup_name(fname))) + fnamecmp = fname; + } else if (partial_dir && partialptr) fnamecmp = partialptr; + else + fnamecmp = fname; } + initial_stats = stats; + /* open the file */ fd1 = do_open(fnamecmp, O_RDONLY, 0); - if (fd1 == -1 && fnamecmp != fname) { - fnamecmp = fname; - fd1 = do_open(fnamecmp, O_RDONLY, 0); - } + if (fd1 == -1 && protocol_version < 29) { + if (fnamecmp != fname) { + fnamecmp = fname; + 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 && basis_dir[0]) { + /* pre-29 allowed only one alternate basis */ + pathjoin(fnamecmpbuf, sizeof fnamecmpbuf, + basis_dir[0], fname); + fnamecmp = fnamecmpbuf; + fd1 = do_open(fnamecmp, O_RDONLY, 0); + } } if (fd1 != -1 && do_fstat(fd1,&st) != 0) { @@ -507,8 +591,6 @@ continue; } - strlcpy(template, fnametmp, sizeof template); - /* we initially set the perms without the * setuid/setgid bits to ensure that there is no race * condition. They are then correctly updated after @@ -522,7 +604,8 @@ * transferred, but that may not be the case with -R */ if (fd2 == -1 && relative_paths && errno == ENOENT && create_directory_path(fnametmp, orig_umask) == 0) { - strlcpy(fnametmp, template, sizeof fnametmp); + /* Get back to name with XXXXXX in it. */ + get_tmpname(fnametmp, fname); fd2 = do_mkstemp(fnametmp, file->mode & INITACCESSPERMS); } if (fd2 == -1) { @@ -538,14 +621,18 @@ cleanup_set(fnametmp, partialptr, file, fd1, fd2); } - if (!am_server && verbose) /* log the transfer */ + /* log the transfer */ + if (log_before_transfer) + log_item(file, &initial_stats, iflags, NULL); + else if (!am_server && verbose && do_progress) rprintf(FINFO, "%s\n", safe_fname(fname)); /* recv file data */ recv_ok = receive_data(f_in, fnamecmp, fd1, st.st_size, fname, fd2, file->length); - log_recv(file, &initial_stats); + if (!log_before_transfer) + log_item(file, &initial_stats, iflags, NULL); if (fd1 != -1) close(fd1); @@ -555,26 +642,35 @@ exit_cleanup(RERR_FILEIO); } - if (recv_ok || inplace) - finish_transfer(fname, fnametmp, file, recv_ok); - else if (keep_partial && partialptr - && handle_partial_dir(partialptr, PDIR_CREATE)) - finish_transfer(partialptr, fnametmp, file, 0); - else { + if ((recv_ok && (!delay_updates || !partialptr)) || inplace) { + finish_transfer(fname, fnametmp, file, recv_ok, 1); + if (partialptr != fname && fnamecmp == partialptr) { + do_unlink(partialptr); + handle_partial_dir(partialptr, PDIR_DELETE); + } + } else if (keep_partial && partialptr + && handle_partial_dir(partialptr, PDIR_CREATE)) { + finish_transfer(partialptr, fnametmp, file, recv_ok, + !partial_dir); + if (delay_updates && recv_ok) { + set_delayed_bit(i); + recv_ok = -1; + } + } else { partialptr = NULL; do_unlink(fnametmp); } - if (partialptr != fname && fnamecmp == partialptr && recv_ok) { - do_unlink(partialptr); - handle_partial_dir(partialptr, PDIR_DELETE); - } - cleanup_disable(); - if (!recv_ok) { - int msgtype = csum_length == SUM_LENGTH || read_batch ? - FERROR : FINFO; + if (recv_ok > 0) { + if (remove_sent_files + || (preserve_hard_links && file->link_u.links)) { + SIVAL(numbuf, 0, i); + send_msg(MSG_SUCCESS, numbuf, 4); + } + } else if (!recv_ok) { + int msgtype = phase || read_batch ? FERROR : FINFO; if (msgtype == FERROR || verbose) { char *errstr, *redostr, *keptstr; if (!(keep_partial && partialptr) && !inplace) @@ -595,17 +691,16 @@ errstr, safe_fname(fname), keptstr, redostr); } - if (csum_length != SUM_LENGTH) { - char buf[4]; - SIVAL(buf, 0, i); - send_msg(MSG_REDO, buf, 4); + if (!phase) { + SIVAL(numbuf, 0, i); + send_msg(MSG_REDO, numbuf, 4); } } } make_backups = save_make_backups; - if (delete_after && recurse && !local_name && flist->count > 0) - delete_files(flist); + if (phase == 2 && delay_updates) /* for protocol_version < 29 */ + handle_delayed_updates(flist, local_name); if (verbose > 2) rprintf(FINFO,"recv_files finished\n"); diff -urN --exclude=patches rsync-2.6.3/rsync.1 rsync-2.6.4/rsync.1 --- rsync-2.6.3/rsync.1 2004-09-30 09:36:01.000000000 -0700 +++ rsync-2.6.4/rsync.1 2005-03-30 19:14:11.000000000 -0800 @@ -1,4 +1,4 @@ -.TH "rsync" "1" "30 Sep 2004" "" "" +.TH "rsync" "1" "30 Mar 2005" "" "" .SH "NAME" rsync \- faster, flexible replacement for rcp .SH "SYNOPSIS" @@ -54,46 +54,39 @@ .IP o for copying local files\&. This is invoked when neither source nor destination path contains a : separator -.IP .IP o for copying from the local machine to a remote machine using a remote shell program as the transport (such as ssh or rsh)\&. This is invoked when the destination path contains a single : separator\&. -.IP .IP o for copying from a remote machine to the local machine using a remote shell program\&. This is invoked when the source contains a : separator\&. -.IP .IP o for copying from a remote rsync server to the local machine\&. This is invoked when the source path contains a :: separator or an rsync:// URL\&. -.IP .IP o for copying from the local machine to a remote rsync server\&. This is invoked when the destination path contains a :: separator or an rsync:// URL\&. -.IP .IP o for copying from a remote machine using a remote shell program as the transport, using rsync server on the remote machine\&. This is invoked when the source path contains a :: -separator and the --rsh=COMMAND (aka "-e COMMAND") option is +separator and the \fB--rsh=COMMAND\fP (aka "\fB-e COMMAND\fP") option is also provided\&. -.IP .IP o for copying from the local machine to a remote machine using a remote shell program as the transport, using rsync server on the remote machine\&. This is invoked when the destination path contains a :: separator and the ---rsh=COMMAND option is also provided\&. -.IP +\fB--rsh=COMMAND\fP option is also provided\&. .IP o for listing files on a remote machine\&. This is done the same way as rsync transfers except that you leave off the -local destination\&. +local destination\&. .PP Note that in all cases (other than listing) at least one of the source and destination paths must be local\&. @@ -108,14 +101,14 @@ for its communications, but it may have been configured to use a different remote shell by default, such as rsh or remsh\&. .PP -You can also specify any remote shell you like, either by using the -e +You can also specify any remote shell you like, either by using the \fB-e\fP command line option, or by setting the RSYNC_RSH environment variable\&. .PP One common substitute is to use ssh, which offers a high degree of security\&. .PP Note that rsync must be installed on both the source and destination -machines\&. +machines\&. .PP .SH "USAGE" .PP @@ -125,7 +118,7 @@ Perhaps the best way to explain the syntax is with some examples: .PP .RS -rsync -t *\&.c foo:src/ +\f(CWrsync -t *\&.c foo:src/\fP .RE .PP This would transfer all files matching the pattern *\&.c from the @@ -135,7 +128,7 @@ differences\&. See the tech report for details\&. .PP .RS -rsync -avz foo:src/bar /data/tmp +\f(CWrsync -avz foo:src/bar /data/tmp\fP .RE .PP This would recursively transfer all files from the directory src/bar on the @@ -146,7 +139,7 @@ size of data portions of the transfer\&. .PP .RS -rsync -avz foo:src/bar/ /data/tmp +\f(CWrsync -avz foo:src/bar/ /data/tmp\fP .RE .PP A trailing slash on the source changes this behavior to avoid creating an @@ -159,10 +152,10 @@ /dest/foo: .PP .RS -rsync -av /src/foo /dest -.RE -.RS -rsync -av /src/foo/ /dest/foo +\f(CWrsync -av /src/foo /dest\fP +.br +\f(CWrsync -av /src/foo/ /dest/foo\fP +.br .RE .PP You can also use rsync in local-only mode, where both the source and @@ -170,7 +163,7 @@ an improved copy command\&. .PP .RS -rsync somehost\&.mydomain\&.com:: +\f(CWrsync somehost\&.mydomain\&.com::\fP .RE .PP This would list all the anonymous rsync modules available on the host @@ -182,7 +175,7 @@ quoted spaces in the SRC\&. Some examples: .PP .RS -rsync host::\&'modname/dir1/file1 modname/dir2/file2\&' /dest +\f(CWrsync host::\&'modname/dir1/file1 modname/dir2/file2\&' /dest\fP .RE .PP This would copy file1 and file2 into /dest from an rsync daemon\&. Each @@ -191,7 +184,7 @@ to be a part of the filenames\&. .PP .RS -rsync -av host:\&'dir1/file1 dir2/file2\&' /dest +\f(CWrsync -av host:\&'dir1/file1 dir2/file2\&' /dest\fP .RE .PP This would copy file1 and file2 into /dest using a remote shell\&. This @@ -203,10 +196,10 @@ in place of the spaces\&. Two examples of this are: .PP .RS -rsync -av host:\&'file\e name\e with\e spaces\&' /dest -.RE -.RS -rsync -av host:file?name?with?spaces /dest +\f(CWrsync -av host:\&'file\e name\e with\e spaces\&' /dest\fP +.br +\f(CWrsync -av host:file?name?with?spaces /dest\fP +.br .RE .PP This latter example assumes that your shell passes through unmatched @@ -216,7 +209,7 @@ .PP It is also possible to use rsync without a remote shell as the transport\&. In this case you will connect to a remote rsync server -running on TCP port 873\&. +running on TCP port 873\&. .PP You may establish the connection via a web proxy by setting the environment variable RSYNC_PROXY to a hostname:port pair pointing to @@ -227,17 +220,14 @@ that: .PP .IP o -you use a double colon :: instead of a single colon to -separate the hostname from the path or an rsync:// URL\&. -.IP +you either use a double colon :: instead of a single colon to +separate the hostname from the path, or you use an rsync:// URL\&. .IP o the remote server may print a message of the day when you connect\&. -.IP .IP o if you specify no path name on the remote server then the list of accessible paths on the server will be shown\&. -.IP .IP o if you specify no local destination then a listing of the specified files on the remote server is provided\&. @@ -245,11 +235,11 @@ Some paths on the remote server may require authentication\&. If so then you will receive a password prompt when you connect\&. You can avoid the password prompt by setting the environment variable RSYNC_PASSWORD to -the password you want to use or using the --password-file option\&. This +the password you want to use or using the \fB--password-file\fP option\&. This may be useful when scripting rsync\&. .PP WARNING: On some systems environment variables are visible to all -users\&. On those systems using --password-file is recommended\&. +users\&. On those systems using \fB--password-file\fP is recommended\&. .PP .SH "CONNECTING TO AN RSYNC SERVER OVER A REMOTE SHELL PROGRAM" .PP @@ -259,37 +249,42 @@ to a remote machine via ssh (for encryption or to get through a firewall), but you still want to have access to the rsync server features (see RUNNING AN RSYNC SERVER OVER A REMOTE SHELL PROGRAM, -below)\&. +below)\&. .PP From the user\&'s perspective, using rsync in this way is the same as using it to connect to an rsync server, except that you must explicitly set the remote shell program on the command line with ---rsh=COMMAND\&. (Setting RSYNC_RSH in the environment will not turn on +\fB--rsh=COMMAND\fP\&. (Setting RSYNC_RSH in the environment will not turn on this functionality\&.) .PP In order to distinguish between the remote-shell user and the rsync server user, you can use \&'-l user\&' on your remote-shell command: .PP -.RS -rsync -av --rsh="ssh -l ssh-user" rsync-user@host::module[/path] local-path -.RE + +.nf + + rsync -av --rsh="ssh -l ssh-user" \e + rsync-user@host::module[/path] local-path +.fi + + .PP The "ssh-user" will be used at the ssh level; the "rsync-user" will be used to check against the rsyncd\&.conf on the remote host\&. .PP .SH "RUNNING AN RSYNC SERVER" .PP -An rsync server is configured using a configuration file\&. Please see the +An rsync server is configured using a configuration file\&. Please see the rsyncd\&.conf(5) man page for more information\&. By default the configuration file is called /etc/rsyncd\&.conf, unless rsync is running over a remote shell program and is not running as root; in that case, the default name -is rsyncd\&.conf in the current directory on the remote computer +is rsyncd\&.conf in the current directory on the remote computer (typically $HOME)\&. .PP .SH "RUNNING AN RSYNC SERVER OVER A REMOTE SHELL PROGRAM" .PP See the rsyncd\&.conf(5) man page for full information on the rsync -server configuration file\&. +server configuration file\&. .PP Several configuration options will not be available unless the remote user is root (e\&.g\&. chroot, setuid/setgid, etc\&.)\&. There is no need to @@ -307,7 +302,7 @@ files and mail folders, I use a cron job that runs .PP .RS -rsync -Cavz \&. arvidsjaur:backup +\f(CWrsync -Cavz \&. arvidsjaur:backup\fP .RE .PP each night over a PPP connection to a duplicate directory on my machine @@ -316,121 +311,145 @@ To synchronize my samba source trees I use the following Makefile targets: .PP -.RS -get: -.br -rsync -avuzb --exclude \&'*~\&' samba:samba/ \&. -.PP -put: -.br -rsync -Cavuzb \&. samba:samba/ -.PP -sync: get put -.RE + +.nf + + get: + rsync -avuzb --exclude \&'*~\&' samba:samba/ \&. + put: + rsync -Cavuzb \&. samba:samba/ + sync: get put +.fi + + .PP this allows me to sync with a CVS directory at the other end of the -connection\&. I then do cvs operations on the remote machine, which saves a -lot of time as the remote cvs protocol isn\&'t very efficient\&. +connection\&. I then do CVS operations on the remote machine, which saves a +lot of time as the remote CVS protocol isn\&'t very efficient\&. .PP I mirror a directory between my "old" and "new" ftp sites with the -command +command: .PP -.RS -rsync -az -e ssh --delete ~ftp/pub/samba/ nimbus:"~ftp/pub/tridge/samba" -.RE +\f(CWrsync -az -e ssh --delete ~ftp/pub/samba nimbus:"~ftp/pub/tridge"\fP .PP -this is launched from cron every few hours\&. +This is launched from cron every few hours\&. .PP .SH "OPTIONS SUMMARY" .PP Here is a short summary of the options available in rsync\&. Please refer -to the detailed description below for a complete description\&. -.PP - +to the detailed description below for a complete description\&. .nf -v, --verbose increase verbosity - -q, --quiet decrease verbosity - -c, --checksum always checksum - -a, --archive archive mode, equivalent to -rlptgoD + -q, --quiet suppress non-error messages + -c, --checksum skip based on checksum, not mod-time & size + -a, --archive archive mode; same as -rlptgoD (no -H) -r, --recursive recurse into directories -R, --relative use relative path names --no-relative turn off --relative --no-implied-dirs don\&'t send implied dirs with -R -b, --backup make backups (see --suffix & --backup-dir) - --backup-dir make backups into this directory + --backup-dir=DIR make backups into hierarchy based in DIR --suffix=SUFFIX backup suffix (default ~ w/o --backup-dir) - -u, --update update only (don\&'t overwrite newer files) - --inplace update the destination files inplace - -K, --keep-dirlinks treat symlinked dir on receiver as dir + -u, --update skip files that are newer on the receiver + --inplace update destination files in-place + -d, --dirs transfer directories without recursing -l, --links copy symlinks as symlinks - -L, --copy-links copy the referent of all symlinks - --copy-unsafe-links copy the referent of "unsafe" symlinks - --safe-links ignore "unsafe" symlinks + -L, --copy-links transform symlink into referent file/dir + --copy-unsafe-links only "unsafe" symlinks are transformed + --safe-links ignore symlinks that point outside the tree -H, --hard-links preserve hard links + -K, --keep-dirlinks treat symlinked dir on receiver as dir -p, --perms preserve permissions -o, --owner preserve owner (root only) -g, --group preserve group -D, --devices preserve devices (root only) -t, --times preserve times + -O, --omit-dir-times omit directories when preserving times -S, --sparse handle sparse files efficiently -n, --dry-run show what would have been transferred - -W, --whole-file copy whole files, no incremental checks - --no-whole-file turn off --whole-file + -W, --whole-file copy files whole (without rsync algorithm) + --no-whole-file always use incremental rsync algorithm -x, --one-file-system don\&'t cross filesystem boundaries -B, --block-size=SIZE force a fixed checksum block-size - -e, --rsh=COMMAND specify the remote shell - --rsync-path=PATH specify path to rsync on the remote machine + -e, --rsh=COMMAND specify the remote shell to use + --rsync-path=PROGRAM specify the rsync to run on 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-excluded also delete excluded files on receiver + --delete-before receiver deletes before transfer (default) + --delete-during receiver deletes during xfer, not before --delete-after receiver deletes after transfer, not before + --delete-excluded also delete excluded files on receiver --ignore-errors delete even if there are I/O errors + --force force deletion of dirs even if not empty --max-delete=NUM don\&'t delete more than NUM files + --max-size=SIZE don\&'t transfer any file larger than SIZE --partial keep partially transferred files --partial-dir=DIR put a partially transferred file into DIR - --force force deletion of dirs even if not empty + --delay-updates put all updated files into place at end --numeric-ids don\&'t map uid/gid values by user/group name --timeout=TIME set I/O timeout in seconds - -I, --ignore-times turn off mod time & file size quick check - --size-only ignore mod time for quick check (use size) - --modify-window=NUM compare mod times with reduced accuracy - -T --temp-dir=DIR create temporary files in directory DIR + -I, --ignore-times don\&'t skip files that match size and time + --size-only skip files that match in size + --modify-window=NUM compare mod-times with reduced accuracy + -T, --temp-dir=DIR create temporary files in directory DIR + -y, --fuzzy find similar file for basis if no dest file --compare-dest=DIR also compare received files relative to DIR - --link-dest=DIR create hardlinks to DIR for unchanged files - -P equivalent to --partial --progress - -z, --compress compress file data - -C, --cvs-exclude auto ignore files in the same way CVS does + --copy-dest=DIR \&.\&.\&. and include copies of unchanged files + --link-dest=DIR hardlink to files in DIR when unchanged + -z, --compress compress file data during the transfer + -C, --cvs-exclude auto-ignore files in the same way CVS does + -f, --filter=RULE add a file-filtering RULE + -F same as --filter=\&'dir-merge /\&.rsync-filter\&' + repeated: --filter=\&'- \&.rsync-filter\&' --exclude=PATTERN exclude files matching PATTERN - --exclude-from=FILE exclude patterns listed in FILE + --exclude-from=FILE read exclude patterns from FILE --include=PATTERN don\&'t exclude files matching PATTERN - --include-from=FILE don\&'t exclude patterns listed in FILE - --files-from=FILE read FILE for list of source-file names - -0 --from0 all file lists are delimited by nulls + --include-from=FILE read include patterns from FILE + --files-from=FILE read list of source-file names from FILE + -0, --from0 all *from file lists are delimited by nulls --version print version number - --daemon run as an rsync daemon - --no-detach do not detach from the parent - --address=ADDRESS bind to the specified address - --config=FILE specify alternate rsyncd\&.conf file - --port=PORT specify alternate rsyncd port number + --port=PORT specify double-colon alternate port number --blocking-io use blocking I/O for the remote shell - --no-blocking-io turn off --blocking-io - --stats give some file transfer stats + --no-blocking-io turn off blocking I/O when it is default + --stats give some file-transfer stats --progress show progress during transfer - --log-format=FORMAT log file transfers using specified format - --password-file=FILE get password from FILE - --bwlimit=KBPS limit I/O bandwidth, KBytes per second - --write-batch=FILE write a batch to FILE - --read-batch=FILE read a batch from FILE - --checksum-seed=NUM set block/file checksum seed - -4 --ipv4 prefer IPv4 - -6 --ipv6 prefer IPv6 + -P same as --partial --progress + -i, --itemize-changes output a change-summary for all updates + --log-format=FORMAT log file-transfers using specified format + --password-file=FILE read password from FILE + --list-only list the files instead of copying them + --bwlimit=KBPS limit I/O bandwidth; KBytes per second + --write-batch=FILE write a batched update to FILE + --read-batch=FILE read a batched update from FILE + --protocol=NUM force an older protocol version to be used + --checksum-seed=NUM set block/file checksum seed (advanced) + -4, --ipv4 prefer IPv4 + -6, --ipv6 prefer IPv6 -h, --help show this help screen +.fi + +.PP +Rsync can also be run as a daemon, in which case the following options are +accepted: +.nf + - + --daemon run as an rsync daemon + --address=ADDRESS bind to the specified address + --bwlimit=KBPS limit I/O bandwidth; KBytes per second + --config=FILE specify alternate rsyncd\&.conf file + --no-detach do not detach from the parent + --port=PORT listen on alternate port number + -v, --verbose increase verbosity + -4, --ipv4 prefer IPv4 + -6, --ipv6 prefer IPv6 + -h, --help show this help screen .fi @@ -445,20 +464,29 @@ .PP .IP "\fB-h, --help\fP" Print a short help page describing the options -available in rsync +available in rsync\&. .IP .IP "\fB--version\fP" -print the rsync version number and exit +print the rsync version number and exit\&. .IP .IP "\fB-v, --verbose\fP" This option increases the amount of information you are given during the transfer\&. By default, rsync works silently\&. A -single -v will give you information about what files are being -transferred and a brief summary at the end\&. Two -v flags will give you +single \fB-v\fP will give you information about what files are being +transferred and a brief summary at the end\&. Two \fB-v\fP flags will give you information on what files are being skipped and slightly more -information at the end\&. More than two -v flags should only be used if +information at the end\&. More than two \fB-v\fP flags should only be used if you are debugging rsync\&. .IP +Note that the names of the transferred files that are output are done using +a default \fB--log-format\fP of "%n%L", which tells you just the name of the +file and, if the item is a symlink, where it points\&. At the single \fB-v\fP +level of verbosity, this does not mention when a file gets its attributes +changed\&. If you ask for an itemized list of changed attributes (either +\fB--itemize-changes\fP or adding "%i" to the \fB--log-format\fP setting), the +output (on the client) increases to mention all items that are changed in +any way\&. See the \fB--log-format\fP option for more details\&. +.IP .IP "\fB-q, --quiet\fP" This option decreases the amount of information you are given during the transfer, notably suppressing information messages @@ -473,18 +501,19 @@ .IP "\fB--size-only\fP" Normally rsync will not transfer any files that are already the same size and have the same modification time-stamp\&. With the ---size-only option, files will not be transferred if they have the same size, +\fB--size-only\fP option, files will not be transferred if they have the same size, regardless of timestamp\&. This is useful when starting to use rsync after using another mirroring system which may not preserve timestamps exactly\&. .IP .IP "\fB--modify-window\fP" -When comparing two timestamps rsync treats -the timestamps as being equal if they are within the value of -modify_window\&. This is normally zero, but you may find it useful to -set this to a larger value in some situations\&. In particular, when -transferring to Windows FAT filesystems which cannot represent times -with a 1 second resolution --modify-window=1 is useful\&. +When comparing two timestamps, rsync treats the +timestamps as being equal if they differ by no more than the modify-window +value\&. This is normally 0 (for an exact match), but you may find it useful +to set this to a larger value in some situations\&. In particular, when +transferring to or from an MS Windows FAT filesystem (which represents +times with a 2-second resolution), \fB--modify-window=1\fP is useful +(allowing times to differ by up to 1 second)\&. .IP .IP "\fB-c, --checksum\fP" This forces the sender to checksum all files using @@ -494,18 +523,18 @@ receiver are not transferred\&. This option can be quite slow\&. .IP .IP "\fB-a, --archive\fP" -This is equivalent to -rlptgoD\&. It is a quick +This is equivalent to \fB-rlptgoD\fP\&. It is a quick way of saying you want recursion and want to preserve almost -everything\&. +everything\&. The only exception to this is if \fB--files-from\fP was +specified, in which case \fB-r\fP is not implied\&. .IP -Note however that \fB-a\fP \fBdoes not preserve hardlinks\fP, because +Note that \fB-a\fP \fBdoes not preserve hardlinks\fP, because finding multiply-linked files is expensive\&. You must separately specify \fB-H\fP\&. .IP .IP "\fB-r, --recursive\fP" This tells rsync to copy directories -recursively\&. If you don\&'t specify this then rsync won\&'t copy -directories at all\&. +recursively\&. See also \fB--dirs\fP (\fB-d\fP)\&. .IP .IP "\fB-R, --relative\fP" Use relative paths\&. This means that the full path @@ -514,42 +543,44 @@ you want to send several different directories at the same time\&. For example, if you used the command .IP - -.nf - -rsync foo/bar/foo\&.c remote:/tmp/ -.fi - - +.RS +\f(CW rsync /foo/bar/foo\&.c remote:/tmp/\fP +.RE .IP then this would create a file called foo\&.c in /tmp/ on the remote machine\&. If instead you used .IP - -.nf - -rsync -R foo/bar/foo\&.c remote:/tmp/ -.fi - - +.RS +\f(CW rsync -R /foo/bar/foo\&.c remote:/tmp/\fP +.RE .IP then a file called /tmp/foo/bar/foo\&.c would be created on the remote -machine -- the full path name is preserved\&. +machine -- the full path name is preserved\&. To limit the amount of +path information that is sent, do something like this: +.IP +.RS +\f(CW cd /foo\fP +.br +\f(CW rsync -R bar/foo\&.c remote:/tmp/\fP +.br +.RE +.IP +That would create /tmp/bar/foo\&.c on the remote machine\&. .IP .IP "\fB--no-relative\fP" -Turn off the --relative option\&. This is only -needed if you want to use --files-from without its implied --relative +Turn off the \fB--relative\fP option\&. This is only +needed if you want to use \fB--files-from\fP without its implied \fB--relative\fP file processing\&. .IP .IP "\fB--no-implied-dirs\fP" -When combined with the --relative option, the +When combined with the \fB--relative\fP option, the implied directories in each path are not explicitly duplicated as part of the transfer\&. This makes the transfer more optimal and also allows the two sides to have non-matching symlinks in the implied part of the -path\&. For instance, if you transfer the file "/path/foo/file" with -R, +path\&. For instance, if you transfer the file "/path/foo/file" with \fB-R\fP, the default is for rsync to ensure that "/path" and "/path/foo" on the destination exactly match the directories/symlinks of the source\&. Using -the --no-implied-dirs option would omit both of these implied dirs, +the \fB--no-implied-dirs\fP option would omit both of these implied dirs, which means that if "/path" was a real directory on one machine and a symlink of the other machine, rsync would not try to change this\&. .IP @@ -557,62 +588,69 @@ With this option, preexisting destination files are renamed as each file is transferred or deleted\&. You can control where the backup file goes and what (if any) suffix gets appended using the ---backup-dir and --suffix options\&. +\fB--backup-dir\fP and \fB--suffix\fP options\&. +Note that if you don\&'t specify \fB--backup-dir\fP, the \fB--omit-dir-times\fP +option will be enabled\&. .IP .IP "\fB--backup-dir=DIR\fP" -In combination with the --backup option, this +In combination with the \fB--backup\fP option, this tells rsync to store all backups in the specified directory\&. This is very useful for incremental backups\&. You can additionally -specify a backup suffix using the --suffix option +specify a backup suffix using the \fB--suffix\fP option (otherwise the files backed up in the specified directory will keep their original filenames)\&. -If DIR is a relative path, it is relative to the destination directory -(which changes in a recursive transfer)\&. .IP .IP "\fB--suffix=SUFFIX\fP" This option allows you to override the default -backup suffix used with the --backup (-b) option\&. The default suffix is a ~ -if no --backup-dir was specified, otherwise it is an empty string\&. +backup suffix used with the \fB--backup\fP (\fB-b\fP) option\&. The default suffix is a ~ +if no -\fB-backup-dir\fP was specified, otherwise it is an empty string\&. .IP .IP "\fB-u, --update\fP" -This forces rsync to skip any files for which the -destination file already exists and has a date later than the source -file\&. +This forces rsync to skip any files which exist on +the destination and have a modified time that is newer than the source +file\&. (If an existing destination file has a modify time equal to the +source file\&'s, it will be updated if the sizes are different\&.) .IP -In the currently implementation, a difference of file format is always +In the current implementation of \fB--update\fP, a difference of file format +between the sender and receiver is always considered to be important enough for an update, no matter what date is on the objects\&. In other words, if the source has a directory or a symlink where the destination has a file, the transfer would occur regardless of the timestamps\&. This might change in the future (feel free to comment on this on the mailing list if you have an opinion)\&. .IP -.IP "\fB-K, --keep-dirlinks\fP" -On the receiving side, if a symlink is -pointing to a directory, it will be treated as matching a directory -from the sender\&. -.IP .IP "\fB--inplace\fP" This causes rsync not to create a new copy of the file and then move it into place\&. Instead rsync will overwrite the existing -file, meaning that the rsync algorithm can\&'t extract the full amount of -network reduction it might otherwise (since it does not yet try to sort -data matches -- a future version may improve this)\&. +file, meaning that the rsync algorithm can\&'t accomplish the full amount of +network reduction it might be able to otherwise (since it does not yet try +to sort data matches)\&. One exception to this is if you combine the option +with \fB--backup\fP, since rsync is smart enough to use the backup file as the +basis file for the transfer\&. .IP This option is useful for transfer of large files with block-based changes or appended data, and also on systems that are disk bound, not network bound\&. .IP -The option implies --partial (since an interrupted transfer does not delete -the file), but conflicts with --partial-dir, --compare-dest, and ---link-dest (a future rsync version will hopefully update the protocol to -remove these restrictions)\&. +The option implies \fB--partial\fP (since an interrupted transfer does not delete +the file), but conflicts with \fB--partial-dir\fP and \fB--delay-updates\fP\&. +Prior to rsync 2\&.6\&.4 \fB--inplace\fP was also incompatible with \fB--compare-dest\fP +and \fB--link-dest\fP\&. .IP WARNING: The file\&'s data will be in an inconsistent state during the transfer (and possibly afterward if the transfer gets interrupted), so you should not use this option to update files that are in use\&. Also note that -rsync will be unable to update a file inplace that is not writable by the +rsync will be unable to update a file in-place that is not writable by the receiving user\&. .IP +.IP "\fB-d, --dirs\fP" +Tell the sending side to include any directories that +are encountered\&. Unlike \fB--recursive\fP, a directory\&'s contents are not copied +unless the directory was specified on the command-line as either "\&." or a +name with a trailing slash (e\&.g\&. "foo/")\&. Without this option or the +\fB--recursive\fP option, rsync will skip all directories it encounters (and +output a message to that effect for each one)\&. +.IP .IP "\fB-l, --links\fP" When symlinks are encountered, recreate the symlink on the destination\&. @@ -622,22 +660,22 @@ they point to (the referent) is copied, rather than the symlink\&. In older versions of rsync, this option also had the side-effect of telling the receiving side to follow symlinks, such as symlinks to directories\&. In a -modern rsync such as this one, you\&'ll need to specify --keep-dirlinks (-K) +modern rsync such as this one, you\&'ll need to specify \fB--keep-dirlinks\fP (\fB-K\fP) to get this extra behavior\&. The only exception is when sending files to -an rsync that is too old to understand -K -- in that case, the -L option -will still have the side-effect of -K on that older receiving rsync\&. +an rsync that is too old to understand \fB-K\fP -- in that case, the \fB-L\fP option +will still have the side-effect of \fB-K\fP on that older receiving rsync\&. .IP .IP "\fB--copy-unsafe-links\fP" This tells rsync to copy the referent of symbolic links that point outside the copied tree\&. Absolute symlinks are also treated like ordinary files, and so are any symlinks in the -source path itself when --relative is used\&. +source path itself when \fB--relative\fP is used\&. .IP .IP "\fB--safe-links\fP" This tells rsync to ignore any symbolic links which point outside the copied tree\&. All absolute symlinks are -also ignored\&. Using this option in conjunction with --relative may -give unexpected results\&. +also ignored\&. Using this option in conjunction with \fB--relative\fP may +give unexpected results\&. .IP .IP "\fB-H, --hard-links\fP" This tells rsync to recreate hard links on @@ -649,6 +687,11 @@ .IP This option can be quite slow, so only use it if you need it\&. .IP +.IP "\fB-K, --keep-dirlinks\fP" +On the receiving side, if a symlink is +pointing to a directory, it will be treated as matching a directory +from the sender\&. +.IP .IP "\fB-W, --whole-file\fP" With this option the incremental rsync algorithm is not used and the whole file is sent as-is instead\&. The transfer may be @@ -658,7 +701,7 @@ the source and destination are specified as local paths\&. .IP .IP "\fB--no-whole-file\fP" -Turn off --whole-file, for use when it is the +Turn off \fB--whole-file\fP, for use when it is the default\&. .IP .IP "\fB-p, --perms\fP" @@ -675,7 +718,7 @@ destination file to be the same as the source file\&. On most systems, only the super-user can set file ownership\&. By default, the preservation is done by name, but may fall back to using the ID number in some -circumstances\&. See the --numeric-ids option for a full discussion\&. +circumstances\&. See the \fB--numeric-ids\fP option for a full discussion\&. .IP .IP "\fB-g, --group\fP" This option causes rsync to set the group of the @@ -683,7 +726,7 @@ program is not running as the super-user, only groups that the receiver is a member of will be preserved\&. By default, the preservation is done by name, but may fall back to using the ID number in some -circumstances\&. See the --numeric-ids option for a full discussion\&. +circumstances\&. See the \fB--numeric-ids\fP option for a full discussion\&. .IP .IP "\fB-D, --devices\fP" This option causes rsync to transfer character and @@ -694,10 +737,16 @@ This tells rsync to transfer modification times along with the files and update them on the remote system\&. Note that if this option is not used, the optimization that excludes files that have not been -modified cannot be effective; in other words, a missing -t or -a will -cause the next transfer to behave as if it used -I, causing all files to be +modified cannot be effective; in other words, a missing \fB-t\fP or \fB-a\fP will +cause the next transfer to behave as if it used \fB-I\fP, causing all files to be updated (though the rsync algorithm will make the update fairly efficient -if the files haven\&'t actually changed, you\&'re much better off using -t)\&. +if the files haven\&'t actually changed, you\&'re much better off using \fB-t\fP)\&. +.IP +.IP "\fB-O, --omit-dir-times\fP" +This tells rsync to omit directories when +it is preserving modification times (see \fB--times\fP)\&. If NFS is sharing +the directories on the receiving side, it is a good idea to use \fB-O\fP\&. +This option is inferred if you use \fB--backup\fP without \fB--backup-dir\fP\&. .IP .IP "\fB-n, --dry-run\fP" This tells rsync to not do any file transfers, @@ -717,56 +766,105 @@ contents of only one filesystem\&. .IP .IP "\fB--existing\fP" -This tells rsync not to create any new files - +This tells rsync not to create any new files -- only update files that already exist on the destination\&. .IP .IP "\fB--ignore-existing\fP" -This tells rsync not to update files that already exist on -the destination\&. +This tells rsync not to update files that already exist on +the destination\&. .IP -.IP "\fB--max-delete=NUM\fP" -This tells rsync not to delete more than NUM -files or directories\&. This is useful when mirroring very large trees -to prevent disasters\&. +.IP "\fB--remove-sent-files\fP" +This tells rsync to remove from the sending +side the files and/or symlinks that are newly created or whose content is +updated on the receiving side\&. Directories and devices are not removed, +nor are files/symlinks whose attributes are merely changed\&. .IP .IP "\fB--delete\fP" -This tells rsync to delete any files on the receiving -side that aren\&'t on the sending side\&. Files that are excluded from -transfer are excluded from being deleted unless you use --delete-excluded\&. +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 +send the whole directory (e\&.g\&. "dir" or "dir/") without using a wildcard +for the directory\&'s contents (e\&.g\&. "dir/*") since the wildcard is expanded +by the shell and rsync thus gets a request to transfer individual files, not +the files\&' parent directory\&. Files that are excluded from transfer are +also excluded from being deleted unless you use the \fB--delete-excluded\fP +option or mark the rules as only matching on the sending side (see the +include/exclude modifiers in the FILTER RULES section)\&. .IP -This option has no effect if directory recursion is not selected\&. +This option has no effect unless directory recursion is enabled\&. .IP This option can be dangerous if used incorrectly! It is a very good idea -to run first using the dry run option (-n) to see what files would be +to run first using the \fB--dry-run\fP option (\fB-n\fP) to see what files would be deleted to make sure important files aren\&'t listed\&. .IP -If the sending side detects any I/O errors then the deletion of any +If the sending side detects any I/O errors, then the deletion of any files at the destination will be automatically disabled\&. This is to prevent temporary filesystem failures (such as NFS errors) on the sending side causing a massive deletion of files on the -destination\&. You can override this with the --ignore-errors option\&. +destination\&. You can override this with the \fB--ignore-errors\fP option\&. +.IP +The \fB--delete\fP option may be combined with one of the --delete-WHEN options +without conflict, as well as \fB--delete-excluded\fP\&. However, if none of the +--delete-WHEN options are specified, rsync will currently choose the +\fB--delete-before\fP algorithm\&. A future version may change this to choose the +\fB--delete-during\fP algorithm\&. See also \fB--delete-after\fP\&. +.IP +.IP "\fB--delete-before\fP" +Request that the file-deletions on the receiving +side be done before the transfer starts\&. This is the default if \fB--delete\fP +or \fB--delete-excluded\fP is specified without one of the --delete-WHEN options\&. +See \fB--delete\fP (which is implied) for more details on file-deletion\&. +.IP +Deleting before the transfer is helpful if the filesystem is tight for space +and removing extraneous files would help to make the transfer possible\&. +However, it does introduce a delay before the start of the transfer, +and this delay might cause the transfer to timeout (if \fB--timeout\fP was +specified)\&. +.IP +.IP "\fB--delete-during, --del\fP" +Request that the file-deletions on the +receiving side be done incrementally as the transfer happens\&. This is +a faster method than choosing the before- or after-transfer algorithm, +but it is only supported beginning with rsync version 2\&.6\&.4\&. +See \fB--delete\fP (which is implied) for more details on file-deletion\&. +.IP +.IP "\fB--delete-after\fP" +Request that the file-deletions on the receiving +side be done after the transfer has completed\&. This is useful if you +are sending new per-directory merge files as a part of the transfer and +you want their exclusions to take effect for the delete phase of the +current transfer\&. +See \fB--delete\fP (which is implied) for more details on file-deletion\&. .IP .IP "\fB--delete-excluded\fP" In addition to deleting the files on the receiving side that are not on the sending side, this tells rsync to also -delete any files on the receiving side that are excluded (see --exclude)\&. -Implies --delete\&. -.IP -.IP "\fB--delete-after\fP" -By default rsync does file deletions on the -receiving side before transferring files to try to ensure that there is -sufficient space on the receiving filesystem\&. If you want to delete -after transferring, use the --delete-after switch\&. Implies --delete\&. +delete any files on the receiving side that are excluded (see \fB--exclude\fP)\&. +See the FILTER RULES section for a way to make individual exclusions behave +this way on the receiver, and for a way to protect files from +\fB--delete-excluded\fP\&. +See \fB--delete\fP (which is implied) for more details on file-deletion\&. .IP .IP "\fB--ignore-errors\fP" -Tells --delete to go ahead and delete files +Tells \fB--delete\fP to go ahead and delete files even when there are I/O errors\&. .IP .IP "\fB--force\fP" This options tells rsync to delete directories even if they are not empty when they are to be replaced by non-directories\&. This -is only relevant without --delete because deletions are now done depth-first\&. -Requires the --recursive option (which is implied by -a) to have any effect\&. +is only relevant without \fB--delete\fP because deletions are now done depth-first\&. +Requires the \fB--recursive\fP option (which is implied by \fB-a\fP) to have any effect\&. +.IP +.IP "\fB--max-delete=NUM\fP" +This tells rsync not to delete more than NUM +files or directories (NUM must be non-zero)\&. +This is useful when mirroring very large trees to prevent disasters\&. +.IP +.IP "\fB--max-size=SIZE\fP" +This tells rsync to avoid transferring any +file that is larger than the specified SIZE\&. The SIZE value can be +suffixed with a letter to indicate a size multiplier (K, M, or G) and +may be a fractional value (e\&.g\&. "\fB--max-size=1\&.5m\fP")\&. .IP .IP "\fB-B, --block-size=BLOCKSIZE\fP" This forces the block size used in @@ -790,22 +888,32 @@ presented to rsync as a single argument\&. For example: .IP .RS --e "ssh -p 2234" +\f(CW -e "ssh -p 2234"\fP .RE .IP (Note that ssh users can alternately customize site-specific connect options in their \&.ssh/config file\&.) .IP You can also choose the remote shell program using the RSYNC_RSH -environment variable, which accepts the same range of values as -e\&. +environment variable, which accepts the same range of values as \fB-e\fP\&. +.IP +See also the \fB--blocking-io\fP option which is affected by this option\&. +.IP +.IP "\fB--rsync-path=PROGRAM\fP" +Use this to specify what program is to be run +on the remote machine to start-up rsync\&. Often used when rsync is not in +the default remote-shell\&'s path (e\&.g\&. --rsync-path=/usr/local/bin/rsync)\&. +Note that PROGRAM is run with the help of a shell, so it can be any +program, script, or command sequence you\&'d care to run, so long as it does +not corrupt the standard-in & standard-out that rsync is using to +communicate\&. .IP -See also the --blocking-io option which is affected by this option\&. +One tricky example is to set a different default directory on the remote +machine for use with the \fB--relative\fP option\&. For instance: .IP -.IP "\fB--rsync-path=PATH\fP" -Use this to specify the path to the copy of -rsync on the remote machine\&. Useful when it\&'s not in your path\&. Note -that this is the full path to the binary, not just the directory that -the binary is in\&. +.RS +\f(CW rsync -avR --rsync-path="cd /a/b && rsync" hst:c/d /e/\fP +.RE .IP .IP "\fB-C, --cvs-exclude\fP" This is a useful shorthand for excluding a @@ -816,9 +924,11 @@ The exclude list is initialized to: .IP .RS -RCS SCCS CVS CVS\&.adm RCSLOG cvslog\&.* tags TAGS \&.make\&.state +.RS +\f(CWRCS SCCS CVS CVS\&.adm RCSLOG cvslog\&.* tags TAGS \&.make\&.state \&.nse_depinfo *~ #* \&.#* ,* _$* *$ *\&.old *\&.bak *\&.BAK *\&.orig *\&.rej -\&.del-* *\&.a *\&.olb *\&.o *\&.obj *\&.so *\&.exe *\&.Z *\&.elc *\&.ln core \&.svn/ +\&.del-* *\&.a *\&.olb *\&.o *\&.obj *\&.so *\&.exe *\&.Z *\&.elc *\&.ln core \&.svn/\fP +.RE .RE .IP then files listed in a $HOME/\&.cvsignore are added to the list and any @@ -826,32 +936,74 @@ are delimited by whitespace)\&. .IP Finally, any file is ignored if it is in the same directory as a -\&.cvsignore file and matches one of the patterns listed therein\&. +\&.cvsignore file and matches one of the patterns listed therein\&. Unlike +rsync\&'s filter/exclude files, these patterns are split on whitespace\&. See the \fBcvs(1)\fP manual for more information\&. .IP -.IP "\fB--exclude=PATTERN\fP" -This option allows you to selectively exclude -certain files from the list of files to be transferred\&. This is most -useful in combination with a recursive transfer\&. +If you\&'re combining \fB-C\fP with your own \fB--filter\fP rules, you should +note that these CVS excludes are appended at the end of your own rules, +regardless of where the \fB-C\fP was placed on the command-line\&. This makes them +a lower priority than any rules you specified explicitly\&. If you want to +control where these CVS excludes get inserted into your filter rules, you +should omit the \fB-C\fP as a command-line option and use a combination of +\fB--filter=:C\fP and \fB--filter=-C\fP (either on your command-line or by +putting the ":C" and "-C" rules into a filter file with your other rules)\&. +The first option turns on the per-directory scanning for the \&.cvsignore +file\&. The second option does a one-time import of the CVS excludes +mentioned above\&. +.IP +.IP "\fB-f, --filter=RULE\fP" +This option allows you to add rules to selectively +exclude certain files from the list of files to be transferred\&. This is +most useful in combination with a recursive transfer\&. .IP -You may use as many --exclude options on the command line as you like +You may use as many \fB--filter\fP options on the command line as you like to build up the list of files to exclude\&. .IP -See the EXCLUDE PATTERNS section for detailed information on this option\&. +See the FILTER RULES section for detailed information on this option\&. +.IP +.IP "\fB-F\fP" +The \fB-F\fP option is a shorthand for adding two \fB--filter\fP rules to +your command\&. The first time it is used is a shorthand for this rule: +.IP +.RS +\f(CW --filter=\&': /\&.rsync-filter\&'\fP +.RE +.IP +This tells rsync to look for per-directory \&.rsync-filter files that have +been sprinkled through the hierarchy and use their rules to filter the +files in the transfer\&. If \fB-F\fP is repeated, it is a shorthand for this +rule: +.IP +.RS +\f(CW --filter=\&'- \&.rsync-filter\&'\fP +.RE +.IP +This filters out the \&.rsync-filter files themselves from the transfer\&. +.IP +See the FILTER RULES section for detailed information on how these options +work\&. +.IP +.IP "\fB--exclude=PATTERN\fP" +This option is a simplified form of the +\fB--filter\fP option that defaults to an exclude rule and does not allow +the full rule-parsing syntax of normal filter rules\&. +.IP +See the FILTER RULES section for detailed information on this option\&. .IP .IP "\fB--exclude-from=FILE\fP" -This option is similar to the --exclude +This option is similar to the \fB--exclude\fP 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\&. .IP .IP "\fB--include=PATTERN\fP" -This option tells rsync to not exclude the -specified pattern of filenames\&. This is useful as it allows you to -build up quite complex exclude/include rules\&. +This option is a simplified form of the +\fB--filter\fP option that defaults to an include rule and does not allow +the full rule-parsing syntax of normal filter rules\&. .IP -See the EXCLUDE PATTERNS section for detailed information on this option\&. +See the FILTER RULES section for detailed information on this option\&. .IP .IP "\fB--include-from=FILE\fP" This specifies a list of include patterns @@ -862,13 +1014,21 @@ Using this option allows you to specify the exact list of files to transfer (as read from the specified FILE or "-" for standard input)\&. It also tweaks the default behavior of rsync to make -transferring just the specified files and directories easier\&. For -instance, the --relative option is enabled by default when this option -is used (use --no-relative if you want to turn that off), all -directories specified in the list are created on the destination (rather -than being noisily skipped without -r), and the -a (--archive) option\&'s -behavior does not imply -r (--recursive) -- specify it explicitly, if -you want it\&. +transferring just the specified files and directories easier: +.IP +.RS +.IP o +The \fB--relative\fP (\fB-R\fP) option is implied, which preserves the path +information that is specified for each item in the file (use +\fB--no-relative\fP if you want to turn that off)\&. +.IP o +The \fB--dirs\fP (\fB-d\fP) option is implied, which will create directories +specified in the list on the destination rather than noisily skipping +them\&. +.IP o +The \fB--archive\fP (\fB-a\fP) option\&'s behavior does not imply \fB--recursive\fP +(\fB-r\fP), so specify it explicitly, if you want it\&. +.RE .IP The file names that are read from the FILE are all relative to the source dir -- any leading slashes are removed and no "\&.\&." references are @@ -876,25 +1036,25 @@ command: .IP .RS -rsync -a --files-from=/tmp/foo /usr remote:/backup +\f(CW rsync -a --files-from=/tmp/foo /usr remote:/backup\fP .RE .IP If /tmp/foo contains the string "bin" (or even "/bin"), the /usr/bin directory will be created as /backup/bin on the remote host (but the -contents of the /usr/bin dir would not be sent unless you specified -r +contents of the /usr/bin dir would not be sent unless you specified \fB-r\fP or the names were explicitly listed in /tmp/foo)\&. Also keep in mind -that the effect of the (enabled by default) --relative option is to +that the effect of the (enabled by default) \fB--relative\fP option is to duplicate only the path info that is read from the file -- it does not force the duplication of the source-spec path (/usr in this case)\&. .IP -In addition, the --files-from file can be read from the remote host +In addition, the \fB--files-from\fP file can be read from the remote host instead of the local host if you specify a "host:" in front of the file (the host must match one end of the transfer)\&. As a short-cut, you can specify just a prefix of ":" to mean "use the remote end of the transfer"\&. For example: .IP .RS -rsync -a --files-from=:/path/file-list src:/ /tmp/copy +\f(CW rsync -a --files-from=:/path/file-list src:/ /tmp/copy\fP .RE .IP This would copy all the files specified in the /path/file-list file that @@ -903,8 +1063,9 @@ .IP "\fB-0, --from0\fP" This tells rsync that the filenames it reads from a file are terminated by a null (\&'\e0\&') character, not a NL, CR, or CR+LF\&. -This affects --exclude-from, --include-from, and --files-from\&. -It does not affect --cvs-exclude (since all names read from a \&.cvsignore +This affects \fB--exclude-from\fP, \fB--include-from\fP, \fB--files-from\fP, and any +merged files specified in a \fB--filter\fP rule\&. +It does not affect \fB--cvs-exclude\fP (since all names read from a \&.cvsignore file are split on whitespace)\&. .IP .IP "\fB-T, --temp-dir=DIR\fP" @@ -913,54 +1074,89 @@ transferred on the receiving side\&. The default behavior is to create the temporary files in the receiving directory\&. .IP +.IP "\fB-y, --fuzzy\fP" +This option tells rsync that it should look for a +basis file for any destination file that is missing\&. The current algorithm +looks in the same directory as the destination file for either a file that +has an identical size and modified-time, or a similarly-named file\&. If +found, rsync uses the fuzzy basis file to try to speed up the transfer\&. +.IP +Note that the use of the \fB--delete\fP option might get rid of any potential +fuzzy-match files, so either use \fB--delete-after\fP or specify some +filename exclusions if you need to prevent this\&. +.IP .IP "\fB--compare-dest=DIR\fP" -This option instructs rsync to use DIR on -the destination machine as an additional directory to compare destination -files against when doing transfers if the files are missing in the -destination directory\&. This is useful for doing transfers to a new -destination while leaving existing files intact, and then doing a -flash-cutover when all files have been successfully transferred (for -example by moving directories around and removing the old directory, -although this skips files that haven\&'t changed; see also --link-dest)\&. -This option increases the usefulness of --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\&. +This option instructs rsync to use \fIDIR\fP on +the destination machine as an additional hierarchy to compare destination +files against doing transfers (if the files are missing in the destination +directory)\&. If a file is found in \fIDIR\fP that is identical to the +sender\&'s file, the file will NOT be transferred to the destination +directory\&. This is useful for creating a sparse backup of just files that +have changed from an earlier backup\&. +.IP +Beginning in version 2\&.6\&.4, multiple \fB--compare-dest\fP directories may be +provided, which will cause rsync to search the list in the order specified +for an exact match\&. +If a match is found that differs only in attributes, a local copy is made +and the attributes updated\&. +If a match is not found, a basis file from one of the \fIDIR\fPs will be +selected to try to speed up the transfer\&. +.IP +If \fIDIR\fP is a relative path, it is relative to the destination directory\&. +See also \fB--copy-dest\fP and \fB--link-dest\fP\&. +.IP +.IP "\fB--copy-dest=DIR\fP" +This option behaves like \fB--compare-dest\fP, but +rsync will also copy unchanged files found in \fIDIR\fP to the destination +directory using a local copy\&. +This is useful for doing transfers to a new destination while leaving +existing files intact, and then doing a flash-cutover when all files have +been successfully transferred\&. +.IP +Multiple \fB--copy-dest\fP directories may be provided, which will cause +rsync to search the list in the order specified for an unchanged file\&. +If a match is not found, a basis file from one of the \fIDIR\fPs will be +selected to try to speed up the transfer\&. +.IP +If \fIDIR\fP is a relative path, it is relative to the destination directory\&. +See also \fB--compare-dest\fP and \fB--link-dest\fP\&. .IP .IP "\fB--link-dest=DIR\fP" -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\&. +This option behaves like \fB--copy-dest\fP, but +unchanged files are hard linked from \fIDIR\fP to the destination directory\&. +The files must be identical in all preserved attributes (e\&.g\&. permissions, +possibly ownership) in order for the files to be linked together\&. An example: .IP - -.nf - - - rsync -av --link-dest=$PWD/prior_dir host:src_dir/ new_dir/ - -.fi - - +.RS +\f(CW rsync -av --link-dest=$PWD/prior_dir host:src_dir/ new_dir/\fP +.RE +.IP +Beginning in version 2\&.6\&.4, multiple \fB--link-dest\fP directories may be +provided, which will cause rsync to search the list in the order specified +for an exact match\&. +If a match is found that differs only in attributes, a local copy is made +and the attributes updated\&. +If a match is not found, a basis file from one of the \fIDIR\fPs will be +selected to try to speed up the transfer\&. +.IP +If \fIDIR\fP is a relative path, it is relative to the destination directory\&. +See also \fB--compare-dest\fP and \fB--copy-dest\fP\&. .IP -Like \fB--compare-dest\fP if DIR is a relative path, it is relative to the -destination directory\&. Note that rsync versions prior to 2\&.6\&.1 had a bug that could prevent ---link-dest from working properly for a non-root user when -o was specified -(or implied by -a)\&. If the receiving rsync is not new enough, you can work -around this bug by avoiding the -o option\&. +\fB--link-dest\fP from working properly for a non-root user when \fB-o\fP was specified +(or implied by \fB-a\fP)\&. You can work-around this bug by avoiding the \fB-o\fP option +when sending to an old rsync\&. .IP .IP "\fB-z, --compress\fP" -With this option, rsync compresses any data from -the files that it sends to the destination machine\&. This -option is useful on slow connections\&. The compression method used is the -same method that gzip uses\&. -.IP -Note this this option typically achieves better compression ratios -that can be achieved by using a compressing remote shell, or a -compressing transport, as it takes advantage of the implicit -information sent for matching data blocks\&. +With this option, rsync compresses the file data +as it is sent to the destination machine, which reduces the amount of data +being transmitted -- something that is useful over a slow connection\&. +.IP +Note this this option typically achieves better compression ratios that can +be achieved by using a compressing remote shell or a compressing transport +because it takes advantage of the implicit information in the matching data +blocks that are not explicitly sent over the connection\&. .IP .IP "\fB--numeric-ids\fP" With this option rsync will transfer numeric group @@ -969,7 +1165,7 @@ .IP By default rsync will use the username and groupname to determine what ownership to give files\&. The special uid 0 and the special group -0 are never mapped via user/group names even if the --numeric-ids +0 are never mapped via user/group names even if the \fB--numeric-ids\fP option is not specified\&. .IP If a user or group has no name on the source system or it has no match @@ -984,45 +1180,12 @@ timeout in seconds\&. If no data is transferred for the specified time then rsync will exit\&. The default is 0, which means no timeout\&. .IP -.IP "\fB--daemon\fP" -This tells rsync that it is to run as a daemon\&. The -daemon may be accessed using the \fBhost::module\fP or -\fBrsync://host/module/\fP syntax\&. -.IP -If standard input is a socket then rsync will assume that it is being -run via inetd, otherwise it will detach from the current terminal and -become a background daemon\&. The daemon will read the config file -(rsyncd\&.conf) on each connect made by a client and respond to -requests accordingly\&. See the rsyncd\&.conf(5) man page for more -details\&. -.IP -.IP "\fB--no-detach\fP" -When running as a daemon, this option instructs -rsync to not detach itself and become a background process\&. This -option is required when running as a service on Cygwin, and may also -be useful when rsync is supervised by a program such as -\fBdaemontools\fP or AIX\&'s \fBSystem Resource Controller\fP\&. -\fB--no-detach\fP is also recommended when rsync is run under a -debugger\&. This option has no effect if rsync is run from inetd or -sshd\&. -.IP -.IP "\fB--address\fP" -By default rsync will bind to the wildcard address -when run as a daemon with the --daemon option or when connecting to a -rsync server\&. The --address option allows you to specify a specific IP -address (or hostname) to bind to\&. This makes virtual hosting possible -in conjunction with the --config option\&. -.IP -.IP "\fB--config=FILE\fP" -This specifies an alternate config file than -the default\&. This is only relevant when --daemon is specified\&. -The default is /etc/rsyncd\&.conf unless the daemon is running over -a remote shell program and the remote user is not root; in that case -the default is rsyncd\&.conf in the current directory (typically $HOME)\&. -.IP .IP "\fB--port=PORT\fP" This specifies an alternate TCP port number to use -rather than the default port 873\&. +rather than the default of 873\&. This is only needed if you are using the +double-colon (::) syntax to connect with an rsync daemon (since the URL +syntax has a way to specify the port as a part of the URL)\&. See also this +option in the \fB--daemon\fP mode section\&. .IP .IP "\fB--blocking-io\fP" This tells rsync to use blocking I/O when launching @@ -1032,14 +1195,110 @@ ssh prefers non-blocking I/O\&.) .IP .IP "\fB--no-blocking-io\fP" -Turn off --blocking-io, for use when it is the +Turn off \fB--blocking-io\fP, for use when it is the default\&. .IP +.IP "\fB-i, --itemize-changes\fP" +Requests a simple itemized list of the +changes that are being made to each file, including attribute changes\&. +This is exactly the same as specifying \fB--log-format=\&'%i %n%L\&'\fP\&. +.IP +The "%i" escape has a cryptic output that is 9 letters long\&. The general +format is like the string \fBUXcstpoga\fP), where \fBU\fP is replaced by the +kind of update being done, \fBX\fP is replaced by the file-type, and the +other letters represent attributes that may be output if they are being +modified\&. +.IP +The update types that replace the \fBU\fP are as follows: +.IP +.RS +.IP o +A \fB<\fP means that a file is being transferred to the remote host +(sent)\&. +.IP o +A \fB>\fP means that a file is being transferred to the local host +(received)\&. +.IP o +A \fBc\fP means that a local change/creation is occuring for the item +(such as the creation of a directory or the changing of a symlink, etc\&.)\&. +.IP o +A \fBh\fP means that the item is a hard-link to another item (requires +\fB--hard-links\fP)\&. +.IP o +A \fB\&.\fP means that the item is not being updated (though it might +have attributes that are being modified)\&. +.RE +.IP +The file-types that replace the \fBX\fP are: \fBf\fP for a file, a \fBd\fP for a +directory, an \fBL\fP for a symlink, and a \fBD\fP for a device\&. +.IP +The other letters in the string above are the actual letters that +will be output if the associated attribute for the item is being updated or +a "\&." for no change\&. Three exceptions to this are: (1) a newly created +item replaces each letter with a "+", (2) an identical item replaces the +dots with spaces, and (3) an unknown attribute replaces each letter with +a "?" (this happens when talking to an older rsync)\&. +.IP +The attribute that is associated with each letter is as follows: +.IP +.RS +.IP o +A \fBc\fP means the checksum of the file is different and will be +updated by the file transfer (requries \fB--checksum\fP)\&. +.IP o +A \fBs\fP means the size of the file is different and will be updated +by the file transfer\&. +.IP o +A \fBt\fP means the modification time is different and is being updated +to the server\&'s value (requires \fB--times\fP)\&. An alternate value of \fBT\fP +means that the time will be set to the transfer time, which happens +anytime a symlink is transferred, or when a file or device is transferred +without \fB--times\fP\&. +.IP o +A \fBp\fP means the permissions are different and are being updated to +the server\&'s value (requires \fB--perms\fP)\&. +.IP o +An \fBo\fP means the owner is different and is being updated to the +server\&'s value (requires \fB--owner\fP and root privileges)\&. +.IP o +A \fBg\fP means the group is different and is being updated to the +server\&'s value (requires \fB--group\fP and the authority to set the group)\&. +.IP o +The \fBa\fP is reserved for a future enhanced version that supports +extended file attributes, such as ACLs\&. +.RE +.IP +One other output is possible: when deleting files, the "%i" will output +the string "*deleting" for each item that is being removed (assuming that +you are talking to a recent enough rsync that it logs deletions instead of +outputting them as a verbose message)\&. +.IP .IP "\fB--log-format=FORMAT\fP" This allows you to specify exactly what the -rsync client logs to stdout on a per-file basis\&. The log format is -specified using the same format conventions as the log format option in -rsyncd\&.conf\&. +rsync client outputs to the user on a per-file basis\&. The format is a text +string containing embedded single-character escape sequences prefixed with +a percent (%) character\&. For a list of the possible escape characters, see +the "log format" setting in the rsyncd\&.conf manpage\&. (Note that this +option does not affect what a daemon logs to its logfile\&.) +.IP +Specifying this option will mention each file, dir, etc\&. that gets updated +in a significant way (a transferred file, a recreated symlink/device, or a +touched directory) unless the itemized-changes escape (%i) is included in +the string, in which case the logging of names increases to mention any +item that is updated in any way (as long as the receiving side is version +2\&.6\&.4)\&. See the \fB--itemized-changes\fP option for a description of the +output of "%i"\&. +.IP +The \fB--verbose\fP option implies a format of "%n%L", but you can use +\fB--log-format\fP without bv(--verbose) if you like, or you can override +the format of its per-file output using this option\&. +.IP +Rsync will output the log-format string prior to a file\&'s transfer unless +one of the transfer-statistic escapes is requested, in which case the +logging is done at the end of the file\&'s transfer\&. When this late logging +is in effect and \fB--progress\fP is also specified, rsync will also output +the name of the file being transferred prior to its progress information +(followed, of course, by the log-format output)\&. .IP .IP "\fB--stats\fP" This tells rsync to print a verbose set of statistics @@ -1050,64 +1309,95 @@ By default, rsync will delete any partially transferred file if the transfer is interrupted\&. In some circumstances it is more desirable to keep partially transferred files\&. Using the ---partial option tells rsync to keep the partial file which should +\fB--partial\fP option tells rsync to keep the partial file which should make a subsequent transfer of the rest of the file much faster\&. .IP .IP "\fB--partial-dir=DIR\fP" -Turns on --partial mode, but tells rsync to -put a partially transferred file into DIR instead of writing out the -file to the destination dir\&. Rsync will also use a file found in this -dir as data to speed up the transfer (i\&.e\&. when you redo the send after -rsync creates a partial file) and delete such a file after it has served -its purpose\&. Note that if --whole-file is specified (or implied) that an -existing partial-dir file will not be used to speedup the transfer (since +A better way to keep partial files than the +\fB--partial\fP option is to specify a \fIDIR\fP that will be used to hold the +partial data (instead of writing it out to the destination file)\&. +On the next transfer, rsync will use a file found in this +dir as data to speed up the resumption of the transfer and then deletes it +after it has served its purpose\&. +Note that if \fB--whole-file\fP is specified (or implied), any partial-dir +file that is found for a file that is being updated will simply be removed +(since rsync is sending files without using the incremental rsync algorithm)\&. .IP -Rsync will create the dir if it is missing (just the last dir -- not the -whole path)\&. This makes it easy to use a relative path (such as -"--partial-dir=\&.rsync-partial") to have rsync create the partial-directory -in the destination file\&'s directory (rsync will also try to remove the DIR -if a partial file was found to exist at the start of the transfer and the -DIR was specified as a relative path)\&. +Rsync will create the \fIDIR\fP if it is missing (just the last dir -- not +the whole path)\&. This makes it easy to use a relative path (such as +"\fB--partial-dir=\&.rsync-partial\fP") to have rsync create the +partial-directory in the destination file\&'s directory when needed, and then +remove it again when the partial file is deleted\&. .IP -If the partial-dir value is not an absolute path, rsync will also add an ---exclude of this value at the end of all your existing excludes\&. This +If the partial-dir value is not an absolute path, rsync will also add a directory +\fB--exclude\fP of this value at the end of all your existing excludes\&. This will prevent partial-dir files from being transferred and also prevent the untimely deletion of partial-dir items on the receiving side\&. An example: -the above --partial-dir option would add an "--exclude=\&.rsync-partial/" -rule at the end of any other include/exclude rules\&. Note that if you are -supplying your own include/exclude rules, you may need to manually insert a +the above \fB--partial-dir\fP option would add an "\fB--exclude=\&.rsync-partial/\fP" +rule at the end of any other filter rules\&. Note that if you are +supplying your own filter rules, you may need to manually insert a rule for this directory exclusion somewhere higher up in the list so that it has a high enough priority to be effective (e\&.g\&., if your rules specify -a trailing --exclude=* rule, the auto-added rule will be ineffective)\&. +a trailing \fB--exclude=\&'*\&'\fP rule, the auto-added rule would never be +reached)\&. .IP -IMPORTANT: the --partial-dir should not be writable by other users or it +IMPORTANT: the \fB--partial-dir\fP should not be writable by other users or it is a security risk\&. E\&.g\&. AVOID "/tmp"\&. .IP You can also set the partial-dir value the RSYNC_PARTIAL_DIR environment -variable\&. Setting this in the environment does not force --partial to be -enabled, but rather it effects where partial files go when --partial (or --P) is used\&. For instance, instead of specifying --partial-dir=\&.rsync-tmp -along with --progress, you could set RSYNC_PARTIAL_DIR=\&.rsync-tmp in your -environment and then just use the -P option to turn on the use of the -\&.rsync-tmp dir for partial transfers\&. The only time the --partial option -does not look for this environment value is when --inplace was also -specified (since --inplace conflicts with --partial-dir)\&. +variable\&. Setting this in the environment does not force \fB--partial\fP to be +enabled, but rather it effects where partial files go when \fB--partial\fP is +specified\&. For instance, instead of using \fB--partial-dir=\&.rsync-tmp\fP +along with \fB--progress\fP, you could set RSYNC_PARTIAL_DIR=\&.rsync-tmp in your +environment and then just use the \fB-P\fP option to turn on the use of the +\&.rsync-tmp dir for partial transfers\&. The only time that the \fB--partial\fP +option does not look for this environment value is (1) when \fB--inplace\fP was +specified (since \fB--inplace\fP conflicts with \fB--partial-dir\fP), or (2) when +\fB--delay-updates\fP was specified (see below)\&. +.IP +For the purposes of the server-config\&'s "refuse options" setting, +\fB--partial-dir\fP does \fInot\fP imply \fB--partial\fP\&. This is so that a +refusal of the \fB--partial\fP option can be used to disallow the overwriting +of destination files with a partial transfer, while still allowing the +safer idiom provided by \fB--partial-dir\fP\&. +.IP +.IP "\fB--delay-updates\fP" +This option puts the temporary file from each +updated file into a holding directory until the end of the +transfer, at which time all the files are renamed into place in rapid +succession\&. This attempts to make the updating of the files a little more +atomic\&. By default the files are placed into a directory named "\&.~tmp~" in +each file\&'s destination directory, but you can override this by specifying +the \fB--partial-dir\fP option\&. (Note that RSYNC_PARTIAL_DIR has no effect +on this value, nor is \fB--partial-dir\fP considered to be implied for the +purposes of the server-config\&'s "refuse options" setting\&.) +Conflicts with \fB--inplace\fP\&. +.IP +This option uses more memory on the receiving side (one bit per file +transferred) and also requires enough free disk space on the receiving +side to hold an additional copy of all the updated files\&. Note also that +you should not use an absolute path to \fB--partial-dir\fP unless there is no +chance of any of the files in the transfer having the same name (since all +the updated files will be put into a single directory if the path is +absolute)\&. +.IP +See also the "atomic-rsync" perl script in the "support" subdir for an +update algorithm that is even more atomic (it uses \fB--link-dest\fP and a +parallel hierarchy of files)\&. .IP .IP "\fB--progress\fP" This option tells rsync to print information showing the progress of the transfer\&. This gives a bored user something to watch\&. -Implies --verbose without incrementing verbosity\&. +Implies \fB--verbose\fP if it wasn\&'t already specified\&. .IP When the file is transferring, the data looks like this: .IP .nf - 782448 63% 110\&.64kB/s 0:00:04 - .fi @@ -1117,14 +1407,12 @@ data over the wire and data being matched locally), and the estimated time remaining in this transfer\&. .IP -After the a file is complete, it the data looks like this: +After a file is complete, the data looks like this: .IP .nf - 1238099 100% 146\&.38kB/s 0:00:08 (5, 57\&.1% of 396) - .fi @@ -1136,7 +1424,7 @@ what percent of the total number of files has been scanned\&. .IP .IP "\fB-P\fP" -The -P option is equivalent to --partial --progress\&. Its +The \fB-P\fP option is equivalent to \fB--partial\fP \fB--progress\fP\&. Its purpose is to make it much easier to specify these two options for a long transfer that may be interrupted\&. .IP @@ -1148,6 +1436,14 @@ must not be world readable\&. It should contain just the password as a single line\&. .IP +.IP "\fB--list-only\fP" +This option will cause the source files to be listed +instead of transferred\&. This option is inferred if there is no destination +specified, so you don\&'t usually need to use it explicitly\&. However, it can +come in handy for a power user that wants to avoid the "\fB-r --exclude=\&'/*/*\&'\fP" +options that rsync might use as a compatibility kluge when generating a +non-recursive listing\&. +.IP .IP "\fB--bwlimit=KBPS\fP" This option allows you to specify a maximum transfer rate in kilobytes per second\&. This option is most effective when @@ -1159,24 +1455,29 @@ .IP .IP "\fB--write-batch=FILE\fP" Record a file that can later be applied to -another identical destination with --read-batch\&. See the "BATCH MODE" +another identical destination with \fB--read-batch\fP\&. See the "BATCH MODE" section for details\&. .IP .IP "\fB--read-batch=FILE\fP" Apply all of the changes stored in FILE, a -file previously generated by --write-batch\&. +file previously generated by \fB--write-batch\fP\&. If \fIFILE\fP is "-" the batch data will be read from standard input\&. See the "BATCH MODE" section for details\&. .IP +.IP "\fB--protocol=NUM\fP" +Force an older protocol version to be used\&. This +is useful for creating a batch file that is compatible with an older +version of rsync\&. For instance, if rsync 2\&.6\&.4 is being used with the +\fB--write-batch\fP option, but rsync 2\&.6\&.3 is what will be used to run the +\fB--read-batch\fP option, you should use "--protocol=28" (when creating the +batch file) to force the older protocol version to be used in the batch +file (assuming you can\&'t upgrade the rsync on the reading system to 2\&.6\&.4)\&. +.IP .IP "\fB-4, --ipv4\fP or \fB-6, --ipv6\fP" Tells rsync to prefer IPv4/IPv6 when creating sockets\&. This only affects sockets that rsync has direct control over, such as the outgoing socket when directly contacting an -rsync daemon, or the incoming sockets that an rsync daemon uses to -listen for connections\&. One of these options may be required in older -versions of Linux to work around an IPv6 bug in the kernel (if you see -an "address already in use" error when nothing else is using the port, -try specifying --ipv6 or --ipv4 when starting the daemon)\&. +rsync daemon\&. See also these options in the \fB--daemon\fP mode section\&. .IP .IP "\fB--checksum-seed=NUM\fP" Set the MD4 checksum seed to the integer @@ -1188,208 +1489,601 @@ in the case where the user wants a more random checksum seed\&. Note that setting NUM to 0 causes rsync to use the default of time() for checksum seed\&. -.IP .PP -.SH "EXCLUDE PATTERNS" +.SH "DAEMON OPTIONS" .PP -The exclude and include patterns specified to rsync allow for flexible -selection of which files to transfer and which files to skip\&. +The options allowed when starting an rsync daemon are as follows: .PP -Rsync builds an ordered list of include/exclude options as specified on -the command line\&. Rsync checks each file and directory -name against each exclude/include pattern in turn\&. The first matching -pattern is acted on\&. If it is an exclude pattern, then that file is -skipped\&. If it is an include pattern then that filename is not -skipped\&. If no matching include/exclude pattern is found then the -filename is not skipped\&. +.IP "\fB--daemon\fP" +This tells rsync that it is to run as a daemon\&. The +daemon you start running may be accessed using an rsync client using +the \fBhost::module\fP or \fBrsync://host/module/\fP syntax\&. +.IP +If standard input is a socket then rsync will assume that it is being +run via inetd, otherwise it will detach from the current terminal and +become a background daemon\&. The daemon will read the config file +(rsyncd\&.conf) on each connect made by a client and respond to +requests accordingly\&. See the rsyncd\&.conf(5) man page for more +details\&. +.IP +.IP "\fB--address\fP" +By default rsync will bind to the wildcard address +when run as a daemon with the \fB--daemon\fP option or when connecting to a +rsync server\&. The \fB--address\fP option allows you to specify a specific IP +address (or hostname) to bind to\&. This makes virtual hosting possible +in conjunction with the \fB--config\fP option\&. See also the "address" global +option in the rsyncd\&.conf manpage\&. +.IP +.IP "\fB--bwlimit=KBPS\fP" +This option allows you to specify a maximum +transfer rate in kilobytes per second for the data the daemon sends\&. +The client can still specify a smaller \fB--bwlimit\fP value, but their +requested value will be rounded down if they try to exceed it\&. See the +client version of this option (above) for some extra details\&. +.IP +.IP "\fB--config=FILE\fP" +This specifies an alternate config file than +the default\&. This is only relevant when \fB--daemon\fP is specified\&. +The default is /etc/rsyncd\&.conf unless the daemon is running over +a remote shell program and the remote user is not root; in that case +the default is rsyncd\&.conf in the current directory (typically $HOME)\&. +.IP +.IP "\fB--no-detach\fP" +When running as a daemon, this option instructs +rsync to not detach itself and become a background process\&. This +option is required when running as a service on Cygwin, and may also +be useful when rsync is supervised by a program such as +\fBdaemontools\fP or AIX\&'s \fBSystem Resource Controller\fP\&. +\fB--no-detach\fP is also recommended when rsync is run under a +debugger\&. This option has no effect if rsync is run from inetd or +sshd\&. +.IP +.IP "\fB--port=PORT\fP" +This specifies an alternate TCP port number for the +daemon to listen on rather than the default of 873\&. See also the "port" +global option in the rsyncd\&.conf manpage\&. +.IP +.IP "\fB-v, --verbose\fP" +This option increases the amount of information the +daemon logs during its startup phase\&. After the client connects, the +daemon\&'s verbosity level will be controlled by the options that the client +used and the "max verbosity" setting in the module\&'s config section\&. +.IP +.IP "\fB-4, --ipv4\fP or \fB-6, --ipv6\fP" +Tells rsync to prefer IPv4/IPv6 +when creating the incoming sockets that the rsync daemon will use to +listen for connections\&. One of these options may be required in older +versions of Linux to work around an IPv6 bug in the kernel (if you see +an "address already in use" error when nothing else is using the port, +try specifying \fB--ipv6\fP or \fB--ipv4\fP when starting the daemon)\&. +.IP +.IP "\fB-h, --help\fP" +When specified after \fB--daemon\fP, print a short help +page describing the options available for starting an rsync daemon\&. .PP -The filenames matched against the exclude/include patterns are relative -to the "root of the transfer"\&. If you think of the transfer as a -subtree of names that are being sent from sender to receiver, the root -is where the tree starts to be duplicated in the destination directory\&. -This root governs where patterns that start with a / match (see below)\&. +.SH "FILTER RULES" .PP -Because the matching is relative to the transfer-root, changing the -trailing slash on a source path or changing your use of the --relative -option affects the path you need to use in your matching (in addition to -changing how much of the file tree is duplicated on the destination -system)\&. The following examples demonstrate this\&. +The filter rules allow for flexible selection of which files to transfer +(include) and which files to skip (exclude)\&. The rules either directly +specify include/exclude patterns or they specify a way to acquire more +include/exclude patterns (e\&.g\&. to read them from a file)\&. +.PP +As the list of files/directories to transfer is built, rsync checks each +name to be transferred against the list of include/exclude patterns in +turn, and the first matching pattern is acted on: if it is an exclude +pattern, then that file is skipped; if it is an include pattern then that +filename is not skipped; if no matching pattern is found, then the +filename is not skipped\&. .PP -Let\&'s say that we want to match two source files, one with an absolute -path of "/home/me/foo/bar", and one with a path of "/home/you/bar/baz"\&. -Here is how the various command choices differ for a 2-source transfer: +Rsync builds an ordered list of filter rules as specified on the +command-line\&. Filter rules have the following syntax: .PP - -.nf - - - Example cmd: rsync -a /home/me /home/you /dest - +/- pattern: /me/foo/bar - +/- pattern: /you/bar/baz - Target file: /dest/me/foo/bar - Target file: /dest/you/bar/baz - - Example cmd: rsync -a /home/me/ /home/you/ /dest - +/- pattern: /foo/bar (note missing "me") - +/- pattern: /bar/baz (note missing "you") - Target file: /dest/foo/bar - Target file: /dest/bar/baz - - Example cmd: rsync -a --relative /home/me/ /home/you /dest - +/- pattern: /home/me/foo/bar (note full path) - +/- pattern: /home/you/bar/baz (ditto) - Target file: /dest/home/me/foo/bar - Target file: /dest/home/you/bar/baz - - Example cmd: cd /home; rsync -a --relative me/foo you/ /dest - +/- pattern: /me/foo/bar (starts at specified path) - +/- pattern: /you/bar/baz (ditto) - Target file: /dest/me/foo/bar - Target file: /dest/you/bar/baz - -.fi - - +.RS +\f(CWRULE [PATTERN_OR_FILENAME]\fP +.br +\f(CWRULE,MODIFIERS [PATTERN_OR_FILENAME]\fP +.br +.RE .PP -The easiest way to see what name you should include/exclude is to just -look at the output when using --verbose and put a / in front of the name -(use the --dry-run option if you\&'re not yet ready to copy any files)\&. -.PP -Note that, when using the --recursive (-r) option (which is implied by -a), -every subcomponent of -every path is visited from the top down, so include/exclude patterns get -applied recursively to each subcomponent\&. -The exclude patterns actually short-circuit the directory traversal stage -when rsync finds the files to send\&. If a pattern excludes a particular -parent directory, it can render a deeper include pattern ineffectual -because rsync did not descend through that excluded section of the -hierarchy\&. +You have your choice of using either short or long RULE names, as described +below\&. If you use a short-named rule, the \&',\&' separating the RULE from the +MODIFIERS is optional\&. The PATTERN or FILENAME that follows (when present) +must come after either a single space or an underscore (_)\&. +Here are the available rule prefixes: .PP -Note also that the --include and --exclude options take one pattern -each\&. To add multiple patterns use the --include-from and ---exclude-from options or multiple --include and --exclude options\&. +.RS +\fBexclude, -\fP specifies an exclude pattern\&. +.br +\fBinclude, +\fP specifies an include pattern\&. +.br +\fBmerge, \&.\fP specifies a merge-file to read for more rules\&. +.br +\fBdir-merge, :\fP specifies a per-directory merge-file\&. +.br +\fBhide, H\fP specifies a pattern for hiding files from the transfer\&. +.br +\fBshow, S\fP files that match the pattern are not hidden\&. +.br +\fBprotect, P\fP specifies a pattern for protecting files from deletion\&. +.br +\fBrisk, R\fP files that match the pattern are not protected\&. +.br +\fBclear, !\fP clears the current include/exclude list (takes no arg) +.br +.RE .PP -The patterns can take several forms\&. The rules are: +When rules are being read from a file, empty lines are ignored, as are +comment lines that start with a "#"\&. .PP -.IP -.IP o -if the pattern starts with a / then it is matched against the -start of the filename, otherwise it is matched against the end of -the filename\&. -This is the equivalent of a leading ^ in regular expressions\&. -Thus "/foo" would match a file called "foo" at the transfer-root -(see above for how this is different from the filesystem-root)\&. -On the other hand, "foo" would match any file called "foo" +Note that the \fB--include\fP/\fB--exclude\fP command-line options do not allow the +full range of rule parsing as described above -- they only allow the +specification of include/exclude patterns plus a "!" token to clear the +list (and the normal comment parsing when rules are read from a file)\&. +If a pattern +does not begin with "- " (dash, space) or "+ " (plus, space), then the +rule will be interpreted as if "+ " (for an include option) or "- " (for +an exclude option) were prefixed to the string\&. A \fB--filter\fP option, on +the other hand, must always contain either a short or long rule name at the +start of the rule\&. +.PP +Note also that the \fB--filter\fP, \fB--include\fP, and \fB--exclude\fP options take one +rule/pattern each\&. To add multiple ones, you can repeat the options on +the command-line, use the merge-file syntax of the \fB--filter\fP option, or +the \fB--include-from\fP/\fB--exclude-from\fP options\&. +.PP +.SH "INCLUDE/EXCLUDE PATTERN RULES" +.PP +You can include and exclude files by specifying patterns using the "+", +"-", etc\&. filter rules (as introduced in the FILTER RULES section above)\&. +The include/exclude rules each specify a pattern that is matched against +the names of the files that are going to be transferred\&. These patterns +can take several forms: +.PP +.IP o +if the pattern starts with a / then it is anchored to a +particular spot in the hierarchy of files, otherwise it is matched +against the end of the pathname\&. This is similar to a leading ^ in +regular expressions\&. +Thus "/foo" would match a file called "foo" at either the "root of the +transfer" (for a global rule) or in the merge-file\&'s directory (for a +per-directory rule)\&. +An unqualified "foo" would match any file or directory named "foo" anywhere in the tree because the algorithm is applied recursively from +the top down; it behaves as if each path component gets a turn at being the -end of the file name\&. -.IP +end of the file name\&. Even the unanchored "sub/foo" would match at +any point in the hierarchy where a "foo" was found within a directory +named "sub"\&. See the section on ANCHORING INCLUDE/EXCLUDE PATTERNS for +a full discussion of how to specify a pattern that matches at the root +of the transfer\&. .IP o if the pattern ends with a / then it will only match a directory, not a file, link, or device\&. -.IP .IP o if the pattern contains a wildcard character from the set *?[ then expression matching is applied using the shell filename matching rules\&. Otherwise a simple string match is used\&. -.IP .IP o the double asterisk pattern "**" will match slashes while a single asterisk pattern "*" will stop at slashes\&. -.IP .IP o if the pattern contains a / (not counting a trailing /) or a "**" -then it is matched against the full filename, including any leading -directory\&. If the pattern doesn\&'t contain a / or a "**", then it is -matched only against the final component of the filename\&. Again, -remember that the algorithm is applied recursively so "full filename" can -actually be any portion of a path below the starting directory\&. -.IP +then it is matched against the full pathname, including any leading +directories\&. If the pattern doesn\&'t contain a / or a "**", then it is +matched only against the final component of the filename\&. +(Remember that the algorithm is applied recursively so "full filename" +can actually be any portion of a path from the starting directory on +down\&.) +.PP +Note that, when using the \fB--recursive\fP (\fB-r\fP) option (which is implied by +\fB-a\fP), every subcomponent of every path is visited from the top down, so +include/exclude patterns get applied recursively to each subcomponent\&'s +full name (e\&.g\&. to include "/foo/bar/baz" the subcomponents "/foo" and +"/foo/bar" must not be excluded)\&. +The exclude patterns actually short-circuit the directory traversal stage +when rsync finds the files to send\&. If a pattern excludes a particular +parent directory, it can render a deeper include pattern ineffectual +because rsync did not descend through that excluded section of the +hierarchy\&. This is particularly important when using a trailing \&'*\&' rule\&. +For instance, this won\&'t work: +.PP +.RS +\f(CW+ /some/path/this-file-will-not-be-found\fP +.br +\f(CW+ /file-is-included\fP +.br +\f(CW- *\fP +.br +.RE +.PP +This fails because the parent directory "some" is excluded by the \&'*\&' +rule, so rsync never visits any of the files in the "some" or "some/path" +directories\&. One solution is to ask for all directories in the hierarchy +to be included by using a single rule: "+ */" (put it somewhere before the +"- *" rule)\&. Another solution is to add specific include rules for all +the parent dirs that need to be visited\&. For instance, this set of rules +works fine: +.PP +.RS +\f(CW+ /some/\fP +.br +\f(CW+ /some/path/\fP +.br +\f(CW+ /some/path/this-file-is-found\fP +.br +\f(CW+ /file-also-included\fP +.br +\f(CW- *\fP +.br +.RE +.PP +Here are some examples of exclude/include matching: +.PP .IP o -if the pattern starts with "+ " (a plus followed by a space) -then it is always considered an include pattern, even if specified as -part of an exclude option\&. The prefix is discarded before matching\&. -.IP +"- *\&.o" would exclude all filenames matching *\&.o .IP o -if the pattern starts with "- " (a minus followed by a space) -then it is always considered an exclude pattern, even if specified as -part of an include option\&. The prefix is discarded before matching\&. -.IP +"- /foo" would exclude a file called foo in the transfer-root directory +.IP o +"- foo/" would exclude any directory called foo +.IP o +"- /foo/*/bar" would exclude any file called bar two +levels below a directory called foo in the transfer-root directory +.IP o +"- /foo/**/bar" would exclude any file called bar two +or more levels below a directory called foo in the transfer-root directory +.IP o +The combination of "+ */", "+ *\&.c", and "- *" would include all +directories and C source files but nothing else\&. +.IP o +The combination of "+ foo/", "+ foo/bar\&.c", and "- *" would include +only the foo directory and foo/bar\&.c (the foo directory must be +explicitly included or it would be excluded by the "*") +.PP +.SH "MERGE-FILE FILTER RULES" +.PP +You can merge whole files into your filter rules by specifying either a +merge (\&.) or a dir-merge (:) filter rule (as introduced in the FILTER RULES +section above)\&. +.PP +There are two kinds of merged files -- single-instance (\&'\&.\&') and +per-directory (\&':\&')\&. A single-instance merge file is read one time, and +its rules are incorporated into the filter list in the place of the "\&." +rule\&. For per-directory merge files, rsync will scan every directory that +it traverses for the named file, merging its contents when the file exists +into the current list of inherited rules\&. These per-directory rule files +must be created on the sending side because it is the sending side that is +being scanned for the available files to transfer\&. These rule files may +also need to be transferred to the receiving side if you want them to +affect what files don\&'t get deleted (see PER-DIRECTORY RULES AND DELETE +below)\&. +.PP +Some examples: +.PP +.RS +\f(CWmerge /etc/rsync/default\&.rules\fP +.br +\f(CW\&. /etc/rsync/default\&.rules\fP +.br +\f(CWdir-merge \&.per-dir-filter\fP +.br +\f(CWdir-merge,n- \&.non-inherited-per-dir-excludes\fP +.br +\f(CW:n- \&.non-inherited-per-dir-excludes\fP +.br +.RE +.PP +The following modifiers are accepted after a merge or dir-merge rule: +.PP +.IP o +A \fB-\fP specifies that the file should consist of only exclude +patterns, with no other rule-parsing except for in-file comments\&. .IP o -if the pattern is a single exclamation mark ! then the current -include/exclude list is reset, removing all previously defined patterns\&. +A \fB+\fP specifies that the file should consist of only include +patterns, with no other rule-parsing except for in-file comments\&. +.IP o +A \fBC\fP is a way to specify that the file should be read in a +CVS-compatible manner\&. This turns on \&'n\&', \&'w\&', and \&'-\&', but also +allows the list-clearing token (!) to be specified\&. If no filename is +provided, "\&.cvsignore" is assumed\&. +.IP o +A \fBe\fP will exclude the merge-file name from the transfer; e\&.g\&. +"dir-merge,e \&.rules" is like "dir-merge \&.rules" and "- \&.rules"\&. +.IP o +An \fBn\fP specifies that the rules are not inherited by subdirectories\&. +.IP o +A \fBw\fP specifies that the rules are word-split on whitespace instead +of the normal line-splitting\&. This also turns off comments\&. Note: the +space that separates the prefix from the rule is treated specially, so +"- foo + bar" is parsed as two rules (assuming that prefix-parsing wasn\&'t +also disabled)\&. +.IP o +You may also specify any of the modifiers for the "+" or "-" rules +(below) in order to have the rules that are read-in from the file +default to having that modifier set\&. For instance, "merge,-/ \&.excl" would +treat the contents of \&.excl as absolute-path excludes, +while "dir-merge,s \&.filt" and ":sC" would each make all their +per-directory rules apply only on the server side\&. +.PP +The following modifiers are accepted after a "+" or "-": +.PP +.IP o +A "/" specifies that the include/exclude should be treated as an +absolute path, relative to the root of the filesystem\&. For example, +"-/ /etc/passwd" would exclude the passwd file any time the transfer +was sending files from the "/etc" directory\&. +.IP o +A "!" specifies that the include/exclude should take effect if +the pattern fails to match\&. For instance, "-! */" would exclude all +non-directories\&. +.IP o +A \fBC\fP is used to indicate that all the global CVS-exclude rules +should be inserted as excludes in place of the "-C"\&. No arg should +follow\&. +.IP o +An \fBs\fP is used to indicate that the rule applies to the sending +side\&. When a rule affects the sending side, it prevents files from +being transferred\&. The default is for a rule to affect both sides +unless \fB--delete-excluded\fP was specified, in which case default rules +become sender-side only\&. See also the hide (H) and show (S) rules, +which are an alternate way to specify server-side includes/excludes\&. +.IP o +An \fBr\fP is used to indicate that the rule applies to the receiving +side\&. When a rule affects the receiving side, it prevents files from +being deleted\&. See the \fBs\fP modifier for more info\&. See also the +protect (P) and risk (R) rules, which are an alternate way to +specify receiver-side includes/excludes\&. +.PP +Per-directory rules are inherited in all subdirectories of the directory +where the merge-file was found unless the \&'n\&' modifier was used\&. Each +subdirectory\&'s rules are prefixed to the inherited per-directory rules +from its parents, which gives the newest rules a higher priority than the +inherited rules\&. The entire set of dir-merge rules are grouped together in +the spot where the merge-file was specified, so it is possible to override +dir-merge rules via a rule that got specified earlier in the list of global +rules\&. When the list-clearing rule ("!") is read from a per-directory +file, it only clears the inherited rules for the current merge file\&. +.PP +Another way to prevent a single rule from a dir-merge file from being inherited is to +anchor it with a leading slash\&. Anchored rules in a per-directory +merge-file are relative to the merge-file\&'s directory, so a pattern "/foo" +would only match the file "foo" in the directory where the dir-merge filter +file was found\&. +.PP +Here\&'s an example filter file which you\&'d specify via \fB--filter="\&. file":\fP +.PP +.RS +\f(CWmerge /home/user/\&.global-filter\fP +.br +\f(CW- *\&.gz\fP +.br +\f(CWdir-merge \&.rules\fP +.br +\f(CW+ *\&.[ch]\fP +.br +\f(CW- *\&.o\fP +.br +.RE +.PP +This will merge the contents of the /home/user/\&.global-filter file at the +start of the list and also turns the "\&.rules" filename into a per-directory +filter file\&. All rules read-in prior to the start of the directory scan +follow the global anchoring rules (i\&.e\&. a leading slash matches at the root +of the transfer)\&. +.PP +If a per-directory merge-file is specified with a path that is a parent +directory of the first transfer directory, rsync will scan all the parent +dirs from that starting point to the transfer directory for the indicated +per-directory file\&. For instance, here is a common filter (see \fB-F\fP): +.PP +.RS +\f(CW--filter=\&': /\&.rsync-filter\&'\fP +.RE +.PP +That rule tells rsync to scan for the file \&.rsync-filter in all +directories from the root down through the parent directory of the +transfer prior to the start of the normal directory scan of the file in +the directories that are sent as a part of the transfer\&. (Note: for an +rsync daemon, the root is always the same as the module\&'s "path"\&.) +.PP +Some examples of this pre-scanning for per-directory files: +.PP +.RS +\f(CWrsync -avF /src/path/ /dest/dir\fP +.br +\f(CWrsync -av --filter=\&': \&.\&./\&.\&./\&.rsync-filter\&' /src/path/ /dest/dir\fP +.br +\f(CWrsync -av --filter=\&': \&.rsync-filter\&' /src/path/ /dest/dir\fP +.br +.RE +.PP +The first two commands above will look for "\&.rsync-filter" in "/" and +"/src" before the normal scan begins looking for the file in "/src/path" +and its subdirectories\&. The last command avoids the parent-dir scan +and only looks for the "\&.rsync-filter" files in each directory that is +a part of the transfer\&. +.PP +If you want to include the contents of a "\&.cvsignore" in your patterns, +you should use the rule ":C", which creates a dir-merge of the \&.cvsignore +file, but parsed in a CVS-compatible manner\&. You can +use this to affect where the \fB--cvs-exclude\fP (\fB-C\fP) option\&'s inclusion of the +per-directory \&.cvsignore file gets placed into your rules by putting the +":C" wherever you like in your filter rules\&. Without this, rsync would +add the dir-merge rule for the \&.cvsignore file at the end of all your other +rules (giving it a lower priority than your command-line rules)\&. For +example: +.PP +.RS +\f(CWcat < out\&.dat - -.fi - - +.RS +\f(CWssh remotehost /bin/true > out\&.dat\fP +.RE .PP then look at out\&.dat\&. If everything is working correctly then out\&.dat should be a zero length file\&. If you are getting the above error from @@ -1569,8 +2246,8 @@ scripts (such as \&.cshrc or \&.profile) that contain output statements for non-interactive logins\&. .PP -If you are having trouble debugging include and exclude patterns, then -try specifying the -vv option\&. At this level of verbosity rsync will +If you are having trouble debugging filter patterns, then +try specifying the \fB-vv\fP option\&. At this level of verbosity rsync will show why each individual file is included or excluded\&. .PP .SH "EXIT VALUES" @@ -1578,9 +2255,9 @@ .IP "\fB0\fP" Success .IP "\fB1\fP" -Syntax or usage error +Syntax or usage error .IP "\fB2\fP" -Protocol incompatibility +Protocol incompatibility .IP "\fB3\fP" Errors selecting input/output files, dirs .IP "\fB4\fP" @@ -1590,62 +2267,59 @@ not by the server\&. .IP "\fB5\fP" Error starting client-server protocol +.IP "\fB6\fP" +Daemon unable to append to log-file .IP "\fB10\fP" -Error in socket I/O +Error in socket I/O .IP "\fB11\fP" -Error in file I/O +Error in file I/O .IP "\fB12\fP" -Error in rsync protocol data stream +Error in rsync protocol data stream .IP "\fB13\fP" -Errors with program diagnostics +Errors with program diagnostics .IP "\fB14\fP" -Error in IPC code +Error in IPC code .IP "\fB20\fP" -Received SIGUSR1 or SIGINT +Received SIGUSR1 or SIGINT .IP "\fB21\fP" -Some error returned by waitpid() +Some error returned by waitpid() .IP "\fB22\fP" -Error allocating core memory buffers +Error allocating core memory buffers .IP "\fB23\fP" Partial transfer due to error .IP "\fB24\fP" Partial transfer due to vanished source files +.IP "\fB25\fP" +The --max-delete limit stopped deletions .IP "\fB30\fP" -Timeout in data send/receive +Timeout in data send/receive .PP .SH "ENVIRONMENT VARIABLES" .PP -.IP .IP "\fBCVSIGNORE\fP" The CVSIGNORE environment variable supplements any -ignore patterns in \&.cvsignore files\&. See the --cvs-exclude option for +ignore patterns in \&.cvsignore files\&. See the \fB--cvs-exclude\fP option for more details\&. -.IP .IP "\fBRSYNC_RSH\fP" The RSYNC_RSH environment variable allows you to override the default shell used as the transport for rsync\&. Command line -options are permitted after the command name, just as in the -e option\&. -.IP +options are permitted after the command name, just as in the \fB-e\fP option\&. .IP "\fBRSYNC_PROXY\fP" The RSYNC_PROXY environment variable allows you to redirect your rsync client to use a web proxy when connecting to a rsync daemon\&. You should set RSYNC_PROXY to a hostname:port pair\&. -.IP .IP "\fBRSYNC_PASSWORD\fP" Setting RSYNC_PASSWORD to the required password allows you to run authenticated rsync connections to an rsync daemon without user intervention\&. Note that this does not supply a password to a shell transport such as ssh\&. -.IP .IP "\fBUSER\fP or \fBLOGNAME\fP" The USER or LOGNAME environment variables are used to determine the default username sent to an rsync server\&. If neither is set, the username defaults to "nobody"\&. -.IP .IP "\fBHOME\fP" The HOME environment variable is used to find the user\&'s default \&.cvsignore file\&. -.IP .PP .SH "FILES" .PP @@ -1655,20 +2329,18 @@ .PP rsyncd\&.conf(5) .PP -.SH "DIAGNOSTICS" -.PP .SH "BUGS" .PP times are transferred as unix time_t values .PP When transferring to FAT filesystems rsync may re-sync unmodified files\&. -See the comments on the --modify-window option\&. +See the comments on the \fB--modify-window\fP option\&. .PP file permissions, devices, etc\&. are transferred as native numerical values .PP -see also the comments on the --delete option +see also the comments on the \fB--delete\fP option .PP Please report bugs! See the website at http://rsync\&.samba\&.org/ @@ -1706,4 +2378,4 @@ Many people have later contributed to it\&. .PP Mailing lists for support and development are available at -http://lists\&.samba\&.org +http://lists\&.samba\&.org diff -urN --exclude=patches rsync-2.6.3/rsync.c rsync-2.6.4/rsync.c --- rsync-2.6.3/rsync.c 2004-09-07 13:37:36.000000000 -0700 +++ rsync-2.6.4/rsync.c 2005-03-14 09:06:08.000000000 -0800 @@ -24,18 +24,20 @@ extern int verbose; extern int dry_run; +extern int daemon_log_format_has_i; extern int preserve_times; +extern int omit_dir_times; extern int am_root; +extern int am_server; extern int am_sender; extern int am_generator; +extern int am_starting_up; extern int preserve_uid; extern int preserve_gid; -extern int force_delete; -extern int recurse; +extern int inplace; extern int keep_dirlinks; extern int make_backups; -extern char *backup_dir; -extern int inplace; +extern struct stats stats; /* @@ -48,81 +50,6 @@ } -/* - * delete a file or directory. If force_delete is set then delete - * recursively - */ -int delete_file(char *fname) -{ - DIR *d; - struct dirent *di; - char buf[MAXPATHLEN]; - STRUCT_STAT st; - int ret; - -#if SUPPORT_LINKS - ret = do_lstat(fname, &st); -#else - ret = do_stat(fname, &st); -#endif - if (ret) - return -1; - - if (!S_ISDIR(st.st_mode)) { - if (robust_unlink(fname) == 0 || errno == ENOENT) - return 0; - rsyserr(FERROR, errno, "delete_file: unlink %s failed", - full_fname(fname)); - return -1; - } - - if (do_rmdir(fname) == 0 || errno == ENOENT) - return 0; - if (!force_delete || !recurse - || (errno != ENOTEMPTY && errno != EEXIST)) { - rsyserr(FERROR, errno, "delete_file: rmdir %s failed", - full_fname(fname)); - return -1; - } - - /* now we do a recsursive delete on the directory ... */ - if (!(d = opendir(fname))) { - rsyserr(FERROR, errno, "delete_file: opendir %s failed", - full_fname(fname)); - return -1; - } - - for (errno = 0, di = readdir(d); di; errno = 0, di = readdir(d)) { - char *dname = d_name(di); - if (dname[0] == '.' && (dname[1] == '\0' - || (dname[1] == '.' && dname[2] == '\0'))) - continue; - pathjoin(buf, sizeof buf, fname, dname); - if (verbose > 0) - rprintf(FINFO, "deleting %s\n", safe_fname(buf)); - if (delete_file(buf) != 0) { - closedir(d); - return -1; - } - } - if (errno) { - rsyserr(FERROR, errno, "delete_file: readdir %s failed", - full_fname(fname)); - closedir(d); - return -1; - } - - closedir(d); - - if (do_rmdir(fname) != 0) { - rsyserr(FERROR, errno, "delete_file: rmdir %s failed", - full_fname(fname)); - return -1; - } - - return 0; -} - int set_perms(char *fname,struct file_struct *file,STRUCT_STAT *st, int flags) { @@ -130,10 +57,9 @@ STRUCT_STAT st2; int change_uid, change_gid; - if (dry_run) - return 0; - if (!st) { + if (dry_run) + return 1; if (link_stat(fname, &st2, 0) < 0) { rsyserr(FERROR, errno, "stat %s failed", full_fname(fname)); @@ -143,14 +69,11 @@ } if (!preserve_times || S_ISLNK(st->st_mode) - || (make_backups && !backup_dir && S_ISDIR(st->st_mode))) + || (S_ISDIR(st->st_mode) && omit_dir_times)) flags |= PERMS_SKIP_MTIME; if (!(flags & PERMS_SKIP_MTIME) && cmp_modtime(st->st_mtime, file->modtime) != 0) { - /* don't complain about not setting times on directories - * because some filesystems can't do it */ - if (set_modtime(fname,file->modtime) != 0 && - !S_ISDIR(st->st_mode)) { + if (set_modtime(fname,file->modtime) != 0) { rsyserr(FERROR, errno, "failed to set times on %s", full_fname(fname)); return 0; @@ -161,17 +84,24 @@ change_uid = am_root && preserve_uid && st->st_uid != file->uid; change_gid = preserve_gid && file->gid != GID_NONE && st->st_gid != file->gid; +#if !defined HAVE_LCHOWN && !defined CHOWN_MODIFIES_SYMLINK + if (S_ISLNK(st->st_mode)) + ; + else +#endif if (change_uid || change_gid) { if (verbose > 2) { if (change_uid) { rprintf(FINFO, - "set uid of %s from %ld to %ld\n", - fname, (long)st->st_uid, (long)file->uid); + "set uid of %s from %ld to %ld\n", + safe_fname(fname), + (long)st->st_uid, (long)file->uid); } if (change_gid) { rprintf(FINFO, - "set gid of %s from %ld to %ld\n", - fname, (long)st->st_gid, (long)file->gid); + "set gid of %s from %ld to %ld\n", + safe_fname(fname), + (long)st->st_gid, (long)file->gid); } } if (do_lchown(fname, @@ -185,8 +115,8 @@ return 0; } /* a lchown had been done - we have to re-stat if the - * destination had the setuid or setgid bits set due - * to the side effect of the chown call */ + * destination had the setuid or setgid bits set due + * to the side effect of the chown call */ if (st->st_mode & (S_ISUID | S_ISGID)) { link_stat(fname, st, keep_dirlinks && S_ISDIR(st->st_mode)); @@ -208,10 +138,12 @@ #endif if (verbose > 1 && flags & PERMS_REPORT) { + enum logcode code = daemon_log_format_has_i || dry_run + ? FCLIENT : FINFO; if (updated) - rprintf(FINFO,"%s\n",fname); + rprintf(code, "%s\n", safe_fname(fname)); else - rprintf(FINFO,"%s is uptodate\n",fname); + rprintf(code, "%s is uptodate\n", safe_fname(fname)); } return updated; } @@ -235,30 +167,32 @@ /* finish off a file transfer, renaming the file and setting the permissions and ownership */ void finish_transfer(char *fname, char *fnametmp, struct file_struct *file, - int ok_to_set_time) + int ok_to_set_time, int overwriting_basis) { int ret; if (inplace) { if (verbose > 2) - rprintf(FINFO, "finishing %s\n", fname); + rprintf(FINFO, "finishing %s\n", safe_fname(fname)); goto do_set_perms; } - if (make_backups && !make_backup(fname)) + if (make_backups && overwriting_basis && !make_backup(fname)) return; /* Change permissions before putting the file into place. */ set_perms(fnametmp, file, NULL, ok_to_set_time ? 0 : PERMS_SKIP_MTIME); /* move tmp file over real file */ - if (verbose > 2) - rprintf(FINFO, "renaming %s to %s\n", fnametmp, fname); + if (verbose > 2) { + rprintf(FINFO, "renaming %s to %s\n", + safe_fname(fnametmp), safe_fname(fname)); + } ret = robust_rename(fnametmp, fname, file->mode & INITACCESSPERMS); if (ret < 0) { rsyserr(FERROR, errno, "%s %s -> \"%s\"", ret == -2 ? "copy" : "rename", - full_fname(fnametmp), fname); + full_fname(fnametmp), safe_fname(fname)); do_unlink(fnametmp); return; } @@ -272,5 +206,7 @@ const char *who_am_i(void) { + if (am_starting_up) + return am_server ? "server" : "client"; return am_sender ? "sender" : am_generator ? "generator" : "receiver"; } diff -urN --exclude=patches rsync-2.6.3/rsync.h rsync-2.6.4/rsync.h --- rsync-2.6.3/rsync.h 2004-09-21 21:10:10.000000000 -0700 +++ rsync-2.6.4/rsync.h 2005-03-28 09:08:47.000000000 -0800 @@ -1,18 +1,18 @@ -/* +/* Copyright (C) by Andrew Tridgell 1996, 2000 Copyright (C) Paul Mackerras 1996 Copyright (C) 2001, 2002 by Martin Pool - + This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. - + This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - + You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. @@ -58,11 +58,15 @@ /* These flags are used in the live flist data. */ #define FLAG_TOP_DIR (1<<0) -#define FLAG_HLINK_EOL (1<<1) /* generator only */ -#define FLAG_MOUNT_POINT (1<<2) /* sender only */ +#define FLAG_HLINK_EOL (1<<1) /* receiver/generator */ +#define FLAG_MOUNT_POINT (1<<2) /* sender */ +#define FLAG_NO_FUZZY (1<<2) /* generator */ +#define FLAG_DEL_HERE (1<<3) /* receiver/generator */ +#define FLAG_SENT (1<<3) /* sender */ +#define FLAG_HLINK_TOL (1<<4) /* receiver/generator */ /* update this if you make incompatible changes */ -#define PROTOCOL_VERSION 28 +#define PROTOCOL_VERSION 29 /* We refuse to interoperate with versions that are not in this range. * Note that we assume we'll work with later versions: the onus is on @@ -92,23 +96,25 @@ #define CHUNK_SIZE (32*1024) #define MAX_MAP_SIZE (256*1024) #define IO_BUFFER_SIZE (4092) +#define MAX_BLOCK_SIZE ((int32)1 << 29) #define IOERR_GENERAL (1<<0) /* For backward compatibility, this must == 1 */ #define IOERR_VANISHED (1<<1) +#define IOERR_DEL_LIMIT (1<<2) #define MAX_ARGS 1000 +#define MAX_BASIS_DIRS 20 + #define MPLEX_BASE 7 -#define NO_EXCLUDES 0 -#define SERVER_EXCLUDES 1 -#define ALL_EXCLUDES 2 +#define NO_FILTERS 0 +#define SERVER_FILTERS 1 +#define ALL_FILTERS 2 #define XFLG_FATAL_ERRORS (1<<0) -#define XFLG_DEF_INCLUDE (1<<1) -#define XFLG_WORDS_ONLY (1<<2) -#define XFLG_WORD_SPLIT (1<<3) -#define XFLG_DIRECTORY (1<<4) +#define XFLG_OLD_PREFIXES (1<<1) +#define XFLG_ANCHORED2ABS (1<<2) #define PERMS_REPORT (1<<0) #define PERMS_SKIP_MTIME (1<<1) @@ -119,18 +125,56 @@ #define PDIR_CREATE 1 #define PDIR_DELETE 0 - -/* Log-message categories. FLOG is only used on the daemon side to - * output messages to the log file. */ -enum logcode { FERROR=1, FINFO=2, FLOG=3 }; +/* Note: 0x00 - 0x7F are used for basis_dir[] indexes! */ +#define FNAMECMP_BASIS_DIR_LOW 0x00 /* Must remain 0! */ +#define FNAMECMP_BASIS_DIR_HIGH 0x7F +#define FNAMECMP_FNAME 0x80 +#define FNAMECMP_PARTIAL_DIR 0x81 +#define FNAMECMP_BACKUP 0x82 +#define FNAMECMP_FUZZY 0x83 + +/* For calling delete_file() */ +#define DEL_NO_RECURSE (1<<1) +#define DEL_FORCE_RECURSE (1<<2) /* recurse even w/o --force */ +#define DEL_TERSE (1<<3) + +/* For use by the itemize_changes code */ +#define ITEM_DUMMY_BIT (1<<0) +#define ITEM_REPORT_CHECKSUM (1<<1) +#define ITEM_REPORT_SIZE (1<<2) +#define ITEM_REPORT_TIME (1<<3) +#define ITEM_REPORT_PERMS (1<<4) +#define ITEM_REPORT_OWNER (1<<5) +#define ITEM_REPORT_GROUP (1<<6) +#define ITEM_REPORT_XATTRS (1<<7) +#define ITEM_BASIS_TYPE_FOLLOWS (1<<11) +#define ITEM_XNAME_FOLLOWS (1<<12) +#define ITEM_IS_NEW (1<<13) +#define ITEM_LOCAL_CHANGE (1<<14) +#define ITEM_TRANSFER (1<<15) +/* These are outside the range of the transmitted flags. */ +#define ITEM_NO_DEST_AND_NO_UPDATE (1<<16) /* used by itemize() */ +#define ITEM_MISSING_DATA (1<<16) /* used by log_formatted() */ +#define ITEM_DELETED (1<<17) /* used by log_formatted() */ + +#define SIGNIFICANT_ITEM_FLAGS (~(\ + ITEM_BASIS_TYPE_FOLLOWS | ITEM_XNAME_FOLLOWS | ITEM_LOCAL_CHANGE)) + + +/* Log-message categories. FLOG and FCLIENT are only used on the daemon + * side for custom logging -- they don't get sent over the socket. */ +enum logcode { FERROR=1, FINFO=2, FLOG=3, FCLIENT=4 }; /* Messages types that are sent over the message channel. The logcode * values must all be present here with identical numbers. */ enum msgcode { - 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 */ - MSG_DATA=0 /* raw data on the multiplexed stream */ + MSG_DATA=0, /* raw data on the multiplexed stream */ + MSG_ERROR=FERROR, MSG_INFO=FINFO, /* remote logging */ + MSG_LOG=FLOG, MSG_FCLIENT=FCLIENT, /* sibling logging */ + MSG_REDO=9, /* reprocess indicated flist index */ + MSG_SUCCESS=100,/* successfully updated indicated flist index */ + MSG_DELETED=101,/* successfully deleted a file on receiving side */ + MSG_DONE=86 /* current phase is done */ }; #include "errcode.h" @@ -139,23 +183,39 @@ /* The default RSYNC_RSH is always set in config.h. */ -#include - +#include +#ifdef HAVE_SYS_TYPES_H +# include +#endif +#ifdef HAVE_SYS_STAT_H +# include +#endif +#ifdef STDC_HEADERS +# include +# include +#else +# ifdef HAVE_STDLIB_H +# include +# endif +#endif +#ifdef HAVE_STRING_H +# if !defined STDC_HEADERS && defined HAVE_MEMORY_H +# include +# endif +# include +#endif +#ifdef HAVE_STRINGS_H +# include +#endif #ifdef HAVE_UNISTD_H -#include +# include #endif -#include -#include #ifdef HAVE_SYS_PARAM_H #include #endif -#ifdef HAVE_STDLIB_H -#include -#endif - -#if defined(HAVE_MALLOC_H) && (defined(HAVE_MALLINFO) || !defined(HAVE_STDLIB_H)) +#if defined HAVE_MALLOC_H && (defined HAVE_MALLINFO || !defined HAVE_STDLIB_H) #include #endif @@ -163,10 +223,6 @@ #include #endif -#ifdef HAVE_STRING_H -#include -#endif - #ifdef TIME_WITH_SYS_TIME #include #include @@ -186,8 +242,6 @@ #endif #endif -#include - #ifdef HAVE_SYS_IOCTL_H #include #endif @@ -238,24 +292,27 @@ #include #include -#if HAVE_DIRENT_H +#ifdef HAVE_DIRENT_H # include #else # define dirent direct -# if HAVE_SYS_NDIR_H +# ifdef HAVE_SYS_NDIR_H # include # endif -# if HAVE_SYS_DIR_H +# ifdef HAVE_SYS_DIR_H # include # endif -# if HAVE_NDIR_H +# ifdef HAVE_NDIR_H # include # endif #endif -#if MAJOR_IN_MKDEV +#ifdef MAJOR_IN_MKDEV #include -#elif MAJOR_IN_SYSMACROS +# if !defined makedev && (defined mkdev || defined _WIN32 || defined __WIN32__) +# define makedev mkdev +# endif +#elif defined MAJOR_IN_SYSMACROS #include #endif @@ -273,61 +330,85 @@ #define uchar unsigned char #endif -#if HAVE_UNSIGNED_CHAR +#ifdef SIGNED_CHAR_OK #define schar signed char #else #define schar char #endif +/* Find a variable that is either exactly 32-bits or longer. + * If some code depends on 32-bit truncation, it will need to + * take special action in a "#if SIZEOF_INT32 > 4" section. */ #ifndef int32 -#if (SIZEOF_INT == 4) -#define int32 int -#elif (SIZEOF_LONG == 4) -#define int32 long -#elif (SIZEOF_SHORT == 4) -#define int32 short -#else -/* I hope this works */ -#define int32 int -#define LARGE_INT32 +#if SIZEOF_INT == 4 +# define int32 int +# define SIZEOF_INT32 4 +#elif SIZEOF_LONG == 4 +# define int32 long +# define SIZEOF_INT32 4 +#elif SIZEOF_SHORT == 4 +# define int32 short +# define SIZEOF_INT32 4 +#elif SIZEOF_INT > 4 +# define int32 int +# define SIZEOF_INT32 SIZEOF_INT +#elif SIZEOF_LONG > 4 +# define int32 long +# define SIZEOF_INT32 SIZEOF_LONG +#else +# error Could not find a 32-bit integer variable #endif +#else +# define SIZEOF_INT32 4 #endif #ifndef uint32 #define uint32 unsigned int32 #endif -#if HAVE_OFF64_T -#define OFF_T off64_t -#define STRUCT_STAT struct stat64 -#else +#if SIZEOF_OFF_T == 8 || !SIZEOF_OFF64_T || !defined HAVE_STRUCT_STAT64 #define OFF_T off_t #define STRUCT_STAT struct stat -#endif - -#if HAVE_OFF64_T -#define int64 off64_t -#elif (SIZEOF_LONG == 8) -#define int64 long -#elif (SIZEOF_INT == 8) -#define int64 int -#elif HAVE_LONGLONG -#define int64 long long #else -/* As long as it gets... */ -#define int64 off_t -#define INT64_IS_OFF_T +#define OFF_T off64_t +#define STRUCT_STAT struct stat64 +#define USE_STAT64_FUNCS 1 #endif -#if (SIZEOF_LONG == 8) -#define uint64 unsigned long -#elif (SIZEOF_INT == 8) -#define uint64 unsigned int -#elif HAVE_LONGLONG -#define uint64 unsigned long long +/* CAVEAT: on some systems, int64 will really be a 32-bit integer IFF + * that's the maximum size the file system can handle and there is no + * 64-bit type available. The rsync source must therefore take steps + * to ensure that any code that really requires a 64-bit integer has + * it (e.g. the checksum code uses two 32-bit integers for its 64-bit + * counter). */ +#if SIZEOF_OFF64_T == 8 +# define int64 off64_t +# define SIZEOF_INT64 8 +#elif SIZEOF_LONG == 8 +# define int64 long +# define SIZEOF_INT64 8 +#elif SIZEOF_INT == 8 +# define int64 int +# define SIZEOF_INT64 8 +#elif SIZEOF_LONG_LONG == 8 +# define int64 long long +# define SIZEOF_INT64 8 +#elif SIZEOF_OFF_T == 8 +# define int64 off_t +# define SIZEOF_INT64 8 +#elif SIZEOF_INT > 8 +# define int64 int +# define SIZEOF_INT64 SIZEOF_INT +#elif SIZEOF_LONG > 8 +# define int64 long +# define SIZEOF_INT64 SIZEOF_LONG +#elif SIZEOF_LONG_LONG > 8 +# define int64 long long +# define SIZEOF_INT64 SIZEOF_LONG_LONG #else /* As long as it gets... */ -#define uint64 unsigned off_t +# define int64 off_t +# define SIZEOF_INT64 SIZEOF_OFF_T #endif /* Starting from protocol version 26, we always use 64-bit @@ -354,11 +435,11 @@ * * FIXME: I don't think the code in flist.c has ever worked on a system * where dev_t is a struct. - */ + */ struct idev { - uint64 inode; - uint64 dev; + int64 inode; + int64 dev; }; #ifndef MIN @@ -401,8 +482,8 @@ #define HL_SKIP 1 struct hlink { + int next; int hlindex; - struct file_struct *next; }; #define F_DEV link_u.idev->dev @@ -418,9 +499,12 @@ char *link; /* Points to symlink string, if a symlink */ } u; OFF_T length; - char *basename; - char *dirname; - char *basedir; + char *basename; /* The current item's name (AKA filename) */ + char *dirname; /* The directory info inside the transfer */ + union { + char *root; /* Sender-side dir info outside transfer */ + int depth; /* Receiver-side directory depth info */ + } dir; union { struct idev *idev; struct hlink *links; @@ -455,18 +539,19 @@ #define WITHOUT_HLINK 0 struct file_list { - int count; - int malloced; + struct file_struct **files; alloc_pool_t file_pool; alloc_pool_t hlink_pool; - struct file_struct **files; + int count; + int malloced; + int low, high; }; #define SUMFLG_SAME_OFFSET (1<<0) struct sum_buf { OFF_T offset; /**< offset in file of this chunk */ - unsigned int len; /**< length of chunk of file */ + int32 len; /**< length of chunk of file */ uint32 sum1; /**< simple checksum */ short flags; /**< flag bits */ char sum2[SUM_LENGTH]; /**< checksum */ @@ -474,23 +559,23 @@ struct sum_struct { OFF_T flength; /**< total file length */ - size_t count; /**< how many chunks */ - unsigned int blength; /**< block_length */ - unsigned int remainder; /**< flength % block_length */ - int s2length; /**< sum2_length */ struct sum_buf *sums; /**< points to info for each chunk */ + int32 count; /**< how many chunks */ + int32 blength; /**< block_length */ + int32 remainder; /**< flength % block_length */ + int s2length; /**< sum2_length */ }; struct map_struct { - char *p; /* Window pointer */ - int fd; /* File Descriptor */ - int p_size; /* Largest window size we allocated */ - int p_len; /* Latest (rounded) window size */ - int def_window_size; /* Default window size */ - int status; /* first errno from read errors */ OFF_T file_size; /* File size (from stat) */ OFF_T p_offset; /* Window start */ OFF_T p_fd_offset; /* offset of cursor in fd ala lseek */ + char *p; /* Window pointer */ + int32 p_size; /* Largest window size we allocated */ + int32 p_len; /* Latest (rounded) window size */ + int32 def_window_size; /* Default window size */ + int fd; /* File Descriptor */ + int status; /* first errno from read errors */ }; #define MATCHFLG_WILD (1<<0) /* pattern has '*', '[', and/or '?' */ @@ -500,16 +585,35 @@ #define MATCHFLG_INCLUDE (1<<4) /* this is an include, not an exclude */ #define MATCHFLG_DIRECTORY (1<<5) /* this matches only directories */ #define MATCHFLG_CLEAR_LIST (1<<6) /* this item is the "!" token */ -struct exclude_struct { - struct exclude_struct *next; +#define MATCHFLG_WORD_SPLIT (1<<7) /* split rules on whitespace */ +#define MATCHFLG_NO_INHERIT (1<<8) /* don't inherit these rules */ +#define MATCHFLG_NO_PREFIXES (1<<9) /* parse no prefixes from patterns */ +#define MATCHFLG_MERGE_FILE (1<<10)/* specifies a file to merge */ +#define MATCHFLG_PERDIR_MERGE (1<<11)/* merge-file is searched per-dir */ +#define MATCHFLG_EXCLUDE_SELF (1<<12)/* merge-file name should be excluded */ +#define MATCHFLG_FINISH_SETUP (1<<13)/* per-dir merge file needs setup */ +#define MATCHFLG_NEGATE (1<<14)/* rule matches when pattern does not */ +#define MATCHFLG_CVS_IGNORE (1<<15)/* rule was -C or :C */ +#define MATCHFLG_SENDER_SIDE (1<<16)/* rule applies to the sending side */ +#define MATCHFLG_RECEIVER_SIDE (1<<17)/* rule applies to the receiving side */ + +#define MATCHFLGS_FROM_CONTAINER (MATCHFLG_ABS_PATH | MATCHFLG_INCLUDE \ + | MATCHFLG_DIRECTORY | MATCHFLG_SENDER_SIDE \ + | MATCHFLG_NEGATE | MATCHFLG_RECEIVER_SIDE) + +struct filter_struct { + struct filter_struct *next; char *pattern; - unsigned int match_flags; - int slash_cnt; + uint32 match_flags; + union { + int slash_cnt; + struct filter_list_struct *mergelist; + } u; }; -struct exclude_list_struct { - struct exclude_struct *head; - struct exclude_struct *tail; +struct filter_list_struct { + struct filter_struct *head; + struct filter_struct *tail; char *debug_type; }; @@ -520,6 +624,8 @@ int64 total_read; int64 literal_data; int64 matched_data; + int64 flist_buildtime; + int64 flist_xfertime; int flist_size; int num_files; int num_transferred_files; @@ -527,15 +633,6 @@ }; -/* we need this function because of the silly way in which duplicate - entries are handled in the file lists - we can't change this - without breaking existing versions */ -static inline int flist_up(struct file_list *flist, int i) -{ - while (!flist->files[i]->basename) i++; - return i; -} - #include "byteorder.h" #include "lib/mdfour.h" #include "lib/wildmatch.h" @@ -553,18 +650,18 @@ int vasprintf(char **ptr, const char *format, va_list ap); #endif -#if !defined(HAVE_VSNPRINTF) || !defined(HAVE_C99_VSNPRINTF) +#if !defined HAVE_VSNPRINTF || !defined HAVE_C99_VSNPRINTF #define vsnprintf rsync_vsnprintf int vsnprintf(char *str, size_t count, const char *fmt, va_list args); #endif -#if !defined(HAVE_SNPRINTF) || !defined(HAVE_C99_VSNPRINTF) +#if !defined HAVE_SNPRINTF || !defined HAVE_C99_VSNPRINTF #define snprintf rsync_snprintf int snprintf(char *str,size_t count,const char *fmt,...); #endif -#if !HAVE_STRERROR +#ifndef HAVE_STRERROR extern char *sys_errlist[]; #define strerror(i) sys_errlist[i] #endif @@ -581,13 +678,6 @@ #define SUPPORT_LINKS HAVE_READLINK #define SUPPORT_HARD_LINKS HAVE_LINK -/* This could be bad on systems which have no lchown and where chown - * follows symbollic links. On such systems it might be better not to - * try to chown symlinks at all. */ -#ifndef HAVE_LCHOWN -#define lchown chown -#endif - #define SIGNAL_CAST (RETSIGTYPE (*)()) #ifndef EWOULDBLOCK @@ -671,9 +761,9 @@ /* work out what fcntl flag to use for non-blocking */ #ifdef O_NONBLOCK # define NONBLOCK_FLAG O_NONBLOCK -#elif defined(SYSV) +#elif defined SYSV # define NONBLOCK_FLAG O_NDELAY -#else +#else # define NONBLOCK_FLAG FNDELAY #endif @@ -693,13 +783,13 @@ #define INITACCESSPERMS 0700 /* handler for null strings in printf format */ -#define NS(s) ((s)?(s):"") +#define NS(s) ((s)?safe_fname(s):"") -#if !defined(__GNUC__) || defined(APPLE) +#if !defined __GNUC__ || defined __APPLE__ /* Apparently the OS X port of gcc gags on __attribute__. * * */ -#define __attribute__(x) +#define __attribute__(x) #endif @@ -757,9 +847,8 @@ extern int verbose; #ifndef HAVE_INET_NTOP -const char * -inet_ntop(int af, const void *src, char *dst, size_t size); -#endif /* !HAVE_INET_NTOP */ +const char *inet_ntop(int af, const void *src, char *dst, size_t size); +#endif #ifndef HAVE_INET_PTON int inet_pton(int af, const char *src, void *dst); diff -urN --exclude=patches rsync-2.6.3/rsync.yo rsync-2.6.4/rsync.yo --- rsync-2.6.3/rsync.yo 2004-09-30 09:35:56.000000000 -0700 +++ rsync-2.6.4/rsync.yo 2005-03-30 19:14:09.000000000 -0800 @@ -1,5 +1,5 @@ mailto(rsync-bugs@samba.org) -manpage(rsync)(1)(30 Sep 2004)()() +manpage(rsync)(1)(30 Mar 2005)()() manpagename(rsync)(faster, flexible replacement for rcp) manpagesynopsis() @@ -49,39 +49,32 @@ itemize( it() for copying local files. This is invoked when neither source nor destination path contains a : separator - it() for copying from the local machine to a remote machine using a remote shell program as the transport (such as ssh or rsh). This is invoked when the destination path contains a single : separator. - it() for copying from a remote machine to the local machine using a remote shell program. This is invoked when the source contains a : separator. - it() for copying from a remote rsync server to the local machine. This is invoked when the source path contains a :: separator or an rsync:// URL. - it() for copying from the local machine to a remote rsync server. This is invoked when the destination path contains a :: separator or an rsync:// URL. - it() for copying from a remote machine using a remote shell program as the transport, using rsync server on the remote machine. This is invoked when the source path contains a :: - separator and the --rsh=COMMAND (aka "-e COMMAND") option is + separator and the bf(--rsh=COMMAND) (aka "bf(-e COMMAND)") option is also provided. - it() for copying from the local machine to a remote machine using a remote shell program as the transport, using rsync server on the remote machine. This is invoked when the destination path contains a :: separator and the - --rsh=COMMAND option is also provided. - + bf(--rsh=COMMAND) option is also provided. it() for listing files on a remote machine. This is done the same way as rsync transfers except that you leave off the - local destination. + local destination. ) Note that in all cases (other than listing) at least one of the source @@ -97,14 +90,14 @@ for its communications, but it may have been configured to use a different remote shell by default, such as rsh or remsh. -You can also specify any remote shell you like, either by using the -e +You can also specify any remote shell you like, either by using the bf(-e) command line option, or by setting the RSYNC_RSH environment variable. One common substitute is to use ssh, which offers a high degree of security. Note that rsync must be installed on both the source and destination -machines. +machines. manpagesection(USAGE) @@ -113,7 +106,7 @@ Perhaps the best way to explain the syntax is with some examples: -quote(rsync -t *.c foo:src/) +quote(tt(rsync -t *.c foo:src/)) This would transfer all files matching the pattern *.c from the current directory to the directory src on the machine foo. If any of @@ -121,7 +114,7 @@ remote-update protocol is used to update the file by sending only the differences. See the tech report for details. -quote(rsync -avz foo:src/bar /data/tmp) +quote(tt(rsync -avz foo:src/bar /data/tmp)) This would recursively transfer all files from the directory src/bar on the machine foo into the /data/tmp/bar directory on the local machine. The @@ -130,7 +123,7 @@ in the transfer. Additionally, compression will be used to reduce the size of data portions of the transfer. -quote(rsync -avz foo:src/bar/ /data/tmp) +quote(tt(rsync -avz foo:src/bar/ /data/tmp)) A trailing slash on the source changes this behavior to avoid creating an additional directory level at the destination. You can think of a trailing @@ -141,32 +134,33 @@ files in the same way, including their setting of the attributes of /dest/foo: -quote(rsync -av /src/foo /dest) -quote(rsync -av /src/foo/ /dest/foo) +quote( +tt(rsync -av /src/foo /dest)nl() +tt(rsync -av /src/foo/ /dest/foo)nl() +) You can also use rsync in local-only mode, where both the source and destination don't have a ':' in the name. In this case it behaves like an improved copy command. -quote(rsync somehost.mydomain.com::) +quote(tt(rsync somehost.mydomain.com::)) This would list all the anonymous rsync modules available on the host somehost.mydomain.com. (See the following section for more details.) - manpagesection(ADVANCED USAGE) The syntax for requesting multiple files from a remote host involves using quoted spaces in the SRC. Some examples: -quote(rsync host::'modname/dir1/file1 modname/dir2/file2' /dest) +quote(tt(rsync host::'modname/dir1/file1 modname/dir2/file2' /dest)) This would copy file1 and file2 into /dest from an rsync daemon. Each additional arg must include the same "modname/" prefix as the first one, and must be preceded by a single space. All other spaces are assumed to be a part of the filenames. -quote(rsync -av host:'dir1/file1 dir2/file2' /dest) +quote(tt(rsync -av host:'dir1/file1 dir2/file2' /dest)) This would copy file1 and file2 into /dest using a remote shell. This word-splitting is done by the remote shell, so if it doesn't work it means @@ -176,18 +170,19 @@ whitespace in a way that the remote shell will understand, or use wildcards in place of the spaces. Two examples of this are: -quote(rsync -av host:'file\ name\ with\ spaces' /dest) -quote(rsync -av host:file?name?with?spaces /dest) +quote( +tt(rsync -av host:'file\ name\ with\ spaces' /dest)nl() +tt(rsync -av host:file?name?with?spaces /dest)nl() +) This latter example assumes that your shell passes through unmatched wildcards. If it complains about "no match", put the name in quotes. - manpagesection(CONNECTING TO AN RSYNC SERVER) It is also possible to use rsync without a remote shell as the transport. In this case you will connect to a remote rsync server -running on TCP port 873. +running on TCP port 873. You may establish the connection via a web proxy by setting the environment variable RSYNC_PROXY to a hostname:port pair pointing to @@ -198,15 +193,12 @@ that: itemize( - it() you use a double colon :: instead of a single colon to - separate the hostname from the path or an rsync:// URL. - + it() you either use a double colon :: instead of a single colon to + separate the hostname from the path, or you use an rsync:// URL. it() the remote server may print a message of the day when you connect. - it() if you specify no path name on the remote server then the list of accessible paths on the server will be shown. - it() if you specify no local destination then a listing of the specified files on the remote server is provided. ) @@ -214,11 +206,11 @@ Some paths on the remote server may require authentication. If so then you will receive a password prompt when you connect. You can avoid the password prompt by setting the environment variable RSYNC_PASSWORD to -the password you want to use or using the --password-file option. This +the password you want to use or using the bf(--password-file) option. This may be useful when scripting rsync. WARNING: On some systems environment variables are visible to all -users. On those systems using --password-file is recommended. +users. On those systems using bf(--password-file) is recommended. manpagesection(CONNECTING TO AN RSYNC SERVER OVER A REMOTE SHELL PROGRAM) @@ -228,35 +220,36 @@ to a remote machine via ssh (for encryption or to get through a firewall), but you still want to have access to the rsync server features (see RUNNING AN RSYNC SERVER OVER A REMOTE SHELL PROGRAM, -below). +below). From the user's perspective, using rsync in this way is the same as using it to connect to an rsync server, except that you must explicitly set the remote shell program on the command line with ---rsh=COMMAND. (Setting RSYNC_RSH in the environment will not turn on +bf(--rsh=COMMAND). (Setting RSYNC_RSH in the environment will not turn on this functionality.) In order to distinguish between the remote-shell user and the rsync server user, you can use '-l user' on your remote-shell command: -quote(rsync -av --rsh="ssh -l ssh-user" rsync-user@host::module[/path] local-path) +verb( rsync -av --rsh="ssh -l ssh-user" \ + rsync-user@host::module[/path] local-path) The "ssh-user" will be used at the ssh level; the "rsync-user" will be used to check against the rsyncd.conf on the remote host. manpagesection(RUNNING AN RSYNC SERVER) -An rsync server is configured using a configuration file. Please see the +An rsync server is configured using a configuration file. Please see the rsyncd.conf(5) man page for more information. By default the configuration file is called /etc/rsyncd.conf, unless rsync is running over a remote shell program and is not running as root; in that case, the default name -is rsyncd.conf in the current directory on the remote computer +is rsyncd.conf in the current directory on the remote computer (typically $HOME). manpagesection(RUNNING AN RSYNC SERVER OVER A REMOTE SHELL PROGRAM) See the rsyncd.conf(5) man page for full information on the rsync -server configuration file. +server configuration file. Several configuration options will not be available unless the remote user is root (e.g. chroot, setuid/setgid, etc.). There is no need to @@ -273,7 +266,7 @@ To backup my wife's home directory, which consists of large MS Word files and mail folders, I use a cron job that runs -quote(rsync -Cavz . arvidsjaur:backup) +quote(tt(rsync -Cavz . arvidsjaur:backup)) each night over a PPP connection to a duplicate directory on my machine "arvidsjaur". @@ -281,112 +274,130 @@ To synchronize my samba source trees I use the following Makefile targets: -quote( get:nl() - rsync -avuzb --exclude '*~' samba:samba/ . - - put:nl() - rsync -Cavuzb . samba:samba/ - - sync: get put) +verb( get: + rsync -avuzb --exclude '*~' samba:samba/ . + put: + rsync -Cavuzb . samba:samba/ + sync: get put) this allows me to sync with a CVS directory at the other end of the -connection. I then do cvs operations on the remote machine, which saves a -lot of time as the remote cvs protocol isn't very efficient. +connection. I then do CVS operations on the remote machine, which saves a +lot of time as the remote CVS protocol isn't very efficient. I mirror a directory between my "old" and "new" ftp sites with the -command +command: -quote(rsync -az -e ssh --delete ~ftp/pub/samba/ nimbus:"~ftp/pub/tridge/samba") +tt(rsync -az -e ssh --delete ~ftp/pub/samba nimbus:"~ftp/pub/tridge") -this is launched from cron every few hours. +This is launched from cron every few hours. manpagesection(OPTIONS SUMMARY) Here is a short summary of the options available in rsync. Please refer -to the detailed description below for a complete description. - -verb( +to the detailed description below for a complete description. verb( -v, --verbose increase verbosity - -q, --quiet decrease verbosity - -c, --checksum always checksum - -a, --archive archive mode, equivalent to -rlptgoD + -q, --quiet suppress non-error messages + -c, --checksum skip based on checksum, not mod-time & size + -a, --archive archive mode; same as -rlptgoD (no -H) -r, --recursive recurse into directories -R, --relative use relative path names --no-relative turn off --relative --no-implied-dirs don't send implied dirs with -R -b, --backup make backups (see --suffix & --backup-dir) - --backup-dir make backups into this directory + --backup-dir=DIR make backups into hierarchy based in DIR --suffix=SUFFIX backup suffix (default ~ w/o --backup-dir) - -u, --update update only (don't overwrite newer files) - --inplace update the destination files inplace - -K, --keep-dirlinks treat symlinked dir on receiver as dir + -u, --update skip files that are newer on the receiver + --inplace update destination files in-place + -d, --dirs transfer directories without recursing -l, --links copy symlinks as symlinks - -L, --copy-links copy the referent of all symlinks - --copy-unsafe-links copy the referent of "unsafe" symlinks - --safe-links ignore "unsafe" symlinks + -L, --copy-links transform symlink into referent file/dir + --copy-unsafe-links only "unsafe" symlinks are transformed + --safe-links ignore symlinks that point outside the tree -H, --hard-links preserve hard links + -K, --keep-dirlinks treat symlinked dir on receiver as dir -p, --perms preserve permissions -o, --owner preserve owner (root only) -g, --group preserve group -D, --devices preserve devices (root only) -t, --times preserve times + -O, --omit-dir-times omit directories when preserving times -S, --sparse handle sparse files efficiently -n, --dry-run show what would have been transferred - -W, --whole-file copy whole files, no incremental checks - --no-whole-file turn off --whole-file + -W, --whole-file copy files whole (without rsync algorithm) + --no-whole-file always use incremental rsync algorithm -x, --one-file-system don't cross filesystem boundaries -B, --block-size=SIZE force a fixed checksum block-size - -e, --rsh=COMMAND specify the remote shell - --rsync-path=PATH specify path to rsync on the remote machine + -e, --rsh=COMMAND specify the remote shell to use + --rsync-path=PROGRAM specify the rsync to run on 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-excluded also delete excluded files on receiver + --delete-before receiver deletes before transfer (default) + --delete-during receiver deletes during xfer, not before --delete-after receiver deletes after transfer, not before + --delete-excluded also delete excluded files on receiver --ignore-errors delete even if there are I/O errors + --force force deletion of dirs even if not empty --max-delete=NUM don't delete more than NUM files + --max-size=SIZE don't transfer any file larger than SIZE --partial keep partially transferred files --partial-dir=DIR put a partially transferred file into DIR - --force force deletion of dirs even if not empty + --delay-updates put all updated files into place at end --numeric-ids don't map uid/gid values by user/group name --timeout=TIME set I/O timeout in seconds - -I, --ignore-times turn off mod time & file size quick check - --size-only ignore mod time for quick check (use size) - --modify-window=NUM compare mod times with reduced accuracy - -T --temp-dir=DIR create temporary files in directory DIR + -I, --ignore-times don't skip files that match size and time + --size-only skip files that match in size + --modify-window=NUM compare mod-times with reduced accuracy + -T, --temp-dir=DIR create temporary files in directory DIR + -y, --fuzzy find similar file for basis if no dest file --compare-dest=DIR also compare received files relative to DIR - --link-dest=DIR create hardlinks to DIR for unchanged files - -P equivalent to --partial --progress - -z, --compress compress file data - -C, --cvs-exclude auto ignore files in the same way CVS does + --copy-dest=DIR ... and include copies of unchanged files + --link-dest=DIR hardlink to files in DIR when unchanged + -z, --compress compress file data during the transfer + -C, --cvs-exclude auto-ignore files in the same way CVS does + -f, --filter=RULE add a file-filtering RULE + -F same as --filter='dir-merge /.rsync-filter' + repeated: --filter='- .rsync-filter' --exclude=PATTERN exclude files matching PATTERN - --exclude-from=FILE exclude patterns listed in FILE + --exclude-from=FILE read exclude patterns from FILE --include=PATTERN don't exclude files matching PATTERN - --include-from=FILE don't exclude patterns listed in FILE - --files-from=FILE read FILE for list of source-file names - -0 --from0 all file lists are delimited by nulls + --include-from=FILE read include patterns from FILE + --files-from=FILE read list of source-file names from FILE + -0, --from0 all *from file lists are delimited by nulls --version print version number - --daemon run as an rsync daemon - --no-detach do not detach from the parent - --address=ADDRESS bind to the specified address - --config=FILE specify alternate rsyncd.conf file - --port=PORT specify alternate rsyncd port number + --port=PORT specify double-colon alternate port number --blocking-io use blocking I/O for the remote shell - --no-blocking-io turn off --blocking-io - --stats give some file transfer stats + --no-blocking-io turn off blocking I/O when it is default + --stats give some file-transfer stats --progress show progress during transfer - --log-format=FORMAT log file transfers using specified format - --password-file=FILE get password from FILE - --bwlimit=KBPS limit I/O bandwidth, KBytes per second - --write-batch=FILE write a batch to FILE - --read-batch=FILE read a batch from FILE - --checksum-seed=NUM set block/file checksum seed - -4 --ipv4 prefer IPv4 - -6 --ipv6 prefer IPv6 - -h, --help show this help screen + -P same as --partial --progress + -i, --itemize-changes output a change-summary for all updates + --log-format=FORMAT log file-transfers using specified format + --password-file=FILE read password from FILE + --list-only list the files instead of copying them + --bwlimit=KBPS limit I/O bandwidth; KBytes per second + --write-batch=FILE write a batched update to FILE + --read-batch=FILE read a batched update from FILE + --protocol=NUM force an older protocol version to be used + --checksum-seed=NUM set block/file checksum seed (advanced) + -4, --ipv4 prefer IPv4 + -6, --ipv6 prefer IPv6 + -h, --help show this help screen) - -) +Rsync can also be run as a daemon, in which case the following options are +accepted: verb( + --daemon run as an rsync daemon + --address=ADDRESS bind to the specified address + --bwlimit=KBPS limit I/O bandwidth; KBytes per second + --config=FILE specify alternate rsyncd.conf file + --no-detach do not detach from the parent + --port=PORT listen on alternate port number + -v, --verbose increase verbosity + -4, --ipv4 prefer IPv4 + -6, --ipv6 prefer IPv6 + -h, --help show this help screen) manpageoptions() @@ -398,18 +409,27 @@ startdit() dit(bf(-h, --help)) Print a short help page describing the options -available in rsync +available in rsync. -dit(bf(--version)) print the rsync version number and exit +dit(bf(--version)) print the rsync version number and exit. dit(bf(-v, --verbose)) This option increases the amount of information you are given during the transfer. By default, rsync works silently. A -single -v will give you information about what files are being -transferred and a brief summary at the end. Two -v flags will give you +single bf(-v) will give you information about what files are being +transferred and a brief summary at the end. Two bf(-v) flags will give you information on what files are being skipped and slightly more -information at the end. More than two -v flags should only be used if +information at the end. More than two bf(-v) flags should only be used if you are debugging rsync. +Note that the names of the transferred files that are output are done using +a default bf(--log-format) of "%n%L", which tells you just the name of the +file and, if the item is a symlink, where it points. At the single bf(-v) +level of verbosity, this does not mention when a file gets its attributes +changed. If you ask for an itemized list of changed attributes (either +bf(--itemize-changes) or adding "%i" to the bf(--log-format) setting), the +output (on the client) increases to mention all items that are changed in +any way. See the bf(--log-format) option for more details. + dit(bf(-q, --quiet)) This option decreases the amount of information you are given during the transfer, notably suppressing information messages from the remote server. This flag is useful when invoking rsync from @@ -421,17 +441,18 @@ dit(bf(--size-only)) Normally rsync will not transfer any files that are already the same size and have the same modification time-stamp. With the ---size-only option, files will not be transferred if they have the same size, +bf(--size-only) option, files will not be transferred if they have the same size, regardless of timestamp. This is useful when starting to use rsync after using another mirroring system which may not preserve timestamps exactly. -dit(bf(--modify-window)) When comparing two timestamps rsync treats -the timestamps as being equal if they are within the value of -modify_window. This is normally zero, but you may find it useful to -set this to a larger value in some situations. In particular, when -transferring to Windows FAT filesystems which cannot represent times -with a 1 second resolution --modify-window=1 is useful. +dit(bf(--modify-window)) When comparing two timestamps, rsync treats the +timestamps as being equal if they differ by no more than the modify-window +value. This is normally 0 (for an exact match), but you may find it useful +to set this to a larger value in some situations. In particular, when +transferring to or from an MS Windows FAT filesystem (which represents +times with a 2-second resolution), bf(--modify-window=1) is useful +(allowing times to differ by up to 1 second). dit(bf(-c, --checksum)) This forces the sender to checksum all files using a 128-bit MD4 checksum before transfer. The checksum is then @@ -439,17 +460,17 @@ which already exist and have the same checksum and size on the receiver are not transferred. This option can be quite slow. -dit(bf(-a, --archive)) This is equivalent to -rlptgoD. It is a quick +dit(bf(-a, --archive)) This is equivalent to bf(-rlptgoD). It is a quick way of saying you want recursion and want to preserve almost -everything. +everything. The only exception to this is if bf(--files-from) was +specified, in which case bf(-r) is not implied. -Note however that bf(-a) bf(does not preserve hardlinks), because +Note that bf(-a) bf(does not preserve hardlinks), because finding multiply-linked files is expensive. You must separately specify bf(-H). dit(bf(-r, --recursive)) This tells rsync to copy directories -recursively. If you don't specify this then rsync won't copy -directories at all. +recursively. See also bf(--dirs) (bf(-d)). dit(bf(-R, --relative)) Use relative paths. This means that the full path names specified on the command line are sent to the server rather than @@ -457,85 +478,100 @@ you want to send several different directories at the same time. For example, if you used the command -verb(rsync foo/bar/foo.c remote:/tmp/) +quote(tt( rsync /foo/bar/foo.c remote:/tmp/)) then this would create a file called foo.c in /tmp/ on the remote machine. If instead you used -verb(rsync -R foo/bar/foo.c remote:/tmp/) +quote(tt( rsync -R /foo/bar/foo.c remote:/tmp/)) then a file called /tmp/foo/bar/foo.c would be created on the remote -machine -- the full path name is preserved. +machine -- the full path name is preserved. To limit the amount of +path information that is sent, do something like this: + +quote( +tt( cd /foo)nl() +tt( rsync -R bar/foo.c remote:/tmp/)nl() +) + +That would create /tmp/bar/foo.c on the remote machine. -dit(bf(--no-relative)) Turn off the --relative option. This is only -needed if you want to use --files-from without its implied --relative +dit(bf(--no-relative)) Turn off the bf(--relative) option. This is only +needed if you want to use bf(--files-from) without its implied bf(--relative) file processing. -dit(bf(--no-implied-dirs)) When combined with the --relative option, the +dit(bf(--no-implied-dirs)) When combined with the bf(--relative) option, the implied directories in each path are not explicitly duplicated as part of the transfer. This makes the transfer more optimal and also allows the two sides to have non-matching symlinks in the implied part of the -path. For instance, if you transfer the file "/path/foo/file" with -R, +path. For instance, if you transfer the file "/path/foo/file" with bf(-R), the default is for rsync to ensure that "/path" and "/path/foo" on the destination exactly match the directories/symlinks of the source. Using -the --no-implied-dirs option would omit both of these implied dirs, +the bf(--no-implied-dirs) option would omit both of these implied dirs, which means that if "/path" was a real directory on one machine and a symlink of the other machine, rsync would not try to change this. dit(bf(-b, --backup)) With this option, preexisting destination files are renamed as each file is transferred or deleted. You can control where the backup file goes and what (if any) suffix gets appended using the ---backup-dir and --suffix options. +bf(--backup-dir) and bf(--suffix) options. +Note that if you don't specify bf(--backup-dir), the bf(--omit-dir-times) +option will be enabled. -dit(bf(--backup-dir=DIR)) In combination with the --backup option, this +dit(bf(--backup-dir=DIR)) In combination with the bf(--backup) option, this tells rsync to store all backups in the specified directory. This is very useful for incremental backups. You can additionally -specify a backup suffix using the --suffix option +specify a backup suffix using the bf(--suffix) option (otherwise the files backed up in the specified directory will keep their original filenames). -If DIR is a relative path, it is relative to the destination directory -(which changes in a recursive transfer). dit(bf(--suffix=SUFFIX)) This option allows you to override the default -backup suffix used with the --backup (-b) option. The default suffix is a ~ -if no --backup-dir was specified, otherwise it is an empty string. +backup suffix used with the bf(--backup) (bf(-b)) option. The default suffix is a ~ +if no -bf(-backup-dir) was specified, otherwise it is an empty string. -dit(bf(-u, --update)) This forces rsync to skip any files for which the -destination file already exists and has a date later than the source -file. +dit(bf(-u, --update)) This forces rsync to skip any files which exist on +the destination and have a modified time that is newer than the source +file. (If an existing destination file has a modify time equal to the +source file's, it will be updated if the sizes are different.) -In the currently implementation, a difference of file format is always +In the current implementation of bf(--update), a difference of file format +between the sender and receiver is always considered to be important enough for an update, no matter what date is on the objects. In other words, if the source has a directory or a symlink where the destination has a file, the transfer would occur regardless of the timestamps. This might change in the future (feel free to comment on this on the mailing list if you have an opinion). -dit(bf(-K, --keep-dirlinks)) On the receiving side, if a symlink is -pointing to a directory, it will be treated as matching a directory -from the sender. - dit(bf(--inplace)) This causes rsync not to create a new copy of the file and then move it into place. Instead rsync will overwrite the existing -file, meaning that the rsync algorithm can't extract the full amount of -network reduction it might otherwise (since it does not yet try to sort -data matches -- a future version may improve this). +file, meaning that the rsync algorithm can't accomplish the full amount of +network reduction it might be able to otherwise (since it does not yet try +to sort data matches). One exception to this is if you combine the option +with bf(--backup), since rsync is smart enough to use the backup file as the +basis file for the transfer. This option is useful for transfer of large files with block-based changes or appended data, and also on systems that are disk bound, not network bound. -The option implies --partial (since an interrupted transfer does not delete -the file), but conflicts with --partial-dir, --compare-dest, and ---link-dest (a future rsync version will hopefully update the protocol to -remove these restrictions). +The option implies bf(--partial) (since an interrupted transfer does not delete +the file), but conflicts with bf(--partial-dir) and bf(--delay-updates). +Prior to rsync 2.6.4 bf(--inplace) was also incompatible with bf(--compare-dest) +and bf(--link-dest). WARNING: The file's data will be in an inconsistent state during the transfer (and possibly afterward if the transfer gets interrupted), so you should not use this option to update files that are in use. Also note that -rsync will be unable to update a file inplace that is not writable by the +rsync will be unable to update a file in-place that is not writable by the receiving user. +dit(bf(-d, --dirs)) Tell the sending side to include any directories that +are encountered. Unlike bf(--recursive), a directory's contents are not copied +unless the directory was specified on the command-line as either "." or a +name with a trailing slash (e.g. "foo/"). Without this option or the +bf(--recursive) option, rsync will skip all directories it encounters (and +output a message to that effect for each one). + dit(bf(-l, --links)) When symlinks are encountered, recreate the symlink on the destination. @@ -543,20 +579,20 @@ they point to (the referent) is copied, rather than the symlink. In older versions of rsync, this option also had the side-effect of telling the receiving side to follow symlinks, such as symlinks to directories. In a -modern rsync such as this one, you'll need to specify --keep-dirlinks (-K) +modern rsync such as this one, you'll need to specify bf(--keep-dirlinks) (bf(-K)) to get this extra behavior. The only exception is when sending files to -an rsync that is too old to understand -K -- in that case, the -L option -will still have the side-effect of -K on that older receiving rsync. +an rsync that is too old to understand bf(-K) -- in that case, the bf(-L) option +will still have the side-effect of bf(-K) on that older receiving rsync. dit(bf(--copy-unsafe-links)) This tells rsync to copy the referent of symbolic links that point outside the copied tree. Absolute symlinks are also treated like ordinary files, and so are any symlinks in the -source path itself when --relative is used. +source path itself when bf(--relative) is used. dit(bf(--safe-links)) This tells rsync to ignore any symbolic links which point outside the copied tree. All absolute symlinks are -also ignored. Using this option in conjunction with --relative may -give unexpected results. +also ignored. Using this option in conjunction with bf(--relative) may +give unexpected results. dit(bf(-H, --hard-links)) This tells rsync to recreate hard links on the remote system to be the same as the local system. Without this @@ -567,6 +603,10 @@ This option can be quite slow, so only use it if you need it. +dit(bf(-K, --keep-dirlinks)) On the receiving side, if a symlink is +pointing to a directory, it will be treated as matching a directory +from the sender. + dit(bf(-W, --whole-file)) With this option the incremental rsync algorithm is not used and the whole file is sent as-is instead. The transfer may be faster if this option is used when the bandwidth between the source and @@ -574,7 +614,7 @@ "disk" is actually a networked filesystem). This is the default when both the source and destination are specified as local paths. -dit(bf(--no-whole-file)) Turn off --whole-file, for use when it is the +dit(bf(--no-whole-file)) Turn off bf(--whole-file), for use when it is the default. dit(bf(-p, --perms)) This option causes rsync to set the destination @@ -589,14 +629,14 @@ destination file to be the same as the source file. On most systems, only the super-user can set file ownership. By default, the preservation is done by name, but may fall back to using the ID number in some -circumstances. See the --numeric-ids option for a full discussion. +circumstances. See the bf(--numeric-ids) option for a full discussion. dit(bf(-g, --group)) This option causes rsync to set the group of the destination file to be the same as the source file. If the receiving program is not running as the super-user, only groups that the receiver is a member of will be preserved. By default, the preservation is done by name, but may fall back to using the ID number in some -circumstances. See the --numeric-ids option for a full discussion. +circumstances. See the bf(--numeric-ids) option for a full discussion. dit(bf(-D, --devices)) This option causes rsync to transfer character and block device information to the remote system to recreate these @@ -605,10 +645,15 @@ dit(bf(-t, --times)) This tells rsync to transfer modification times along with the files and update them on the remote system. Note that if this option is not used, the optimization that excludes files that have not been -modified cannot be effective; in other words, a missing -t or -a will -cause the next transfer to behave as if it used -I, causing all files to be +modified cannot be effective; in other words, a missing bf(-t) or bf(-a) will +cause the next transfer to behave as if it used bf(-I), causing all files to be updated (though the rsync algorithm will make the update fairly efficient -if the files haven't actually changed, you're much better off using -t). +if the files haven't actually changed, you're much better off using bf(-t)). + +dit(bf(-O, --omit-dir-times)) This tells rsync to omit directories when +it is preserving modification times (see bf(--times)). If NFS is sharing +the directories on the receiving side, it is a good idea to use bf(-O). +This option is inferred if you use bf(--backup) without bf(--backup-dir). dit(bf(-n, --dry-run)) This tells rsync to not do any file transfers, instead it will just report the actions it would have taken. @@ -624,50 +669,95 @@ boundaries when recursing. This is useful for transferring the contents of only one filesystem. -dit(bf(--existing)) This tells rsync not to create any new files - +dit(bf(--existing)) This tells rsync not to create any new files -- only update files that already exist on the destination. dit(bf(--ignore-existing)) -This tells rsync not to update files that already exist on -the destination. +This tells rsync not to update files that already exist on +the destination. -dit(bf(--max-delete=NUM)) This tells rsync not to delete more than NUM -files or directories. This is useful when mirroring very large trees -to prevent disasters. - -dit(bf(--delete)) This tells rsync to delete any files on the receiving -side that aren't on the sending side. Files that are excluded from -transfer are excluded from being deleted unless you use --delete-excluded. +dit(bf(--remove-sent-files)) This tells rsync to remove from the sending +side the files and/or symlinks that are newly created or whose content is +updated on the receiving side. Directories and devices are not removed, +nor are files/symlinks whose attributes are merely changed. + +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 +send the whole directory (e.g. "dir" or "dir/") without using a wildcard +for the directory's contents (e.g. "dir/*") since the wildcard is expanded +by the shell and rsync thus gets a request to transfer individual files, not +the files' parent directory. Files that are excluded from transfer are +also excluded from being deleted unless you use the bf(--delete-excluded) +option or mark the rules as only matching on the sending side (see the +include/exclude modifiers in the FILTER RULES section). -This option has no effect if directory recursion is not selected. +This option has no effect unless directory recursion is enabled. This option can be dangerous if used incorrectly! It is a very good idea -to run first using the dry run option (-n) to see what files would be +to run first using the bf(--dry-run) option (bf(-n)) to see what files would be deleted to make sure important files aren't listed. -If the sending side detects any I/O errors then the deletion of any +If the sending side detects any I/O errors, then the deletion of any files at the destination will be automatically disabled. This is to prevent temporary filesystem failures (such as NFS errors) on the sending side causing a massive deletion of files on the -destination. You can override this with the --ignore-errors option. +destination. You can override this with the bf(--ignore-errors) option. + +The bf(--delete) option may be combined with one of the --delete-WHEN options +without conflict, as well as bf(--delete-excluded). However, if none of the +--delete-WHEN options are specified, rsync will currently choose the +bf(--delete-before) algorithm. A future version may change this to choose the +bf(--delete-during) algorithm. See also bf(--delete-after). + +dit(bf(--delete-before)) Request that the file-deletions on the receiving +side be done before the transfer starts. This is the default if bf(--delete) +or bf(--delete-excluded) is specified without one of the --delete-WHEN options. +See bf(--delete) (which is implied) for more details on file-deletion. + +Deleting before the transfer is helpful if the filesystem is tight for space +and removing extraneous files would help to make the transfer possible. +However, it does introduce a delay before the start of the transfer, +and this delay might cause the transfer to timeout (if bf(--timeout) was +specified). + +dit(bf(--delete-during, --del)) Request that the file-deletions on the +receiving side be done incrementally as the transfer happens. This is +a faster method than choosing the before- or after-transfer algorithm, +but it is only supported beginning with rsync version 2.6.4. +See bf(--delete) (which is implied) for more details on file-deletion. + +dit(bf(--delete-after)) Request that the file-deletions on the receiving +side be done after the transfer has completed. This is useful if you +are sending new per-directory merge files as a part of the transfer and +you want their exclusions to take effect for the delete phase of the +current transfer. +See bf(--delete) (which is implied) for more details on file-deletion. dit(bf(--delete-excluded)) In addition to deleting the files on the receiving side that are not on the sending side, this tells rsync to also -delete any files on the receiving side that are excluded (see --exclude). -Implies --delete. - -dit(bf(--delete-after)) By default rsync does file deletions on the -receiving side before transferring files to try to ensure that there is -sufficient space on the receiving filesystem. If you want to delete -after transferring, use the --delete-after switch. Implies --delete. +delete any files on the receiving side that are excluded (see bf(--exclude)). +See the FILTER RULES section for a way to make individual exclusions behave +this way on the receiver, and for a way to protect files from +bf(--delete-excluded). +See bf(--delete) (which is implied) for more details on file-deletion. -dit(bf(--ignore-errors)) Tells --delete to go ahead and delete files +dit(bf(--ignore-errors)) Tells bf(--delete) to go ahead and delete files even when there are I/O errors. dit(bf(--force)) This options tells rsync to delete directories even if they are not empty when they are to be replaced by non-directories. This -is only relevant without --delete because deletions are now done depth-first. -Requires the --recursive option (which is implied by -a) to have any effect. +is only relevant without bf(--delete) because deletions are now done depth-first. +Requires the bf(--recursive) option (which is implied by bf(-a)) to have any effect. + +dit(bf(--max-delete=NUM)) This tells rsync not to delete more than NUM +files or directories (NUM must be non-zero). +This is useful when mirroring very large trees to prevent disasters. + +dit(bf(--max-size=SIZE)) This tells rsync to avoid transferring any +file that is larger than the specified SIZE. The SIZE value can be +suffixed with a letter to indicate a size multiplier (K, M, or G) and +may be a fractional value (e.g. "bf(--max-size=1.5m)"). dit(bf(-B, --block-size=BLOCKSIZE)) This forces the block size used in the rsync algorithm to a fixed value. It is normally selected based on @@ -688,20 +778,28 @@ Command-line arguments are permitted in COMMAND provided that COMMAND is presented to rsync as a single argument. For example: -quote(-e "ssh -p 2234") +quote(tt( -e "ssh -p 2234")) (Note that ssh users can alternately customize site-specific connect options in their .ssh/config file.) You can also choose the remote shell program using the RSYNC_RSH -environment variable, which accepts the same range of values as -e. +environment variable, which accepts the same range of values as bf(-e). -See also the --blocking-io option which is affected by this option. +See also the bf(--blocking-io) option which is affected by this option. -dit(bf(--rsync-path=PATH)) Use this to specify the path to the copy of -rsync on the remote machine. Useful when it's not in your path. Note -that this is the full path to the binary, not just the directory that -the binary is in. +dit(bf(--rsync-path=PROGRAM)) Use this to specify what program is to be run +on the remote machine to start-up rsync. Often used when rsync is not in +the default remote-shell's path (e.g. --rsync-path=/usr/local/bin/rsync). +Note that PROGRAM is run with the help of a shell, so it can be any +program, script, or command sequence you'd care to run, so long as it does +not corrupt the standard-in & standard-out that rsync is using to +communicate. + +One tricky example is to set a different default directory on the remote +machine for use with the bf(--relative) option. For instance: + +quote(tt( rsync -avR --rsync-path="cd /a/b && rsync" hst:c/d /e/)) 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 @@ -710,38 +808,74 @@ The exclude list is initialized to: -quote(RCS SCCS CVS CVS.adm RCSLOG cvslog.* tags TAGS .make.state +quote(quote(tt(RCS SCCS CVS CVS.adm RCSLOG cvslog.* tags TAGS .make.state .nse_depinfo *~ #* .#* ,* _$* *$ *.old *.bak *.BAK *.orig *.rej -.del-* *.a *.olb *.o *.obj *.so *.exe *.Z *.elc *.ln core .svn/) +.del-* *.a *.olb *.o *.obj *.so *.exe *.Z *.elc *.ln core .svn/))) then files listed in a $HOME/.cvsignore are added to the list and any files listed in the CVSIGNORE environment variable (all cvsignore names are delimited by whitespace). Finally, any file is ignored if it is in the same directory as a -.cvsignore file and matches one of the patterns listed therein. +.cvsignore file and matches one of the patterns listed therein. Unlike +rsync's filter/exclude files, these patterns are split on whitespace. See the bf(cvs(1)) manual for more information. -dit(bf(--exclude=PATTERN)) This option allows you to selectively exclude -certain files from the list of files to be transferred. This is most -useful in combination with a recursive transfer. +If you're combining bf(-C) with your own bf(--filter) rules, you should +note that these CVS excludes are appended at the end of your own rules, +regardless of where the bf(-C) was placed on the command-line. This makes them +a lower priority than any rules you specified explicitly. If you want to +control where these CVS excludes get inserted into your filter rules, you +should omit the bf(-C) as a command-line option and use a combination of +bf(--filter=:C) and bf(--filter=-C) (either on your command-line or by +putting the ":C" and "-C" rules into a filter file with your other rules). +The first option turns on the per-directory scanning for the .cvsignore +file. The second option does a one-time import of the CVS excludes +mentioned above. + +dit(bf(-f, --filter=RULE)) This option allows you to add rules to selectively +exclude certain files from the list of files to be transferred. This is +most useful in combination with a recursive transfer. -You may use as many --exclude options on the command line as you like +You may use as many bf(--filter) options on the command line as you like to build up the list of files to exclude. -See the EXCLUDE PATTERNS section for detailed information on this option. +See the FILTER RULES section for detailed information on this option. + +dit(bf(-F)) The bf(-F) option is a shorthand for adding two bf(--filter) rules to +your command. The first time it is used is a shorthand for this rule: + +quote(tt( --filter=': /.rsync-filter')) + +This tells rsync to look for per-directory .rsync-filter files that have +been sprinkled through the hierarchy and use their rules to filter the +files in the transfer. If bf(-F) is repeated, it is a shorthand for this +rule: + +quote(tt( --filter='- .rsync-filter')) + +This filters out the .rsync-filter files themselves from the transfer. -dit(bf(--exclude-from=FILE)) This option is similar to the --exclude +See the FILTER RULES section for detailed information on how these options +work. + +dit(bf(--exclude=PATTERN)) This option is a simplified form of the +bf(--filter) option that defaults to an exclude rule and does not allow +the full rule-parsing syntax of normal filter rules. + +See the FILTER RULES section for detailed information on this option. + +dit(bf(--exclude-from=FILE)) This option is similar to the bf(--exclude) 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 em(FILE) is bf(-) 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 -build up quite complex exclude/include rules. +dit(bf(--include=PATTERN)) This option is a simplified form of the +bf(--filter) option that defaults to an include rule and does not allow +the full rule-parsing syntax of normal filter rules. -See the EXCLUDE PATTERNS section for detailed information on this option. +See the FILTER RULES section for detailed information on this option. dit(bf(--include-from=FILE)) This specifies a list of include patterns from a file. @@ -750,44 +884,50 @@ dit(bf(--files-from=FILE)) Using this option allows you to specify the exact list of files to transfer (as read from the specified FILE or "-" for standard input). It also tweaks the default behavior of rsync to make -transferring just the specified files and directories easier. For -instance, the --relative option is enabled by default when this option -is used (use --no-relative if you want to turn that off), all -directories specified in the list are created on the destination (rather -than being noisily skipped without -r), and the -a (--archive) option's -behavior does not imply -r (--recursive) -- specify it explicitly, if -you want it. +transferring just the specified files and directories easier: + +quote(itemize( + it() The bf(--relative) (bf(-R)) option is implied, which preserves the path + information that is specified for each item in the file (use + bf(--no-relative) if you want to turn that off). + it() The bf(--dirs) (bf(-d)) option is implied, which will create directories + specified in the list on the destination rather than noisily skipping + them. + it() The bf(--archive) (bf(-a)) option's behavior does not imply bf(--recursive) + (bf(-r)), so specify it explicitly, if you want it. +)) The file names that are read from the FILE are all relative to the source dir -- any leading slashes are removed and no ".." references are allowed to go higher than the source dir. For example, take this command: -quote(rsync -a --files-from=/tmp/foo /usr remote:/backup) +quote(tt( rsync -a --files-from=/tmp/foo /usr remote:/backup)) If /tmp/foo contains the string "bin" (or even "/bin"), the /usr/bin directory will be created as /backup/bin on the remote host (but the -contents of the /usr/bin dir would not be sent unless you specified -r +contents of the /usr/bin dir would not be sent unless you specified bf(-r) or the names were explicitly listed in /tmp/foo). Also keep in mind -that the effect of the (enabled by default) --relative option is to +that the effect of the (enabled by default) bf(--relative) option is to duplicate only the path info that is read from the file -- it does not force the duplication of the source-spec path (/usr in this case). -In addition, the --files-from file can be read from the remote host +In addition, the bf(--files-from) file can be read from the remote host instead of the local host if you specify a "host:" in front of the file (the host must match one end of the transfer). As a short-cut, you can specify just a prefix of ":" to mean "use the remote end of the transfer". For example: -quote(rsync -a --files-from=:/path/file-list src:/ /tmp/copy) +quote(tt( rsync -a --files-from=:/path/file-list src:/ /tmp/copy)) This would copy all the files specified in the /path/file-list file that was located on the remote "src" host. dit(bf(-0, --from0)) This tells rsync that the filenames it reads from a file are terminated by a null ('\0') character, not a NL, CR, or CR+LF. -This affects --exclude-from, --include-from, and --files-from. -It does not affect --cvs-exclude (since all names read from a .cvsignore +This affects bf(--exclude-from), bf(--include-from), bf(--files-from), and any +merged files specified in a bf(--filter) rule. +It does not affect bf(--cvs-exclude) (since all names read from a .cvsignore file are split on whitespace). dit(bf(-T, --temp-dir=DIR)) This option instructs rsync to use DIR as a @@ -795,45 +935,82 @@ transferred on the receiving side. The default behavior is to create the temporary files in the receiving directory. -dit(bf(--compare-dest=DIR)) This option instructs rsync to use DIR on -the destination machine as an additional directory to compare destination -files against when doing transfers if the files are missing in the -destination directory. This is useful for doing transfers to a new -destination while leaving existing files intact, and then doing a -flash-cutover when all files have been successfully transferred (for -example by moving directories around and removing the old directory, -although this skips files that haven't changed; see also --link-dest). -This option increases the usefulness of --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 bf(--compare-dest) but -also will create hard links from em(DIR) to the destination directory for -unchanged files. Files with changed ownership or permissions will not be -linked. +dit(bf(-y, --fuzzy)) This option tells rsync that it should look for a +basis file for any destination file that is missing. The current algorithm +looks in the same directory as the destination file for either a file that +has an identical size and modified-time, or a similarly-named file. If +found, rsync uses the fuzzy basis file to try to speed up the transfer. + +Note that the use of the bf(--delete) option might get rid of any potential +fuzzy-match files, so either use bf(--delete-after) or specify some +filename exclusions if you need to prevent this. + +dit(bf(--compare-dest=DIR)) This option instructs rsync to use em(DIR) on +the destination machine as an additional hierarchy to compare destination +files against doing transfers (if the files are missing in the destination +directory). If a file is found in em(DIR) that is identical to the +sender's file, the file will NOT be transferred to the destination +directory. This is useful for creating a sparse backup of just files that +have changed from an earlier backup. + +Beginning in version 2.6.4, multiple bf(--compare-dest) directories may be +provided, which will cause rsync to search the list in the order specified +for an exact match. +If a match is found that differs only in attributes, a local copy is made +and the attributes updated. +If a match is not found, a basis file from one of the em(DIR)s will be +selected to try to speed up the transfer. + +If em(DIR) is a relative path, it is relative to the destination directory. +See also bf(--copy-dest) and bf(--link-dest). + +dit(bf(--copy-dest=DIR)) This option behaves like bf(--compare-dest), but +rsync will also copy unchanged files found in em(DIR) to the destination +directory using a local copy. +This is useful for doing transfers to a new destination while leaving +existing files intact, and then doing a flash-cutover when all files have +been successfully transferred. + +Multiple bf(--copy-dest) directories may be provided, which will cause +rsync to search the list in the order specified for an unchanged file. +If a match is not found, a basis file from one of the em(DIR)s will be +selected to try to speed up the transfer. + +If em(DIR) is a relative path, it is relative to the destination directory. +See also bf(--compare-dest) and bf(--link-dest). + +dit(bf(--link-dest=DIR)) This option behaves like bf(--copy-dest), but +unchanged files are hard linked from em(DIR) to the destination directory. +The files must be identical in all preserved attributes (e.g. permissions, +possibly ownership) in order for the files to be linked together. An example: -verb( - rsync -av --link-dest=$PWD/prior_dir host:src_dir/ new_dir/ -) +quote(tt( rsync -av --link-dest=$PWD/prior_dir host:src_dir/ new_dir/)) + +Beginning in version 2.6.4, multiple bf(--link-dest) directories may be +provided, which will cause rsync to search the list in the order specified +for an exact match. +If a match is found that differs only in attributes, a local copy is made +and the attributes updated. +If a match is not found, a basis file from one of the em(DIR)s will be +selected to try to speed up the transfer. + +If em(DIR) is a relative path, it is relative to the destination directory. +See also bf(--compare-dest) and bf(--copy-dest). -Like bf(--compare-dest) if DIR is a relative path, it is relative to the -destination directory. Note that rsync versions prior to 2.6.1 had a bug that could prevent ---link-dest from working properly for a non-root user when -o was specified -(or implied by -a). If the receiving rsync is not new enough, you can work -around this bug by avoiding the -o option. - -dit(bf(-z, --compress)) With this option, rsync compresses any data from -the files that it sends to the destination machine. This -option is useful on slow connections. The compression method used is the -same method that gzip uses. - -Note this this option typically achieves better compression ratios -that can be achieved by using a compressing remote shell, or a -compressing transport, as it takes advantage of the implicit -information sent for matching data blocks. +bf(--link-dest) from working properly for a non-root user when bf(-o) was specified +(or implied by bf(-a)). You can work-around this bug by avoiding the bf(-o) option +when sending to an old rsync. + +dit(bf(-z, --compress)) With this option, rsync compresses the file data +as it is sent to the destination machine, which reduces the amount of data +being transmitted -- something that is useful over a slow connection. + +Note this this option typically achieves better compression ratios that can +be achieved by using a compressing remote shell or a compressing transport +because it takes advantage of the implicit information in the matching data +blocks that are not explicitly sent over the connection. dit(bf(--numeric-ids)) With this option rsync will transfer numeric group and user IDs rather than using user and group names and mapping them @@ -841,7 +1018,7 @@ By default rsync will use the username and groupname to determine what ownership to give files. The special uid 0 and the special group -0 are never mapped via user/group names even if the --numeric-ids +0 are never mapped via user/group names even if the bf(--numeric-ids) option is not specified. If a user or group has no name on the source system or it has no match @@ -855,40 +1032,11 @@ timeout in seconds. If no data is transferred for the specified time then rsync will exit. The default is 0, which means no timeout. -dit(bf(--daemon)) This tells rsync that it is to run as a daemon. The -daemon may be accessed using the bf(host::module) or -bf(rsync://host/module/) syntax. - -If standard input is a socket then rsync will assume that it is being -run via inetd, otherwise it will detach from the current terminal and -become a background daemon. The daemon will read the config file -(rsyncd.conf) on each connect made by a client and respond to -requests accordingly. See the rsyncd.conf(5) man page for more -details. - -dit(bf(--no-detach)) When running as a daemon, this option instructs -rsync to not detach itself and become a background process. This -option is required when running as a service on Cygwin, and may also -be useful when rsync is supervised by a program such as -bf(daemontools) or AIX's bf(System Resource Controller). -bf(--no-detach) is also recommended when rsync is run under a -debugger. This option has no effect if rsync is run from inetd or -sshd. - -dit(bf(--address)) By default rsync will bind to the wildcard address -when run as a daemon with the --daemon option or when connecting to a -rsync server. The --address option allows you to specify a specific IP -address (or hostname) to bind to. This makes virtual hosting possible -in conjunction with the --config option. - -dit(bf(--config=FILE)) This specifies an alternate config file than -the default. This is only relevant when --daemon is specified. -The default is /etc/rsyncd.conf unless the daemon is running over -a remote shell program and the remote user is not root; in that case -the default is rsyncd.conf in the current directory (typically $HOME). - dit(bf(--port=PORT)) This specifies an alternate TCP port number to use -rather than the default port 873. +rather than the default of 873. This is only needed if you are using the +double-colon (::) syntax to connect with an rsync daemon (since the URL +syntax has a way to specify the port as a part of the URL). See also this +option in the bf(--daemon) mode section. dit(bf(--blocking-io)) This tells rsync to use blocking I/O when launching a remote shell transport. If the remote shell is either rsh or remsh, @@ -896,13 +1044,96 @@ blocking I/O, otherwise it defaults to using non-blocking I/O. (Note that ssh prefers non-blocking I/O.) -dit(bf(--no-blocking-io)) Turn off --blocking-io, for use when it is the +dit(bf(--no-blocking-io)) Turn off bf(--blocking-io), for use when it is the default. +dit(bf(-i, --itemize-changes)) Requests a simple itemized list of the +changes that are being made to each file, including attribute changes. +This is exactly the same as specifying bf(--log-format='%i %n%L'). + +The "%i" escape has a cryptic output that is 9 letters long. The general +format is like the string bf(UXcstpoga)), where bf(U) is replaced by the +kind of update being done, bf(X) is replaced by the file-type, and the +other letters represent attributes that may be output if they are being +modified. + +The update types that replace the bf(U) are as follows: + +quote(itemize( + it() A bf(<) means that a file is being transferred to the remote host + (sent). + it() A bf(>) means that a file is being transferred to the local host + (received). + it() A bf(c) means that a local change/creation is occuring for the item + (such as the creation of a directory or the changing of a symlink, etc.). + it() A bf(h) means that the item is a hard-link to another item (requires + bf(--hard-links)). + it() A bf(.) means that the item is not being updated (though it might + have attributes that are being modified). +)) + +The file-types that replace the bf(X) are: bf(f) for a file, a bf(d) for a +directory, an bf(L) for a symlink, and a bf(D) for a device. + +The other letters in the string above are the actual letters that +will be output if the associated attribute for the item is being updated or +a "." for no change. Three exceptions to this are: (1) a newly created +item replaces each letter with a "+", (2) an identical item replaces the +dots with spaces, and (3) an unknown attribute replaces each letter with +a "?" (this happens when talking to an older rsync). + +The attribute that is associated with each letter is as follows: + +quote(itemize( + it() A bf(c) means the checksum of the file is different and will be + updated by the file transfer (requries bf(--checksum)). + it() A bf(s) means the size of the file is different and will be updated + by the file transfer. + it() A bf(t) means the modification time is different and is being updated + to the server's value (requires bf(--times)). An alternate value of bf(T) + means that the time will be set to the transfer time, which happens + anytime a symlink is transferred, or when a file or device is transferred + without bf(--times). + it() A bf(p) means the permissions are different and are being updated to + the server's value (requires bf(--perms)). + it() An bf(o) means the owner is different and is being updated to the + server's value (requires bf(--owner) and root privileges). + it() A bf(g) means the group is different and is being updated to the + server's value (requires bf(--group) and the authority to set the group). + it() The bf(a) is reserved for a future enhanced version that supports + extended file attributes, such as ACLs. +)) + +One other output is possible: when deleting files, the "%i" will output +the string "*deleting" for each item that is being removed (assuming that +you are talking to a recent enough rsync that it logs deletions instead of +outputting them as a verbose message). + dit(bf(--log-format=FORMAT)) This allows you to specify exactly what the -rsync client logs to stdout on a per-file basis. The log format is -specified using the same format conventions as the log format option in -rsyncd.conf. +rsync client outputs to the user on a per-file basis. The format is a text +string containing embedded single-character escape sequences prefixed with +a percent (%) character. For a list of the possible escape characters, see +the "log format" setting in the rsyncd.conf manpage. (Note that this +option does not affect what a daemon logs to its logfile.) + +Specifying this option will mention each file, dir, etc. that gets updated +in a significant way (a transferred file, a recreated symlink/device, or a +touched directory) unless the itemized-changes escape (%i) is included in +the string, in which case the logging of names increases to mention any +item that is updated in any way (as long as the receiving side is version +2.6.4). See the bf(--itemized-changes) option for a description of the +output of "%i". + +The bf(--verbose) option implies a format of "%n%L", but you can use +bf(--log-format) without bv(--verbose) if you like, or you can override +the format of its per-file output using this option. + +Rsync will output the log-format string prior to a file's transfer unless +one of the transfer-statistic escapes is requested, in which case the +logging is done at the end of the file's transfer. When this late logging +is in effect and bf(--progress) is also specified, rsync will also output +the name of the file being transferred prior to its progress information +(followed, of course, by the log-format output). dit(bf(--stats)) This tells rsync to print a verbose set of statistics on the file transfer, allowing you to tell how effective the rsync @@ -911,70 +1142,98 @@ dit(bf(--partial)) By default, rsync will delete any partially transferred file if the transfer is interrupted. In some circumstances it is more desirable to keep partially transferred files. Using the ---partial option tells rsync to keep the partial file which should +bf(--partial) option tells rsync to keep the partial file which should make a subsequent transfer of the rest of the file much faster. -dit(bf(--partial-dir=DIR)) Turns on --partial mode, but tells rsync to -put a partially transferred file into DIR instead of writing out the -file to the destination dir. Rsync will also use a file found in this -dir as data to speed up the transfer (i.e. when you redo the send after -rsync creates a partial file) and delete such a file after it has served -its purpose. Note that if --whole-file is specified (or implied) that an -existing partial-dir file will not be used to speedup the transfer (since +dit(bf(--partial-dir=DIR)) A better way to keep partial files than the +bf(--partial) option is to specify a em(DIR) that will be used to hold the +partial data (instead of writing it out to the destination file). +On the next transfer, rsync will use a file found in this +dir as data to speed up the resumption of the transfer and then deletes it +after it has served its purpose. +Note that if bf(--whole-file) is specified (or implied), any partial-dir +file that is found for a file that is being updated will simply be removed +(since rsync is sending files without using the incremental rsync algorithm). -Rsync will create the dir if it is missing (just the last dir -- not the -whole path). This makes it easy to use a relative path (such as -"--partial-dir=.rsync-partial") to have rsync create the partial-directory -in the destination file's directory (rsync will also try to remove the DIR -if a partial file was found to exist at the start of the transfer and the -DIR was specified as a relative path). +Rsync will create the em(DIR) if it is missing (just the last dir -- not +the whole path). This makes it easy to use a relative path (such as +"bf(--partial-dir=.rsync-partial)") to have rsync create the +partial-directory in the destination file's directory when needed, and then +remove it again when the partial file is deleted. -If the partial-dir value is not an absolute path, rsync will also add an ---exclude of this value at the end of all your existing excludes. This +If the partial-dir value is not an absolute path, rsync will also add a directory +bf(--exclude) of this value at the end of all your existing excludes. This will prevent partial-dir files from being transferred and also prevent the untimely deletion of partial-dir items on the receiving side. An example: -the above --partial-dir option would add an "--exclude=.rsync-partial/" -rule at the end of any other include/exclude rules. Note that if you are -supplying your own include/exclude rules, you may need to manually insert a +the above bf(--partial-dir) option would add an "bf(--exclude=.rsync-partial/)" +rule at the end of any other filter rules. Note that if you are +supplying your own filter rules, you may need to manually insert a rule for this directory exclusion somewhere higher up in the list so that it has a high enough priority to be effective (e.g., if your rules specify -a trailing --exclude=* rule, the auto-added rule will be ineffective). +a trailing bf(--exclude='*') rule, the auto-added rule would never be +reached). -IMPORTANT: the --partial-dir should not be writable by other users or it +IMPORTANT: the bf(--partial-dir) should not be writable by other users or it is a security risk. E.g. AVOID "/tmp". You can also set the partial-dir value the RSYNC_PARTIAL_DIR environment -variable. Setting this in the environment does not force --partial to be -enabled, but rather it effects where partial files go when --partial (or --P) is used. For instance, instead of specifying --partial-dir=.rsync-tmp -along with --progress, you could set RSYNC_PARTIAL_DIR=.rsync-tmp in your -environment and then just use the -P option to turn on the use of the -.rsync-tmp dir for partial transfers. The only time the --partial option -does not look for this environment value is when --inplace was also -specified (since --inplace conflicts with --partial-dir). +variable. Setting this in the environment does not force bf(--partial) to be +enabled, but rather it effects where partial files go when bf(--partial) is +specified. For instance, instead of using bf(--partial-dir=.rsync-tmp) +along with bf(--progress), you could set RSYNC_PARTIAL_DIR=.rsync-tmp in your +environment and then just use the bf(-P) option to turn on the use of the +.rsync-tmp dir for partial transfers. The only time that the bf(--partial) +option does not look for this environment value is (1) when bf(--inplace) was +specified (since bf(--inplace) conflicts with bf(--partial-dir)), or (2) when +bf(--delay-updates) was specified (see below). + +For the purposes of the server-config's "refuse options" setting, +bf(--partial-dir) does em(not) imply bf(--partial). This is so that a +refusal of the bf(--partial) option can be used to disallow the overwriting +of destination files with a partial transfer, while still allowing the +safer idiom provided by bf(--partial-dir). + +dit(bf(--delay-updates)) This option puts the temporary file from each +updated file into a holding directory until the end of the +transfer, at which time all the files are renamed into place in rapid +succession. This attempts to make the updating of the files a little more +atomic. By default the files are placed into a directory named ".~tmp~" in +each file's destination directory, but you can override this by specifying +the bf(--partial-dir) option. (Note that RSYNC_PARTIAL_DIR has no effect +on this value, nor is bf(--partial-dir) considered to be implied for the +purposes of the server-config's "refuse options" setting.) +Conflicts with bf(--inplace). + +This option uses more memory on the receiving side (one bit per file +transferred) and also requires enough free disk space on the receiving +side to hold an additional copy of all the updated files. Note also that +you should not use an absolute path to bf(--partial-dir) unless there is no +chance of any of the files in the transfer having the same name (since all +the updated files will be put into a single directory if the path is +absolute). + +See also the "atomic-rsync" perl script in the "support" subdir for an +update algorithm that is even more atomic (it uses bf(--link-dest) and a +parallel hierarchy of files). dit(bf(--progress)) This option tells rsync to print information showing the progress of the transfer. This gives a bored user something to watch. -Implies --verbose without incrementing verbosity. +Implies bf(--verbose) if it wasn't already specified. When the file is transferring, the data looks like this: -verb( - 782448 63% 110.64kB/s 0:00:04 -) +verb( 782448 63% 110.64kB/s 0:00:04) This tells you the current file size, the percentage of the transfer that is complete, the current calculated file-completion rate (including both data over the wire and data being matched locally), and the estimated time remaining in this transfer. -After the a file is complete, it the data looks like this: +After a file is complete, the data looks like this: -verb( - 1238099 100% 146.38kB/s 0:00:08 (5, 57.1% of 396) -) +verb( 1238099 100% 146.38kB/s 0:00:08 (5, 57.1% of 396)) This tells you the final file size, that it's 100% complete, the final transfer rate for the file, the amount of elapsed time it took to transfer @@ -982,7 +1241,7 @@ These additional numbers tell you how many files have been updated, and what percent of the total number of files has been scanned. -dit(bf(-P)) The -P option is equivalent to --partial --progress. Its +dit(bf(-P)) The bf(-P) option is equivalent to bf(--partial) bf(--progress). Its purpose is to make it much easier to specify these two options for a long transfer that may be interrupted. @@ -993,6 +1252,13 @@ must not be world readable. It should contain just the password as a single line. +dit(bf(--list-only)) This option will cause the source files to be listed +instead of transferred. This option is inferred if there is no destination +specified, so you don't usually need to use it explicitly. However, it can +come in handy for a power user that wants to avoid the "bf(-r --exclude='/*/*')" +options that rsync might use as a compatibility kluge when generating a +non-recursive listing. + dit(bf(--bwlimit=KBPS)) This option allows you to specify a maximum transfer rate in kilobytes per second. This option is most effective when using rsync with large files (several megabytes and up). Due to the nature @@ -1002,22 +1268,26 @@ of zero specifies no limit. dit(bf(--write-batch=FILE)) Record a file that can later be applied to -another identical destination with --read-batch. See the "BATCH MODE" +another identical destination with bf(--read-batch). See the "BATCH MODE" section for details. dit(bf(--read-batch=FILE)) Apply all of the changes stored in FILE, a -file previously generated by --write-batch. +file previously generated by bf(--write-batch). If em(FILE) is "-" the batch data will be read from standard input. See the "BATCH MODE" section for details. +dit(bf(--protocol=NUM)) Force an older protocol version to be used. This +is useful for creating a batch file that is compatible with an older +version of rsync. For instance, if rsync 2.6.4 is being used with the +bf(--write-batch) option, but rsync 2.6.3 is what will be used to run the +bf(--read-batch) option, you should use "--protocol=28" (when creating the +batch file) to force the older protocol version to be used in the batch +file (assuming you can't upgrade the rsync on the reading system to 2.6.4). + dit(bf(-4, --ipv4) or bf(-6, --ipv6)) Tells rsync to prefer IPv4/IPv6 when creating sockets. This only affects sockets that rsync has direct control over, such as the outgoing socket when directly contacting an -rsync daemon, or the incoming sockets that an rsync daemon uses to -listen for connections. One of these options may be required in older -versions of Linux to work around an IPv6 bug in the kernel (if you see -an "address already in use" error when nothing else is using the port, -try specifying --ipv6 or --ipv4 when starting the daemon). +rsync daemon. See also these options in the bf(--daemon) mode section. dit(bf(--checksum-seed=NUM)) Set the MD4 checksum seed to the integer NUM. This 4 byte checksum seed is included in each block and file @@ -1028,179 +1298,502 @@ in the case where the user wants a more random checksum seed. Note that setting NUM to 0 causes rsync to use the default of time() for checksum seed. - enddit() -manpagesection(EXCLUDE PATTERNS) +manpagesection(DAEMON OPTIONS) -The exclude and include patterns specified to rsync allow for flexible -selection of which files to transfer and which files to skip. +The options allowed when starting an rsync daemon are as follows: -Rsync builds an ordered list of include/exclude options as specified on -the command line. Rsync checks each file and directory -name against each exclude/include pattern in turn. The first matching -pattern is acted on. If it is an exclude pattern, then that file is -skipped. If it is an include pattern then that filename is not -skipped. If no matching include/exclude pattern is found then the -filename is not skipped. +startdit() +dit(bf(--daemon)) This tells rsync that it is to run as a daemon. The +daemon you start running may be accessed using an rsync client using +the bf(host::module) or bf(rsync://host/module/) syntax. + +If standard input is a socket then rsync will assume that it is being +run via inetd, otherwise it will detach from the current terminal and +become a background daemon. The daemon will read the config file +(rsyncd.conf) on each connect made by a client and respond to +requests accordingly. See the rsyncd.conf(5) man page for more +details. -The filenames matched against the exclude/include patterns are relative -to the "root of the transfer". If you think of the transfer as a -subtree of names that are being sent from sender to receiver, the root -is where the tree starts to be duplicated in the destination directory. -This root governs where patterns that start with a / match (see below). +dit(bf(--address)) By default rsync will bind to the wildcard address +when run as a daemon with the bf(--daemon) option or when connecting to a +rsync server. The bf(--address) option allows you to specify a specific IP +address (or hostname) to bind to. This makes virtual hosting possible +in conjunction with the bf(--config) option. See also the "address" global +option in the rsyncd.conf manpage. -Because the matching is relative to the transfer-root, changing the -trailing slash on a source path or changing your use of the --relative -option affects the path you need to use in your matching (in addition to -changing how much of the file tree is duplicated on the destination -system). The following examples demonstrate this. +dit(bf(--bwlimit=KBPS)) This option allows you to specify a maximum +transfer rate in kilobytes per second for the data the daemon sends. +The client can still specify a smaller bf(--bwlimit) value, but their +requested value will be rounded down if they try to exceed it. See the +client version of this option (above) for some extra details. -Let's say that we want to match two source files, one with an absolute -path of "/home/me/foo/bar", and one with a path of "/home/you/bar/baz". -Here is how the various command choices differ for a 2-source transfer: +dit(bf(--config=FILE)) This specifies an alternate config file than +the default. This is only relevant when bf(--daemon) is specified. +The default is /etc/rsyncd.conf unless the daemon is running over +a remote shell program and the remote user is not root; in that case +the default is rsyncd.conf in the current directory (typically $HOME). -verb( - Example cmd: rsync -a /home/me /home/you /dest - +/- pattern: /me/foo/bar - +/- pattern: /you/bar/baz - Target file: /dest/me/foo/bar - Target file: /dest/you/bar/baz - - Example cmd: rsync -a /home/me/ /home/you/ /dest - +/- pattern: /foo/bar (note missing "me") - +/- pattern: /bar/baz (note missing "you") - Target file: /dest/foo/bar - Target file: /dest/bar/baz - - Example cmd: rsync -a --relative /home/me/ /home/you /dest - +/- pattern: /home/me/foo/bar (note full path) - +/- pattern: /home/you/bar/baz (ditto) - Target file: /dest/home/me/foo/bar - Target file: /dest/home/you/bar/baz - - Example cmd: cd /home; rsync -a --relative me/foo you/ /dest - +/- pattern: /me/foo/bar (starts at specified path) - +/- pattern: /you/bar/baz (ditto) - Target file: /dest/me/foo/bar - Target file: /dest/you/bar/baz -) - -The easiest way to see what name you should include/exclude is to just -look at the output when using --verbose and put a / in front of the name -(use the --dry-run option if you're not yet ready to copy any files). - -Note that, when using the --recursive (-r) option (which is implied by -a), -every subcomponent of -every path is visited from the top down, so include/exclude patterns get -applied recursively to each subcomponent. -The exclude patterns actually short-circuit the directory traversal stage -when rsync finds the files to send. If a pattern excludes a particular -parent directory, it can render a deeper include pattern ineffectual -because rsync did not descend through that excluded section of the -hierarchy. +dit(bf(--no-detach)) When running as a daemon, this option instructs +rsync to not detach itself and become a background process. This +option is required when running as a service on Cygwin, and may also +be useful when rsync is supervised by a program such as +bf(daemontools) or AIX's bf(System Resource Controller). +bf(--no-detach) is also recommended when rsync is run under a +debugger. This option has no effect if rsync is run from inetd or +sshd. -Note also that the --include and --exclude options take one pattern -each. To add multiple patterns use the --include-from and ---exclude-from options or multiple --include and --exclude options. +dit(bf(--port=PORT)) This specifies an alternate TCP port number for the +daemon to listen on rather than the default of 873. See also the "port" +global option in the rsyncd.conf manpage. + +dit(bf(-v, --verbose)) This option increases the amount of information the +daemon logs during its startup phase. After the client connects, the +daemon's verbosity level will be controlled by the options that the client +used and the "max verbosity" setting in the module's config section. -The patterns can take several forms. The rules are: +dit(bf(-4, --ipv4) or bf(-6, --ipv6)) Tells rsync to prefer IPv4/IPv6 +when creating the incoming sockets that the rsync daemon will use to +listen for connections. One of these options may be required in older +versions of Linux to work around an IPv6 bug in the kernel (if you see +an "address already in use" error when nothing else is using the port, +try specifying bf(--ipv6) or bf(--ipv4) when starting the daemon). -itemize( +dit(bf(-h, --help)) When specified after bf(--daemon), print a short help +page describing the options available for starting an rsync daemon. +enddit() + +manpagesection(FILTER RULES) + +The filter rules allow for flexible selection of which files to transfer +(include) and which files to skip (exclude). The rules either directly +specify include/exclude patterns or they specify a way to acquire more +include/exclude patterns (e.g. to read them from a file). + +As the list of files/directories to transfer is built, rsync checks each +name to be transferred against the list of include/exclude patterns in +turn, and the first matching pattern is acted on: if it is an exclude +pattern, then that file is skipped; if it is an include pattern then that +filename is not skipped; if no matching pattern is found, then the +filename is not skipped. + +Rsync builds an ordered list of filter rules as specified on the +command-line. Filter rules have the following syntax: + +quote( +tt(RULE [PATTERN_OR_FILENAME])nl() +tt(RULE,MODIFIERS [PATTERN_OR_FILENAME])nl() +) + +You have your choice of using either short or long RULE names, as described +below. If you use a short-named rule, the ',' separating the RULE from the +MODIFIERS is optional. The PATTERN or FILENAME that follows (when present) +must come after either a single space or an underscore (_). +Here are the available rule prefixes: + +quote( +bf(exclude, -) specifies an exclude pattern. nl() +bf(include, +) specifies an include pattern. nl() +bf(merge, .) specifies a merge-file to read for more rules. nl() +bf(dir-merge, :) specifies a per-directory merge-file. nl() +bf(hide, H) specifies a pattern for hiding files from the transfer. nl() +bf(show, S) files that match the pattern are not hidden. nl() +bf(protect, P) specifies a pattern for protecting files from deletion. nl() +bf(risk, R) files that match the pattern are not protected. nl() +bf(clear, !) clears the current include/exclude list (takes no arg) nl() +) - it() if the pattern starts with a / then it is matched against the - start of the filename, otherwise it is matched against the end of - the filename. - This is the equivalent of a leading ^ in regular expressions. - Thus "/foo" would match a file called "foo" at the transfer-root - (see above for how this is different from the filesystem-root). - On the other hand, "foo" would match any file called "foo" +When rules are being read from a file, empty lines are ignored, as are +comment lines that start with a "#". + +Note that the bf(--include)/bf(--exclude) command-line options do not allow the +full range of rule parsing as described above -- they only allow the +specification of include/exclude patterns plus a "!" token to clear the +list (and the normal comment parsing when rules are read from a file). +If a pattern +does not begin with "- " (dash, space) or "+ " (plus, space), then the +rule will be interpreted as if "+ " (for an include option) or "- " (for +an exclude option) were prefixed to the string. A bf(--filter) option, on +the other hand, must always contain either a short or long rule name at the +start of the rule. + +Note also that the bf(--filter), bf(--include), and bf(--exclude) options take one +rule/pattern each. To add multiple ones, you can repeat the options on +the command-line, use the merge-file syntax of the bf(--filter) option, or +the bf(--include-from)/bf(--exclude-from) options. + +manpagesection(INCLUDE/EXCLUDE PATTERN RULES) + +You can include and exclude files by specifying patterns using the "+", +"-", etc. filter rules (as introduced in the FILTER RULES section above). +The include/exclude rules each specify a pattern that is matched against +the names of the files that are going to be transferred. These patterns +can take several forms: + +itemize( + it() if the pattern starts with a / then it is anchored to a + particular spot in the hierarchy of files, otherwise it is matched + against the end of the pathname. This is similar to a leading ^ in + regular expressions. + Thus "/foo" would match a file called "foo" at either the "root of the + transfer" (for a global rule) or in the merge-file's directory (for a + per-directory rule). + An unqualified "foo" would match any file or directory named "foo" anywhere in the tree because the algorithm is applied recursively from + the top down; it behaves as if each path component gets a turn at being the - end of the file name. - + end of the file name. Even the unanchored "sub/foo" would match at + any point in the hierarchy where a "foo" was found within a directory + named "sub". See the section on ANCHORING INCLUDE/EXCLUDE PATTERNS for + a full discussion of how to specify a pattern that matches at the root + of the transfer. it() if the pattern ends with a / then it will only match a directory, not a file, link, or device. - it() if the pattern contains a wildcard character from the set *?[ then expression matching is applied using the shell filename matching rules. Otherwise a simple string match is used. - it() the double asterisk pattern "**" will match slashes while a single asterisk pattern "*" will stop at slashes. - it() if the pattern contains a / (not counting a trailing /) or a "**" - then it is matched against the full filename, including any leading - directory. If the pattern doesn't contain a / or a "**", then it is - matched only against the final component of the filename. Again, - remember that the algorithm is applied recursively so "full filename" can - actually be any portion of a path below the starting directory. - - it() if the pattern starts with "+ " (a plus followed by a space) - then it is always considered an include pattern, even if specified as - part of an exclude option. The prefix is discarded before matching. - - it() if the pattern starts with "- " (a minus followed by a space) - then it is always considered an exclude pattern, even if specified as - part of an include option. The prefix is discarded before matching. - - it() if the pattern is a single exclamation mark ! then the current - include/exclude list is reset, removing all previously defined patterns. + then it is matched against the full pathname, including any leading + directories. If the pattern doesn't contain a / or a "**", then it is + matched only against the final component of the filename. + (Remember that the algorithm is applied recursively so "full filename" + can actually be any portion of a path from the starting directory on + down.) ) -The +/- rules are most useful in a list that was read from a file, allowing -you to have a single exclude list that contains both include and exclude -options in the proper order. - -Remember that the matching occurs at every step in the traversal of the -directory hierarchy, so you must be sure that all the parent directories of -the files you want to include are not excluded. This is particularly -important when using a trailing '*' rule. For instance, this won't work: +Note that, when using the bf(--recursive) (bf(-r)) option (which is implied by +bf(-a)), every subcomponent of every path is visited from the top down, so +include/exclude patterns get applied recursively to each subcomponent's +full name (e.g. to include "/foo/bar/baz" the subcomponents "/foo" and +"/foo/bar" must not be excluded). +The exclude patterns actually short-circuit the directory traversal stage +when rsync finds the files to send. If a pattern excludes a particular +parent directory, it can render a deeper include pattern ineffectual +because rsync did not descend through that excluded section of the +hierarchy. This is particularly important when using a trailing '*' rule. +For instance, this won't work: -verb( - + /some/path/this-file-will-not-be-found - + /file-is-included - - * +quote( +tt(+ /some/path/this-file-will-not-be-found)nl() +tt(+ /file-is-included)nl() +tt(- *)nl() ) -This fails because the parent directory "some" is excluded by the '*' rule, -so rsync never visits any of the files in the "some" or "some/path" +This fails because the parent directory "some" is excluded by the '*' +rule, so rsync never visits any of the files in the "some" or "some/path" directories. One solution is to ask for all directories in the hierarchy -to be included by using a single rule: --include='*/' (put it somewhere -before the --exclude='*' rule). Another solution is to add specific -include rules for all the parent dirs that need to be visited. For -instance, this set of rules works fine: - -verb( - + /some/ - + /some/path/ - + /some/path/this-file-is-found - + /file-also-included - - * +to be included by using a single rule: "+ */" (put it somewhere before the +"- *" rule). Another solution is to add specific include rules for all +the parent dirs that need to be visited. For instance, this set of rules +works fine: + +quote( +tt(+ /some/)nl() +tt(+ /some/path/)nl() +tt(+ /some/path/this-file-is-found)nl() +tt(+ /file-also-included)nl() +tt(- *)nl() ) Here are some examples of exclude/include matching: itemize( - it() --exclude "*.o" would exclude all filenames matching *.o - it() --exclude "/foo" would exclude a file called foo in the transfer-root directory - it() --exclude "foo/" would exclude any directory called foo - it() --exclude "/foo/*/bar" would exclude any file called bar two + it() "- *.o" would exclude all filenames matching *.o + it() "- /foo" would exclude a file called foo in the transfer-root directory + it() "- foo/" would exclude any directory called foo + it() "- /foo/*/bar" would exclude any file called bar two levels below a directory called foo in the transfer-root directory - it() --exclude "/foo/**/bar" would exclude any file called bar two + it() "- /foo/**/bar" would exclude any file called bar two or more levels below a directory called foo in the transfer-root directory - it() --include "*/" --include "*.c" --exclude "*" would include all - directories and C source files - it() --include "foo/" --include "foo/bar.c" --exclude "*" would include - only foo/bar.c (the foo/ directory must be explicitly included or - it would be excluded by the "*") + it() The combination of "+ */", "+ *.c", and "- *" would include all + directories and C source files but nothing else. + it() The combination of "+ foo/", "+ foo/bar.c", and "- *" would include + only the foo directory and foo/bar.c (the foo directory must be + explicitly included or it would be excluded by the "*") ) -manpagesection(BATCH MODE) +manpagesection(MERGE-FILE FILTER RULES) + +You can merge whole files into your filter rules by specifying either a +merge (.) or a dir-merge (:) filter rule (as introduced in the FILTER RULES +section above). + +There are two kinds of merged files -- single-instance ('.') and +per-directory (':'). A single-instance merge file is read one time, and +its rules are incorporated into the filter list in the place of the "." +rule. For per-directory merge files, rsync will scan every directory that +it traverses for the named file, merging its contents when the file exists +into the current list of inherited rules. These per-directory rule files +must be created on the sending side because it is the sending side that is +being scanned for the available files to transfer. These rule files may +also need to be transferred to the receiving side if you want them to +affect what files don't get deleted (see PER-DIRECTORY RULES AND DELETE +below). + +Some examples: + +quote( +tt(merge /etc/rsync/default.rules)nl() +tt(. /etc/rsync/default.rules)nl() +tt(dir-merge .per-dir-filter)nl() +tt(dir-merge,n- .non-inherited-per-dir-excludes)nl() +tt(:n- .non-inherited-per-dir-excludes)nl() +) + +The following modifiers are accepted after a merge or dir-merge rule: + +itemize( + it() A bf(-) specifies that the file should consist of only exclude + patterns, with no other rule-parsing except for in-file comments. + it() A bf(+) specifies that the file should consist of only include + patterns, with no other rule-parsing except for in-file comments. + it() A bf(C) is a way to specify that the file should be read in a + CVS-compatible manner. This turns on 'n', 'w', and '-', but also + allows the list-clearing token (!) to be specified. If no filename is + provided, ".cvsignore" is assumed. + it() A bf(e) will exclude the merge-file name from the transfer; e.g. + "dir-merge,e .rules" is like "dir-merge .rules" and "- .rules". + it() An bf(n) specifies that the rules are not inherited by subdirectories. + it() A bf(w) specifies that the rules are word-split on whitespace instead + of the normal line-splitting. This also turns off comments. Note: the + space that separates the prefix from the rule is treated specially, so + "- foo + bar" is parsed as two rules (assuming that prefix-parsing wasn't + also disabled). + it() You may also specify any of the modifiers for the "+" or "-" rules + (below) in order to have the rules that are read-in from the file + default to having that modifier set. For instance, "merge,-/ .excl" would + treat the contents of .excl as absolute-path excludes, + while "dir-merge,s .filt" and ":sC" would each make all their + per-directory rules apply only on the server side. +) + +The following modifiers are accepted after a "+" or "-": + +itemize( + it() A "/" specifies that the include/exclude should be treated as an + absolute path, relative to the root of the filesystem. For example, + "-/ /etc/passwd" would exclude the passwd file any time the transfer + was sending files from the "/etc" directory. + it() A "!" specifies that the include/exclude should take effect if + the pattern fails to match. For instance, "-! */" would exclude all + non-directories. + it() A bf(C) is used to indicate that all the global CVS-exclude rules + should be inserted as excludes in place of the "-C". No arg should + follow. + it() An bf(s) is used to indicate that the rule applies to the sending + side. When a rule affects the sending side, it prevents files from + being transferred. The default is for a rule to affect both sides + unless bf(--delete-excluded) was specified, in which case default rules + become sender-side only. See also the hide (H) and show (S) rules, + which are an alternate way to specify server-side includes/excludes. + it() An bf(r) is used to indicate that the rule applies to the receiving + side. When a rule affects the receiving side, it prevents files from + being deleted. See the bf(s) modifier for more info. See also the + protect (P) and risk (R) rules, which are an alternate way to + specify receiver-side includes/excludes. +) + +Per-directory rules are inherited in all subdirectories of the directory +where the merge-file was found unless the 'n' modifier was used. Each +subdirectory's rules are prefixed to the inherited per-directory rules +from its parents, which gives the newest rules a higher priority than the +inherited rules. The entire set of dir-merge rules are grouped together in +the spot where the merge-file was specified, so it is possible to override +dir-merge rules via a rule that got specified earlier in the list of global +rules. When the list-clearing rule ("!") is read from a per-directory +file, it only clears the inherited rules for the current merge file. + +Another way to prevent a single rule from a dir-merge file from being inherited is to +anchor it with a leading slash. Anchored rules in a per-directory +merge-file are relative to the merge-file's directory, so a pattern "/foo" +would only match the file "foo" in the directory where the dir-merge filter +file was found. + +Here's an example filter file which you'd specify via bf(--filter=". file":) + +quote( +tt(merge /home/user/.global-filter)nl() +tt(- *.gz)nl() +tt(dir-merge .rules)nl() +tt(+ *.[ch])nl() +tt(- *.o)nl() +) + +This will merge the contents of the /home/user/.global-filter file at the +start of the list and also turns the ".rules" filename into a per-directory +filter file. All rules read-in prior to the start of the directory scan +follow the global anchoring rules (i.e. a leading slash matches at the root +of the transfer). + +If a per-directory merge-file is specified with a path that is a parent +directory of the first transfer directory, rsync will scan all the parent +dirs from that starting point to the transfer directory for the indicated +per-directory file. For instance, here is a common filter (see bf(-F)): + +quote(tt(--filter=': /.rsync-filter')) + +That rule tells rsync to scan for the file .rsync-filter in all +directories from the root down through the parent directory of the +transfer prior to the start of the normal directory scan of the file in +the directories that are sent as a part of the transfer. (Note: for an +rsync daemon, the root is always the same as the module's "path".) + +Some examples of this pre-scanning for per-directory files: + +quote( +tt(rsync -avF /src/path/ /dest/dir)nl() +tt(rsync -av --filter=': ../../.rsync-filter' /src/path/ /dest/dir)nl() +tt(rsync -av --filter=': .rsync-filter' /src/path/ /dest/dir)nl() +) + +The first two commands above will look for ".rsync-filter" in "/" and +"/src" before the normal scan begins looking for the file in "/src/path" +and its subdirectories. The last command avoids the parent-dir scan +and only looks for the ".rsync-filter" files in each directory that is +a part of the transfer. + +If you want to include the contents of a ".cvsignore" in your patterns, +you should use the rule ":C", which creates a dir-merge of the .cvsignore +file, but parsed in a CVS-compatible manner. You can +use this to affect where the bf(--cvs-exclude) (bf(-C)) option's inclusion of the +per-directory .cvsignore file gets placed into your rules by putting the +":C" wherever you like in your filter rules. Without this, rsync would +add the dir-merge rule for the .cvsignore file at the end of all your other +rules (giving it a lower priority than your command-line rules). For +example: + +quote( +tt(cat < out.dat -) - +quote(tt(ssh remotehost /bin/true > out.dat)) + then look at out.dat. If everything is working correctly then out.dat should be a zero length file. If you are getting the above error from rsync then you will probably find that out.dat contains some text or @@ -1362,63 +1949,58 @@ scripts (such as .cshrc or .profile) that contain output statements for non-interactive logins. -If you are having trouble debugging include and exclude patterns, then -try specifying the -vv option. At this level of verbosity rsync will +If you are having trouble debugging filter patterns, then +try specifying the bf(-vv) option. At this level of verbosity rsync will show why each individual file is included or excluded. manpagesection(EXIT VALUES) startdit() dit(bf(0)) Success -dit(bf(1)) Syntax or usage error -dit(bf(2)) Protocol incompatibility +dit(bf(1)) Syntax or usage error +dit(bf(2)) Protocol incompatibility dit(bf(3)) Errors selecting input/output files, dirs dit(bf(4)) Requested action not supported: an attempt was made to manipulate 64-bit files on a platform that cannot support them; or an option was specified that is supported by the client and not by the server. dit(bf(5)) Error starting client-server protocol -dit(bf(10)) Error in socket I/O -dit(bf(11)) Error in file I/O -dit(bf(12)) Error in rsync protocol data stream -dit(bf(13)) Errors with program diagnostics -dit(bf(14)) Error in IPC code -dit(bf(20)) Received SIGUSR1 or SIGINT -dit(bf(21)) Some error returned by waitpid() -dit(bf(22)) Error allocating core memory buffers +dit(bf(6)) Daemon unable to append to log-file +dit(bf(10)) Error in socket I/O +dit(bf(11)) Error in file I/O +dit(bf(12)) Error in rsync protocol data stream +dit(bf(13)) Errors with program diagnostics +dit(bf(14)) Error in IPC code +dit(bf(20)) Received SIGUSR1 or SIGINT +dit(bf(21)) Some error returned by waitpid() +dit(bf(22)) Error allocating core memory buffers dit(bf(23)) Partial transfer due to error dit(bf(24)) Partial transfer due to vanished source files -dit(bf(30)) Timeout in data send/receive +dit(bf(25)) The --max-delete limit stopped deletions +dit(bf(30)) Timeout in data send/receive enddit() manpagesection(ENVIRONMENT VARIABLES) startdit() - dit(bf(CVSIGNORE)) The CVSIGNORE environment variable supplements any -ignore patterns in .cvsignore files. See the --cvs-exclude option for +ignore patterns in .cvsignore files. See the bf(--cvs-exclude) option for more details. - dit(bf(RSYNC_RSH)) The RSYNC_RSH environment variable allows you to override the default shell used as the transport for rsync. Command line -options are permitted after the command name, just as in the -e option. - +options are permitted after the command name, just as in the bf(-e) option. dit(bf(RSYNC_PROXY)) The RSYNC_PROXY environment variable allows you to redirect your rsync client to use a web proxy when connecting to a rsync daemon. You should set RSYNC_PROXY to a hostname:port pair. - dit(bf(RSYNC_PASSWORD)) Setting RSYNC_PASSWORD to the required password allows you to run authenticated rsync connections to an rsync daemon without user intervention. Note that this does not supply a password to a shell transport such as ssh. - dit(bf(USER) or bf(LOGNAME)) The USER or LOGNAME environment variables are used to determine the default username sent to an rsync server. If neither is set, the username defaults to "nobody". - dit(bf(HOME)) The HOME environment variable is used to find the user's default .cvsignore file. - enddit() manpagefiles() @@ -1429,20 +2011,18 @@ rsyncd.conf(5) -manpagediagnostics() - manpagebugs() times are transferred as unix time_t values When transferring to FAT filesystems rsync may re-sync unmodified files. -See the comments on the --modify-window option. +See the comments on the bf(--modify-window) option. file permissions, devices, etc. are transferred as native numerical values -see also the comments on the --delete option +see also the comments on the bf(--delete) option Please report bugs! See the website at url(http://rsync.samba.org/)(http://rsync.samba.org/) @@ -1480,4 +2060,4 @@ Many people have later contributed to it. Mailing lists for support and development are available at -url(http://lists.samba.org)(lists.samba.org) +url(http://lists.samba.org)(lists.samba.org) diff -urN --exclude=patches rsync-2.6.3/rsyncd.conf.5 rsync-2.6.4/rsyncd.conf.5 --- rsync-2.6.3/rsyncd.conf.5 2004-09-30 09:36:04.000000000 -0700 +++ rsync-2.6.4/rsyncd.conf.5 2005-03-30 19:14:12.000000000 -0800 @@ -1,4 +1,4 @@ -.TH "rsyncd\&.conf" "5" "30 Sep 2004" "" "" +.TH "rsyncd\&.conf" "5" "30 Mar 2005" "" "" .SH "NAME" rsyncd\&.conf \- configuration file for rsync server .SH "SYNOPSIS" @@ -19,7 +19,7 @@ name of the module in square brackets and continues until the next module begins\&. Modules contain parameters of the form \&'name = value\&'\&. .PP -The file is line-based - that is, each newline-terminated line represents +The file is line-based -- that is, each newline-terminated line represents either a comment, a module name or a parameter\&. .PP Only the first equals sign in a parameter is significant\&. Whitespace before @@ -41,7 +41,7 @@ .PP .SH "LAUNCHING THE RSYNC DAEMON" .PP -The rsync daemon is launched by specifying the --daemon option to +The rsync daemon is launched by specifying the \fB--daemon\fP option to rsync\&. .PP The daemon must run with root privileges if you wish to use chroot, to @@ -51,22 +51,30 @@ .PP You can launch it either via inetd, as a stand-alone daemon, or from an rsync client via a remote shell\&. If run as a stand-alone daemon then -just run the command "rsync --daemon" from a suitable startup script\&. +just run the command "\fBrsync --daemon\fP" from a suitable startup script\&. If run from an rsync client via a remote shell (by specifying both the -"-e/--rsh" option and server mode with "::" or "rsync://"), the --daemon +\fB--rsh\fP (\fB-e\fP) option and server mode with "::" or "rsync://"), the \fB--daemon\fP option is automatically passed to the remote side\&. .PP When run via inetd you should add a line like this to /etc/services: .PP -.RS -rsync 873/tcp -.RE + +.nf + + rsync 873/tcp +.fi + + .PP and a single line something like this to /etc/inetd\&.conf: .PP -.RS -rsync stream tcp nowait root /usr/bin/rsync rsyncd --daemon -.RE + +.nf + + rsync stream tcp nowait root /usr/bin/rsync rsyncd --daemon +.fi + + .PP Replace "/usr/bin/rsync" with the path to where you have rsync installed on your system\&. You will then need to send inetd a HUP signal to tell it to @@ -147,7 +155,7 @@ (see below)\&. When "use chroot" is false, for security reasons, symlinks may only be relative paths pointing to other files within the root path, and leading slashes are removed from most absolute paths (options -such as --backup-dir, --compare-dest, etc\&. interpret an absolute path as +such as \fB--backup-dir\fP, \fB--compare-dest\fP, etc\&. interpret an absolute path as rooted in the module\&'s "path" dir, just as if chroot was specified)\&. The default for "use chroot" is true\&. .IP @@ -157,16 +165,31 @@ process in the chroot namespace will need to have access to the resources used by these library functions (traditionally /etc/passwd and /etc/group)\&. If these resources are not available, rsync will only be -able to copy the IDs, just as if the --numeric-ids option had been +able to copy the IDs, just as if the \fB--numeric-ids\fP option had been specified\&. .IP Note that you are free to setup user/group information in the chroot area differently from your normal system\&. For example, you could abbreviate the list of users and groups\&. Also, you can protect this information from being downloaded/uploaded by adding an exclude rule to the rsync\&.conf file -(e\&.g\&. "exclude = /etc/")\&. Note that having the exclusion affect uploads +(e\&.g\&. "exclude = /etc/**")\&. Note that having the exclusion affect uploads is a relatively new feature in rsync, so make sure your server is running -at least 2\&.6\&.3 to effect this\&. +at least 2\&.6\&.3 to effect this\&. Also note that it is safest to exclude a +directory and all its contents combining the rule "/some/dir/" with the +rule "/some/dir/**" just to be sure that rsync will not allow deeper +access to some of the excluded files inside the directory (rsync tries to +do this automatically, but you might as well specify both to be extra +sure)\&. +.IP +.IP "\fBport\fP" +You can override the default port the daemon will listen on +by specifying this value (defaults to 873)\&. This is ignored if the daemon +is being run by inetd, and is superseded by the \fB--port\fP command-line option\&. +.IP +.IP "\fBaddress\fP" +You can override the default IP address the daemon +will listen on by specifying this value\&. This is ignored if the daemon is +being run by inetd, and is superseded by the \fB--address\fP command-line option\&. .IP .IP "\fBmax connections\fP" The "max connections" option allows you to @@ -175,6 +198,12 @@ message telling them to try later\&. The default is 0 which means no limit\&. See also the "lock file" option\&. .IP +.IP "\fBmax verbosity\fP" +The "max verbosity" option allows you to control +the maximum amount of verbose information that you\&'ll allow the daemon to +generate (since the information goes into the log file)\&. The default is 1, +which allows the client to request one level of verbosity\&. +.IP .IP "\fBlock file\fP" The "lock file" option specifies the file to use to support the "max connections" option\&. The rsync server uses record @@ -215,11 +244,22 @@ was run as root\&. This complements the "uid" option\&. The default is gid -2, which is normally the group "nobody"\&. .IP +.IP "\fBfilter\fP" +The "filter" option allows you to specify a space-separated +list of filter rules that the server will not allow to be read or written\&. +This is only superficially equivalent to the client specifying these +patterns with the \fB--filter\fP option\&. Only one "filter" option may be +specified, but it may contain as many rules as you like, including +merge-file rules\&. Note that per-directory merge-file rules do not provide +as much protection as global rules, but they can be used to make \fB--delete\fP +work better when a client downloads the server\&'s files (if the per-dir +merge files are included in the transfer)\&. +.IP .IP "\fBexclude\fP" The "exclude" option allows you to specify a space-separated list of patterns that the server will not allow to be read or written\&. This is only superficially equivalent to the client -specifying these patterns with the --exclude option\&. Only one "exclude" +specifying these patterns with the \fB--exclude\fP option\&. Only one "exclude" option may be specified, but you can use "-" and "+" before patterns to specify exclude/include\&. .IP @@ -233,14 +273,14 @@ The "exclude from" option specifies a filename on the server that contains exclude patterns, one per line\&. This is only superficially equivalent -to the client specifying the --exclude-from option with an equivalent file\&. +to the client specifying the \fB--exclude-from\fP option with an equivalent file\&. See the "exclude" option above\&. .IP .IP "\fBinclude\fP" The "include" option allows you to specify a space-separated list of patterns which rsync should not exclude\&. This is only superficially equivalent to the client specifying these patterns with -the --include option because it applies only on the server\&. This is +the \fB--include\fP option because it applies only on the server\&. This is useful as it allows you to build up quite complex exclude/include rules\&. Only one "include" option may be specified, but you can use "+" and "-" before patterns to switch include/exclude\&. See the "exclude" option @@ -250,7 +290,7 @@ The "include from" option specifies a filename on the server that contains include patterns, one per line\&. This is only superficially equivalent to the client specifying the ---include-from option with a equivalent file\&. +\fB--include-from\fP option with a equivalent file\&. See the "exclude" option above\&. .IP .IP "\fBauth users\fP" @@ -301,42 +341,39 @@ .IP Each pattern can be in one of five forms: .IP +.RS .IP o a dotted decimal IPv4 address of the form a\&.b\&.c\&.d, or an IPv6 address of the form a:b:c::d:e:f\&. In this case the incoming machine\&'s IP address must match exactly\&. -.IP .IP o an address/mask in the form ipaddr/n where ipaddr is the IP address and n is the number of one bits in the netmask\&. All IP addresses which match the masked IP address will be allowed in\&. -.IP .IP o an address/mask in the form ipaddr/maskaddr where ipaddr is the IP address and maskaddr is the netmask in dotted decimal notation for IPv4, or similar for IPv6, e\&.g\&. ffff:ffff:ffff:ffff:: instead of /64\&. All IP addresses which match the masked IP address will be allowed in\&. -.IP .IP o a hostname\&. The hostname as determined by a reverse lookup will be matched (case insensitive) against the pattern\&. Only an exact match is allowed in\&. -.IP .IP o a hostname pattern using wildcards\&. These are matched using the same rules as normal unix filename matching\&. If the pattern matches then the client is allowed in\&. +.RE .IP Note IPv6 link-local addresses can have a scope in the address specification: .IP .RS -fe80::1%link1 -.RE -.RS -fe80::%link1/64 -.RE -.RS -fe80::%link1/ffff:ffff:ffff:ffff:: +\f(CW fe80::1%link1\fP +.br +\f(CW fe80::%link1/64\fP +.br +\f(CW fe80::%link1/ffff:ffff:ffff:ffff::\fP +.br .RE .IP You can also combine "hosts allow" with a separate "hosts deny" @@ -360,11 +397,11 @@ .IP "\fBignore errors\fP" The "ignore errors" option tells rsyncd to ignore I/O errors on the server when deciding whether to run the delete -phase of the transfer\&. Normally rsync skips the --delete step if any -I/O errors have occurred in order to prevent disasterous deletion due +phase of the transfer\&. Normally rsync skips the \fB--delete\fP step if any +I/O errors have occurred in order to prevent disastrous deletion due to a temporary resource shortage or other I/O error\&. In some cases this test is counter productive so you can use this option to turn off this -behaviour\&. +behavior\&. .IP .IP "\fBignore nonreadable\fP" This tells the rsync server to completely @@ -375,17 +412,28 @@ .IP "\fBtransfer logging\fP" The "transfer logging" option enables per-file logging of downloads and uploads in a format somewhat similar to that -used by ftp daemons\&. If you want to customize the log formats look at -the log format option\&. +used by ftp daemons\&. The server always logs the transfer at the end, so +if a transfer is aborted, no mention will be made in the log file\&. +.IP +If you want to customize the log lines, see the "log format" option\&. .IP .IP "\fBlog format\fP" The "log format" option allows you to specify the -format used for logging file transfers when transfer logging is -enabled\&. The format is a text string containing embedded single -character escape sequences prefixed with a percent (%) character\&. +format used for logging file transfers when transfer logging is enabled\&. +The format is a text string containing embedded single-character escape +sequences prefixed with a percent (%) character\&. An optional numeric +field width may also be specified between the percent and the escape +letter (e\&.g\&. "%-50n %8l %07p")\&. +.IP +The default log format is "%o %h [%a] %m (%u) %f %l", and a "%t [%p] " +is always prefixed when using the "log file" option\&. +(A perl script that will summarize this default log format is included +in the rsync source code distribution in the "support" subdirectory: +rsyncstats\&.) .IP -The prefixes that are understood are: +The single-character escapes that are understood are as follows: .IP +.RS .IP o %h for the remote host name .IP o @@ -395,9 +443,15 @@ .IP o %p for the process ID of this rsync session .IP o -%o for the operation, which is either "send" or "recv" +%o for the operation, which is "send", "recv", or "del\&." +(the latter includes the trailing period) +.IP o +%f for the filename (long form on sender; no trailing "/") .IP o -%f for the filename +%n for the filename (short form; trailing "/" on dir) +.IP o +%L either the string " -> SYMLINK", or " => HARDLINK" or an +empty string (where \fBSYMLINK\fP or \fBHARDLINK\fP is a filename) .IP o %P for the module path .IP o @@ -411,12 +465,16 @@ .IP o %c when sending files this gives the number of checksum bytes received for this file +.IP o +%i an itemized list of what is being updated +.RE .IP -The default log format is "%o %h [%a] %m (%u) %f %l", and a "%t [%p] " -is always added to the beginning when using the "log file" option\&. +For a list of what the characters mean that are output by "%i", see the +\fB--itemize-changes\fP option in the rsync manpage\&. .IP -A perl script called rsyncstats to summarize this format is included -in the rsync source code distribution\&. +Note that some of the logged output changes when talking with older +rsync versions\&. For instance, deleted files were only output as verbose +messages prior to rsync 2\&.6\&.4\&. .IP .IP "\fBtimeout\fP" The "timeout" option allows you to override the @@ -432,13 +490,20 @@ be refused by your rsync server\&. You may specify the full option name, its one-letter abbreviation, or a wild-card string that matches multiple options\&. -For example, this would refuse --checksum (-c) and all the options that -start with "delete": +For example, this would refuse \fB--checksum\fP (\fB-c\fP) and all the various +delete options: .IP .RS -refuse options = c delete* +\f(CW refuse options = c delete\fP .RE .IP +The reason the above refuses all delete options is that the options imply +\fB--delete\fP, and implied options are refused just like explicit options\&. +As an additional safety feature, the refusal of "delete" also refuses +\fBremove-sent-files\fP when the daemon is the sender; if you want the latter +without the former, instead refuse "delete-*" -- that refuses all the +delete modes without affecting \fB--remove-sent-files\fP\&. +.IP When an option is refused, the server prints an error message and exits\&. To prevent all compression, you can use "dont compress = *" (see below) instead of "refuse options = compress" to avoid returning an error to a @@ -455,13 +520,7 @@ case-insensitive wildcard patterns\&. Any source filename matching one of the patterns will not be compressed during transfer\&. .IP -The default setting is -.nf - -*\&.gz *\&.tgz *\&.zip *\&.z *\&.rpm *\&.deb *\&.iso *\&.bz2 *\&.tbz -.fi - - +The default setting is \f(CW*\&.gz *\&.tgz *\&.zip *\&.z *\&.rpm *\&.deb *\&.iso *\&.bz2 *\&.tbz\fP .IP .PP .SH "AUTHENTICATION STRENGTH" @@ -483,7 +542,7 @@ .PP .SH "RUNNING AN RSYNC SERVER OVER A REMOTE SHELL PROGRAM" .PP -If rsync is run with both the --daemon and --rsh (-e) options, it will +If rsync is run with both the \fB--daemon\fP and \fB--rsh\fP (\fB-e\fP) options, it will spawn an rsync daemon using a remote shell connection\&. Several configuration options will not be available unless the remote user is root (e\&.g\&. chroot, setuid/setgid, etc\&.)\&. There is no need to configure @@ -495,21 +554,21 @@ where command would be .PP .RS -rsync --server --daemon \&. +\f(CWrsync --server --daemon \&.\fP .RE .PP NOTE: rsync\&'s argument parsing expects the trailing "\&.", so make sure that it\&'s there\&. If you want to use an rsyncd\&.conf(5)-style configuration file other than the default, you can added a ---config option to the \fIcommand\fP: +\fB--config\fP option to the \fIcommand\fP: .PP .RS -rsync --server --daemon --config=\fIfile\fP \&. +\f(CWrsync --server --daemon --config=em(file) \&.\fP .RE .PP Note that the "--server" here is the internal option that rsync uses to run the remote version of rsync that it communicates with, and thus you -should not be using the --server option under normal circumstances\&. +should not be using the \fB--server\fP option under normal circumstances\&. .PP .SH "EXAMPLES" .PP @@ -530,21 +589,17 @@ .PP A more sophisticated example would be: .PP -uid = nobody -.br -gid = nobody -.br -use chroot = no -.br -max connections = 4 -.br -syslog facility = local5 -.br -pid file = /var/run/rsyncd\&.pid -.PP .nf + +uid = nobody +gid = nobody +use chroot = no +max connections = 4 +syslog facility = local5 +pid file = /var/run/rsyncd\&.pid + [ftp] path = /var/ftp/pub comment = whole ftp area (approx 6\&.1 GB) @@ -573,9 +628,12 @@ .PP The /etc/rsyncd\&.secrets file would look something like this: .PP -tridge:mypass +.RS +\f(CWtridge:mypass\fP +.br +\f(CWsusan:herpass\fP .br -susan:herpass +.RE .PP .SH "FILES" .PP @@ -623,7 +681,8 @@ .PP .SH "AUTHOR" .PP -rsync was written by Andrew Tridgell and Paul Mackerras\&. They may be -contacted via email at tridge@samba\&.org and -Paul\&.Mackerras@cs\&.anu\&.edu\&.au +rsync was written by Andrew Tridgell and Paul Mackerras\&. +Many people have later contributed to it\&. .PP +Mailing lists for support and development are available at +http://lists\&.samba\&.org diff -urN --exclude=patches rsync-2.6.3/rsyncd.conf.yo rsync-2.6.4/rsyncd.conf.yo --- rsync-2.6.3/rsyncd.conf.yo 2004-09-30 09:35:56.000000000 -0700 +++ rsync-2.6.4/rsyncd.conf.yo 2005-03-30 19:14:09.000000000 -0800 @@ -1,5 +1,5 @@ mailto(rsync-bugs@samba.org) -manpage(rsyncd.conf)(5)(30 Sep 2004)()() +manpage(rsyncd.conf)(5)(30 Mar 2005)()() manpagename(rsyncd.conf)(configuration file for rsync server) manpagesynopsis() @@ -19,7 +19,7 @@ name of the module in square brackets and continues until the next module begins. Modules contain parameters of the form 'name = value'. -The file is line-based - that is, each newline-terminated line represents +The file is line-based -- that is, each newline-terminated line represents either a comment, a module name or a parameter. Only the first equals sign in a parameter is significant. Whitespace before @@ -41,7 +41,7 @@ manpagesection(LAUNCHING THE RSYNC DAEMON) -The rsync daemon is launched by specifying the --daemon option to +The rsync daemon is launched by specifying the bf(--daemon) option to rsync. The daemon must run with root privileges if you wish to use chroot, to @@ -51,18 +51,18 @@ You can launch it either via inetd, as a stand-alone daemon, or from an rsync client via a remote shell. If run as a stand-alone daemon then -just run the command "rsync --daemon" from a suitable startup script. +just run the command "bf(rsync --daemon)" from a suitable startup script. If run from an rsync client via a remote shell (by specifying both the -"-e/--rsh" option and server mode with "::" or "rsync://"), the --daemon +bf(--rsh) (bf(-e)) option and server mode with "::" or "rsync://"), the bf(--daemon) option is automatically passed to the remote side. When run via inetd you should add a line like this to /etc/services: -quote(rsync 873/tcp) +verb( rsync 873/tcp) and a single line something like this to /etc/inetd.conf: -quote(rsync stream tcp nowait root /usr/bin/rsync rsyncd --daemon) +verb( rsync stream tcp nowait root /usr/bin/rsync rsyncd --daemon) Replace "/usr/bin/rsync" with the path to where you have rsync installed on your system. You will then need to send inetd a HUP signal to tell it to @@ -139,7 +139,7 @@ (see below). When "use chroot" is false, for security reasons, symlinks may only be relative paths pointing to other files within the root path, and leading slashes are removed from most absolute paths (options -such as --backup-dir, --compare-dest, etc. interpret an absolute path as +such as bf(--backup-dir), bf(--compare-dest), etc. interpret an absolute path as rooted in the module's "path" dir, just as if chroot was specified). The default for "use chroot" is true. @@ -149,16 +149,29 @@ process in the chroot namespace will need to have access to the resources used by these library functions (traditionally /etc/passwd and /etc/group). If these resources are not available, rsync will only be -able to copy the IDs, just as if the --numeric-ids option had been +able to copy the IDs, just as if the bf(--numeric-ids) option had been specified. Note that you are free to setup user/group information in the chroot area differently from your normal system. For example, you could abbreviate the list of users and groups. Also, you can protect this information from being downloaded/uploaded by adding an exclude rule to the rsync.conf file -(e.g. "exclude = /etc/"). Note that having the exclusion affect uploads +(e.g. "exclude = /etc/**"). Note that having the exclusion affect uploads is a relatively new feature in rsync, so make sure your server is running -at least 2.6.3 to effect this. +at least 2.6.3 to effect this. Also note that it is safest to exclude a +directory and all its contents combining the rule "/some/dir/" with the +rule "/some/dir/**" just to be sure that rsync will not allow deeper +access to some of the excluded files inside the directory (rsync tries to +do this automatically, but you might as well specify both to be extra +sure). + +dit(bf(port)) You can override the default port the daemon will listen on +by specifying this value (defaults to 873). This is ignored if the daemon +is being run by inetd, and is superseded by the bf(--port) command-line option. + +dit(bf(address)) You can override the default IP address the daemon +will listen on by specifying this value. This is ignored if the daemon is +being run by inetd, and is superseded by the bf(--address) command-line option. dit(bf(max connections)) The "max connections" option allows you to specify the maximum number of simultaneous connections you will allow. @@ -166,6 +179,11 @@ message telling them to try later. The default is 0 which means no limit. See also the "lock file" option. +dit(bf(max verbosity)) The "max verbosity" option allows you to control +the maximum amount of verbose information that you'll allow the daemon to +generate (since the information goes into the log file). The default is 1, +which allows the client to request one level of verbosity. + dit(bf(lock file)) The "lock file" option specifies the file to use to support the "max connections" option. The rsync server uses record locking on this file to ensure that the max connections limit is not @@ -200,10 +218,20 @@ was run as root. This complements the "uid" option. The default is gid -2, which is normally the group "nobody". +dit(bf(filter)) The "filter" option allows you to specify a space-separated +list of filter rules that the server will not allow to be read or written. +This is only superficially equivalent to the client specifying these +patterns with the bf(--filter) option. Only one "filter" option may be +specified, but it may contain as many rules as you like, including +merge-file rules. Note that per-directory merge-file rules do not provide +as much protection as global rules, but they can be used to make bf(--delete) +work better when a client downloads the server's files (if the per-dir +merge files are included in the transfer). + dit(bf(exclude)) The "exclude" option allows you to specify a space-separated list of patterns that the server will not allow to be read or written. This is only superficially equivalent to the client -specifying these patterns with the --exclude option. Only one "exclude" +specifying these patterns with the bf(--exclude) option. Only one "exclude" option may be specified, but you can use "-" and "+" before patterns to specify exclude/include. @@ -216,13 +244,13 @@ dit(bf(exclude from)) The "exclude from" option specifies a filename on the server that contains exclude patterns, one per line. This is only superficially equivalent -to the client specifying the --exclude-from option with an equivalent file. +to the client specifying the bf(--exclude-from) option with an equivalent file. See the "exclude" option above. dit(bf(include)) The "include" option allows you to specify a space-separated list of patterns which rsync should not exclude. This is only superficially equivalent to the client specifying these patterns with -the --include option because it applies only on the server. This is +the bf(--include) option because it applies only on the server. This is useful as it allows you to build up quite complex exclude/include rules. Only one "include" option may be specified, but you can use "+" and "-" before patterns to switch include/exclude. See the "exclude" option @@ -231,7 +259,7 @@ dit(bf(include from)) The "include from" option specifies a filename on the server that contains include patterns, one per line. This is only superficially equivalent to the client specifying the ---include-from option with a equivalent file. +bf(--include-from) option with a equivalent file. See the "exclude" option above. dit(bf(auth users)) The "auth users" option specifies a comma and @@ -278,34 +306,32 @@ Each pattern can be in one of five forms: -itemize( +quote(itemize( it() a dotted decimal IPv4 address of the form a.b.c.d, or an IPv6 address of the form a:b:c::d:e:f. In this case the incoming machine's IP address must match exactly. - it() an address/mask in the form ipaddr/n where ipaddr is the IP address and n is the number of one bits in the netmask. All IP addresses which match the masked IP address will be allowed in. - it() an address/mask in the form ipaddr/maskaddr where ipaddr is the IP address and maskaddr is the netmask in dotted decimal notation for IPv4, or similar for IPv6, e.g. ffff:ffff:ffff:ffff:: instead of /64. All IP addresses which match the masked IP address will be allowed in. - it() a hostname. The hostname as determined by a reverse lookup will be matched (case insensitive) against the pattern. Only an exact match is allowed in. - it() a hostname pattern using wildcards. These are matched using the same rules as normal unix filename matching. If the pattern matches then the client is allowed in. -) +)) Note IPv6 link-local addresses can have a scope in the address specification: -quote(fe80::1%link1) -quote(fe80::%link1/64) -quote(fe80::%link1/ffff:ffff:ffff:ffff::) +quote( +tt( fe80::1%link1)nl() +tt( fe80::%link1/64)nl() +tt( fe80::%link1/ffff:ffff:ffff:ffff::)nl() +) You can also combine "hosts allow" with a separate "hosts deny" option. If both options are specified then the "hosts allow" option s @@ -326,11 +352,11 @@ dit(bf(ignore errors)) The "ignore errors" option tells rsyncd to ignore I/O errors on the server when deciding whether to run the delete -phase of the transfer. Normally rsync skips the --delete step if any -I/O errors have occurred in order to prevent disasterous deletion due +phase of the transfer. Normally rsync skips the bf(--delete) step if any +I/O errors have occurred in order to prevent disastrous deletion due to a temporary resource shortage or other I/O error. In some cases this test is counter productive so you can use this option to turn off this -behaviour. +behavior. dit(bf(ignore nonreadable)) This tells the rsync server to completely ignore files that are not readable by the user. This is useful for @@ -339,23 +365,37 @@ dit(bf(transfer logging)) The "transfer logging" option enables per-file logging of downloads and uploads in a format somewhat similar to that -used by ftp daemons. If you want to customize the log formats look at -the log format option. +used by ftp daemons. The server always logs the transfer at the end, so +if a transfer is aborted, no mention will be made in the log file. + +If you want to customize the log lines, see the "log format" option. dit(bf(log format)) The "log format" option allows you to specify the -format used for logging file transfers when transfer logging is -enabled. The format is a text string containing embedded single -character escape sequences prefixed with a percent (%) character. +format used for logging file transfers when transfer logging is enabled. +The format is a text string containing embedded single-character escape +sequences prefixed with a percent (%) character. An optional numeric +field width may also be specified between the percent and the escape +letter (e.g. "%-50n %8l %07p"). -The prefixes that are understood are: +The default log format is "%o %h [%a] %m (%u) %f %l", and a "%t [%p] " +is always prefixed when using the "log file" option. +(A perl script that will summarize this default log format is included +in the rsync source code distribution in the "support" subdirectory: +rsyncstats.) + +The single-character escapes that are understood are as follows: -itemize( +quote(itemize( it() %h for the remote host name it() %a for the remote IP address it() %l for the length of the file in bytes it() %p for the process ID of this rsync session - it() %o for the operation, which is either "send" or "recv" - it() %f for the filename + it() %o for the operation, which is "send", "recv", or "del." + (the latter includes the trailing period) + it() %f for the filename (long form on sender; no trailing "/") + it() %n for the filename (short form; trailing "/" on dir) + it() %L either the string " -> SYMLINK", or " => HARDLINK" or an + empty string (where bf(SYMLINK) or bf(HARDLINK) is a filename) it() %P for the module path it() %m for the module name it() %t for the current date time @@ -363,13 +403,15 @@ it() %b for the number of bytes actually transferred it() %c when sending files this gives the number of checksum bytes received for this file -) + it() %i an itemized list of what is being updated +)) -The default log format is "%o %h [%a] %m (%u) %f %l", and a "%t [%p] " -is always added to the beginning when using the "log file" option. +For a list of what the characters mean that are output by "%i", see the +bf(--itemize-changes) option in the rsync manpage. -A perl script called rsyncstats to summarize this format is included -in the rsync source code distribution. +Note that some of the logged output changes when talking with older +rsync versions. For instance, deleted files were only output as verbose +messages prior to rsync 2.6.4. dit(bf(timeout)) The "timeout" option allows you to override the clients choice for I/O timeout for this module. Using this option you @@ -383,10 +425,17 @@ be refused by your rsync server. You may specify the full option name, its one-letter abbreviation, or a wild-card string that matches multiple options. -For example, this would refuse --checksum (-c) and all the options that -start with "delete": +For example, this would refuse bf(--checksum) (bf(-c)) and all the various +delete options: + +quote(tt( refuse options = c delete)) -quote(refuse options = c delete*) +The reason the above refuses all delete options is that the options imply +bf(--delete), and implied options are refused just like explicit options. +As an additional safety feature, the refusal of "delete" also refuses +bf(remove-sent-files) when the daemon is the sender; if you want the latter +without the former, instead refuse "delete-*" -- that refuses all the +delete modes without affecting bf(--remove-sent-files). When an option is refused, the server prints an error message and exits. To prevent all compression, you can use "dont compress = *" (see below) @@ -403,7 +452,7 @@ case-insensitive wildcard patterns. Any source filename matching one of the patterns will not be compressed during transfer. -The default setting is verb(*.gz *.tgz *.zip *.z *.rpm *.deb *.iso *.bz2 *.tbz) +The default setting is tt(*.gz *.tgz *.zip *.z *.rpm *.deb *.iso *.bz2 *.tbz) enddit() @@ -426,7 +475,7 @@ manpagesection(RUNNING AN RSYNC SERVER OVER A REMOTE SHELL PROGRAM) -If rsync is run with both the --daemon and --rsh (-e) options, it will +If rsync is run with both the bf(--daemon) and bf(--rsh) (bf(-e)) options, it will spawn an rsync daemon using a remote shell connection. Several configuration options will not be available unless the remote user is root (e.g. chroot, setuid/setgid, etc.). There is no need to configure @@ -437,18 +486,18 @@ "command=em(COMMAND)" syntax in the remote user's authorized_keys entry, where command would be -quote(rsync --server --daemon .) +quote(tt(rsync --server --daemon .)) NOTE: rsync's argument parsing expects the trailing ".", so make sure that it's there. If you want to use an rsyncd.conf(5)-style configuration file other than the default, you can added a ---config option to the em(command): +bf(--config) option to the em(command): -quote(rsync --server --daemon --config=em(file) .) +quote(tt(rsync --server --daemon --config=em(file) .)) Note that the "--server" here is the internal option that rsync uses to run the remote version of rsync that it communicates with, and thus you -should not be using the --server option under normal circumstances. +should not be using the bf(--server) option under normal circumstances. manpagesection(EXAMPLES) @@ -461,17 +510,17 @@ comment = ftp export area ) - A more sophisticated example would be: -uid = nobody nl() -gid = nobody nl() -use chroot = no nl() -max connections = 4 nl() -syslog facility = local5 nl() +verb( +uid = nobody +gid = nobody +use chroot = no +max connections = 4 +syslog facility = local5 pid file = /var/run/rsyncd.pid -verb([ftp] +[ftp] path = /var/ftp/pub comment = whole ftp area (approx 6.1 GB) @@ -496,8 +545,10 @@ The /etc/rsyncd.secrets file would look something like this: -tridge:mypass nl() -susan:herpass +quote( +tt(tridge:mypass)nl() +tt(susan:herpass)nl() +) manpagefiles() @@ -545,7 +596,8 @@ manpageauthor() -rsync was written by Andrew Tridgell and Paul Mackerras. They may be -contacted via email at tridge@samba.org and -Paul.Mackerras@cs.anu.edu.au +rsync was written by Andrew Tridgell and Paul Mackerras. +Many people have later contributed to it. +Mailing lists for support and development are available at +url(http://lists.samba.org)(lists.samba.org) diff -urN --exclude=patches rsync-2.6.3/runtests.sh rsync-2.6.4/runtests.sh --- rsync-2.6.3/runtests.sh 2004-02-03 21:34:29.000000000 -0800 +++ rsync-2.6.4/runtests.sh 2005-02-20 13:04:03.000000000 -0800 @@ -126,12 +126,10 @@ RUNSHFLAGS='-e' # for Solaris -PATH="/usr/xpg4/bin/:$PATH" +[ -d /usr/xpg4/bin ] && PATH="/usr/xpg4/bin/:$PATH" -if [ -n "$loglevel" ] && [ "$loglevel" -gt 8 ] -then - if set -x - then +if [ "x$loglevel" != x ] && [ "$loglevel" -gt 8 ]; then + if set -x; then # If it doesn't work the first time, don't keep trying. RUNSHFLAGS="$RUNSHFLAGS -x" fi @@ -142,33 +140,39 @@ echo " rsync_bin=$rsync_bin" echo " srcdir=$srcdir" -testuser=`id -un || whoami || echo UNKNOWN` +if [ -f /usr/bin/whoami ]; then + testuser=`/usr/bin/whoami` +elif [ -f /usr/ucb/whoami ]; then + testuser=`/usr/ucb/whoami` +elif [ -f /bin/whoami ]; then + testuser=`/bin/whoami` +else + testuser=`id -un 2>/dev/null || echo ${LOGNAME:-${USERNAME:-${USER:-'UNKNOWN'}}}` +fi echo " testuser=$testuser" echo " os=`uname -a`" # It must be "yes", not just nonnull -if test "x$preserve_scratch" = xyes -then +if [ "x$preserve_scratch" = xyes ]; then echo " preserve_scratch=yes" else echo " preserve_scratch=no" fi -if test ! -f $rsync_bin -then +if [ ! -f "$rsync_bin" ]; then echo "rsync_bin $rsync_bin is not a file" >&2 exit 2 fi -if test ! -d $srcdir -then +if [ ! -d "$srcdir" ]; then echo "srcdir $srcdir is not a directory" >&2 exit 2 fi RSYNC="$rsync_bin" +#RSYNC="valgrind --tool=addrcheck $rsync_bin" export rsync_bin RSYNC @@ -198,14 +202,13 @@ return 0 } -if [ "x$whichtests" = x ] -then +if [ "x$whichtests" = x ]; then whichtests="*.test" fi for testscript in $suitedir/$whichtests do - testbase=`echo $testscript | sed 's!.*/!!' | sed -e 's/.test\$//'` + testbase=`echo $testscript | sed -e 's!.*/!!' -e 's/.test\$//'` scratchdir="$scratchbase.$testbase" prep_scratch @@ -250,8 +253,7 @@ *) echo "FAIL $testbase" failed=`expr $failed + 1` - if [ "x$nopersist" = "xyes" ] - then + if [ "x$nopersist" = xyes ]; then exit 1 fi esac diff -urN --exclude=patches rsync-2.6.3/sender.c rsync-2.6.4/sender.c --- rsync-2.6.3/sender.c 2004-09-19 21:17:42.000000000 -0700 +++ rsync-2.6.4/sender.c 2005-03-28 09:29:27.000000000 -0800 @@ -20,15 +20,23 @@ #include "rsync.h" extern int verbose; -extern int csum_length; -extern struct stats stats; -extern int io_error; extern int dry_run; extern int am_server; extern int am_daemon; +extern int log_before_transfer; +extern int log_format_has_i; +extern int daemon_log_format_has_i; +extern int csum_length; +extern int io_error; extern int protocol_version; +extern int remove_sent_files; +extern int updating_basis_file; extern int make_backups; +extern int do_progress; +extern int inplace; extern struct stats stats; +extern struct file_list *the_file_list; +extern char *log_format; /** @@ -38,22 +46,6 @@ * and transmits them to the receiver. The sender process runs on the * machine holding the source files. **/ -void read_sum_head(int f, struct sum_struct *sum) -{ - sum->count = read_int(f); - sum->blength = read_int(f); - if (protocol_version < 27) { - sum->s2length = csum_length; - } else { - sum->s2length = read_int(f); - if (sum->s2length > MD4_SUM_LENGTH) { - rprintf(FERROR, "Invalid checksum length %ld\n", - (long)sum->s2length); - exit_cleanup(RERR_PROTOCOL); - } - } - sum->remainder = read_int(f); -} /** * Receive the checksums for a buffer @@ -61,7 +53,7 @@ static struct sum_struct *receive_sums(int f) { struct sum_struct *s; - int i; + int32 i; OFF_T offset = 0; if (!(s = new(struct sum_struct))) @@ -72,8 +64,8 @@ s->sums = NULL; if (verbose > 3) { - rprintf(FINFO, "count=%ld n=%u rem=%u\n", - (long)s->count, s->blength, s->remainder); + rprintf(FINFO, "count=%.0f n=%ld rem=%ld\n", + (double)s->count, (long)s->blength, (long)s->remainder); } if (s->count == 0) @@ -82,14 +74,14 @@ if (!(s->sums = new_array(struct sum_buf, s->count))) out_of_memory("receive_sums"); - for (i = 0; i < (int)s->count; i++) { + for (i = 0; i < s->count; i++) { s->sums[i].sum1 = read_int(f); read_buf(f, s->sums[i].sum2, s->s2length); s->sums[i].offset = offset; s->sums[i].flags = 0; - if (i == (int)s->count-1 && s->remainder != 0) + if (i == s->count-1 && s->remainder != 0) s->sums[i].len = s->remainder; else s->sums[i].len = s->blength; @@ -108,7 +100,97 @@ return s; } +void successful_send(int ndx) +{ + char fname[MAXPATHLEN]; + struct file_struct *file; + unsigned int offset; + + if (ndx < 0 || ndx >= the_file_list->count) + return; + + file = the_file_list->files[ndx]; + /* The generator might tell us about symlinks we didn't send. */ + if (!(file->flags & FLAG_SENT) && !S_ISLNK(file->mode)) + return; + 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 > 1) { + rprintf(FINFO, "sender removed %s\n", + safe_fname(fname + offset)); + } +} + +static void write_ndx_and_attrs(int f_out, int ndx, int iflags, + uchar fnamecmp_type, char *buf, int len) +{ + write_int(f_out, ndx); + if (protocol_version < 29) + return; + write_shortint(f_out, iflags); + if (iflags & ITEM_BASIS_TYPE_FOLLOWS) + write_byte(f_out, fnamecmp_type); + if (iflags & ITEM_XNAME_FOLLOWS) + write_vstring(f_out, buf, len); +} + +/* This is also used by receive.c with f_out = -1. */ +int read_item_attrs(int f_in, int f_out, int ndx, uchar *type_ptr, + char *buf, int *len_ptr) +{ + int len; + uchar fnamecmp_type = FNAMECMP_FNAME; + int iflags = protocol_version >= 29 ? read_shortint(f_in) + : ITEM_TRANSFER | ITEM_MISSING_DATA; + + /* Handle the new keep-alive (no-op) packet. */ + if (ndx == the_file_list->count && iflags == ITEM_IS_NEW) + ; + else if (ndx < 0 || ndx >= the_file_list->count) { + rprintf(FERROR, "Invalid file index: %d (count=%d) [%s]\n", + ndx, the_file_list->count, who_am_i()); + exit_cleanup(RERR_PROTOCOL); + } else if (iflags == ITEM_IS_NEW) { + rprintf(FERROR, "Invalid itemized flag word: %x [%s]\n", + iflags, who_am_i()); + exit_cleanup(RERR_PROTOCOL); + } + if (iflags & ITEM_BASIS_TYPE_FOLLOWS) + fnamecmp_type = read_byte(f_in); + *type_ptr = fnamecmp_type; + + if (iflags & ITEM_XNAME_FOLLOWS) { + if ((len = read_vstring(f_in, buf, MAXPATHLEN)) < 0) + exit_cleanup(RERR_PROTOCOL); + } else { + *buf = '\0'; + len = -1; + } + *len_ptr = len; + + /* Temporary handling of 2.6.4pre3 */ + if (iflags & ITEM_DUMMY_BIT && iflags & (ITEM_LOCAL_CHANGE|ITEM_TRANSFER)) + iflags &= ~ITEM_DUMMY_BIT; + + if (iflags & ITEM_TRANSFER) { + if (!S_ISREG(the_file_list->files[ndx]->mode)) { + rprintf(FERROR, + "received request to transfer non-regular file: %d [%s]\n", + ndx, who_am_i()); + exit_cleanup(RERR_PROTOCOL); + } + } else if (f_out >= 0) { + write_ndx_and_attrs(f_out, ndx, iflags, + fnamecmp_type, buf, len); + } + + return iflags; +} void send_files(struct file_list *flist, int f_out, int f_in) { @@ -117,12 +199,16 @@ struct map_struct *mbuf = NULL; STRUCT_STAT st; char *fname2, fname[MAXPATHLEN]; - int i; + char xname[MAXPATHLEN]; + uchar fnamecmp_type; + int iflags, xlen; struct file_struct *file; - int phase = 0; + int phase = 0, max_phase = protocol_version >= 29 ? 2 : 1; struct stats initial_stats; int save_make_backups = make_backups; - int j; + int itemizing = am_daemon ? daemon_log_format_has_i + : !am_server && log_format_has_i; + int i, j; if (verbose > 2) rprintf(FINFO, "send_files starting\n"); @@ -132,35 +218,27 @@ i = read_int(f_in); if (i == -1) { - if (phase == 0) { - phase++; - csum_length = SUM_LENGTH; - write_int(f_out, -1); - if (verbose > 2) - rprintf(FINFO, "send_files phase=%d\n", phase); - /* For inplace: redo phase turns off the backup - * flag so that we do a regular inplace send. */ - make_backups = 0; - continue; - } - break; + if (++phase > max_phase) + break; + csum_length = SUM_LENGTH; + if (verbose > 2) + rprintf(FINFO, "send_files phase=%d\n", phase); + write_int(f_out, -1); + /* For inplace: redo phase turns off the backup + * flag so that we do a regular inplace send. */ + make_backups = 0; + continue; } - if (i < 0 || i >= flist->count) { - rprintf(FERROR, "Invalid file index %d (count=%d)\n", - i, flist->count); - exit_cleanup(RERR_PROTOCOL); - } + iflags = read_item_attrs(f_in, f_out, i, &fnamecmp_type, + xname, &xlen); + if (iflags == ITEM_IS_NEW) /* no-op packet */ + continue; file = flist->files[i]; - - stats.current_file_index = i; - stats.num_transferred_files++; - stats.total_transferred_size += file->length; - - if (file->basedir) { + if (file->dir.root) { /* N.B. We're sure that this fits, so offset is OK. */ - offset = strlcpy(fname, file->basedir, sizeof fname); + offset = strlcpy(fname, file->dir.root, sizeof fname); if (!offset || fname[offset-1] != '/') fname[offset++] = '/'; } else @@ -170,10 +248,29 @@ if (verbose > 2) rprintf(FINFO, "send_files(%d, %s)\n", i, fname); - if (dry_run) { - if (!am_server && verbose) /* log the transfer */ - rprintf(FINFO, "%s\n", safe_fname(fname2)); - write_int(f_out, i); + if (!(iflags & ITEM_TRANSFER)) { + maybe_log_item(file, iflags, itemizing, xname); + continue; + } + if (phase == 2) { + rprintf(FERROR, + "got transfer request in phase 2 [%s]\n", + who_am_i()); + exit_cleanup(RERR_PROTOCOL); + } + + updating_basis_file = inplace && (protocol_version >= 29 + ? fnamecmp_type == FNAMECMP_FNAME : !make_backups); + + stats.current_file_index = i; + stats.num_transferred_files++; + stats.total_transferred_size += file->length; + + if (dry_run) { /* log the transfer */ + if (!am_server && log_format) + log_item(file, &stats, iflags, NULL); + write_ndx_and_attrs(f_out, i, iflags, fnamecmp_type, + xname, xlen); continue; } @@ -214,8 +311,8 @@ } if (st.st_size) { - OFF_T map_size = MAX(s->blength * 3, MAX_MAP_SIZE); - mbuf = map_file(fd, st.st_size, map_size, s->blength); + int32 read_size = MAX(s->blength * 3, MAX_MAP_SIZE); + mbuf = map_file(fd, st.st_size, read_size, s->blength); } else mbuf = NULL; @@ -224,7 +321,8 @@ safe_fname(fname), (double)st.st_size); } - write_int(f_out, i); + write_ndx_and_attrs(f_out, i, iflags, fnamecmp_type, + xname, xlen); write_sum_head(f_out, s); if (verbose > 2) { @@ -232,13 +330,19 @@ safe_fname(fname)); } - if (!am_server && verbose) /* log the transfer */ + if (log_before_transfer) + log_item(file, &initial_stats, iflags, NULL); + else if (!am_server && verbose && do_progress) rprintf(FINFO, "%s\n", safe_fname(fname2)); set_compression(fname); match_sums(f_out, s, mbuf, st.st_size); - log_send(file, &initial_stats); + if (do_progress) + end_progress(st.st_size); + + if (!log_before_transfer) + log_item(file, &initial_stats, iflags, NULL); if (mbuf) { j = unmap_file(mbuf); @@ -257,6 +361,9 @@ 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; diff -urN --exclude=patches rsync-2.6.3/socket.c rsync-2.6.4/socket.c --- rsync-2.6.3/socket.c 2004-09-16 10:22:31.000000000 -0700 +++ rsync-2.6.4/socket.c 2005-02-28 19:39:32.000000000 -0800 @@ -90,7 +90,7 @@ if (*cp == '\r') *cp = '\0'; if (strncmp(buffer, "HTTP/", 5) != 0) { - rprintf(FERROR, "bad response from proxy - %s\n", + rprintf(FERROR, "bad response from proxy -- %s\n", buffer); return -1; } @@ -98,7 +98,7 @@ while (*cp == ' ') cp++; if (*cp != '2') { - rprintf(FERROR, "bad response from proxy - %s\n", + rprintf(FERROR, "bad response from proxy -- %s\n", buffer); return -1; } @@ -198,7 +198,7 @@ strlcpy(buffer, h, sizeof buffer); /* Is the USER:PASS@ prefix present? */ - if ((cp = strchr(buffer, '@')) != NULL) { + if ((cp = strrchr(buffer, '@')) != NULL) { *cp++ = '\0'; /* The remainder is the HOST:PORT part. */ h = cp; @@ -455,7 +455,7 @@ #ifdef INET6 if (errno == EADDRINUSE && i > 0) { rprintf(FINFO, - "Try using --ipv4 or --ipv6 to avoid this listen() error."); + "Try using --ipv4 or --ipv6 to avoid this listen() error.\n"); } #endif exit_cleanup(RERR_SOCKETIO); @@ -506,8 +506,8 @@ int ret; for (i = 0; sp[i] >= 0; i++) close(sp[i]); - /* open log file in child before possibly giving - * up privileges */ + /* Re-open log file in child before possibly giving + * up privileges (see log_close() above). */ log_open(); ret = fn(fd, fd); close_all(); @@ -525,7 +525,6 @@ close(fd); } } - free(sp); } @@ -620,7 +619,7 @@ case OPT_ON: if (got_value) - rprintf(FERROR,"syntax error - %s does not take a value\n",tok); + rprintf(FERROR,"syntax error -- %s does not take a value\n",tok); { int on = socket_options[i].value; @@ -654,14 +653,12 @@ /* detach from the terminal */ #ifdef HAVE_SETSID setsid(); -#else -#ifdef TIOCNOTTY +#elif defined TIOCNOTTY i = open("/dev/tty", O_RDWR); if (i >= 0) { ioctl(i, (int)TIOCNOTTY, (char *)0); close(i); } -#endif /* TIOCNOTTY */ #endif /* make sure that stdin, stdout an stderr don't stuff things * up (library functions, for example) */ @@ -697,7 +694,7 @@ goto failed; memset(&sock2, 0, sizeof sock2); -#if HAVE_SOCKADDR_IN_LEN +#ifdef HAVE_SOCKADDR_IN_LEN sock2.sin_len = sizeof sock2; #endif sock2.sin_family = PF_INET; diff -urN --exclude=patches rsync-2.6.3/support/Makefile rsync-2.6.4/support/Makefile --- rsync-2.6.3/support/Makefile 1969-12-31 16:00:00.000000000 -0800 +++ rsync-2.6.4/support/Makefile 2005-01-11 10:37:37.000000000 -0800 @@ -0,0 +1,6 @@ +all: savetransfer + +savetransfer: savetransfer.o + +clean: + rm -f *.o savetransfer diff -urN --exclude=patches rsync-2.6.3/support/atomic-rsync rsync-2.6.4/support/atomic-rsync --- rsync-2.6.3/support/atomic-rsync 1969-12-31 16:00:00.000000000 -0800 +++ rsync-2.6.4/support/atomic-rsync 2005-01-14 11:23:20.000000000 -0800 @@ -0,0 +1,90 @@ +#!/usr/bin/perl +# +# This script lets you update a hierarchy of files in an atomic way by +# first creating a new hierarchy using --link-dest to rsync, and then +# swapping the hierarchy into place. See the usage message for more +# details and some important caveats! + +use strict; +use Cwd 'abs_path'; + +my $RSYNC_PROG = '/usr/bin/rsync'; +my $RM_PROG = '/bin/rm'; + +my $dest_dir = $ARGV[-1]; +usage(1) if $dest_dir eq '' || $dest_dir =~ /^--/; + +if (!-d $dest_dir) { + print STDERR "$dest_dir is not a directory.\n\n"; + usage(1); +} + +if (@_ = grep(/^--(link|compare)-dest/, @ARGV)) { + $_ = join(' or ', @_); + print STDERR "You may not use $_ as an rsync option.\n\n"; + usage(1); +} + +$dest_dir = abs_path($dest_dir); +if ($dest_dir eq '/') { + print STDERR 'You must not use "/" as the destination directory.', "\n\n"; + usage(1); +} + +my $old_dir = "$dest_dir~old~"; +my $new_dir = $ARGV[-1] = "$dest_dir~new~"; + +system($RM_PROG, '-rf', $old_dir) if -d $old_dir; + +if (system($RSYNC_PROG, "--link-dest=$dest_dir", @ARGV)) { + if ($? == -1) { + print "failed to execute $RSYNC_PROG: $!\n"; + } elsif ($? & 127) { + printf "child died with signal %d, %s coredump\n", + ($? & 127), ($? & 128) ? 'with' : 'without'; + } else { + printf "child exited with value %d\n", $? >> 8; + } + exit $?; +} + +rename($dest_dir, $old_dir) or die "Unable to rename $new_dir to $old_dir: $!"; +rename($new_dir, $dest_dir) or die "Unable to rename $new_dir to $dest_dir: $!"; + +exit; + + +sub usage +{ + my($ret) = @_; + my $fh = $ret ? *STDERR : *STDOUT; + print $fh <) { + $_ = (split)[1]; + next unless s#^\Q$dir$trailing\E##o && $_ ne ''; + print "- /$trailing$_\n"; +} +close IN; diff -urN --exclude=patches rsync-2.6.3/support/rrsync rsync-2.6.4/support/rrsync --- rsync-2.6.3/support/rrsync 1969-12-31 16:00:00.000000000 -0800 +++ rsync-2.6.4/support/rrsync 2005-02-19 17:04:12.000000000 -0800 @@ -0,0 +1,74 @@ +#!/usr/bin/perl +# Name: /usr/local/bin/rrsync (should also have a symlink in /usr/bin) +# Purpose: Restricts rsync to subdirectory declared in .ssh/authorized_keys +# Author: Joe Smith 30-Sep-2004 +# Modified by Wayne Davison 12-Jan-2005 + +use Socket; +use constant LOGFILE => 'rrsync.log'; +my $Usage = <*?#\$ + s/(\s)/\\$1/g; # Re-escape whitespace + push(@dirs, $_); +} +push(@dirs, $subdir) unless @dirs; +$dir = join(' ', @dirs); + +if (-f LOGFILE and open LOG,'>>',LOGFILE) { + my ($mm,$hh) = (localtime)[1,2]; + my $host = $ENV{SSH_CONNECTION} || 'unknown'; + $host =~ s/ .*//; # Keep only the client's IP addr + $host =~ s/^::ffff://; + $host = gethostbyaddr(inet_aton($host),AF_INET) || $host; + my $dir_result = $dir eq $orig ? " OK" : "> \"$dir\""; + printf LOG "%02d:%02d %-13s [%s] =%s\n", $hh, $mm, $host, $command, $dir_result; + close LOG; +} + +exec "$cmd \"$dir\"" or die "exec($cmd \"$dir\") failed: $? $!"; +# Note: This assumes that the rsync protocol will not be maliciously hijacked. diff -urN --exclude=patches rsync-2.6.3/support/rsyncstats rsync-2.6.4/support/rsyncstats --- rsync-2.6.3/support/rsyncstats 1998-11-22 16:30:27.000000000 -0800 +++ rsync-2.6.4/support/rsyncstats 2005-02-19 11:36:54.000000000 -0800 @@ -1,72 +1,67 @@ -#! /usr/bin/perl -# --------------------------------------------------------------------------- -# -# USAGE: rsyncstats -# -# OPTIONS: -# -f Use for the log file -# -h include report on hourly traffic -# -d include report on domain traffic -# -t report on total traffic by section -# -D report only on traffic from -# -l Depth of path detail for sections -# -s
Section to report on, For example: -s /pub will report -# only on paths under /pub +#!/usr/bin/perl # # This script parses the default logfile format produced by rsync when running -# as a daemon with transfer logging enabled. It is derived from the xferstats -# script that comes with wuftpd +# as a daemon with transfer logging enabled. It also parses a slightly tweaked +# version of the default format where %o has been replaced with %i. # -# Andrew Tridgell, October 1998 -# rsync-bugs@samba.org +# This script is derived from the xferstats script that comes with wuftpd. See +# the usage message at the bottom for the options it takes. # -# --------------------------------------------------------------------------- +# Andrew Tridgell, October 1998 -# edit the next line to customize for your default log file +use Getopt::Long; + +# You may wish to edit the next line to customize for your default log file. $usage_file = "/var/adm/rsyncd.log"; # Edit the following lines for default report settings. # Entries defined here will be over-ridden by the command line. -$opt_h = 1; -$opt_d = 0; -$opt_t = 1; -$opt_l = 2; - -require 'getopts.pl'; -&Getopts('f:rahdD:l:s:'); - -if ($opt_r) { $real = 1;} -if ($opt_a) { $anon = 1;} -if ($real == 0 && $anon == 0) { $anon = 1; } -if ($opt_f) {$usage_file = $opt_f;} - -open (LOG,$usage_file) || die "Error opening usage log file: $usage_file\n"; - -if ($opt_D) {print "Transfer Totals include the '$opt_D' domain only.\n"; - print "All other domains are filtered out for this report.\n\n";} - -if ($opt_s) {print "Transfer Totals include the '$opt_s' section only.\n"; - print "All other sections are filtered out for this report.\n\n";} +$hourly_report = 0; +$domain_report = 0; +$total_report = 0; +$depth_limit = 9999; +$only_section = ''; + +&Getopt::Long::Configure('bundling'); +&usage if !&GetOptions( + 'hourly-report|h' => \$hourly_report, + 'domain-report|d' => \$domain_report, + 'domain|D:s' => \$only_domain, + 'total-report|t' => \$total_report, + 'depth-limit|l:i' => \$depth_limit, + 'real|r' => \$real, + 'anon|a' => \$anon, + 'section|s:s' => \$only_section, + 'file|f:s' => \$usage_file, +); + +$anon = 1 if !$real && !$anon; + +open(LOG, $usage_file) || die "Error opening usage log file: $usage_file\n"; + +if ($only_domain) { + print "Transfer Totals include the '$only_domain' domain only.\n"; + print "All other domains are filtered out for this report.\n\n"; +} + +if ($only_section) { + print "Transfer Totals include the '$only_section' section only.\n"; + print "All other sections are filtered out for this report.\n\n"; +} line: while () { - @line = split; - - $day = $line[0]; - $time = $line[1]; - $pid = $line[2]; - $op = $line[3]; - $host = $line[4]; - $ip = $line[5]; - $module = $line[6]; - $user = $line[7]; - $file = $line[8]; - $bytes = $line[9]; - - next if ($#line != 9); - - next if ($op != "send" && $op != "recv"); + next unless ($day,$time,$op,$host,$module,$file,$bytes) + = m#^ (\d+/\d\d/\d\d)\s+(\d\d:\d\d:\d\d)\s+\[\d+\]\s+(send|recv|[<>]f\S+)\s+ + (\S+)\s+\[\d+\.\d+\.\d+\.\d+\]\s+(\S+)\s+\(\S*\)\s+(.*)\s+(\d+) $ #x; + + # TODO actually divide the data by into send/recv categories + if ($op =~ /^>/) { + $op = 'send'; + } elsif ($op =~ /^ 0 || $#address < 2 ) { $domain = "unresolved"; } - if ($opt_D) { - next unless (substr($domain,0,length("$opt_D")) eq "$opt_D"); + if ($only_domain ne '') { + next unless (substr($domain,0,length($only_domain)) eq $only_domain); } -# printf ("c=%d day=%s bytes=%d file=%s path=%s\n", +# printf("c=%d day=%s bytes=%d file=%s path=%s\n", # $#line, $daytime, $bytes, $file, $pathkey); $xferfiles++; # total files sent @@ -117,20 +114,20 @@ } close LOG; -@syslist = keys(systemfiles); -@dates = sort datecompare keys(xferbytes); +#@syslist = keys %systemfiles; +@dates = sort datecompare keys %xferbytes; if ($xferfiles == 0) {die "There was no data to process.\n";} print "TOTALS FOR SUMMARY PERIOD ", $dates[0], " TO ", $dates[$#dates], "\n\n"; -printf ("Files Transmitted During Summary Period %12.0f\n", $xferfiles); -printf ("Bytes Transmitted During Summary Period %12.0f\n", $xferbytes); -printf ("Systems Using Archives %12.0f\n\n", $#syslist+1); +printf("Files Transmitted During Summary Period %12.0f\n", $xferfiles); +printf("Bytes Transmitted During Summary Period %12.0f\n", $xferbytes); +#printf("Systems Using Archives %12.0f\n\n", $#syslist+1); -printf ("Average Files Transmitted Daily %12.0f\n", +printf("Average Files Transmitted Daily %12.0f\n", $xferfiles / ($#dates + 1)); -printf ("Average Bytes Transmitted Daily %12.0f\n", +printf("Average Bytes Transmitted Daily %12.0f\n", $xferbytes / ($#dates + 1)); format top1 = @@ -150,7 +147,7 @@ $^ = top1; $~ = line1; -foreach $date ( sort datecompare keys(xferbytes) ) { +foreach $date (sort datecompare keys %xferbytes) { $nfiles = $xferfiles{$date}; $nbytes = $xferbytes{$date}; @@ -159,7 +156,7 @@ write; } -if ($opt_t) { +if ($total_report) { format top2 = Total Transfers from each Archive Section (By bytes) @@ -179,7 +176,7 @@ $^ = top2; $~ = line2; -foreach $section ( sort bytecompare keys(groupfiles) ) { +foreach $section (sort bytecompare keys %groupfiles) { $files = $groupfiles{$section}; $bytes = $groupbytes{$section}; @@ -193,7 +190,7 @@ if ( $xferbytes < 1 ) { $xferbytes = 1; } } -if ($opt_d) { +if ($domain_report) { format top3 = Total Transfer Amount By Domain @@ -212,7 +209,7 @@ $^ = top3; $~ = line3; -foreach $domain ( sort domnamcompare keys(domainfiles) ) { +foreach $domain (sort domnamcompare keys %domainfiles) { if ( $domainsecs{$domain} < 1 ) { $domainsecs{$domain} = 1; } @@ -226,7 +223,7 @@ } -if ($opt_h) { +if ($hourly_report) { format top8 = @@ -248,7 +245,7 @@ $^ = top8; $~ = line8; -foreach $hour ( sort keys(xfertbytes) ) { +foreach $hour (sort keys %xfertbytes) { $nfiles = $xfertfiles{$hour}; $nbytes = $xfertbytes{$hour}; @@ -284,3 +281,19 @@ } +sub usage +{ + die < +#endif + extern int dry_run; extern int read_only; extern int list_only; @@ -55,7 +59,7 @@ return symlink(fname1, fname2); } -#if HAVE_LINK +#ifdef HAVE_LINK int do_link(char *fname1, char *fname2) { if (dry_run) return 0; @@ -68,17 +72,47 @@ { if (dry_run) return 0; RETURN_ERROR_IF_RO_OR_LO; +#ifndef HAVE_LCHOWN +#define lchown chown +#endif return lchown(path, owner, group); } -#if HAVE_MKNOD int do_mknod(char *pathname, mode_t mode, dev_t dev) { if (dry_run) return 0; RETURN_ERROR_IF_RO_OR_LO; +#if !defined MKNOD_CREATES_FIFOS && defined HAVE_MKFIFO + if (S_ISFIFO(mode)) + return mkfifo(pathname, mode); +#endif +#if !defined MKNOD_CREATES_SOCKETS && defined HAVE_SYS_UN_H + if (S_ISSOCK(mode)) { + int sock; + struct sockaddr_un saddr; + unsigned int len; + + saddr.sun_family = AF_UNIX; + len = strlcpy(saddr.sun_path, pathname, sizeof saddr.sun_path); +#ifdef HAVE_SOCKADDR_UN_LEN + saddr.sun_len = len >= sizeof saddr.sun_path + ? sizeof saddr.sun_path : len + 1; +#endif + + if ((sock = socket(PF_UNIX, SOCK_STREAM, 0)) < 0 + || (unlink(pathname) < 0 && errno != ENOENT) + || (bind(sock, (struct sockaddr*)&saddr, sizeof saddr)) < 0) + return -1; + close(sock); + return do_chmod(pathname, mode); + } +#endif +#ifdef HAVE_MKNOD return mknod(pathname, mode, dev); -} +#else + return -1; #endif +} int do_rmdir(char *pathname) { @@ -97,7 +131,7 @@ return open(pathname, flags | O_BINARY, mode); } -#if HAVE_CHMOD +#ifdef HAVE_CHMOD int do_chmod(const char *path, mode_t mode) { int code; @@ -152,7 +186,7 @@ RETURN_ERROR_IF(dry_run, 0); RETURN_ERROR_IF(read_only, EROFS); -#if HAVE_SECURE_MKSTEMP && HAVE_FCHMOD && (!HAVE_OPEN64 || HAVE_MKSTEMP64) +#if defined HAVE_SECURE_MKSTEMP && defined HAVE_FCHMOD && (!defined HAVE_OPEN64 || defined HAVE_MKSTEMP64) { int fd = mkstemp(template); if (fd == -1) @@ -164,6 +198,9 @@ errno = errno_save; return -1; } +#if defined HAVE_SETMODE && O_BINARY + setmode(fd, O_BINARY); +#endif return fd; } #else @@ -175,27 +212,29 @@ int do_stat(const char *fname, STRUCT_STAT *st) { -#if HAVE_OFF64_T +#ifdef USE_STAT64_FUNCS return stat64(fname, st); #else return stat(fname, st); #endif } -#if SUPPORT_LINKS int do_lstat(const char *fname, STRUCT_STAT *st) { -#if HAVE_OFF64_T +#ifdef SUPPORT_LINKS +# ifdef USE_STAT64_FUNCS return lstat64(fname, st); -#else +# else return lstat(fname, st); +# endif +#else + return do_stat(fname, st); #endif } -#endif int do_fstat(int fd, STRUCT_STAT *st) { -#if HAVE_OFF64_T +#ifdef USE_STAT64_FUNCS return fstat64(fd, st); #else return fstat(fd, st); @@ -204,7 +243,7 @@ OFF_T do_lseek(int fd, OFF_T offset, int whence) { -#if HAVE_OFF64_T +#if SIZEOF_OFF64_T off64_t lseek64(); return lseek64(fd, offset, whence); #else @@ -212,20 +251,9 @@ #endif } -#ifdef USE_MMAP -void *do_mmap(void *start, int len, int prot, int flags, int fd, OFF_T offset) -{ -#if HAVE_OFF64_T - return mmap64(start, len, prot, flags, fd, offset); -#else - return mmap(start, len, prot, flags, fd, offset); -#endif -} -#endif - char *d_name(struct dirent *di) { -#if HAVE_BROKEN_READDIR +#ifdef HAVE_BROKEN_READDIR return (di->d_name - 2); #else return di->d_name; diff -urN --exclude=patches rsync-2.6.3/t_stub.c rsync-2.6.4/t_stub.c --- rsync-2.6.3/t_stub.c 2004-07-29 09:06:38.000000000 -0700 +++ rsync-2.6.4/t_stub.c 2005-01-25 02:39:14.000000000 -0800 @@ -29,7 +29,7 @@ int modify_window = 0; int module_id = -1; char *partial_dir; -struct exclude_list_struct server_exclude_list; +struct filter_list_struct server_filter_list; void rprintf(UNUSED(enum logcode code), const char *format, ...) { @@ -56,7 +56,7 @@ exit(code); } - int check_exclude(UNUSED(struct exclude_list_struct *listp), UNUSED(char *name), + int check_filter(UNUSED(struct filter_list_struct *listp), UNUSED(char *name), UNUSED(int name_is_dir)) { /* This function doesn't really get called in this test context, so diff -urN --exclude=patches rsync-2.6.3/testsuite/chown.test rsync-2.6.4/testsuite/chown.test --- rsync-2.6.3/testsuite/chown.test 2004-05-17 17:41:35.000000000 -0700 +++ rsync-2.6.4/testsuite/chown.test 2005-03-17 18:10:34.000000000 -0800 @@ -15,6 +15,16 @@ set -x +case `id -u` in +'') ;; # If "id" failed, try to continue... +0) ;; +*) if [ -f /usr/bin/fakeroot ]; then + echo "Let's try re-running the script under fakeroot..." + exec /usr/bin/fakeroot /bin/sh "$0" + fi + ;; +esac + # Build some hardlinks mkdir "$fromdir" diff -urN --exclude=patches rsync-2.6.3/testsuite/compare-dest.test rsync-2.6.4/testsuite/compare-dest.test --- rsync-2.6.3/testsuite/compare-dest.test 2004-07-22 18:39:19.000000000 -0700 +++ rsync-2.6.4/testsuite/compare-dest.test 2005-03-11 09:36:05.000000000 -0800 @@ -9,25 +9,31 @@ . "$suitedir/rsync.fns" -set -x - -altdir="$tmpdir/alt" +alt1dir="$tmpdir/alt1" +alt2dir="$tmpdir/alt2" # Build some files/dirs/links to copy +set -x + hands_setup # Setup the alt and chk dirs -$RSYNC -av --include=text --include='*/' --exclude='*' "$fromdir/" "$altdir/" +$RSYNC -av --include=text --include='*/' --exclude='*' "$fromdir/" "$alt1dir/" +$RSYNC -av --include=etc-ltr-list --include='*/' --exclude='*' "$fromdir/" "$alt2dir/" sleep 1 touch "$fromdir/dir/text" -$RSYNC -av --exclude=/text "$fromdir/" "$chkdir/" +$RSYNC -av --exclude=/text --exclude=etc-ltr-list "$fromdir/" "$chkdir/" # Let's do it! -checkit "$RSYNC -avv --no-whole-file --compare-dest=\"$altdir\" \ +checkit "$RSYNC -avv --no-whole-file \ + --compare-dest=\"$alt1dir\" --compare-dest=\"$alt2dir\" \ \"$fromdir/\" \"$todir/\"" "$chkdir" "$todir" +checkit "$RSYNC -avv --no-whole-file \ + --copy-dest=\"$alt1dir\" --copy-dest=\"$alt2dir\" \ + \"$fromdir/\" \"$todir/\"" "$fromdir" "$todir" # The script would have aborted on error, so getting here means we've won. exit 0 diff -urN --exclude=patches rsync-2.6.3/testsuite/daemon-gzip-download.test rsync-2.6.4/testsuite/daemon-gzip-download.test --- rsync-2.6.3/testsuite/daemon-gzip-download.test 2004-05-17 17:41:51.000000000 -0700 +++ rsync-2.6.4/testsuite/daemon-gzip-download.test 2005-02-26 11:47:43.000000000 -0800 @@ -26,6 +26,8 @@ RSYNC_CONNECT_PROG="$RSYNC --config=$conf --daemon" export RSYNC_CONNECT_PROG +set -x + hands_setup # Build chkdir with a normal rsync and an --exclude. diff -urN --exclude=patches rsync-2.6.3/testsuite/daemon-gzip-upload.test rsync-2.6.4/testsuite/daemon-gzip-upload.test --- rsync-2.6.3/testsuite/daemon-gzip-upload.test 2004-05-17 17:41:51.000000000 -0700 +++ rsync-2.6.4/testsuite/daemon-gzip-upload.test 2005-02-26 11:47:43.000000000 -0800 @@ -20,6 +20,8 @@ RSYNC_CONNECT_PROG="$RSYNC --config=$conf --daemon" export RSYNC_CONNECT_PROG +set -x + hands_setup # Build chkdir with a normal rsync and an --exclude. diff -urN --exclude=patches rsync-2.6.3/testsuite/delete.test rsync-2.6.4/testsuite/delete.test --- rsync-2.6.3/testsuite/delete.test 1969-12-31 16:00:00.000000000 -0800 +++ rsync-2.6.4/testsuite/delete.test 2005-02-26 11:47:43.000000000 -0800 @@ -0,0 +1,29 @@ +#! /bin/sh + +# Copyright (C) 2005 by Wayne Davison + +# This program is distributable under the terms of the GNU GPL see +# COPYING). + +# Test rsync handling of various delete directives. + +. "$suitedir/rsync.fns" + +set -x + +hands_setup + +makepath "$chkdir" + +# Create two chk dirs, one with a copy of the source files, and one with +# what we expect to be left behind by the copy using --remove-sent-files. +$RSYNC -av "$fromdir/" "$chkdir/copy/" +$RSYNC -av -f 'exclude,! */' "$fromdir/" "$chkdir/empty/" + +checkit "$RSYNC -avv --remove-sent-files \ + \"$fromdir/\" \"$todir/\"" "$chkdir/copy" "$todir" + +diff -r "$chkdir/empty" "$fromdir" + +# The script would have aborted on error, so getting here means we've won. +exit 0 diff -urN --exclude=patches rsync-2.6.3/testsuite/devices.test rsync-2.6.4/testsuite/devices.test --- rsync-2.6.3/testsuite/devices.test 2004-09-23 09:34:43.000000000 -0700 +++ rsync-2.6.4/testsuite/devices.test 2005-03-17 18:10:34.000000000 -0800 @@ -9,14 +9,17 @@ . "$suitedir/rsync.fns" -set -x - # Build some hardlinks case `id -u` in '') ;; # If "id" failed, try to continue... -0) ;; -*) test_skipped "Rsync won't copy devices unless we're root" ;; +0) ;; +*) if [ -f /usr/bin/fakeroot ]; then + echo "Let's try re-running the script under fakeroot..." + exec /usr/bin/fakeroot /bin/sh "$0" + fi + test_skipped "Rsync won't copy devices unless we're root" + ;; esac # TODO: Need to test whether hardlinks are possible on this OS/filesystem @@ -30,7 +33,7 @@ mknod "$fromdir/block3" b 105 73 || test_skipped "Can't create block device node unless root" mkfifo "$fromdir/fifo" || test_skipped "Can't run mkfifo" -checkit "$RSYNC -aHvv \"$fromdir/\" \"$todir/\"" "$fromdir" "$todir" +checkit "$RSYNC -aHvv \"$fromdir/\" \"$todir/\"" "$fromdir" "$todir" skip_file_diff # The script would have aborted on error, so getting here means we've won. exit 0 diff -urN --exclude=patches rsync-2.6.3/testsuite/exclude.test rsync-2.6.4/testsuite/exclude.test --- rsync-2.6.3/testsuite/exclude.test 2004-05-23 17:16:07.000000000 -0700 +++ rsync-2.6.4/testsuite/exclude.test 2005-02-26 11:47:43.000000000 -0800 @@ -1,6 +1,6 @@ #! /bin/sh -# Copyright (C) 2003 by Wayne Davison +# Copyright (C) 2003, 2004, 2005 by Wayne Davison # This program is distributable under the terms of the GNU GPL see # COPYING). @@ -12,30 +12,66 @@ . "$suitedir/rsync.fns" -set -x - HOME="$scratchdir" CVSIGNORE='*.junk' export HOME CVSIGNORE +set -x + # Build some files/dirs/links to copy makepath "$fromdir/foo/down/to/you" makepath "$fromdir/bar/down/to/foo/too" +makepath "$fromdir/bar/down/to/bar/baz" makepath "$fromdir/mid/for/foo/and/that/is/who" +cat >"$fromdir/.filt" <"$fromdir/foo/file1" echo removed >"$fromdir/foo/file2" echo cvsout >"$fromdir/foo/file2.old" +cat >"$fromdir/foo/.filt" <"$fromdir/bar/.filt" <"$fromdir/bar/down/to/home-cvs-exclude" +cat >"$fromdir/bar/down/to/.filt2" <"$fromdir/bar/down/to/foo/.filt2" <"$fromdir/bar/down/to/foo/file1" echo cvsout >"$fromdir/bar/down/to/foo/file1.bak" echo gone >"$fromdir/bar/down/to/foo/file3" echo lost >"$fromdir/bar/down/to/foo/file4" -echo cvsout >"$fromdir/bar/down/to/foo/file4.junk" +echo weird >"$fromdir/bar/down/to/foo/+ file3" +echo cvsout-but-filtin >"$fromdir/bar/down/to/foo/file4.junk" echo smashed >"$fromdir/bar/down/to/foo/to" +cat >"$fromdir/bar/down/to/bar/.filt2" <"$fromdir/bar/down/to/bar/baz/file5.deep" +# This one should be ineffectual +cat >"$fromdir/mid/.filt2" <"$fromdir/mid/one-in-one-out" echo one-in-one-out >"$fromdir/mid/.cvsignore" echo cvsin >"$fromdir/mid/one-for-all" +cat >"$fromdir/mid/.filt" <"$fromdir/mid/for/one-in-one-out" echo expunged >"$fromdir/mid/for/foo/extra" echo retained >"$fromdir/mid/for/foo/keep" @@ -45,6 +81,7 @@ excl="$scratchdir/exclude-from" cat >"$excl" <"$todir"/bar/down/to/bar/baz/nodel.deep +cp -p "$todir"/bar/down/to/bar/baz/nodel.deep "$chkdir"/bar/down/to/bar/baz + +$RSYNC -av --existing --filter='-! */' "$fromdir/" "$chkdir/" + +# Now, test if rsync excludes the same files, this time with a merge-exclude +# file. + +checkit "sed '/!/d' \"$excl\" | + $RSYNC -avv -f dir-merge_.filt -f merge_- \ + --delete-during \"$fromdir/\" \"$todir/\"" "$chkdir" "$todir" + +# Remove the files that will be deleted. + +rm "$chkdir"/.filt +rm "$chkdir"/bar/.filt +rm "$chkdir"/bar/down/to/.filt2 +rm "$chkdir"/bar/down/to/foo/.filt2 +rm "$chkdir"/bar/down/to/bar/.filt2 +rm "$chkdir"/mid/.filt + +$RSYNC -av --protocol=28 --existing --include='*/' --exclude='*' "$fromdir/" "$chkdir/" + +# Now, try the prior command with --delete-before and some side-specific +# rules. + +checkit "sed '/!/d' \"$excl\" | + $RSYNC -avv -f :s_.filt -f .s_- -f P_nodel.deep \ + --delete-before \"$fromdir/\" \"$todir/\"" "$chkdir" "$todir" + +# Next, we'll test some rule-restricted filter files. + +cat >"$fromdir/bar/down/.excl" <"$fromdir/bar/down/to/foo/.excl" < + +# This program is distributable under the terms of the GNU GPL see +# COPYING). + +# Test rsync handling of the --fuzzy option. + +. "$suitedir/rsync.fns" + +set -x + +mkdir "$fromdir" +mkdir "$todir" + +cp -p "$srcdir"/rsync.c "$fromdir"/rsync.c +cp -p "$fromdir"/rsync.c "$todir"/rsync2.c + +# Let's do it! +checkit "$RSYNC -avvi --no-whole-file --fuzzy --delete-after \ + \"$fromdir/\" \"$todir/\"" "$fromdir" "$todir" + +# The script would have aborted on error, so getting here means we've won. +exit 0 diff -urN --exclude=patches rsync-2.6.3/testsuite/hardlinks.test rsync-2.6.4/testsuite/hardlinks.test --- rsync-2.6.3/testsuite/hardlinks.test 2004-05-17 17:41:40.000000000 -0700 +++ rsync-2.6.4/testsuite/hardlinks.test 2005-03-04 16:23:55.000000000 -0800 @@ -31,7 +31,7 @@ ln "$name2" "$name3" || fail "Can't create hardlink" cp "$name2" "$name4" || fail "Can't copy file" -checkit "$RSYNC -aHvv \"$fromdir/\" \"$todir/\"" "$fromdir" "$todir" +checkit "$RSYNC -aHivv \"$fromdir/\" \"$todir/\"" "$fromdir" "$todir" # The script would have aborted on error, so getting here means we've won. exit 0 diff -urN --exclude=patches rsync-2.6.3/testsuite/longdir.test rsync-2.6.4/testsuite/longdir.test --- rsync-2.6.3/testsuite/longdir.test 2004-05-18 02:47:42.000000000 -0700 +++ rsync-2.6.4/testsuite/longdir.test 2005-03-23 08:04:17.000000000 -0800 @@ -7,7 +7,7 @@ . "$suitedir/rsync.fns" -# set -x +set -x hands_setup @@ -17,7 +17,11 @@ makepath "$longdir" || test_skipped "unable to create long directory" touch "$longdir/1" || test_skipped "unable to create files in long directory" date > "$longdir/1" -ls -la / > "$longdir/2" +if [ -r /etc ]; then + ls -la /etc >"$longdir/2" +else + ls -la / >"$longdir/2" +fi checkit "$RSYNC --delete -avH \"$fromdir/\" \"$todir\"" "$fromdir/" "$todir" # The script would have aborted on error, so getting here means we've won. diff -urN --exclude=patches rsync-2.6.3/testsuite/merge.test rsync-2.6.4/testsuite/merge.test --- rsync-2.6.3/testsuite/merge.test 2004-05-17 17:41:38.000000000 -0700 +++ rsync-2.6.4/testsuite/merge.test 2005-02-26 11:47:43.000000000 -0800 @@ -19,8 +19,8 @@ mkdir "$from1dir" "$from2dir" "$from3dir" mkdir "$from2dir"/sub1 "$from3dir"/sub1 -mkdir "$from3dir"/sub2 -mkdir "$chkdir" "$chkdir"/sub1 "$chkdir"/sub2 +mkdir "$from3dir"/sub2 "$from1dir"/dir-and-not-dir +mkdir "$chkdir" "$chkdir"/sub1 "$chkdir"/sub2 "$chkdir"/dir-and-not-dir echo "one" >"$from1dir"/one cp -p "$from1dir"/one "$from2dir"/one cp -p "$from1dir"/one "$from3dir"/one @@ -34,13 +34,19 @@ echo "sub2" >"$from3dir"/sub1/dos echo "sub3" >"$from2dir"/sub1/tres echo "subby" >"$from3dir"/sub2/subby +echo "extra" >"$from1dir"/dir-and-not-dir/inside +echo "not-dir" >"$from3dir"/dir-and-not-dir cp -p "$from1dir"/one "$from1dir"/two "$from2dir"/three "$from3dir"/four "$from1dir"/five "$from3dir"/six "$chkdir" +cp -p "$from1dir"/dir-and-not-dir/inside "$chkdir"/dir-and-not-dir cp -p "$from2dir"/sub1/uno "$from3dir"/sub1/dos "$from2dir"/sub1/tres "$chkdir"/sub1 cp -p "$from3dir"/sub2/subby "$chkdir"/sub2 # Get rid of any directory-time differences -$RSYNC -av --existing --include='*/' --exclude='*' "$from1dir/" "$from2dir/" "$from3dir/" "$chkdir/" +$RSYNC -av --existing -f 'exclude,! */' "$from1dir/" "$from2dir/" +$RSYNC -av --existing -f 'exclude,! */' "$from2dir/" "$from3dir/" +$RSYNC -av --existing -f 'exclude,! */' "$from1dir/" "$chkdir/" +$RSYNC -av --existing -f 'exclude,! */' "$from3dir/" "$chkdir/" checkit "$RSYNC -aHvv \"$from1dir/\" \"$from2dir/\" \"$from3dir/\" \"$todir/\"" "$chkdir" "$todir" diff -urN --exclude=patches rsync-2.6.3/testsuite/rsync.fns rsync-2.6.4/testsuite/rsync.fns --- rsync-2.6.3/testsuite/rsync.fns 2004-09-16 10:16:36.000000000 -0700 +++ rsync-2.6.4/testsuite/rsync.fns 2005-02-20 23:26:59.000000000 -0800 @@ -50,7 +50,7 @@ rsync_ls_lR() { - find "$@" -print | sort | xargs "$TOOLDIR/tls" + find "$@" -print | sort | sed 's/ /\\ /g' | xargs "$TOOLDIR/tls" } rsync_getgroups() { @@ -166,19 +166,22 @@ fi echo "-------------" - echo "check how the files compare with diff:" - echo "" - for f in `cd "$2"; find . -type f -print ` - do - diff $diffopt "$2"/"$f" "$3"/"$f" || failed=YES - done - - echo "-------------" echo "check how the directory listings compare with diff:" echo "" ( cd "$2" && rsync_ls_lR . ) > "$tmpdir/ls-from" ( cd "$3" && rsync_ls_lR . ) > "$tmpdir/ls-to" diff $diffopt "$tmpdir/ls-from" "$tmpdir/ls-to" || failed=YES + + echo "-------------" + echo "check how the files compare with diff:" + echo "" + if [ "x$4" != x ]; then + echo " === Skipping (as directed) ===" + else + diff -r $diffopt "$2" "$3" || failed=YES + fi + + echo "-------------" if [ -z "$failed" ] ; then return 0 else diff -urN --exclude=patches rsync-2.6.3/testsuite/ssh-basic.test rsync-2.6.4/testsuite/ssh-basic.test --- rsync-2.6.3/testsuite/ssh-basic.test 2004-05-17 17:41:46.000000000 -0700 +++ rsync-2.6.4/testsuite/ssh-basic.test 2005-01-17 14:23:09.000000000 -0800 @@ -28,7 +28,7 @@ # nothing to do. hands_setup -runtest "ssh: basic test" 'checkit "$RSYNC -avH -e ssh --rsync-path=$RSYNC \"$fromdir/\" \"localhost:$todir\"" "$fromdir/" "$todir"' +runtest "ssh: basic test" 'checkit "$RSYNC -avH -e ssh --rsync-path=\"$RSYNC\" \"$fromdir/\" \"localhost:$todir\"" "$fromdir/" "$todir"' # Added by Steve Bonds Feb 2 2003 # I assumed that "F1" was intended to hold a single file for testing if @@ -40,4 +40,4 @@ mv "$todir/$F1" "$todir/ThisShouldGo" -runtest "ssh: renamed file" 'checkit "$RSYNC --delete -avH -e ssh --rsync-path=$RSYNC \"$fromdir/\" \"localhost:$todir\"" "$fromdir/" "$todir"' +runtest "ssh: renamed file" 'checkit "$RSYNC --delete -avH -e ssh --rsync-path=\"$RSYNC\" \"$fromdir/\" \"localhost:$todir\"" "$fromdir/" "$todir"' diff -urN --exclude=patches rsync-2.6.3/tls.c rsync-2.6.4/tls.c --- rsync-2.6.3/tls.c 2004-09-22 22:33:48.000000000 -0700 +++ rsync-2.6.4/tls.c 2005-01-19 11:30:29.000000000 -0800 @@ -66,7 +66,7 @@ char datebuf[50]; char linkbuf[4096]; - if (do_lstat(fname, &buf) == -1) + if (do_lstat(fname, &buf) < 0) failed("stat", fname); /* The size of anything but a regular file is probably not diff -urN --exclude=patches rsync-2.6.3/token.c rsync-2.6.4/token.c --- rsync-2.6.3/token.c 2004-07-14 19:20:08.000000000 -0700 +++ rsync-2.6.4/token.c 2005-02-14 00:28:00.000000000 -0800 @@ -65,11 +65,11 @@ } /* non-compressing recv token */ -static int simple_recv_token(int f,char **data) +static int32 simple_recv_token(int f, char **data) { - static int residue; + static int32 residue; static char *buf; - int n; + int32 n; if (!buf) { buf = new_array(char, CHUNK_SIZE); @@ -78,7 +78,7 @@ } if (residue == 0) { - int i = read_int(f); + int32 i = read_int(f); if (i <= 0) return i; residue = i; @@ -93,22 +93,21 @@ /* non-compressing send token */ -static void simple_send_token(int f,int token, - struct map_struct *buf,OFF_T offset,int n) +static void simple_send_token(int f, int32 token, struct map_struct *buf, + OFF_T offset, int32 n) { if (n > 0) { - int l = 0; - while (l < n) { - int n1 = MIN(CHUNK_SIZE,n-l); - write_int(f,n1); - write_buf(f,map_ptr(buf,offset+l,n1),n1); - l += n1; + int32 len = 0; + while (len < n) { + int32 n1 = MIN(CHUNK_SIZE, n-len); + write_int(f, n1); + write_buf(f, map_ptr(buf, offset+len, n1), n1); + len += n1; } } /* a -2 token means to send data only and no token */ - if (token != -2) { - write_int(f,-(token+1)); - } + if (token != -2) + write_int(f, -(token+1)); } @@ -129,9 +128,9 @@ #define AVAIL_OUT_SIZE(avail_in_size) ((avail_in_size)*1001/1000+16) /* For coding runs of tokens */ -static int last_token = -1; -static int run_start; -static int last_run_end; +static int32 last_token = -1; +static int32 run_start; +static int32 last_run_end; /* Deflation state */ static z_stream tx_strm; @@ -149,10 +148,10 @@ /* Send a deflated token */ static void -send_deflated_token(int f, int token, - struct map_struct *buf, OFF_T offset, int nb, int toklen) +send_deflated_token(int f, int32 token, struct map_struct *buf, OFF_T offset, + int32 nb, int32 toklen) { - int n, r; + int32 n, r; static int init_done, flush_pending; if (last_token == -1) { @@ -261,18 +260,24 @@ /* end of file - clean up */ write_byte(f, END_FLAG); } else if (token != -2) { - /* add the data in the current block to the compressor's - history and hash table */ - tx_strm.next_in = (Bytef *) map_ptr(buf, offset, toklen); - tx_strm.avail_in = toklen; - tx_strm.next_out = (Bytef *) obuf; - tx_strm.avail_out = AVAIL_OUT_SIZE(CHUNK_SIZE); - r = deflate(&tx_strm, Z_INSERT_ONLY); - if (r != Z_OK || tx_strm.avail_in != 0) { - rprintf(FERROR, "deflate on token returned %d (%d bytes left)\n", - r, tx_strm.avail_in); - exit_cleanup(RERR_STREAMIO); - } + /* Add the data in the current block to the compressor's + * history and hash table. */ + do { + /* Break up long sections in the same way that + * see_deflate_token() does. */ + int32 n1 = toklen > 0xffff ? 0xffff : toklen; + toklen -= n1; + tx_strm.next_in = (Bytef *)map_ptr(buf, offset, n1); + tx_strm.avail_in = n1; + tx_strm.next_out = (Bytef *) obuf; + tx_strm.avail_out = AVAIL_OUT_SIZE(CHUNK_SIZE); + r = deflate(&tx_strm, Z_INSERT_ONLY); + if (r != Z_OK || tx_strm.avail_in != 0) { + rprintf(FERROR, "deflate on token returned %d (%d bytes left)\n", + r, tx_strm.avail_in); + exit_cleanup(RERR_STREAMIO); + } + } while (toklen > 0); } } @@ -286,16 +291,16 @@ static char *dbuf; /* for decoding runs of tokens */ -static int rx_token; -static int rx_run; +static int32 rx_token; +static int32 rx_run; /* Receive a deflated token and inflate it */ -static int -recv_deflated_token(int f, char **data) +static int32 recv_deflated_token(int f, char **data) { - int n, r, flag; static int init_done; - static int saved_flag; + static int32 saved_flag; + int32 n, flag; + int r; for (;;) { switch (recv_state) { @@ -422,9 +427,10 @@ * put the data corresponding to a token that we've just returned * from recv_deflated_token into the decompressor's history buffer. */ -static void see_deflate_token(char *buf, int len) +static void see_deflate_token(char *buf, int32 len) { - int r, blklen; + int r; + int32 blklen; unsigned char hdr[5]; rx_strm.avail_in = 0; @@ -465,14 +471,13 @@ * If token == -1 then we have reached EOF * If n == 0 then don't send a buffer */ -void send_token(int f,int token,struct map_struct *buf,OFF_T offset, - int n,int toklen) +void send_token(int f, int32 token, struct map_struct *buf, OFF_T offset, + int32 n, int32 toklen) { - if (!do_compression) { - simple_send_token(f,token,buf,offset,n); - } else { + if (!do_compression) + simple_send_token(f, token, buf, offset, n); + else send_deflated_token(f, token, buf, offset, n, toklen); - } } @@ -482,7 +487,7 @@ * if the return value is -i then it represents token i-1 * if the return value is 0 then the end has been reached */ -int recv_token(int f,char **data) +int32 recv_token(int f, char **data) { int tok; @@ -497,7 +502,7 @@ /* * look at the data corresponding to a token, if necessary */ -void see_token(char *data, int toklen) +void see_token(char *data, int32 toklen) { if (do_compression) see_deflate_token(data, toklen); diff -urN --exclude=patches rsync-2.6.3/uidlist.c rsync-2.6.4/uidlist.c --- rsync-2.6.3/uidlist.c 2004-04-28 10:31:31.000000000 -0700 +++ rsync-2.6.4/uidlist.c 2005-02-13 16:53:44.000000000 -0800 @@ -26,7 +26,7 @@ #include "rsync.h" #ifdef HAVE_GETGROUPS -# if !defined(GETGROUPS_T) +# ifndef GETGROUPS_T # define GETGROUPS_T gid_t # endif #endif diff -urN --exclude=patches rsync-2.6.3/util.c rsync-2.6.4/util.c --- rsync-2.6.3/util.c 2004-09-07 14:26:26.000000000 -0700 +++ rsync-2.6.4/util.c 2005-03-30 11:34:20.000000000 -0800 @@ -32,7 +32,7 @@ extern int module_id; extern int modify_window; extern char *partial_dir; -extern struct exclude_list_struct server_exclude_list; +extern struct filter_list_struct server_filter_list; int sanitize_paths = 0; @@ -79,7 +79,7 @@ { int ret; -#if HAVE_SOCKETPAIR +#ifdef HAVE_SOCKETPAIR ret = socketpair(AF_UNIX, SOCK_STREAM, 0, fd); #else ret = pipe(fd); @@ -105,9 +105,9 @@ "ABCDEFGHIJKLMNOPQRSTUVWXYZ" "0123456789" ",.-_=+@/") != strlen(*cmd)) { - rprintf(FINFO, "\"%s\" ", *cmd); + rprintf(FINFO, "\"%s\" ", safe_fname(*cmd)); } else { - rprintf(FINFO, "%s ", *cmd); + rprintf(FINFO, "%s ", safe_fname(*cmd)); } } rprintf(FINFO, "\n"); @@ -130,22 +130,22 @@ int set_modtime(char *fname, time_t modtime) { - if (dry_run) - return 0; - if (verbose > 2) { rprintf(FINFO, "set modtime of %s to (%ld) %s", - fname, (long)modtime, + safe_fname(fname), (long)modtime, asctime(localtime(&modtime))); } + if (dry_run) + return 0; + { #ifdef HAVE_UTIMBUF struct utimbuf tbuf; tbuf.actime = time(NULL); tbuf.modtime = modtime; return utime(fname,&tbuf); -#elif defined(HAVE_UTIME) +#elif defined HAVE_UTIME time_t t[2]; t[0] = time(NULL); t[1] = modtime; @@ -245,7 +245,8 @@ /** Copy a file. * - * This is used in conjunction with the --temp-dir and --backup options */ + * This is used in conjunction with the --temp-dir, --backup, and + * --copy-dest options. */ int copy_file(char *source, char *dest, mode_t mode) { int ifd; @@ -350,7 +351,7 @@ if (verbose > 0) { rprintf(FINFO,"renaming %s to %s because of text busy\n", - fname, path); + safe_fname(fname), safe_fname(path)); } /* maybe we should return rename()'s exit status? Nah. */ @@ -479,14 +480,14 @@ return fcntl(fd,F_SETLK,&lock) == 0; } -static int exclude_server_path(char *arg) +static int filter_server_path(char *arg) { char *s; - if (server_exclude_list.head) { + if (server_filter_list.head) { for (s = arg; (s = strchr(s, '/')) != NULL; ) { *s = '\0'; - if (check_exclude(&server_exclude_list, arg, 1) < 0) { + if (check_filter(&server_filter_list, arg, 1) < 0) { /* We must leave arg truncated! */ return 1; } @@ -502,7 +503,7 @@ char **argv = *argv_ptr; int argc = *argc_ptr; int maxargs = *maxargs_ptr; -#if !(defined(HAVE_GLOB) && defined(HAVE_GLOB_H)) +#if !defined HAVE_GLOB || !defined HAVE_GLOB_H if (argc == maxargs) { maxargs += MAX_ARGS; if (!(argv = realloc_array(argv, char *, maxargs))) @@ -513,7 +514,7 @@ if (!*s) s = "."; s = argv[argc++] = strdup(s); - exclude_server_path(s); + filter_server_path(s); #else glob_t globbuf; int i; @@ -529,7 +530,7 @@ s = strdup(s); memset(&globbuf, 0, sizeof globbuf); - if (!exclude_server_path(s)) + if (!filter_server_path(s)) glob(s, 0, NULL, &globbuf); if (MAX((int)globbuf.gl_pathc, 1) > maxargs - argc) { maxargs += globbuf.gl_pathc + MAX_ARGS; @@ -876,28 +877,31 @@ return 1; } -/** - * Return the filename, turning any newlines into '?'s. This ensures that - * outputting it on a line of its own cannot generate an empty line. This - * function can handle only 2 names at a time! - **/ -const char *safe_fname(const char *fname) -{ - static char fbuf1[MAXPATHLEN], fbuf2[MAXPATHLEN]; - static char *fbuf = fbuf2; - char *nl = strchr(fname, '\n'); - - if (!nl) - return fname; - - fbuf = fbuf == fbuf1 ? fbuf2 : fbuf1; - strlcpy(fbuf, fname, MAXPATHLEN); - nl = fbuf + (nl - (char *)fname); - do { - *nl = '?'; - } while ((nl = strchr(nl+1, '\n')) != NULL); +/* Return the filename, turning any non-printable characters into '?'s. + * This ensures that outputting it on a line of its own cannot generate an + * empty line. This function can return only MAX_SAFE_NAMES values at a + * time! The returned value can be longer than MAXPATHLEN (because we + * may be trying to output an error about a too-long filename)! */ +char *safe_fname(const char *fname) +{ +#define MAX_SAFE_NAMES 4 + static char fbuf[MAX_SAFE_NAMES][MAXPATHLEN*2]; + static int ndx = 0; + int limit = sizeof fbuf / MAX_SAFE_NAMES - 1; + char *t; + + ndx = (ndx + 1) % MAX_SAFE_NAMES; + for (t = fbuf[ndx]; *fname; fname++) { + if (!isprint(*(uchar*)fname)) + *t++ = '?'; + else + *t++ = *fname; + if (--limit == 0) + break; + } + *t = '\0'; - return fbuf; + return fbuf[ndx]; } /** @@ -919,25 +923,21 @@ p1 = p2 = ""; else { p1 = curr_dir; - p2 = "/"; + for (p2 = p1; *p2 == '/'; p2++) {} + if (*p2) + p2 = "/"; } if (module_id >= 0) { m1 = " (in "; m2 = lp_name(module_id); m3 = ")"; - if (*p1) { + if (p1 == curr_dir) { if (!lp_use_chroot(module_id)) { char *p = lp_path(module_id); if (*p != '/' || p[1]) p1 += strlen(p); } - if (!*p1) - p2++; - else - p1++; } - else - fn++; } else m1 = m2 = m3 = ""; @@ -966,9 +966,17 @@ fn = fname; if ((int)pathjoin(t, sz, partial_dir, fn) >= sz) return NULL; - if (server_exclude_list.head - && check_exclude(&server_exclude_list, partial_fname, 0) < 0) - return NULL; + if (server_filter_list.head) { + static int len; + if (!len) + len = strlen(partial_dir); + t[len] = '\0'; + if (check_filter(&server_filter_list, partial_fname, 1) < 0) + return NULL; + t[len] = '/'; + if (check_filter(&server_filter_list, partial_fname, 0) < 0) + return NULL; + } return partial_fname; } @@ -990,11 +998,7 @@ dir = partial_fname; if (create) { STRUCT_STAT st; -#if SUPPORT_LINKS int statret = do_lstat(dir, &st); -#else - int statret = do_stat(dir, &st); -#endif if (statret == 0 && !S_ISDIR(st.st_mode)) { if (do_unlink(dir) < 0) return 0; @@ -1217,3 +1221,110 @@ return malloc(size * num); return realloc(ptr, size * num); } + +/* Take a filename and filename length and return the most significant + * filename suffix we can find. This ignores suffixes such as "~", + * ".bak", ".orig", ".~1~", etc. */ +const char *find_filename_suffix(const char *fn, int fn_len, int *len_ptr) +{ + const char *suf, *s; + BOOL had_tilde; + int s_len; + + /* One or more dots at the start aren't a suffix. */ + while (fn_len && *fn == '.') fn++, fn_len--; + + /* Ignore the ~ in a "foo~" filename. */ + if (fn_len > 1 && fn[fn_len-1] == '~') + fn_len--, had_tilde = True; + else + had_tilde = False; + + /* Assume we don't find an suffix. */ + suf = ""; + *len_ptr = 0; + + /* Find the last significant suffix. */ + for (s = fn + fn_len; fn_len > 1; ) { + while (*--s != '.' && s != fn) {} + if (s == fn) + break; + s_len = fn_len - (s - fn); + fn_len = s - fn; + if (s_len == 4) { + if (strcmp(s+1, "bak") == 0 + || strcmp(s+1, "old") == 0) + continue; + } else if (s_len == 5) { + if (strcmp(s+1, "orig") == 0) + continue; + } else if (s_len > 2 && had_tilde + && s[1] == '~' && isdigit(*(uchar*)(s+2))) + continue; + *len_ptr = s_len; + suf = s; + if (s_len == 1) + break; + /* Determine if the suffix is all digits. */ + for (s++, s_len--; s_len > 0; s++, s_len--) { + if (!isdigit(*(uchar*)s)) + return suf; + } + /* An all-digit suffix may not be that signficant. */ + s = suf; + } + + return suf; +} + +/* This is an implementation of the Levenshtein distance algorithm. It + * was implemented to avoid needing a two-dimensional matrix (to save + * memory). It was also tweaked to try to factor in the ASCII distance + * between changed characters as a minor distance quantity. The normal + * Levenshtein units of distance (each signifying a single change between + * the two strings) are defined as a "UNIT". */ + +#define UNIT (1 << 16) + +uint32 fuzzy_distance(const char *s1, int len1, const char *s2, int len2) +{ + uint32 a[MAXPATHLEN], diag, above, left, diag_inc, above_inc, left_inc; + int32 cost; + int i1, i2; + + if (!len1 || !len2) { + if (!len1) { + s1 = s2; + len1 = len2; + } + for (i1 = 0, cost = 0; i1 < len1; i1++) + cost += s1[i1]; + return (int32)len1 * UNIT + cost; + } + + for (i2 = 0; i2 < len2; i2++) + a[i2] = (i2+1) * UNIT; + + for (i1 = 0; i1 < len1; i1++) { + diag = i1 * UNIT; + above = (i1+1) * UNIT; + for (i2 = 0; i2 < len2; i2++) { + left = a[i2]; + if ((cost = *((uchar*)s1+i1) - *((uchar*)s2+i2)) != 0) { + if (cost < 0) + cost = UNIT - cost; + else + cost = UNIT + cost; + } + diag_inc = diag + cost; + left_inc = left + UNIT + *((uchar*)s1+i1); + above_inc = above + UNIT + *((uchar*)s2+i2); + a[i2] = above = left < above + ? (left_inc < diag_inc ? left_inc : diag_inc) + : (above_inc < diag_inc ? above_inc : diag_inc); + diag = left; + } + } + + return a[len2-1]; +} diff -urN --exclude=patches rsync-2.6.3/zlib/deflate.c rsync-2.6.4/zlib/deflate.c --- rsync-2.6.3/zlib/deflate.c 2002-03-11 17:14:58.000000000 -0800 +++ rsync-2.6.4/zlib/deflate.c 2005-01-02 01:03:44.000000000 -0800 @@ -47,7 +47,7 @@ * */ -/* @(#) $Id: deflate.c,v 1.4 2002/03/12 01:14:58 mbp Exp $ */ +/* @(#) $Id: deflate.c,v 1.6 2005/01/02 09:03:44 wayned Exp $ */ #include "deflate.h" @@ -1110,6 +1110,11 @@ s->strstart += s->lookahead; s->lookahead = 0; + if (flush == Z_INSERT_ONLY) { + s->block_start = s->strstart; + continue; + } + /* Emit a stored block if pending_buf will be full: */ max_start = s->block_start + max_block_size; if (s->strstart == 0 || (ulg)s->strstart >= max_start) { @@ -1125,6 +1130,11 @@ FLUSH_BLOCK(s, 0); } } + if (flush == Z_INSERT_ONLY) { + s->block_start = s->strstart; + return need_more; + } + FLUSH_BLOCK(s, flush == Z_FINISH); return flush == Z_FINISH ? finish_done : block_done; }