Compare commits

..

384 Commits

Author SHA1 Message Date
Wayne Davison
6f0c56304f Preparing for release of 3.2.0pre2 2020-06-15 11:53:19 -07:00
Wayne Davison
2452ad3663 Fixed setting of rsync_lastver var. 2020-06-15 11:52:54 -07:00
Wayne Davison
1fa38546a0 Document how to setup rsyncd behind a TLS proxy. 2020-06-15 11:36:24 -07:00
Wayne Davison
249e28c75a Rename "haproxy header" to "proxy protocol". 2020-06-15 11:33:23 -07:00
Wayne Davison
6273153c5f Add preliminary gnutls support. 2020-06-15 11:19:36 -07:00
Wayne Davison
628dcceb8d Choose openssl before stunnel. 2020-06-15 10:41:08 -07:00
Wayne Davison
00ec415a69 Tweak the stunnel4 Verify config; tweak the rsync-ssl docs/usage. 2020-06-15 09:36:13 -07:00
Wayne Davison
ec8035cef9 A minor NEWS tweak. 2020-06-15 09:21:26 -07:00
Wayne Davison
775f64f4b8 Add a warning header to the generated help-*.h files. 2020-06-14 18:49:38 -07:00
Wayne Davison
660274bfb7 A few more md -> html improvements 2020-06-14 18:28:30 -07:00
Wayne Davison
59cf9ff797 More NEWS improvements. 2020-06-14 18:00:18 -07:00
Wayne Davison
ff272503b0 Output who_am_i() info in all rsyserr() messages. 2020-06-14 15:54:42 -07:00
Wayne Davison
43a939e3f2 Improve some md files. 2020-06-14 15:29:45 -07:00
Wayne Davison
b65b6db304 Add handling of non-breaking space & double-dash. 2020-06-14 15:29:45 -07:00
Wayne Davison
7b1f8f57c3 Update rrsync & its opt-culling script. 2020-06-13 22:11:37 -07:00
Wayne Davison
c32012d199 Need to indent a code block in the README. 2020-06-13 21:31:26 -07:00
Wayne Davison
9ba6ce1b67 More release improvements. 2020-06-13 21:21:26 -07:00
Wayne Davison
ca9e247762 Mention renamed .md files. 2020-06-13 20:42:33 -07:00
Wayne Davison
f27a630e46 Don't use c++ comments. 2020-06-13 20:12:15 -07:00
Wayne Davison
243a9d9be0 A few more release script fixes. 2020-06-13 20:11:06 -07:00
Wayne Davison
c528f8d5c8 Preparing for release of 3.2.0pre1 2020-06-13 19:16:26 -07:00
Wayne Davison
1d1c0f14e1 Make -4 & -6 also able to affect an ssh remote shell. 2020-06-13 19:15:02 -07:00
Wayne Davison
e63ff70eae Some indentation fixes. 2020-06-13 19:15:02 -07:00
Wayne Davison
8a70f1420b Some fixes for the release script & other helpers. 2020-06-13 19:15:00 -07:00
Wayne Davison
cdf58a7aba Change alt_dest_name() to alt_dest_opt(). 2020-06-13 12:04:13 -07:00
Wayne Davison
1d6c9676f9 Change 3 alt-dest vars to just one + some defines. 2020-06-13 11:47:08 -07:00
Wayne Davison
3d29fa99ec Tweak a couple var names. 2020-06-13 11:47:04 -07:00
Wayne Davison
d167935874 Change a function name. 2020-06-13 03:03:33 -07:00
Wayne Davison
d326961290 Fix overzealous setting of mtime & tweak time comparisons
- Stop setting the mtime on a file we didn't transfer (or didn't verify
  the checksum) when the time diff is within the modify window.
- Stop computing a time difference (-1|0|1) when all we care about is
  time equality.
2020-06-13 02:41:30 -07:00
Wayne Davison
7dec4029ee Convert a couple files to UTF-8; more Copyright years. 2020-06-13 02:41:04 -07:00
Wayne Davison
ab0189c813 Make use of poptDupArgv(). 2020-06-12 23:28:27 -07:00
Wayne Davison
bb484a799e The unalias argv array needs room for a trailing NULL. 2020-06-12 23:19:14 -07:00
Wayne Davison
ad9f1571ce Add hashtable to delete_in_dir() to fix -x deletions 2020-06-12 17:42:56 -07:00
Wayne Davison
f800557824 Tweak the hashtable routines to be a little clearer and easier. 2020-06-12 17:42:41 -07:00
Wayne Davison
13f81f4aa7 Tweak a usage message. 2020-06-12 10:20:33 -07:00
Wayne Davison
d3ae752c53 Fix running prepare-source from a separate build dir. 2020-06-12 09:29:42 -07:00
Wayne Davison
e3437244b5 Improve how the help lines are harvested from the md file. 2020-06-12 08:50:51 -07:00
Wayne Davison
1efeb59166 Enable SIMD by default (if g++ is around). 2020-06-12 08:29:36 -07:00
Wayne Davison
d4fc18f375 Use the refused-option code to disable options that aren't compiled into the source. 2020-06-11 22:53:29 -07:00
Wayne Davison
58680edb12 Improve checkcsum/compress info that may differ between packaged versions. 2020-06-11 22:03:10 -07:00
Wayne Davison
34141954c7 Add packaging notes to NEWS. 2020-06-11 20:35:18 -07:00
Wayne Davison
cba00be622 Translate man page's option list into .h files for options.h to use. 2020-06-11 20:34:23 -07:00
Wayne Davison
de78dd685b Simplify the install of rsync-ssl by unifying 2 scripts. 2020-06-11 20:26:56 -07:00
Wayne Davison
88abb50229 Promote newer compressors to the start of the list. 2020-06-11 20:26:56 -07:00
Wayne Davison
6d6b8595df Remove generated doc files via make clean. 2020-06-11 20:26:45 -07:00
Wayne Davison
66bd4774a8 Allow maintainer to build with /usr/local prefix but document /usr. 2020-06-11 19:15:08 -07:00
Wayne Davison
c117fa4bf9 Create a get_device_size() helper function. 2020-06-11 16:09:36 -07:00
Wayne Davison
b040825b86 Improve the haproxy header docs. 2020-06-11 15:23:35 -07:00
Wayne Davison
3c793ef153 Use /dev/shm instead of requiring /dev/shm/tmp. 2020-06-11 14:33:25 -07:00
Wayne Davison
cff0764b7f Add haproxy header parameter to rsync daemon 2020-06-11 14:22:25 -07:00
Wayne Davison
a3377921eb Add early exec daemon parameter.
Inspired by Ciprian Dorin Craciun's `bootstrap exec` patch.
2020-06-10 21:38:37 -07:00
Wayne Davison
a61ffbafe5 Make sure the tmpdir2 dir is writable. 2020-06-10 13:59:02 -07:00
Wayne Davison
190b474610 Mention how to run a single test. 2020-06-10 13:59:02 -07:00
Wayne Davison
85e90b0f80 Update copyright year in runtests.sh too. 2020-06-10 13:59:02 -07:00
Wayne Davison
516ca6a442 Add support for /run/shm/tmp dir so the CI action doesn't skip a test. 2020-06-10 13:17:41 -07:00
Wayne Davison
fe993ca94d Have the CI actions run make check29 & check30. 2020-06-10 12:02:40 -07:00
Wayne Davison
f8683063fb Fix a couple batchfile issues. 2020-06-10 11:23:14 -07:00
Wayne Davison
7c83eb6e63 Improve gensend rule & list of PHONY targets. 2020-06-10 09:44:23 -07:00
Wayne Davison
58e8ecf48f Improvements for release process; a gensend hook. 2020-06-10 09:31:01 -07:00
Wayne Davison
c5e44330a5 Fix double-gen of manpages. 2020-06-10 00:39:30 -07:00
Wayne Davison
ae82762c31 Fix the output with -D; a few minor tweaks. 2020-06-10 00:26:29 -07:00
Wayne Davison
2ac7401b44 Mention the github rsync home. 2020-06-09 18:08:29 -07:00
Wayne Davison
44af79223e The samba rsync server now requires ssl. 2020-06-09 17:28:07 -07:00
Wayne Davison
03fc62ad2f More man processing improvements
- Support the commonmark library in addition to cmarkgfm.
- Remove github-flavor from the markup.
- A few more html style improvements.
2020-06-09 17:02:41 -07:00
Wayne Davison
68c865c9e6 A few more man page script improvements. 2020-06-09 09:17:37 -07:00
Wayne Davison
6dc94e39a7 Output the files at the end; fix a missing double-quote. 2020-06-09 00:58:07 -07:00
Wayne Davison
8146b04ffb Fix the html title. 2020-06-08 22:52:58 -07:00
Wayne Davison
5b19cf7875 A couple man page tweaks. 2020-06-08 22:48:14 -07:00
Wayne Davison
53fae55652 Change man page src format from yodl to markdown.
This removes the yodl dependency, which is sometimes hard to track down.
Instead, this uses a python3 script that leverages the cmarkgfm library
to turn the source file into html.  Then, the script parses the html in
order to turn the tag stream into a nroff stream using a simple state
machine. While it's doing that it also implements one added format rule
that turns an ordinal list that starts at 0 into a description list
(since markdown doesn't have an easy description list idiom).
2020-06-08 21:03:42 -07:00
Wayne Davison
bd66a92e7c Tweak the new heading 2020-06-07 19:46:22 -07:00
Sebastian Andrzej Siewior
165ef61de3 Add OpenSSL license exception also to COPYING
Add the OpenSSL license exception also to the COPYING file which
contains the license related information.

Signed-off-by: Sebastian Andrzej Siewior <sebastian@breakpoint.cc>
2020-06-07 19:46:22 -07:00
Wayne Davison
7dbbde8c5e Use ZSTD_CLEVEL_DEFAULT define. 2020-06-07 19:30:24 -07:00
Wayne Davison
888f4f9503 Put the rsync-ssl-rsh helper script into a lib dir. 2020-06-07 19:25:18 -07:00
Wayne Davison
2c6f0581ac A couple minor fixes. 2020-06-04 22:54:38 -07:00
Wayne Davison
916faecb83 Only sender can output non-final stats on error
The receiving side's stats are split between 2 processes until the very end.
2020-06-04 21:40:43 -07:00
Wayne Davison
5d7b71b7a7 Make use of O_NOFOLLOW if it is defined. 2020-06-04 19:47:59 -07:00
Wayne Davison
0dde65a26b Mention more NEWS items. 2020-06-04 19:08:04 -07:00
Wayne Davison
b177311aee Use a lock to not fail on a left-over pid file. 2020-06-04 19:08:03 -07:00
Wayne Davison
778f0dff9b Use more switch statements. 2020-06-04 16:17:12 -07:00
Wayne Davison
342579aa6f Make -V the short opt for --version. 2020-06-04 15:52:38 -07:00
Wayne Davison
01b9bbb0f9 Avoid a deadlock due to huge amounts of verbose messages.
Allow the receiver to increase their iobuf.msg xbuf if it fills up. This
ensures that the receiver will never block trying to output a message,
and thus it will always drain the data from the sender and keep the
whole thing from clogging up.
2020-06-04 14:20:51 -07:00
Wayne Davison
852a0b29c3 Tweak --copy-as docs a bit more. 2020-06-04 13:07:50 -07:00
Wayne Davison
55290c8584 Add hostname "lh" as a --no-cd localhost. 2020-06-04 12:58:02 -07:00
Wayne Davison
e633091d23 Fix change_dir() leaving appended slash in curr_dir on failure. 2020-06-04 12:35:24 -07:00
Wayne Davison
4c9fdb9f74 Handle --skip-compress right for new compressors
Some compressors can't completely turn off, so minimize the level
when a file is being "skipped".
2020-06-02 18:06:09 -07:00
Wayne Davison
e0d30a22d7 Mention that rsync --version outputs checksum & compress lists. 2020-06-02 17:21:51 -07:00
Wayne Davison
42ec4e3090 Update ccpp.yml
Switch to ubuntu-20.04 and add a couple dev libs.
2020-06-02 17:20:22 -07:00
Wayne Davison
3735002751 Some improvements to the release mechanism
- Some manpage changes to make them more consistent and to add a section
  that the release script expects in rsync-ssl.
- Fixed some issues in release-rsync pertaining to various file changes,
  such as the .md file changes.
- Change the gpg handling to stop prompting for a passphrase since gpg
  now makes use of gpg-agent (and the old gpg script is apparently not
  passing through fd 2 that git needs to get status).
2020-06-02 16:54:07 -07:00
Wayne Davison
d47a80c05e Move the CSUM defines. 2020-06-01 18:49:15 -07:00
Wayne Davison
9dd9952138 A few style tweaks. 2020-06-01 18:38:06 -07:00
Jorrit Jongma
71c4ae2336 Move OpenSSL-related MD4/5 defines and imports to lib/mdigest.h
Works just as well, prevents having to repeat them across files
2020-06-01 17:57:38 -07:00
Wayne Davison
c0268d9217 Some improvements for --msgs2stderr and --daemon.
- Set am_daemon to -1 (from 1) when the daemon is run via rsh.
- Only disable --msgs2stderr for a normal (socket) daemon.
- Forward a -q to the server if --msgs2stderr was also specified.
- Added --no-msgs2stderr option to allow it to be overridden.
2020-05-31 16:02:46 -07:00
Wayne Davison
da448cdc99 Mention the latest NEWS items. 2020-05-30 05:54:09 -07:00
Wayne Davison
d619a87aa5 Avoid noop_io_until_death() if --msgs2stderr was specified. 2020-05-30 05:53:59 -07:00
benrubson
a931301bef Search for double-fuzzy files only when needed 2020-05-29 23:13:15 -07:00
Wayne Davison
265b0bc9bb Silence a strncpy() warning. 2020-05-29 17:35:56 -07:00
Wayne Davison
13f249a826 Silence some g++ warnings. 2020-05-29 17:24:15 -07:00
Wayne Davison
c66e08acb3 Give configure's snprintf() test a guaranteed short string at the start. 2020-05-29 17:24:05 -07:00
Wayne Davison
f5446552f3 Silence gcc7.1 warnings about snprintf(). 2020-05-29 14:18:08 -07:00
Wayne Davison
364d302bca Fix regex issue due to python 3.8 bug. 2020-05-28 20:48:24 -07:00
Wayne Davison
60e71c1b8b A few minor xxhash changes. 2020-05-28 20:40:23 -07:00
Wayne Davison
342921eb97 Merge pull request #5 from benrubson/daemonstats
Have daemon log data sent/received even when exiting with an error.
2020-05-28 13:42:47 -07:00
Wayne Davison
df0ed76a76 Add stub for canonical_checksum(). 2020-05-28 12:46:46 -07:00
Wayne Davison
d7521f5428 The xxh* checksums don't need to be reversed on output. 2020-05-28 12:33:36 -07:00
Wayne Davison
c7f10de442 Switch to using LZ4_compress_default(). 2020-05-28 11:40:52 -07:00
Wayne Davison
f60bd811e9 Use MSG_FLUSH in a couple more spots. 2020-05-28 00:41:39 -07:00
Wayne Davison
cd0637a953 Merge pull request #2 from benrubson/flush
Help final error messages get to the sender. Is particularly helpful when talking with an older rsync client. Adds a new flush type of MSG_FLUSH.
2020-05-27 23:35:25 -07:00
Wayne Davison
8809f65b13 A couple minor tweaks. 2020-05-26 22:36:56 -07:00
benrubson
c906619620 Log data sent/received even if error 2020-05-26 19:53:25 +02:00
Wayne Davison
5710d2fe2e Simplify the capabilities array. 2020-05-26 08:05:24 -07:00
benrubson
32fe5fbc11 Correctly send last error to sender 2020-05-26 16:24:30 +02:00
Wayne Davison
bcb0a24a8f Convert NEWS & OLDNEWS into .md files. 2020-05-26 02:24:33 -07:00
Wayne Davison
96ed96dabd Fix the parsing of the --version capabilities. 2020-05-25 23:42:51 -07:00
Wayne Davison
8ad2ca9ae2 Install yodl for the CI builds. 2020-05-25 23:42:51 -07:00
Wayne Davison
23a37ecac4 Get indent right. 2020-05-25 23:33:11 -07:00
Wayne Davison
47bae3abf6 Improve output of capabilities in --version list.
It now wraps better as the "no " prefixes change, and it makes it easier
to maintain patches that add items into the capabilities list.
2020-05-25 23:24:46 -07:00
Wayne Davison
dff9dd56a0 Remove xxhash from capabilities list.
It's now listed in the "Checksum list:" output.
2020-05-25 21:31:40 -07:00
Wayne Davison
7182508a75 Fix a couple deb names. 2020-05-25 21:21:58 -07:00
Wayne Davison
cb0fe9e195 Improve CI setup. 2020-05-25 21:17:51 -07:00
Wayne Davison
87f2984df0 Improve how negotiated info affects batch files. 2020-05-25 19:19:59 -07:00
Wayne Davison
24ce3e9d54 Tweak the --zz option to --zc (aka --compress-choice). 2020-05-25 16:57:47 -07:00
Wayne Davison
98cddfaf7a Rename a couple files to .md 2020-05-25 15:05:06 -07:00
Wayne Davison
d1fcb8ce9d Add some extra indent. 2020-05-25 14:59:51 -07:00
Wayne Davison
b4ace35304 Create ccpp.yml 2020-05-25 14:43:25 -07:00
Wayne Davison
888ce058d8 Two sparse fixes from Yuxuan Shui.
- Make "len" parameter of do_punch_hole an OFF_T.
- Clear sparse_past_write in sparse_end(), otherwise when write_sparse()
  is called for the next file, do_punch_hole() will be called with a pos
  that's not actually the current position in file, causing it to fail.
2020-05-25 14:01:52 -07:00
Wayne Davison
c394e86184 Include lz4 compression support.
Based on a patch that was emailed to me without a valid return address.
2020-05-25 13:45:56 -07:00
Wayne Davison
4aaadc2f29 Include zstd compression support.
Based on a patch by Sebastian A. Siewior. Fixes bug #14338.
2020-05-25 13:44:48 -07:00
Wayne Davison
abef92c037 Fix handling of a compressor that has no off_level. 2020-05-25 13:02:56 -07:00
Wayne Davison
87019d7721 Output the default checksum & compress lists in the --version output. 2020-05-25 13:02:12 -07:00
Wayne Davison
fc265c5a92 A couple minor configure.ac tweaks. 2020-05-25 11:50:44 -07:00
Wayne Davison
d999efe6e5 Make compression-level handling generic. 2020-05-25 11:18:51 -07:00
Wayne Davison
97e8c55ee8 Some minor tweaks & tidying up. 2020-05-24 22:50:51 -07:00
Wayne Davison
739fa96737 Change odd-ball map_ptr() to use remainder like the others. 2020-05-24 20:38:48 -07:00
Jorrit Jongma
d474f2986e Improve performance of file_checksum()
Previously files were hashed in blocks of CSUM_CHUNK (64) bytes. This
causes significant overhead. The CSUM_CHUNK define cannot be changed as
md5.c depends on it, but there is no obvious reason to use it in
file_checksum(). By using CHUNK_SIZE (32 kB) instead, in some test
cases throughput more than doubles.
2020-05-24 20:33:33 -07:00
Wayne Davison
a863c62cd1 More NEWS updates. 2020-05-24 20:19:15 -07:00
Wayne Davison
5ac353d845 Prefer zlibx compression consistently instead of having 2 possible default preference orders. 2020-05-24 19:52:08 -07:00
Wayne Davison
faecd066a6 Don't auto-foward debug options to the server side anymore. 2020-05-24 19:37:15 -07:00
Wayne Davison
6efc43cc0a Fix -z choice with older rsyncs. 2020-05-24 19:16:05 -07:00
Wayne Davison
4496e0e8e7 A few more compression tweaks. 2020-05-24 18:43:03 -07:00
Wayne Davison
64d5ea39c0 More compress changes
- Add the zlibx (external-code compatible) compression name.
- Re-enable zlib support with the external library so it can be
  tried as a fallback if zlibx isn't available.
- Add --compress-choice=STR (aka -zz=STR) option.
- Make --cc=STR an alias for --checksum-choice=STR.
- Hook up the new compression negotiation logic.
2020-05-24 17:24:42 -07:00
Wayne Davison
4af8403aa2 Fix negotiation of none & improve NSTR debug msgs. 2020-05-24 13:49:06 -07:00
Wayne Davison
2f84a6bd73 Add support for negotiated checksum names. 2020-05-24 13:22:19 -07:00
Wayne Davison
eda15d52a8 Make xxh64 the "main_name" for the current xxhash. 2020-05-24 02:10:05 -07:00
Wayne Davison
741d5f10c6 Fix some warnings. 2020-05-24 02:04:14 -07:00
Wayne Davison
4f92fd8ddd Some more checksum improvements
- Add/improve --debug=CSUM2 messages.
- Add an "xxh64" alias for "xxhash" name because we should be
  getting a few more xxhash variations in the future.
- Tweak the matching code to handle entries that have multiple
  names.
- Tweak some of the vars/defines.
2020-05-24 01:00:53 -07:00
Wayne Davison
7f2359a5cc Improve some early debug-message newlines.
Avoid a newline issue during the output of --DEBUG=CSUM info from
both the server and the client -- we need to output the full message
with its newline as much as possible.
2020-05-23 21:51:28 -07:00
Wayne Davison
6e942e5898 Avoid re-evaluating the args of SIVAL* w/CAREFUL_ALIGNMENT. 2020-05-23 21:43:53 -07:00
Wayne Davison
1c9bb168bb Unify the checksum context memory, since we only use one at a time. 2020-05-23 18:52:03 -07:00
Wayne Davison
799de21af6 Fixed the use of openssl MD4 for transfer checksums. 2020-05-23 16:22:36 -07:00
Wayne Davison
1cb1edeb68 Optional openssl support for MD4 pre-transfer checksums (but, sadly, not transfer checksums). 2020-05-23 12:30:58 -07:00
Wayne Davison
15c1162b24 Add optional use of the openssl crypto lib for MD5. 2020-05-23 10:06:59 -07:00
Wayne Davison
a7175ee029 Mention a few more news items. 2020-05-22 23:26:25 -07:00
Wayne Davison
68516f91be Add "input" handling for cmd_txt_*() pkglib.py. 2020-05-22 22:49:02 -07:00
Jorrit Jongma
531ffa8104 Optimized assembler version of md5_process() for x86-64
Originally created by Marc Bevand and placed in the public domain.
Enable/disabled via the same --enable-simd configure switch as
the rolling checksum optimizations.
2020-05-22 22:37:21 -07:00
Wayne Davison
d7212df0f1 A little more safety in negotiate_checksum(). 2020-05-22 19:29:05 -07:00
Wayne Davison
a28bc3ebf6 Promoting xxhash support. 2020-05-22 17:59:12 -07:00
Wayne Davison
55bb4dab7a Some checksum improvements
- Improve csum negotation logic.
- Define the csum names in a single structure.
- Add --debug=CSUM.
2020-05-22 17:59:12 -07:00
Jorrit Jongma
5fa4209ca0 AVX2 optimized version of get_checksum1() for x86-64
Additionally restructures build switches and defines from SSE2 to SIMD,
to allow potential reuse should patches become available with SIMD
instructions for other processor architectures.

(Some minor tweaks of Jorrit's patch to avoid requiring GNU make and to
avoid C++ comments in .c files.)
2020-05-22 11:31:31 -07:00
Wayne Davison
4f6c8c6652 Checksum negotiation & more bits for compat_flags
- Add checksum negotiation to the protocol so that we can easily add new
  checksum algorithms and each will be used when both sides support it.
- Increase the size of the compat_flags value in the protocol from a
  byte to an int.
2020-05-22 09:52:14 -07:00
Wayne Davison
a7303a3d3d Fix a bug in the writing of the batch.sh file
Fix the code that writes the options and the default destination path
into the batch.sh file to be able to handle options being specified
after source/dest args.
2020-05-22 08:27:07 -07:00
Jorrit Jongma
70c6b408dc SSE2/SSSE3 optimized version of get_checksum1() for x86-64
Requires compilation using GCC C++ front end, build scripts have been
modified accordingly. C++ is only used when the optimization is enabled
(g++ as compiler, x86-64 build target, --enable-sse2 is passed to
configure).

(Wayne made a few tweaks, including making it disabled by default.)
2020-05-21 14:41:55 -07:00
Wayne Davison
be7af36c51 Tweak the accept/refuse strings a bit. 2020-05-18 00:06:06 -07:00
Wayne Davison
3b36bde953 Add back a lost "*" and document the refusing of log-file* opts. 2020-05-17 23:28:35 -07:00
Wayne Davison
c3986d4c5a More manpage improvements for "refuse options". 2020-05-17 22:19:25 -07:00
Wayne Davison
b3a1a0ca9d Add the ability to negate matches for the daemon's "refuse options". 2020-05-17 21:29:11 -07:00
Wayne Davison
e448d31d63 Need to flush early errors before we exit. 2020-05-17 21:20:15 -07:00
Wayne Davison
37de48979e Some pkglib improvements. 2020-05-17 20:32:43 -07:00
Wayne Davison
08f955e17b A couple more manpage fixes. 2020-05-13 00:20:03 -07:00
Wayne Davison
3435ae9bd0 A bit more manpage tweaking. 2020-05-13 00:11:57 -07:00
Wayne Davison
7a9295778c Change r'\1%s\2' to r'\g<1>%s\2'. 2020-05-06 17:23:34 -07:00
Wayne Davison
f7746d0000 A couple extra function checks for future features. 2020-04-29 22:14:49 -07:00
Wayne Davison
96a6ea0f26 Convert another packaging script to python3. 2020-04-29 21:25:17 -07:00
Wayne Davison
6242786158 A few superficial tweaks. 2020-04-29 19:41:56 -07:00
Wayne Davison
b430ceec7a Use a varint to send the file-list flags
If both sides support the "V" compatibility flag, we send the file-list
flags as a varint instead of a 1-or-2 byte value.  This upgrades the
number of reserved flag bits from 1 to 17 with very few extra bytes in
typical file-list data.
2020-04-29 18:22:52 -07:00
Wayne Davison
3a7bf54ad5 A resumed partial-dir file is transferred in-place.
Fixed bug #13071.
2020-04-29 17:02:14 -07:00
Wayne Davison
c1cb307b4b Fix a couple issues with the atime file-list value. 2020-04-26 18:42:37 -07:00
Wayne Davison
af6118d98b Allow a missing parent dir when --delete-missing-args was specified. 2020-04-26 18:10:40 -07:00
Wayne Davison
ea3337a210 Add extensions to the default no-compress list.
Fixes bug #13749.
2020-04-26 17:07:58 -07:00
Wayne Davison
035a13f7e4 Add a few new opts to rrsync. 2020-04-26 14:54:45 -07:00
Wayne Davison
f14adfd75e Some var cleanup; move test-util vars into t_stub.c. 2020-04-26 14:54:43 -07:00
Wayne Davison
d218be3482 Update a few more copyright years. 2020-04-25 23:34:16 -07:00
Wayne Davison
f4c077e85e Change pending version to 3.2.0 (currently 3.2.0dev). 2020-04-25 23:30:42 -07:00
Wayne Davison
1c7785ab1e Change do_setattrlist_times() to use an stp arg. 2020-04-25 21:39:11 -07:00
Wayne Davison
87257f869c Change --set-notime to --open-noatime. 2020-04-23 14:32:26 -07:00
Wayne Davison
b936741032 Added --atimes and --set-noatime options. 2020-04-23 13:24:15 -07:00
Wayne Davison
2b2a3c87b6 Mention more changes in the NEWS. 2020-04-23 13:18:07 -07:00
Wayne Davison
6e962ac51e Eliminate .in for rsync-ssl. 2020-04-22 14:53:06 -07:00
Wayne Davison
991ab811cb Turn nightly-rsync into a python script. 2020-04-22 12:43:25 -07:00
Wayne Davison
3249824264 Some more rsync-ssl improvements:
- Make the rsync-ssl default behavior more user friendly.
- Install rsync-ssl & rsync-ssl-rsh in the regular install rules.
- Add a manpage for rsync-ssl (which is also installed).
- Get rid of the rsync-ssl-client package in our spec file.
2020-04-22 12:40:14 -07:00
Wayne Davison
1c465dc33a Change the name of the rsh-ssl-rsync script. 2020-04-22 10:52:01 -07:00
Wayne Davison
2a87d78f69 Change the rsync-ssl helper script
The new rsh-ssl-rsync helper script (replacing stunnel-rsync) supports
openssl in addition to stunnel.  The RSYNC_SSL_TYPE environment variable
can be set to specify which type of connection to use, and the first arg
to rsync-ssl can be --type=stunnel or --type=openssl to override the env
var or the default of "stunnel".  The helper script now looks for
stunnel4 or stunnel on the PATH at runtime instead of having configure
look for it at compile time.
2020-04-19 14:00:33 -07:00
Wayne Davison
3ba4db7030 Two more spelling fixes and some year updates. 2020-04-16 09:31:02 -07:00
Wayne Davison
d29702134a Spelling fixes from a Fossies run done by Jens. 2020-04-15 17:42:23 -07:00
Wayne Davison
1c82a1e1e5 A few file-data improvements. 2020-04-12 15:51:20 -07:00
Wayne Davison
2d0c7adba9 Change some packaging tools into python3 and make a few improvements. 2020-04-12 00:13:35 -07:00
Wayne Davison
0b4b31a960 Add a (pending) release line for 3.1.4. 2020-04-11 17:59:22 -07:00
Wayne Davison
8a21e5a8c6 Use the --quiet option. 2020-04-09 18:42:31 -07:00
Wayne Davison
fa9c8d04d4 Put the year-tweak script into packaging dir. 2020-04-09 15:17:09 -07:00
Wayne Davison
c5fabfb068 Set Copyright years and make them easier to update
I replaced git-set-file-times with an improved version that I wrote
recently (in python3). A new script uses it to figure out the
last-modified year for each *.[ch] file and updates its copyright.
It also puts the latest year into the latest-year.h file for the
output of --version.
2020-04-09 15:11:37 -07:00
Wayne Davison
e2aee6c4af Switch RSYNC_PORT to -1 in check_for_hostspec(). 2020-04-07 19:21:37 -07:00
Wayne Davison
2598ca668b Fix the default skip-compress list.
The default value of the skip-compress list actually comes from the
daemon's default lp_dont_compress() value, but a while back the vars
stopped getting default values in a non-daemon run. I added a call to
reset_daemon_vars() so that the "Vars" values get set from "Defaults".
2020-04-07 18:15:09 -07:00
Wayne Davison
cd7ad50bc8 Tweak the grep to look for sys/sysmacros.h. 2020-04-07 15:32:06 -07:00
Wayne Davison
5e4a1441cb Avoid the include warnings for major(). 2020-04-07 15:16:19 -07:00
Wayne Davison
9dea2ae87c Make use of the new RSYNC_PORT env var. 2020-04-07 13:36:01 -07:00
Ethan Sommer via rsync
795268bb7c Replace mkproto.pl with mkproto.awk
This replaces the build dependency on perl with one on awk which is
already used throughout the build system and is much more ubiquitous
than perl.
2020-04-07 13:08:05 -07:00
Wayne Davison
70cbc66b7f Set RSYNC_PORT in the env for a daemon-over-rsh connection.
Fixes bug #14163.
2020-04-05 19:34:27 -07:00
Wayne Davison
b63276e70f A quick fix for some perl patch-helper scripts. 2020-04-05 17:18:32 -07:00
Wayne Davison
b0c03e2be9 Another tweak for a change in git status. 2020-04-05 17:12:29 -07:00
Wayne Davison
8475e0e492 Tweak some indentation. 2020-04-05 17:03:15 -07:00
Wayne Davison
7f06cc7ed0 Don't throw an error if a potential fuzzy dir isn't a dir
Add a flag for calling get_dirlist() and for send_directory() that
indicates that the dirname is allowed to not be a directory.  Based
on a patch by Ben Rubson.  Fixes bug #13445.
2020-04-05 16:41:15 -07:00
Wayne Davison
10d40508e6 Use "exit 1" in atomic-rsync for error exit.
Fixes bug #15469.
2020-04-05 16:23:07 -07:00
Wayne Davison
daf8f7a669 Some configure improvements for strict C99 compilers (based on a patch by Florian Weimer). 2020-04-05 16:19:54 -07:00
Wayne Davison
15fa9ab06d Add progress output via SIGINFO and SIGVTALRM
On BSD-ish systems you can type Ctrl+T to see the current file and
the progress output (in --info=progress2 format).  On hosts w/o
SIGINFO, use something like "killall -VTALRM rsync" or a more
targetted "kill -VTALRM PID ..." call (as needed).
2020-04-05 15:07:31 -07:00
Wayne Davison
7e70e4842b No need to forward --write-devices to a remote sender. 2020-04-05 12:01:48 -07:00
Wayne Davison
9e9d33a2db Added the --write-devices option.
This is a fleshed out version of the old one in the patches repo with
documentation & proper handling of the implied --inplace option for a
daemon's option-rufusing considerations. I ommitted the -w short option
as I would hate for someone to turn this on accidentally.
2020-04-05 11:56:28 -07:00
Wayne Davison
b32aa4797d Make exit_cleanup() use _exit() if called from a signal handler.
Fixes bug #13982.
2020-04-05 10:26:40 -07:00
Wayne Davison
826ddc5403 Enhance the validation of --block-size for older protocols.
Fixes bug #13974.
2020-04-05 10:05:25 -07:00
Wayne Davison
3bd4e1e8cd Make the --copy-links caveat a little clearer. 2020-04-05 09:43:59 -07:00
Wayne Davison
51e23e0ab7 Use nanosleep if it is available.
Fixes bug #14328.
2020-04-05 09:22:00 -07:00
Wayne Davison
08650cb14c Add a --copy-as=USER[:GROUP] option
This can be used by a root-run rsync to try to make reading or writing
files safer in a situation where you can't run the whole rsync command
as a non-root user.
2020-03-29 13:18:20 -07:00
Wayne Davison
24c28cd715 Match the latest git "clean" text. 2019-03-19 09:35:59 -07:00
Wayne Davison
c0c6a97c35 Try to fix the iconv crash in bug 11338.
Applying Michal Ruprich's suggested patch for the rwrite() function that
should hopefully help with a bug that I couldn't reproduce.
2019-03-16 11:51:49 -07:00
Wayne Davison
d47d379216 Fix bug in try_dests_reg that Florian Zumbiehl pointed out.
If the alternate-destination code was scanning multiple alt dirs and it
found the right size/mtime/checksum info but not the right xattrs, it
would keep scanning the other dirs for a better xattr match, but it
would omit the unchanged-file check that needs to happen first.
2019-03-16 11:12:53 -07:00
Wayne Davison
eb1b138ec2 Clarify the cut-off point for --copy-safe-links. 2019-03-16 10:55:50 -07:00
Wayne Davison
13f596433b Some doc tweaks suggested by Clément Pit-Claudel. 2019-03-16 10:10:14 -07:00
Wayne Davison
3fe4469bfa Fix zlib CVE-2016-9843. 2019-03-16 09:56:11 -07:00
Wayne Davison
8eb50bce43 Fix zlib CVE-2016-9842. 2019-03-16 09:56:11 -07:00
Wayne Davison
fc10fafa25 Fix zlib CVE-2016-9841. 2019-03-16 09:56:11 -07:00
Wayne Davison
efcbec3df5 Fix zlib CVE-2016-9840. 2019-03-16 09:56:11 -07:00
Wayne Davison
3e2e4b5a33 Tweak the copyright year. 2019-03-16 09:15:49 -07:00
Wayne Davison
79332c0d66 Fix --remove-source-files sanity check w/--copy-links the right way.
Fixes bug #10494.
2019-03-16 09:09:09 -07:00
Wayne Davison
bdfc296faf Handle a run from down inside the checkout tree. 2019-03-15 12:20:55 -07:00
Wayne Davison
2ad1c4e800 Improve write-only --sender check & handle 2 new options. 2019-01-15 11:18:36 -08:00
Wayne Davison
0da7ba57b5 Update option culling to handle latest changes. 2019-01-15 11:16:50 -08:00
Wayne Davison
b3d12c5a3d Use a separate pass-by-value pointer for clarity. 2019-01-15 10:46:29 -08:00
Wayne Davison
bc7402aa3a Avoid warning about leaked mem (didn't affect rsync's pool use). 2019-01-15 10:46:29 -08:00
Wayne Davison
f233dffbd6 Avoid leaving a file open on error return. 2019-01-15 10:38:00 -08:00
Wayne Davison
c2da3809f7 Fix --prealloc to keep file-size 0 when possible. 2019-01-15 08:59:35 -08:00
Wayne Davison
48346c878f Reject --log-file when read-only. 2019-01-09 13:35:21 -08:00
Wayne Davison
a0274c08b5 Improve check for ".." and guard against dash args. 2019-01-09 13:35:21 -08:00
Wayne Davison
f627e27749 Save each expanded daemon-config string on first use to
avoid a new alloc on every use (one that was not freed).
2019-01-09 13:35:21 -08:00
Wayne Davison
0b6cae6792 No need to strdup each new section since we stopped using free(). 2019-01-08 20:30:58 -08:00
Wayne Davison
e5610f1877 Avoid a yodl macro warning. 2019-01-08 16:39:48 -08:00
Wayne Davison
c376170644 Make sure that some memory zeroing always happens. 2019-01-08 14:46:41 -08:00
Wayne Davison
48163179eb Avoid a yodl macro warning. 2019-01-08 13:38:19 -08:00
Wayne Davison
b4c1b27e03 Fix 2 spelling errors pointed out by bug 13734. 2019-01-08 13:34:32 -08:00
Wayne Davison
c90b87e021 Avoid a failed test if dirs report 1 hlink (e.g. WSL weirdness). 2019-01-04 21:43:50 -08:00
Wayne Davison
ad17b21889 Silence fall-through warnings. 2019-01-04 15:06:30 -08:00
Wayne Davison
a366868535 Avoid a potential out-of-bounds read in daemon mode if argc is 0. 2018-12-15 16:59:18 -08:00
Wayne Davison
f55d35c5a0 Try to be clearer that --append-verify isn't a general-purpose-copy option. 2018-11-20 14:17:32 -08:00
Wayne Davison
6af8e11450 Don't force cygwin to solaris ACLs anymore. 2018-11-20 14:11:42 -08:00
Wayne Davison
1a288c06d9 Document how a leading comma changes the gid parsing. 2018-11-20 13:44:09 -08:00
Wayne Davison
4aeb093206 Fix itemizing of wrong dir name on some --iconv transfers.
Fixes bug #13492.
2018-11-20 13:21:32 -08:00
Wayne Davison
1eb7a7061a Need to mark xattr rules in get_rule_prefix().
This fixes the bug of xattr filters getting sent as a normal filter rule
(since the 'x' was dropped in the prefix).
2018-06-14 15:22:53 -07:00
Wayne Davison
eec6ab7615 Avoid a compiler error/warning about shifting a negative value.
Fixes bug #13268.
2018-03-25 19:11:41 -07:00
Wayne Davison
5df9847f06 Allow some pre-/post-xfer exec shell restrictions.
Support both RSYNC_SHELL & RSYNC_NO_XFER_EXEC environment variables.
2018-03-25 11:02:50 -07:00
Wayne Davison
fb7a162f53 Prepare the repository for more development. 2018-03-25 10:04:29 -07:00
Wayne Davison
d73762eea3 Preparing for release of 3.1.3 2018-01-28 15:24:27 -08:00
Wayne Davison
d58405a353 Mention nanoseconds change. 2018-01-15 11:25:04 -08:00
Wayne Davison
0f8e9e2d86 Don't force nanoseconds if a file wasn't transferred or checksummed. 2018-01-15 10:58:31 -08:00
Wayne Davison
c4a3f55be3 Preparing for release of 3.1.3pre1 2018-01-14 21:34:42 -08:00
Wayne Davison
473108ae6e Tweak copyright date. 2018-01-14 19:55:07 -08:00
Wayne Davison
e401959b89 Mention more changes. 2018-01-14 19:51:25 -08:00
Jeriko One
7706303828 Ignore --protect-args when already sent by client
In parse_arguments when --protect-args is encountered the function exits
early. The caller is expected to check protect_args, and recall
parse_arguments setting protect_args to 2. This patch prevents the
client from resetting protect_args during the second pass of
parse_arguments. This prevents parse_arguments returning early the
second time before it's able to sanitize the arguments it received.
2018-01-09 17:51:30 -08:00
Wayne Davison
f5e8a17e09 Fix issue with earlier path-check (fixes "make check")
and make a BOOL more explicit.
2017-12-03 16:27:11 -08:00
Jeriko One
5509597dec Check daemon filter against fnamecmp in recv_files(). 2017-12-03 16:13:06 -08:00
Jeriko One
70aeb5fddd Sanitize xname in read_ndx_and_attrs. 2017-12-03 16:13:05 -08:00
Jeriko One
3e06d40029 Check fname in recv_files sooner. 2017-12-03 16:12:28 -08:00
Wayne Davison
416e719bea More archaic-checksum improvements. This makes the len vars clearer
and ensures that only the flist code gets the 2-byte digest len.
2017-11-07 14:01:13 -08:00
Wayne Davison
9f5dc9309d Use the right sum len. 2017-11-07 13:32:10 -08:00
Wayne Davison
b984e9dbd4 Replace startdit|enddit with description for newer yodl.
Fixes bug 13115.
2017-11-05 12:29:14 -08:00
Wayne Davison
c60d9fcab1 Add missing closing paren that Paul Slootman pointed out. 2017-11-05 11:56:52 -08:00
Wayne Davison
47a63d90e7 Enforce trailing \0 when receiving xattr name values.
Fixes bug 13112.
2017-11-05 11:46:09 -08:00
Wayne Davison
bc112b0e7f Use full MD4 len for archaic protocol auth. 2017-10-30 13:34:18 -07:00
Wayne Davison
8a82feeb7c Don't overflow an allocated dest buf when input path is empty.
Fixes bug 13105.
2017-10-29 15:53:28 -07:00
Wayne Davison
0350f95e7b Add an extra argc validation in do_server_sender().
Fixes bug 13104.
2017-10-29 15:52:56 -07:00
Wayne Davison
9a480deec4 Only allow a modern checksum method for passwords. 2017-10-24 20:44:37 -07:00
Wayne Davison
c252546cee Don't forget to tweak sum_update(). 2017-10-24 20:44:20 -07:00
Wayne Davison
7b8a4ecd6f Handle archaic checksums properly. 2017-10-24 15:42:43 -07:00
Wayne Davison
17b849c97a Set our_uid & our_gid values when changed by the daemon.
Fixes bug 10719.
2017-10-09 17:13:00 -07:00
Wayne Davison
276a9836bd Mention --link-dest limit. 2017-10-08 09:30:18 -07:00
Wayne Davison
c140b2e749 Mention refusing delete for write-only. 2017-10-08 09:18:10 -07:00
Wayne Davison
b547302943 Mention -O is forced, not just implied. 2017-10-08 08:52:33 -07:00
Wayne Davison
136c6c7734 Fix double-fuzzy + link-dest issue.
Fixes bug 11866.
2017-10-08 08:39:37 -07:00
Wayne Davison
3fb1634f21 Fix possible buffer overrun for some large name_len values.
Fixes bug 12568.
2017-10-07 17:54:05 -07:00
Wayne Davison
881addc9e1 Add "daemon chroot|uid|gid" parameters.
This allows the daemon to run chrooted as any uid+gid you like
(prior to the transfer possibly changing the chroot and/or the
uid+gid further). Based on the patch in #12817.
2017-09-04 14:20:16 -07:00
Wayne Davison
b7799aaefe Add nanosecond mtime support for Mac OS X.
Slightly tweaked the patch contributed by Heikki Lindholm.
2017-08-31 08:22:14 -07:00
Wayne Davison
ce854cf021 Add "syslog tag" to rsync daemon config. 2017-04-29 13:49:14 -07:00
Wayne Davison
9e7b8ab7cf Don't allow --daemon or --server alias via popt.
Fixes bug 12576.
2017-02-20 11:09:16 -08:00
Wayne Davison
87bc224011 Add a way to specify xattr name filtering. 2017-01-22 16:01:45 -08:00
Wayne Davison
a4e8b552d6 Join some lines. 2017-01-22 15:55:54 -08:00
Wayne Davison
62652202c4 Get rid of some superfluous double-quotes in error messages. 2017-01-22 15:42:36 -08:00
Wayne Davison
001adf5096 Fix extern of preallocated_len w/o SUPPORT_PREALLOCATION. 2016-10-31 09:06:50 -07:00
Wayne Davison
ff66fd4bb6 More fixes for --progress quirks.
This patch avoids inconsistent evaluation of options in the
show_filelist_p() function by turning it into a var.  We
also avoid setting "output_needs_newline" if --quiet was
specified.
2016-10-29 15:26:10 -07:00
Wayne Davison
e02b89d0d3 We need a LF after filelist-progress with a CR.
Fixes bug 12367.
2016-10-29 14:33:44 -07:00
Wayne Davison
d1a1fec134 Use S_BLKSIZE when multiplying st_blocks. 2016-10-15 11:33:07 -07:00
Wayne Davison
f3873b3d88 Support --sparse combined with --preallocate or --inplace.
The new code tries to punch holes in the destination file using newer
Linux fallocate features. It also supports a --whole-file + --sparse +
--inplace copy on any filesystem by truncating the destination file.
2016-10-10 11:53:03 -07:00
Stefan Metzmacher
6e3b2102bc xattrs: maintain a hashtable in order to speed up find_matching_xattr()
As a testcase I've used one directory on gpfs with 1000000 files,
each with an xattr called 'name$i' having a value of 'value$i'.
So we also have 1000000 unique xattrs. The source and dest directories
are already in sync before. So the rsync command is basically a noop,
just verifying that everything is already in sync.

The results before this patchset are:

  [gpfs]# time rsync -a -P -X -q source-xattr/ dest-with-xattr/

  real    8m46.191s
  user    6m29.016s
  sys     0m24.883s

  [gpfs]# time rsync -a -P -q source-xattr/ dest-without-xattr/

  real    1m58.462s
  user    0m0.957s
  sys     0m11.801s

With the patchset I got:

  [gpfs]# time /gpfs/rsync.install/bin/rsync -a -P -X -q source-xattr/ dest-with-xattr/

  real    2m4.150s
  user    0m1.917s
  sys     0m17.077s

  [gpfs]# time /gpfs/rsync.install/bin/rsync -a -P -q source-xattr/ dest-without-xattr/
  real    1m59.534s
  user    0m0.924s
  sys     0m11.599s

It means the time in userspace dropped from 6m29.016s down to 0m1.917s!
Without -X we get ~ 0m0.9s with or without the patch.

Part of a patchset for bug 5324.
2016-08-14 14:37:49 -07:00
Stefan Metzmacher
cc29b94d0f hashtable: add hashlittle() from lookup3.c, by Bob Jenkins
Part of a patchset for bug 5324.
2016-08-14 14:20:19 -07:00
Stefan Metzmacher
6eb71beaff xattrs: introduce a rsync_xa_list struct as layer between two nested item_lists
We have the global 'item_list rsync_xal_l', this maintains an array
of rsync_xa_list structure, one per file.

Each rsync_xa_list structure maintains an array of rsync_xa structure,
while each represent a single xattr with name and value.

Part of a patchset for bug 5324.
2016-08-14 14:20:16 -07:00
Stefan Metzmacher
39d7e3ec25 xattrs: let rsync_xal_store() return ndx.
Part of a patchset for bug 5324.
2016-08-14 13:54:34 -07:00
Stefan Metzmacher
ac97bc14f6 xattrs: add const to empty_xattr
Part of a patchset for bug 5324.
2016-08-14 13:54:34 -07:00
Greg Whiteley
31e93c3228 Makefile: rounding.h generation requires proto.h via rsync.h
Bug 12029 - Makefile missing dep gives parallel race for rounding.h

Signed-off-by: Greg Whiteley <greg.whiteley@gmail.com>
2016-07-20 08:34:26 -07:00
Wayne Davison
a720d81d0a Fix "could not find xattr #1" errors.
The abbreviated-xattr code can get requests that are not in the same
order as the xattr list, so we need to support wrap-around scanning
of the available xattrs. Fixes bug 6590.
2016-06-26 12:06:09 -07:00
Wayne Davison
359758d611 Fix path check when prior_dir_file is NULL. 2016-06-04 11:53:33 -07:00
Wayne Davison
1f83b51d71 Improve the top-level section on include/exclude traversal.
This is my edit of some suggestions by Karl O. Pinc.
2016-05-07 15:55:26 -07:00
Wayne Davison
a5a7d3a297 Add --checksum-choice option to choose the checksum algorithms. 2016-05-01 17:06:54 -07:00
Wayne Davison
4fc78878e0 Tweak indentation only. 2016-05-01 16:29:34 -07:00
Wayne Davison
b973bffa94 If a backup fails (e.g. full disk) rsync should fail.
Fixes bug 11668.
2016-04-17 16:31:57 -07:00
Wayne Davison
d1c80404fe Output "UNKNOWN" if starttime or endtime is -1.
Fixes bug 11382.
2016-04-17 16:11:04 -07:00
Wayne Davison
9a12959ab6 Support only splitting users/groups on commas.
Fixes bug 11817.
2016-04-17 15:56:11 -07:00
Wayne Davison
070c810e2d Tweak non-fatal output when man pages cannot be created. 2016-04-17 11:43:46 -07:00
Wayne Davison
71ec4609eb Fix use of obsolete compile macro.
Fixes bug 11813.
2016-04-17 11:20:38 -07:00
Wayne Davison
0f7db203fb Only output about new backup dirs when requested.
Fixes bug 11812.
2016-04-17 11:06:58 -07:00
Wayne Davison
4e25abc9a9 Fix/improve the sort functions.
Fixes bug 11704.
2016-01-31 14:40:51 -08:00
Wayne Davison
839dbff2aa Add support for comparing nanoseconds on the receiver.
This patch adds the ability to specify --modify-window=-1 (aka -@-1) to
ask rsync to compare files with the full nanosecond timestamps.  The
default is still -@0 for the moment, which ignores nanoseconds in time
comparisons.  Changing the default to -1 would cause a copy from ext4 to
ext3 to constantly compare as different, or a copy there and back again
to do a full copy as it zeroed all the nanosecond times.  Such a change
might be too much of a functional difference for things like backup
solutions to handle without a warning period.  The current plan is to
support nanosecond comparisons for those that want them, and possibly
change the default window value from 0 to -1 at some point in the
future.
2016-01-24 11:16:10 -08:00
Wayne Davison
f6f5ea4173 Prepare the repository for more development. 2016-01-24 11:12:32 -08:00
Wayne Davison
9a37d9cb1e Fix a tweak that should have been untweaked. 2015-12-24 13:09:47 -08:00
Wayne Davison
16b49716d5 Preparing for release of 3.1.2 2015-12-21 12:00:49 -08:00
Wayne Davison
58faa1e8b9 Improve the "use chroot" & "numeric ids" info a bit more. 2015-12-21 11:56:33 -08:00
Wayne Davison
9250e9ac23 Improve the comment a bit more. 2015-12-21 10:54:02 -08:00
Wayne Davison
3623d94fe7 Fix rule for out-of-tree builds.
Fixes bug 11635.
2015-12-18 16:09:58 -08:00
Wayne Davison
cbc42b9c16 Don't allow an empty flag name to --info & --debug. 2015-12-18 14:46:28 -08:00
Wayne Davison
6ff5824c25 Document expand_item_list's args & make sure incr==0 works OK. 2015-12-18 14:41:22 -08:00
Wayne Davison
32de6b7cb4 Fix return of stat info from try_dests_reg().
The try_dests_reg() function could sometimes tweak the stat struct's
info when it should have been left unchanged.  This fixes bug 11545
(where an ACL check of a file that was mistakenly thought to be a
directory failed).
2015-12-05 11:10:24 -08:00
Wayne Davison
bb853b3205 Add -wo option for write-only rrsync mode. 2015-09-13 16:23:54 -07:00
Wayne Davison
cce44865c1 Fixed logging of %b & %c when using --log-file.
The %b and %c escapes were outputting cumulative values when logged via
--log-file only (the bug didn't affect daemon transfer logging or the
output of the client's --out-format info).  Also unified the %b & %c
switch case to make it easier to maintain.  Fixes bug 11496.
2015-09-07 10:07:17 -07:00
Wayne Davison
1983198097 Add support for netbsd in xattrs case.
Closes bug-suggestion 11484.
2015-09-02 12:20:52 -07:00
Wayne Davison
2a7355fb56 Change daemon's gid list to use an "item_list". 2015-08-24 11:54:00 -07:00
Wayne Davison
3da1dc4d18 Add configure option to set max daemon gid list.
Fixes bug 11456.
2015-08-24 10:09:57 -07:00
Wayne Davison
abfb41e63e Avoid creating even the top-level backup dir until needed.
Fixes bug 11423.
2015-08-23 21:58:18 -07:00
Wayne Davison
9d1cd2437c Improve make_path() error return for non-dir element. 2015-08-23 21:55:16 -07:00
Wayne Davison
f8d2ecd223 Preparing for release of 3.1.2pre1 2015-08-08 12:47:35 -07:00
Wayne Davison
453914e35b Update the copyright year. 2015-08-08 12:47:03 -07:00
Wayne Davison
3f26e38f86 Mention latest fixes. 2015-08-08 12:42:13 -07:00
Wayne Davison
81d1ca0683 Don't create so many empty backup dirs.
Fixes bug 10724.
2015-08-08 12:19:42 -07:00
Wayne Davison
289ccbd02f Allow samba.org hostname to be overridden. 2015-08-02 11:15:17 -07:00
Wayne Davison
85d3877be9 Improve mergedir filter handling internals.
Fixes bug 10995.
2015-07-13 10:56:13 -07:00
Wayne Davison
e203245d76 Make sure chk subdir can't diverge in time from its src subdir. 2015-07-12 14:00:45 -07:00
Wayne Davison
dfbcc4f7ec Avoid --remove-sent-file issue for non-regular files. 2015-07-12 13:26:01 -07:00
Wayne Davison
0bcb8b639a Mention local-only effect of --msgs2stderr. 2015-07-12 13:10:05 -07:00
Wayne Davison
77f750f167 Mention how we handle a module named "global". 2015-07-12 10:38:32 -07:00
Wayne Davison
23afe20780 Brant Gurganus's autoconf updates.
This improves some obsolete autoconf macros and increases the minimum
autoconf version from 2.60 to 2.69.  Fixes bug 11369.
2015-07-07 10:37:12 -07:00
Wayne Davison
e12a6c087c Add parent-dir validation for --no-inc-recurse too. 2015-07-04 16:25:23 -07:00
Wayne Davison
6feb7d37df Change "fail" to "test_fail".
Fixes bug 11322.
2015-06-10 15:20:01 -07:00
Wayne Davison
81ff413bb0 Make the checksum_seed a bit harder to predict. 2015-05-11 14:32:45 -07:00
Wayne Davison
eac858085e Add compat flag to allow proper seed checksum order.
Fixes the equivalent of librsync's CVE-2014-8242 issue.
2015-05-11 12:36:20 -07:00
Wayne Davison
2ac35b4507 Pass -I option to aclocal. 2015-05-01 15:17:41 -07:00
Tiziano Müller
3bc319766d Use AS_IF instead of plain if/then/fi 2015-05-01 14:26:21 -07:00
Tiziano Müller
a689fb1f5f Ignore .deps directories. 2015-05-01 14:26:21 -07:00
Tiziano Müller
b560a96b2c Check for perl and assign it to a var since it is needed for generating the protocol header. 2015-05-01 14:26:21 -07:00
Tiziano Müller
51e3c3da85 Remove dead targets from build system 2015-05-01 14:26:21 -07:00
Wayne Davison
461086bbe7 Handle configure's new version style. 2015-05-01 14:26:21 -07:00
Tiziano Müller
00694610a6 Specify package name and version in call to AC_INIT 2015-05-01 14:26:21 -07:00
Tiziano Müller
8e3a6db842 Properly quote arguments for AC_LIBOBJ. 2015-05-01 14:26:21 -07:00
Wayne Davison
8354cad53e Must define LIBOBJDIR in the Makefile. 2015-05-01 14:26:05 -07:00
Tiziano Müller
317a0e8ca5 Use AC_CONFIG_LIBOBJ_DIR and AC_REPLACE_FUNCS to adhere to autoconf standards 2015-04-26 17:54:08 -07:00
Tiziano Müller
066ad8c719 Modularize m4 macros
Split acinclude.m4 into one file per function in m4/
2015-04-26 17:54:06 -07:00
Tiziano Müller
ec4f644d2f Properly quote m4 macro 2015-04-26 16:50:41 -07:00
Wayne Davison
4bf342c60f Update generated-files logic. 2015-04-26 16:50:41 -07:00
Tiziano Müller
a2f733c664 Rename aclocal.m4 to acinclude.m4 and add make target
It is common practice to split up m4 files for easier maintenance and
generate the required aclocal.m4 using `aclocal` instead.
2015-04-26 16:50:16 -07:00
Stefan Behrens
3ea74eb388 rsync: fix of-by-one in check of snprintf() result.
Fixes bug 11229.
2015-04-22 10:31:04 -07:00
Wayne Davison
962f8b9004 Complain if an inc-recursive path is not right for its dir.
This ensures that a malicious sender can't use a just-sent
symlink as a trasnfer path.
2014-12-31 13:48:42 -08:00
Wayne Davison
ae189e18de Mention that --append can be dangerous. 2014-12-31 13:10:46 -08:00
Wayne Davison
5b34561cf7 Call set_modtime even if only NSEC is different. 2014-12-31 13:10:37 -08:00
Wayne Davison
5546dab329 Use usleep() for msleep() if it is available. 2014-11-27 12:02:56 -08:00
Wayne Davison
6128f56694 Add a missing closing paren. 2014-10-10 14:15:11 -07:00
Wayne Davison
743f5a30d5 Prepare the repository for more development. 2014-09-06 11:00:52 -07:00
Wayne Davison
a955e93316 Mention DRY RUN in --debug=exit output. 2014-09-06 10:47:13 -07:00
Wayne Davison
aca7dd3bff Adding the long options that BackupPC likes to use. 2014-09-04 13:44:50 -07:00
Wayne Davison
bc55aa04df Set GIT_MERGE_AUTOEDIT=no in the environment. 2014-07-31 15:59:32 -07:00
Wayne Davison
f438d5abe0 Match latest git's repo branch message. 2014-07-31 14:52:30 -07:00
Wayne Davison
6fe798392b Match latest git's repo status messages. 2014-07-31 14:47:09 -07:00
Wayne Davison
6ceb9ea012 Remove superfluous ${INSTALL_STRIP} uses. 2014-07-31 14:39:09 -07:00
Wayne Davison
6900d35cce Fix a typo. 2014-07-31 14:38:16 -07:00
Wayne Davison
7cb0de6326 Preparing for release of 3.1.1 2014-06-22 09:50:03 -07:00
Wayne Davison
61e74afc42 Add a clarification about shell wildcard expansion. 2014-06-22 09:41:17 -07:00
Wayne Davison
0466e46b9f Make sure the link() destination file doesn't exist. 2014-06-22 09:04:24 -07:00
Wayne Davison
aa4c6db043 Make sure cmp_time() doesn't mess up due to a time_t overflow.
Fixes bug 10643.
2014-06-15 17:53:34 -07:00
Wayne Davison
edb0d9c792 Updated NEWS & tweaked a comment. 2014-06-14 09:55:37 -07:00
Wayne Davison
6ffd8f2169 Put zlib and popt -I options early in the CFLAGS. 2014-06-14 09:48:56 -07:00
Wayne Davison
ba43e88527 Fix hard-link bugs when receiver isn't capable.
If the receiving side cannot hard-link symlinks and/or special files
(including devices) then we now properly handle incoming hard-linked
items (creating separate identical items).
2014-06-13 16:05:08 -07:00
Wayne Davison
ff08acd4f2 Added a flag to disable xattr hlink optimization.
I added a compatibility flag for protocol 31 that will let both sides
know if they should be using the xattr optimization that attempted to
avoid sending xattr info for hardlinked files.  Since this optimization
was causing some issues, this compatibility flag will ensure that both
sides know if they should be trying to use the optimization or not.
2014-06-08 10:42:14 -07:00
Wayne Davison
03bb593f81 I missed this tweak in the undo of a prior xattr optimization. 2014-06-08 10:21:27 -07:00
156 changed files with 18477 additions and 11977 deletions

31
.github/workflows/ccpp.yml vendored Normal file
View File

@@ -0,0 +1,31 @@
name: C CI
on:
push:
branches: [ master ]
pull_request:
branches: [ master ]
jobs:
build:
runs-on: ubuntu-20.04
steps:
- uses: actions/checkout@v2
- name: prepare-packages
run: sudo apt-get install fakeroot acl libacl1-dev attr libattr1-dev liblz4-dev libzstd-dev libxxhash-dev python3-cmarkgfm
- name: prepare-source
run: ./prepare-source
- name: configure
run: ./configure --with-included-popt --with-protected-args --with-included-zlib --enable-simd
- name: make
run: make
- name: version-summary
run: ./rsync --version
- name: make check
run: make check
- name: make check30
run: make check30
- name: make check29
run: make check29

12
.gitignore vendored
View File

@@ -12,10 +12,14 @@ config.h.in
config.h.in.old
config.log
config.status
aclocal.m4
/proto.h
/proto.h-tstamp
/rsync.1
/rsyncd.conf.5
/rsync*.1
/rsync*.5
/rsync*.html
/help-rsync*.h
/.md2man-works
/autom4te*.cache
/confdefs.h
/conftest*
@@ -23,8 +27,6 @@ config.status
/getgroups
/gmon.out
/rsync
/rsync-ssl
/stunnel-rsync
/stunnel-rsyncd.conf
/shconfig
/testdir
@@ -44,3 +46,5 @@ config.status
/testsuite/devices-fake.test
/testsuite/xattrs-hlink.test
/patches
/SaVeDiR
.deps

View File

@@ -672,3 +672,12 @@ may consider it more useful to permit linking proprietary applications with
the library. If this is what you want to do, use the GNU Lesser General
Public License instead of this License. But first, please read
<http://www.gnu.org/philosophy/why-not-lgpl.html>.
REGARDING OPENSSL AND XXHASH
In addition, as a special exception, the copyright holders give
permission to dynamically link rsync with the OpenSSL and xxhash
libraries when those libraries are being distributed in compliance
with their license terms, and to distribute a dynamically linked
combination of rsync and these libraries. This is also considered
to be covered under the GPL's System Libraries exception.

View File

@@ -1,13 +1,13 @@
To build and install rsync:
$ ./configure
$ make
# make install
$ ./configure
$ make
# make install
You may set the installation directory and other parameters by options
to ./configure. To see them, use:
$ ./configure --help
$ ./configure --help
Configure tries to figure out if the local system uses group "nobody" or
"nogroup" by looking in the /etc/group file. (This is only used for the

View File

@@ -4,16 +4,19 @@
prefix=@prefix@
datarootdir=@datarootdir@
exec_prefix=@exec_prefix@
stunnel4=@STUNNEL4@
bindir=@bindir@
libdir=@libdir@/rsync
mandir=@mandir@
LIBS=@LIBS@
CC=@CC@
CFLAGS=@CFLAGS@
CPPFLAGS=@CPPFLAGS@
CXX=@CXX@
CXXFLAGS=@CXXFLAGS@
EXEEXT=@EXEEXT@
LDFLAGS=@LDFLAGS@
LIBOBJDIR=lib/
INSTALLCMD=@INSTALL@
INSTALLMAN=@INSTALL@
@@ -28,7 +31,10 @@ VERSION=@RSYNC_VERSION@
.SUFFIXES:
.SUFFIXES: .c .o
GENFILES=configure.sh config.h.in proto.h proto.h-tstamp rsync.1 rsyncd.conf.5
SIMD_x86_64=simd-checksum-x86_64.o lib/md5-asm-x86_64.o
GENFILES=configure.sh aclocal.m4 config.h.in proto.h proto.h-tstamp rsync.1 rsync.1.html \
rsync-ssl.1 rsync-ssl.1.html rsyncd.conf.5 rsyncd.conf.5.html
HEADERS=byteorder.h config.h errcode.h proto.h rsync.h ifuncs.h itypes.h inums.h \
lib/pool_alloc.h
LIBOBJ=lib/wildmatch.o lib/compat.o lib/snprintf.o lib/mdfour.o lib/md5.o \
@@ -43,9 +49,9 @@ OBJS3=progress.o pipe.o
DAEMON_OBJ = params.o loadparm.o clientserver.o access.o connection.o authenticate.o
popt_OBJS=popt/findme.o popt/popt.o popt/poptconfig.o \
popt/popthelp.o popt/poptparse.o
OBJS=$(OBJS1) $(OBJS2) $(OBJS3) $(DAEMON_OBJ) $(LIBOBJ) @BUILD_ZLIB@ @BUILD_POPT@
OBJS=$(OBJS1) $(OBJS2) $(OBJS3) @SIMD@ $(DAEMON_OBJ) $(LIBOBJ) @BUILD_ZLIB@ @BUILD_POPT@
TLS_OBJ = tls.o syscall.o lib/compat.o lib/snprintf.o lib/permstring.o lib/sysxattrs.o @BUILD_POPT@
TLS_OBJ = tls.o syscall.o t_stub.o lib/compat.o lib/snprintf.o lib/permstring.o lib/sysxattrs.o @BUILD_POPT@
# Programs we must have to run the test cases
CHECK_PROGS = rsync$(EXEEXT) tls$(EXEEXT) getgroups$(EXEEXT) getfsdev$(EXEEXT) \
@@ -62,24 +68,23 @@ CHECK_OBJS=tls.o testrun.o getgroups.o getfsdev.o t_stub.o t_unsafe.o trimslash.
$(CC) -I. -I$(srcdir) $(CFLAGS) $(CPPFLAGS) -c $< @CC_SHOBJ_FLAG@
@OBJ_RESTORE@
all: Makefile rsync$(EXEEXT) rsync-ssl stunnel-rsync stunnel-rsyncd.conf @MAKE_MAN@
.PHONY: all
all: Makefile rsync$(EXEEXT) stunnel-rsyncd.conf man
.PHONY: install
install: all
-${MKDIR_P} ${DESTDIR}${bindir}
${INSTALLCMD} ${INSTALL_STRIP} -m 755 rsync$(EXEEXT) ${DESTDIR}${bindir}
${INSTALLCMD} -m 755 rsync-ssl ${DESTDIR}${bindir}
-${MKDIR_P} ${DESTDIR}${mandir}/man1
-${MKDIR_P} ${DESTDIR}${mandir}/man5
if test -f rsync.1; then ${INSTALLMAN} -m 644 rsync.1 ${DESTDIR}${mandir}/man1; fi
if test -f rsync-ssl.1; then ${INSTALLMAN} -m 644 rsync-ssl.1 ${DESTDIR}${mandir}/man1; fi
if test -f rsyncd.conf.5; then ${INSTALLMAN} -m 644 rsyncd.conf.5 ${DESTDIR}${mandir}/man5; fi
install-ssl-client: rsync-ssl stunnel-rsync
-${MKDIR_P} ${DESTDIR}${bindir}
${INSTALLCMD} ${INSTALL_STRIP} -m 755 rsync-ssl ${DESTDIR}${bindir}
${INSTALLCMD} ${INSTALL_STRIP} -m 755 stunnel-rsync ${DESTDIR}${bindir}
install-ssl-daemon: stunnel-rsyncd.conf
-${MKDIR_P} ${DESTDIR}/etc/stunnel
${INSTALLCMD} ${INSTALL_STRIP} -m 644 stunnel-rsyncd.conf ${DESTDIR}/etc/stunnel/rsyncd.conf
${INSTALLCMD} -m 644 stunnel-rsyncd.conf ${DESTDIR}/etc/stunnel/rsyncd.conf
@if ! ls /etc/rsync-ssl/certs/server.* >/dev/null 2>/dev/null; then \
echo "Note that you'll need to install the certificate used by /etc/stunnel/rsyncd.conf"; \
fi
@@ -94,10 +99,14 @@ rsync$(EXEEXT): $(OBJS)
$(OBJS): $(HEADERS)
$(CHECK_OBJS): $(HEADERS)
options.o: latest-year.h help-rsync.h help-rsyncd.h
flist.o: rounding.h
rounding.h: rounding.c rsync.h
help-rsync.h help-rsyncd.h: rsync.1.md
./help-from-md "$(srcdir)/$<" $@
rounding.h: rounding.c rsync.h proto.h
@for r in 0 1 3; do \
if $(CC) $(CFLAGS) $(CPPFLAGS) $(LDFLAGS) -o rounding -DEXTRA_ROUNDING=$$r -I. $(srcdir)/rounding.c >rounding.out 2>&1; then \
echo "#define EXTRA_ROUNDING $$r" >rounding.h; \
@@ -115,6 +124,12 @@ rounding.h: rounding.c rsync.h
fi
@rm -f rounding.out
simd-checksum-x86_64.o: simd-checksum-x86_64.cpp
$(CXX) $(CXXFLAGS) $(CPPFLAGS) -c -o $@ $<
lib/md5-asm-x86_64.o: lib/md5-asm-x86_64.s
$(CC) -c -o $@ $<
tls$(EXEEXT): $(TLS_OBJ)
$(CC) $(CFLAGS) $(LDFLAGS) -o $@ $(TLS_OBJ) $(LIBS)
@@ -127,7 +142,7 @@ getgroups$(EXEEXT): getgroups.o
getfsdev$(EXEEXT): getfsdev.o
$(CC) $(CFLAGS) $(LDFLAGS) -o $@ getfsdev.o $(LIBS)
TRIMSLASH_OBJ = trimslash.o syscall.o lib/compat.o lib/snprintf.o
TRIMSLASH_OBJ = trimslash.o syscall.o t_stub.o lib/compat.o lib/snprintf.o
trimslash$(EXEEXT): $(TRIMSLASH_OBJ)
$(CC) $(CFLAGS) $(LDFLAGS) -o $@ $(TRIMSLASH_OBJ) $(LIBS)
@@ -135,13 +150,18 @@ T_UNSAFE_OBJ = t_unsafe.o syscall.o util.o util2.o t_stub.o lib/compat.o lib/snp
t_unsafe$(EXEEXT): $(T_UNSAFE_OBJ)
$(CC) $(CFLAGS) $(LDFLAGS) -o $@ $(T_UNSAFE_OBJ) $(LIBS)
.PHONY: conf
conf: configure.sh config.h.in
.PHONY: gen
gen: conf proto.h man
.PHONY: gensend
gensend: gen
rsync -aivzc $(GENFILES) samba.org:/home/ftp/pub/rsync/generated-files/
rsync -aic $(GENFILES) $${SAMBA_HOST-samba.org}:/home/ftp/pub/rsync/generated-files/
conf:
cd $(srcdir) && $(MAKE) -f prepare-source.mak conf
aclocal.m4: $(srcdir)/m4/*.m4
aclocal -I $(srcdir)/m4
configure.sh config.h.in: configure.ac aclocal.m4
@if test -f configure.sh; then cp -p configure.sh configure.sh.old; else touch configure.sh.old; fi
@@ -170,6 +190,7 @@ configure.sh config.h.in: configure.ac aclocal.m4
fi \
fi
.PHONY: reconfigure
reconfigure: configure.sh
./config.status --recheck
./config.status
@@ -189,52 +210,46 @@ Makefile: Makefile.in config.status configure.sh config.h.in
fi \
fi
rsync-ssl: $(srcdir)/rsync-ssl.in Makefile
sed 's;\@bindir\@;$(bindir);g' <$(srcdir)/rsync-ssl.in >rsync-ssl
@chmod +x rsync-ssl
stunnel-rsync: $(srcdir)/stunnel-rsync.in Makefile
sed 's;\@stunnel4\@;$(stunnel4);g' <$(srcdir)/stunnel-rsync.in >stunnel-rsync
@chmod +x stunnel-rsync
stunnel-rsyncd.conf: $(srcdir)/stunnel-rsyncd.conf.in Makefile
sed 's;\@bindir\@;$(bindir);g' <$(srcdir)/stunnel-rsyncd.conf.in >stunnel-rsyncd.conf
.PHONY: proto
proto: proto.h-tstamp
proto.h: proto.h-tstamp
@if test -f proto.h; then :; else cp -p $(srcdir)/proto.h .; fi
proto.h-tstamp: $(srcdir)/*.c $(srcdir)/lib/compat.c config.h
perl $(srcdir)/mkproto.pl $(srcdir)/*.c $(srcdir)/lib/compat.c
awk -f $(srcdir)/mkproto.awk $(srcdir)/*.c $(srcdir)/lib/compat.c
man: rsync.1 rsyncd.conf.5 man-copy
.PHONY: man
man: rsync.1 rsync-ssl.1 rsyncd.conf.5
man-copy:
@-if test -f rsync.1; then :; else echo 'Copying srcdir rsync.1'; cp -p $(srcdir)/rsync.1 .; fi
@-if test -f rsyncd.conf.5; then :; else echo 'Copying srcdir rsyncd.conf.5'; cp -p $(srcdir)/rsyncd.conf.5 .; fi
rsync.1: rsync.1.md md2man NEWS.md Makefile
@$(srcdir)/maybe-make-man $(srcdir) rsync.1.md
rsync.1: rsync.yo
yodl2man -o rsync.1 $(srcdir)/rsync.yo
-$(srcdir)/tweak_manpage rsync.1
rsync-ssl.1: rsync-ssl.1.md md2man NEWS.md Makefile
@$(srcdir)/maybe-make-man $(srcdir) rsync-ssl.1.md
rsyncd.conf.5: rsyncd.conf.yo
yodl2man -o rsyncd.conf.5 $(srcdir)/rsyncd.conf.yo
-$(srcdir)/tweak_manpage rsyncd.conf.5
rsyncd.conf.5: rsyncd.conf.5.md md2man NEWS.md Makefile
@$(srcdir)/maybe-make-man $(srcdir) rsyncd.conf.5.md
.PHONY: clean
clean: cleantests
rm -f *~ $(OBJS) $(CHECK_PROGS) $(CHECK_OBJS) $(CHECK_SYMLINKS) \
rounding rounding.h *.old
rounding rounding.h *.old rsync*.1 rsync*.5 rsync*.html
.PHONY: cleantests
cleantests:
rm -rf ./testtmp*
# We try to delete built files from both the source and build
# directories, just in case somebody previously configured things in
# the source directory.
.PHONY: distclean
distclean: clean
rm -f Makefile config.h config.status
rm -f rsync-ssl stunnel-rsync stunnel-rsyncd.conf
rm -f stunnel-rsyncd.conf
rm -f lib/dummy popt/dummy zlib/dummy
rm -f $(srcdir)/Makefile $(srcdir)/config.h $(srcdir)/config.status
rm -f $(srcdir)/lib/dummy $(srcdir)/popt/dummy $(srcdir)/zlib/dummy
@@ -247,14 +262,14 @@ distclean: clean
# this target is really just for my use. It only works on a limited
# range of machines and is used to produce a list of potentially
# dead (ie. unused) functions in the code. (tridge)
.PHONY: finddead
finddead:
nm *.o */*.o |grep 'U ' | awk '{print $$2}' | sort -u > nmused.txt
nm *.o */*.o |grep 'T ' | awk '{print $$3}' | sort -u > nmfns.txt
comm -13 nmused.txt nmfns.txt
# 'check' is the GNU name, 'test' is the name for everybody else :-)
.PHONY: check test
.PHONY: test
test: check
# There seems to be no standard way to specify some variables as
@@ -267,16 +282,19 @@ test: check
# catch Bash-isms earlier even if we're running on GNU. Of course, we
# might lose in the future where POSIX diverges from old sh.
.PHONY: check
check: all $(CHECK_PROGS) $(CHECK_SYMLINKS)
rsync_bin=`pwd`/rsync$(EXEEXT) $(srcdir)/runtests.sh
.PHONY: check29
check29: all $(CHECK_PROGS) $(CHECK_SYMLINKS)
rsync_bin=`pwd`/rsync$(EXEEXT) $(srcdir)/runtests.sh --protocol=29
.PHONY: check30
check30: all $(CHECK_PROGS) $(CHECK_SYMLINKS)
rsync_bin=`pwd`/rsync$(EXEEXT) $(srcdir)/runtests.sh --protocol=30
wildtest.o: wildtest.c lib/wildmatch.c rsync.h config.h
wildtest.o: wildtest.c t_stub.o lib/wildmatch.c rsync.h config.h
wildtest$(EXEEXT): wildtest.o lib/compat.o lib/snprintf.o @BUILD_POPT@
$(CC) $(CFLAGS) $(LDFLAGS) -o $@ wildtest.o lib/compat.o lib/snprintf.o @BUILD_POPT@ $(LIBS)
@@ -293,6 +311,7 @@ testsuite/xattrs-hlink.test:
# check a version installed from a binary or some other source tree,
# if you want.
.PHONY: installcheck
installcheck: $(CHECK_PROGS) $(CHECK_SYMLINKS)
POSIXLY_CORRECT=1 TOOLDIR=`pwd` rsync_bin="$(bindir)/rsync$(EXEEXT)" srcdir="$(srcdir)" $(srcdir)/runtests.sh
@@ -303,21 +322,12 @@ installcheck: $(CHECK_PROGS) $(CHECK_SYMLINKS)
splint:
splint +unixlib +gnuextensions -weak rsync.c
rsync.dvi: doc/rsync.texinfo
texi2dvi -o $@ $<
rsync.ps: rsync.dvi
dvips -ta4 -o $@ $<
rsync.pdf: doc/rsync.texinfo
texi2dvi -o $@ --pdf $<
.PHONY: doxygen
doxygen:
cd $(srcdir) && rm dox/html/* && doxygen
# for maintainers only
.PHONY: doxygen-upload
doxygen-upload:
rsync -avzv $(srcdir)/dox/html/ --delete \
samba.org:/home/httpd/html/rsync/doxygen/head/
$${SAMBA_HOST-samba.org}:/home/httpd/html/rsync/doxygen/head/

105
NEWS
View File

@@ -1,105 +0,0 @@
NEWS for rsync 3.1.1 (UNRELEASED)
Protocol: 31 (unchanged)
Changes since 3.1.0:
BUG FIXES:
- If the receiver gets bogus filenames from the sender (an unexpected
leading slash or a ".." infix dir), exit with an error. This prevents a
malicious sender from trying to inject filenames that would affect an
area outside the destination directories.
- Fixed a failure to remove the partial-transfer temp file when interrupted
(and rsync is not saving the partial files).
- Changed the chown/group/xattr-set order to avoid losing some security-
related xattr info (that would get cleared by a chown).
- Fixed a bug in the xattr-finding code that could make a non-root-run
receiver not able to find some xattr numbers.
- Fixed a bug in the early daemon protocol where a timeout failed to be
honored (e.g. if the remote side fails to send us the initial protocol
greeting).
- Fixed unintended inclusion of commas in file numbers in the daemon log.
- We once again send the 'f' sub-flag (of -e) to the server side so it
knows that we can handle incremental-recursion directory errors properly
in older protocols.
- Fixed an issue with too-aggressive keep-alive messages causing a problem
for older rsync versions early in the transfer.
- Fixed an incorrect message about backup-directory-creation when using
--dry-run and the backup dir is not an absolute path.
- Fixed a bug where a failed deletion and/or a failed sender-side removal
would not affect the exit code.
- Fixed a bug that caused a failure when combining --delete-missing-args
with --xattrs and/or --acls.
- Fixed a strange dir_depth assertion error that was caused by empty-dir
removals and/or duplicate files in the transfer.
- Fixed a problem with --info=progress2's output stats where rsync would
only update the stats at the end of each file's transfer. It now uses
the data that is flowing for the current file, making the stats more
accurate and less jumpy.
- Fixed an itemize bug that affected the combo of --link-dest, -X, and -n.
- Fixed a problem with delete messages not appearing in the log file when
the user didn't use --verbose.
- Improve chunked xattr reading for OS X.
- Removed an attempted hard-link xattr optimization that was causing a
transfer failure. (If you need to interact with an rsync 3.1.0 using
--hard-links & --xattrs, you can specify --protocol=30.)
- We now generate a better error if the buffer overflows in do_mknod().
- Fixed a problem reading more than 16 ACLs on some OSes.
- Fixed the reading of the secrets file to avoid an infinite wait when
the username is missing.
- Fixed a parsing problem in the --usermap/--groupmap options when using
MIN-MAX numbers.
- Switched Cygwin back to using socketpair "pipes" to try to speed it up.
- Added knowledge of a few new options to rrsync.
ENHANCEMENTS:
- Tweaked the temp-file naming when --temp-dir=DIR is used: the temp-file
names will not get a '.' prepended.
- Added support for a new-compression idiom that does not compress all the
matching data in a transfer. This can help rsync to use less cpu when a
transfer has a lot of matching data, and also makes rsync compatible with
a non-bundled zlib. See the --new-compress and --old-compress options in
the manpage.
- Added the support/rsync-no-vanished wrapper script.
- Made configure more prominently mention when we failed to find yodl (in
case the user wants to be able to generate manpages from *.yo files).
- Have manpage mention how a daemon's max-verbosity setting affects info
and debug options. Also added more clarification on backslash removals
for excludes that contain wildcards.
- Have configure check if for the attr lib (for getxattr) for those systems
that need to link against it explicitly.
- Change the early dir-creation logic to only use that idiom in an
inc-recursive copy that is preserving directory times. e.g. using
--omit-dir-times will avoid these early directories being created.
DEVELOPER RELATED:
- We now include an example systemd file (in packaging/systemd).

192
NEWS.md Normal file
View File

@@ -0,0 +1,192 @@
# NEWS for rsync 3.2.0 (UNRELEASED)
Protocol: 31 (unchanged)
## Changes since 3.1.3:
### BUG FIXES:
- Avoid a potential out-of-bounds read in daemon mode if argc can be made to
become 0.
- Fix the default list of skip-compress files for non-daemon transfers.
- Fix xattr filter rules losing an 'x' attribute in a non-local transfer.
- Avoid an error when a check for a potential fuzzy file happens to reference
a directory.
- Make the atomic-rsync helper script have a more consistent error-exit.
- Make sure that a signal handler calls `_exit()` instead of exit().
- Various zlib fixes, including security fixes for CVE-2016-9843,
CVE-2016-9842, CVE-2016-9841, and CVE-2016-9840.
- Fixed an issue with `--remove-source-files` not removing a source symlink
when combined with `--copy-links`.
- Fixed a bug where the daemon would fail to write early fatal error messages
to the client, such as refused or unknown command-line options.
- Fixed the block-size validation logic when dealing with older protocols.
- Some rrsync fixes and enhancements to handle the latest options.
- Fixed a problem with the `--link-dest`|`--copy-dest` code when `--xattrs`
was specified along with multiple alternate-destination directories (it
could possibly choose a bad file match while trying to find a better xattr
match).
- Fixed a couple bugs in the handling of files with the `--sparse` option.
- Fixed a bug in the writing of the batch.sh file (w/--write-batch) when the
source & destination args were not last on the command-line.
- Avoid a hang when an overabundance of messages clogs up all the I/O buffers.
- Fixed a mismatch in the RSYNC_PID values put into the environment of
`pre-xfer exec` and a `post-xfer exec`.
- Fixed a crash in the `--iconv` code.
- Fixed a rare crash in the popt_unalias() code.
### ENHANCEMENTS:
- Various checksum enhancements, including the optional use of openssl's MD4 &
MD5 checksum algorithms, some x86-64 optimizations for the rolling checksum,
some x86-64 optimizations for the (non-openssl) MD5 checksum, the addition
of xxhash checksum support, and a negotiation heuristic that ensures that it
is easier to add new checksum algorithms in the future. The environment
variable `RSYNC_CHECKSUM_LIST` can be used to customize the preference order
of the negotiation, or use `--checksum-choice` (`--cc`) to force a choice.
- Various compression enhancements, including the addition of zstd and lz4
compression algorithms and a negotiation heuristic that picks the best
compression option supported by both sides. The environment variable
`RSYNC_COMPRESS_LIST` can be used to customize the preference order of the
negotiation, or use `--compress-choice` (`--zc`) to force a choice.
- Added a --debug=NSTR option that outputs details of the new negotiation
strings (for checksums and compression). The first level just outputs the
result of each negotiation on the client, level 2 outputs the values of the
strings that were sent to and received from the server, and level 3 outputs
all those values on the server side too (when given the debug option).
- The --debug=OPTS command-line option is no longer auto-forwarded to the
remote rsync which allows for the client and server to have different levels
of debug specified. This also allows for newer debug options to be
specified, such as using --debug=NSTR to see the negotiated hash result,
without having the command fail if the server version is too old to handle
that debug item. Use -M--debug=OPTS to send the options to the remote side.
- Added the `--atimes` option based on the long-standing patch (just with some
fixes that the patch has been needing).
- Added `--open-noatime` option to open files using `O_NOATIME`.
- Added the `--write-devices` option based on the long-standing patch.
- Added openssl & preliminary gnutls support to the rsync-ssl script, which is
now installed by default. This was unified with the old stunnel-rsync
helper script to simplify packaging. Note that the script accepts the use
of --type=gnutls for gnutls testing, but does not look for gnutls-cli on the
path yet. The use of type=gnutls will not work right until gnutls-cli no
longer drops data.
- Rsync was enhanced to set the `RSYNC_PORT` environment variable when running
a daemon-over-rsh script. Its value is the user-specified port number (set
via `--port` or an rsync:// URL) or 0 if the user didn't override the port.
- Added the `proxy protocol` daemon parameter that allows your rsyncd to know
the real remote IP when it is setup behind a proxy.
- Added negated matching to the daemon's `refuse options` setting by using
match strings that start with a `!` (such as `!compress*`). This lets you
refuse all options except for a particular approved list, for example.
- Added the `early exec` daemon parameter that runs a script before the
transfer parameters are known, allowing some early setup based on module
name.
- Added status output in response to a signal (via both SIGINFO & SIGVTALRM).
- Added `--copy-as=USER` option to give some extra security to root-run rsync
commands into/from untrusted directories (such as backups and restores).
- When resuming the transfer of a file in the `--partial-dir`, rsync will now
update that partial file in-place instead of creating yet another tmp file
copy. This requires both sender & receiver to be at least v3.2.0.
- Added support for `RSYNC_SHELL` & `RSYNC_NO_XFER_EXEC` environment variables
that affect the pre-xfer exec and post-xfer exec rsync daemon options.
- Optimize the `--fuzzy --fuzzy` heuristic to avoid the fuzzy directory scan
until all other basis-file options are exhausted (such as `--link-dest`).
- Have the daemon log include the normal-exit sent/received stats when the
transfer exited with an error when possible (i.e. if it is the sender).
- The daemon now locks its pid file (when configured to use one) so that it
will not fail to start when the file exists and it is unlocked.
- Various man page improvements, including some html representations (that
aren't installed by default).
- Made -V the short option for --version and improved its information.
- Forward -4 or -6 to the ssh command, making it easier to type than
`--rsh='ssh -4'` (or -6).
### PACKAGING RELATED:
- Add installed binary: /usr/bin/rsync-sll
- Add installed man page: /usr/man/man1/rsync-ssl.1
- Tweak auxilliary doc file names, such as: README.md, INSTALL.md, NEWS.md, &
OLDNEWS.md.
- The rsync-ssl script wants to run openssl or stunnel4, so consider adding a
dependency for one of those options (though it's probably fine to just let
it complain about being unable to find the program and let the user decide
if they want to install one or the other).
- If you packaged rsync + rsync-ssl + rsync-ssl-daemon as separate packages,
the rsync-ssl package is now gone (rsync-ssl should be considered to be
mainstream now that Samba requires SSL for its rsync daemon).
- Add _build_ dependency for liblz4-dev, libxxhash-dev, libzstd-dev, and
libssl-dev. These development libraries will give rsync extra compression
algorithms, extra checksum algorithms, and allow use of openssl's crypto
lib for (potentially) faster MD4/MD5 checksums.
- Add _build_ dependency for g++ to enable the SIMD checksum optimizations.
- Add _build_ dependency for _either_ python3-cmarkcfm or python3-commonmark
to allow for patching of man pages or building a git release. Note that
cmarkcfm is faster than commonmark, but they generate the same data.
- Remove yodl _build_ dependency (if it was even listed before).
### DEVELOPER RELATED:
- Silenced some annoying warnings about major() & minor() by improving an
autoconf include-file check.
- Converted the man pages from yodl to markdown. They are now processed via a
simple python3 script using the cmarkgfm **or** commonmark library. This
should make it easier to package rsync, since yodl has gotten obscure.
- Improved some configure checks to work better with strict C99 compilers.
- Some perl building/packaging scripts were recoded into awk and python3.
- Some defines in byteorder.h were changed into static inline functions that
will help to ensure that the args don't get evaluated multiple times on
"careful alignment" hosts.
- Some code typos were fixed (as pointed out by a Fossies run).
------------------------------------------------------------------------------

3599
OLDNEWS
View File

File diff suppressed because it is too large Load Diff

3863
OLDNEWS.md Normal file
View File

File diff suppressed because it is too large Load Diff

View File

@@ -65,7 +65,7 @@ WEB SITE
The main rsync web site is here:
http://rsync.samba.org/
> http://rsync.samba.org/
You'll find a FAQ list, downloads, resources, HTML versions of the
manpages, etc.
@@ -80,7 +80,7 @@ list, and there is also an announcement-only mailing list for those that
want official announcements. See the mailing-list page for full
details:
http://rsync.samba.org/lists.html
> http://rsync.samba.org/lists.html
BUG REPORTS
@@ -88,34 +88,38 @@ BUG REPORTS
To visit this web page for full the details on bug reporting:
http://rsync.samba.org/bugzilla.html
> http://rsync.samba.org/bugzilla.html
That page contains links to the current bug list, and information on how
to report a bug well. You might also like to try searching the Internet
for the error message you've received, or looking in the mailing list
archives at:
http://mail-archive.com/rsync@lists.samba.org/
> http://mail-archive.com/rsync@lists.samba.org/
To send a bug report, follow the instructions on the bug-tracking
page of the web site.
Alternately, email your bug report to rsync@lists.samba.org .
Alternately, email your bug report to <rsync@lists.samba.org>.
GIT REPOSITORY
--------------
If you want to get the very latest version of rsync direct from the
source code repository then you can use git:
source code repository, then you will need to use git. The git repo
is hosted on github and on samba's site. Feel free to access it here:
git clone git://git.samba.org/rsync.git
> https://github.com/WayneD/rsync
or clone it from its samba repo:
> git clone git://git.samba.org/rsync.git
See the download page for full details on all the ways to grab the
source, including nightly tar files, web-browsing of the git repository,
etc.:
source:
http://rsync.samba.org/download.html
> http://rsync.samba.org/download.html
COPYRIGHT
@@ -129,12 +133,17 @@ Rsync may be used, modified and redistributed only under the terms of
the GNU General Public License, found in the file COPYING in this
distribution, or at:
http://www.fsf.org/licenses/gpl.html
> http://www.fsf.org/licenses/gpl.html
AVAILABILITY
------------
The main web site for rsync is http://rsync.samba.org/
The main ftp site is ftp://rsync.samba.org/pub/rsync/
This is also available as rsync://rsync.samba.org/rsyncftp/
This is also available as rsync://download.samba.org/rsyncftp/ if you
connect via ssl. Use the `rsync-ssl` script if you have it, otherwise
connect to the rsync server via a normal rsync command and it will
output some instructions for how to connect.

4
TODO
View File

@@ -94,7 +94,7 @@ Handling IPv6 on old machines
platforms that have a half-working implementation, so redefining
these functions clashes with system headers, and leaving them out
breaks. This affects at least OSF/1, RedHat 5, and Cobalt, which
are moderately improtant.
are moderately important.
Perhaps the simplest solution would be to have two different files
implementing the same interface, and choose either the new or the
@@ -236,7 +236,7 @@ Memory accounting
At exit, show how much memory was used for the file list, etc.
Also we do a wierd exponential-growth allocation in flist.c. I'm
We also do a weird exponential-growth allocation in flist.c. I'm
not sure this makes sense with modern mallocs. At any rate it will
make us allocate a huge amount of memory for large file lists.

View File

@@ -2,7 +2,7 @@
* Routines to authenticate access to a daemon (hosts allow/deny).
*
* Copyright (C) 1998 Andrew Tridgell
* Copyright (C) 2004-2014 Wayne Davison
* Copyright (C) 2004-2020 Wayne Davison
*
* 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
@@ -158,8 +158,7 @@ static int match_address(const char *addr, const char *tok)
break;
#ifdef INET6
case PF_INET6:
{
case PF_INET6: {
struct sockaddr_in6 *sin6a, *sin6t;
sin6a = (struct sockaddr_in6 *)resa->ai_addr;
@@ -171,20 +170,19 @@ static int match_address(const char *addr, const char *tok)
addrlen = 16;
#ifdef HAVE_SOCKADDR_IN6_SCOPE_ID
if (sin6t->sin6_scope_id &&
sin6a->sin6_scope_id != sin6t->sin6_scope_id) {
if (sin6t->sin6_scope_id && sin6a->sin6_scope_id != sin6t->sin6_scope_id) {
ret = 0;
goto out;
}
#endif
break;
}
}
#endif
default:
rprintf(FLOG, "unknown family %u\n", rest->ai_family);
ret = 0;
goto out;
rprintf(FLOG, "unknown family %u\n", rest->ai_family);
ret = 0;
goto out;
}
bits = -1;

92
aclocal.m4 vendored
View File

@@ -1,92 +0,0 @@
dnl AC_VALIDATE_CACHE_SYSTEM_TYPE[(cmd)]
dnl if the cache file is inconsistent with the current host,
dnl target and build system types, execute CMD or print a default
dnl error message.
AC_DEFUN(AC_VALIDATE_CACHE_SYSTEM_TYPE, [
AC_REQUIRE([AC_CANONICAL_SYSTEM])
AC_MSG_CHECKING([config.cache system type])
if { test x"${ac_cv_host_system_type+set}" = x"set" &&
test x"$ac_cv_host_system_type" != x"$host"; } ||
{ test x"${ac_cv_build_system_type+set}" = x"set" &&
test x"$ac_cv_build_system_type" != x"$build"; } ||
{ test x"${ac_cv_target_system_type+set}" = x"set" &&
test x"$ac_cv_target_system_type" != x"$target"; }; then
AC_MSG_RESULT([different])
ifelse($#, 1, [$1],
[AC_MSG_ERROR(["you must remove config.cache and restart configure"])])
else
AC_MSG_RESULT([same])
fi
ac_cv_host_system_type="$host"
ac_cv_build_system_type="$build"
ac_cv_target_system_type="$target"
])
dnl Check for socklen_t: historically on BSD it is an int, and in
dnl POSIX 1g it is a type of its own, but some platforms use different
dnl types for the argument to getsockopt, getpeername, etc. So we
dnl have to test to find something that will work.
dnl This is no good, because passing the wrong pointer on C compilers is
dnl likely to only generate a warning, not an error. We don't call this at
dnl the moment.
AC_DEFUN([TYPE_SOCKLEN_T],
[
AC_CHECK_TYPE([socklen_t], ,[
AC_MSG_CHECKING([for socklen_t equivalent])
AC_CACHE_VAL([rsync_cv_socklen_t_equiv],
[
# Systems have either "struct sockaddr *" or
# "void *" as the second argument to getpeername
rsync_cv_socklen_t_equiv=
for arg2 in "struct sockaddr" void; do
for t in int size_t unsigned long "unsigned long"; do
AC_TRY_COMPILE([
#include <sys/types.h>
#include <sys/socket.h>
int getpeername (int, $arg2 *, $t *);
],[
$t len;
getpeername(0,0,&len);
],[
rsync_cv_socklen_t_equiv="$t"
break
])
done
done
if test "x$rsync_cv_socklen_t_equiv" = x; then
AC_MSG_ERROR([Cannot find a type to use in place of socklen_t])
fi
])
AC_MSG_RESULT($rsync_cv_socklen_t_equiv)
AC_DEFINE_UNQUOTED(socklen_t, $rsync_cv_socklen_t_equiv,
[type to use in place of socklen_t if not defined])],
[#include <sys/types.h>
#include <sys/socket.h>])
])
dnl AC_HAVE_TYPE(TYPE,INCLUDES)
AC_DEFUN([AC_HAVE_TYPE], [
AC_REQUIRE([AC_HEADER_STDC])
cv=`echo "$1" | sed 'y%./+- %__p__%'`
AC_MSG_CHECKING(for $1)
AC_CACHE_VAL([ac_cv_type_$cv],
AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[
AC_INCLUDES_DEFAULT
$2]],
[[$1 foo;]])],
[eval "ac_cv_type_$cv=yes"],
[eval "ac_cv_type_$cv=no"]))dnl
ac_foo=`eval echo \\$ac_cv_type_$cv`
AC_MSG_RESULT($ac_foo)
if test "$ac_foo" = yes; then
ac_tr_hdr=HAVE_`echo $1 | sed 'y%abcdefghijklmnopqrstuvwxyz./- %ABCDEFGHIJKLMNOPQRSTUVWXYZ____%'`
if false; then
AC_CHECK_TYPES($1)
fi
AC_DEFINE_UNQUOTED($ac_tr_hdr, 1, [Define if you have type `$1'])
fi
])

25
acls.c
View File

@@ -3,7 +3,7 @@
*
* Copyright (C) 1996 Andrew Tridgell
* Copyright (C) 1996 Paul Mackerras
* Copyright (C) 2006-2014 Wayne Davison
* Copyright (C) 2006-2020 Wayne Davison
*
* 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
@@ -48,7 +48,7 @@ extern int preserve_specials;
/* When we send the access bits over the wire, we shift them 2 bits to the
* left and use the lower 2 bits as flags (relevant only to a name entry).
* This makes the protocol more efficient than sending a value that would
* be likely to have its hightest bits set. */
* be likely to have its highest bits set. */
#define XFLAG_NAME_FOLLOWS 0x0001u
#define XFLAG_NAME_IS_USER 0x0002u
@@ -332,14 +332,12 @@ static BOOL unpack_smb_acl(SMB_ACL_T sacl, rsync_acl *racl)
if (temp_ida_list.count) {
#ifdef SMB_ACL_NEED_SORT
if (temp_ida_list.count > 1) {
qsort(temp_ida_list.items, temp_ida_list.count,
sizeof (id_access), id_access_sorter);
qsort(temp_ida_list.items, temp_ida_list.count, sizeof (id_access), id_access_sorter);
}
#endif
if (!(racl->names.idas = new_array(id_access, temp_ida_list.count)))
out_of_memory("unpack_smb_acl");
memcpy(racl->names.idas, temp_ida_list.items,
temp_ida_list.count * sizeof (id_access));
memcpy(racl->names.idas, temp_ida_list.items, temp_ida_list.count * sizeof (id_access));
} else
racl->names.idas = NULL;
@@ -825,14 +823,12 @@ void cache_tmp_acl(struct file_struct *file, stat_x *sxp)
if (prior_access_count == (size_t)-1)
prior_access_count = access_acl_list.count;
F_ACL(file) = cache_rsync_acl(sxp->acc_acl,
SMB_ACL_TYPE_ACCESS, &access_acl_list);
F_ACL(file) = cache_rsync_acl(sxp->acc_acl, SMB_ACL_TYPE_ACCESS, &access_acl_list);
if (S_ISDIR(sxp->st.st_mode)) {
if (prior_default_count == (size_t)-1)
prior_default_count = default_acl_list.count;
F_DIR_DEFACL(file) = cache_rsync_acl(sxp->def_acl,
SMB_ACL_TYPE_DEFAULT, &default_acl_list);
F_DIR_DEFACL(file) = cache_rsync_acl(sxp->def_acl, SMB_ACL_TYPE_DEFAULT, &default_acl_list);
}
}
@@ -996,8 +992,7 @@ static int set_rsync_acl(const char *fname, acl_duo *duo_item,
mode = 0; /* eliminate compiler warning */
#else
if (type == SMB_ACL_TYPE_ACCESS) {
cur_mode = change_sacl_perms(duo_item->sacl, &duo_item->racl,
cur_mode, mode);
cur_mode = change_sacl_perms(duo_item->sacl, &duo_item->racl, cur_mode, mode);
if (cur_mode == (mode_t)-1)
return 0;
}
@@ -1117,14 +1112,12 @@ int default_perms_for_dir(const char *dir)
case ENOSYS:
/* No ACLs are available. */
break;
case ENOENT:
if (dry_run) {
default:
if (dry_run && errno == ENOENT) {
/* We're doing a dry run, so the containing directory
* wasn't actually created. Don't worry about it. */
break;
}
/* Otherwise fall through. */
default:
rprintf(FWARNING,
"default_perms_for_dir: sys_acl_get_file(%s, %s): %s, falling back on umask\n",
dir, str_acl_type(SMB_ACL_TYPE_DEFAULT), strerror(errno));

View File

@@ -2,7 +2,7 @@
* Support rsync daemon authentication.
*
* Copyright (C) 1998-2000 Andrew Tridgell
* Copyright (C) 2002-2014 Wayne Davison
* Copyright (C) 2002-2020 Wayne Davison
*
* 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
@@ -71,7 +71,7 @@ static void gen_challenge(const char *addr, char *challenge)
SIVAL(input, 20, tv.tv_usec);
SIVAL(input, 24, getpid());
sum_init(0);
sum_init(-1, 0);
sum_update(input, sizeof input);
len = sum_end(digest);
@@ -85,7 +85,7 @@ static void generate_hash(const char *in, const char *challenge, char *out)
char buf[MAX_DIGEST_LEN];
int len;
sum_init(0);
sum_init(-1, 0);
sum_update(in, strlen(in));
sum_update(challenge, strlen(challenge));
len = sum_end(buf);
@@ -162,8 +162,8 @@ static const char *check_secret(int module, const char *user, const char *group,
fclose(fh);
memset(line, 0, sizeof line);
memset(pass2, 0, sizeof pass2);
force_memzero(line, sizeof line);
force_memzero(pass2, sizeof pass2);
return err;
}
@@ -279,17 +279,18 @@ char *auth_server(int f_in, int f_out, int module, const char *host,
/* See if authorizing user is a real user, and if so, see
* if it is in a group that matches tok+1 wildmat. */
if (auth_uid_groups_cnt < 0) {
gid_t gid_list[64];
item_list gid_list = EMPTY_ITEM_LIST;
uid_t auth_uid;
auth_uid_groups_cnt = sizeof gid_list / sizeof (gid_t);
if (!user_to_uid(line, &auth_uid, False)
|| getallgroups(auth_uid, gid_list, &auth_uid_groups_cnt) != NULL)
|| getallgroups(auth_uid, &gid_list) != NULL)
auth_uid_groups_cnt = 0;
else {
gid_t *gid_array = gid_list.items;
auth_uid_groups_cnt = gid_list.count;
if ((auth_uid_groups = new_array(char *, auth_uid_groups_cnt)) == NULL)
out_of_memory("auth_server");
for (j = 0; j < auth_uid_groups_cnt; j++)
auth_uid_groups[j] = gid_to_group(gid_list[j]);
auth_uid_groups[j] = gid_to_group(gid_array[j]);
}
}
for (j = 0; j < auth_uid_groups_cnt; j++) {
@@ -317,8 +318,8 @@ char *auth_server(int f_in, int f_out, int module, const char *host,
err = check_secret(module, line, group, challenge, pass);
}
memset(challenge, 0, sizeof challenge);
memset(pass, 0, strlen(pass));
force_memzero(challenge, sizeof challenge);
force_memzero(pass, strlen(pass));
if (auth_uid_groups) {
int j;
@@ -356,12 +357,12 @@ void auth_client(int fd, const char *user, const char *challenge)
/* XXX: cyeoh says that getpass is deprecated, because
* it may return a truncated password on some systems,
* and it is not in the LSB.
*
* Andrew Klein says that getpassphrase() is present
* on Solaris and reads up to 256 characters.
*
* OpenBSD has a readpassphrase() that might be more suitable.
*/
*
* Andrew Klein says that getpassphrase() is present
* on Solaris and reads up to 256 characters.
*
* OpenBSD has a readpassphrase() that might be more suitable.
*/
pass = getpass("Password: ");
}

View File

@@ -2,7 +2,7 @@
* Backup handling code.
*
* Copyright (C) 1999 Andrew Tridgell
* Copyright (C) 2003-2014 Wayne Davison
* Copyright (C) 2003-2020 Wayne Davison
*
* 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
@@ -157,6 +157,18 @@ static BOOL copy_valid_path(const char *fname)
char *get_backup_name(const char *fname)
{
if (backup_dir) {
static int initialized = 0;
if (!initialized) {
int ret;
if (backup_dir_len > 1)
backup_dir_buf[backup_dir_len-1] = '\0';
ret = make_path(backup_dir_buf, 0);
if (backup_dir_len > 1)
backup_dir_buf[backup_dir_len-1] = '/';
if (ret < 0)
return NULL;
initialized = 1;
}
/* copy fname into backup_dir_buf while validating the dirs. */
if (copy_valid_path(fname))
return backup_dir_buf;
@@ -208,23 +220,24 @@ static inline int link_or_rename(const char *from, const char *to,
return 0;
}
/* Hard-link, rename, or copy an item to the backup name. Returns 2 if item
* was duplicated into backup area, 1 if item was moved, or 0 for failure.*/
/* Hard-link, rename, or copy an item to the backup name. Returns 0 for
* failure, 1 if item was moved, 2 if item was duplicated or hard linked
* into backup area, or 3 if item doesn't exist or isn't a regular file. */
int make_backup(const char *fname, BOOL prefer_rename)
{
stat_x sx;
struct file_struct *file;
int save_preserve_xattrs;
char *buf = get_backup_name(fname);
char *buf;
int ret = 0;
if (!buf)
return 0;
init_stat_x(&sx);
/* Return success if no file to keep. */
if (x_lstat(fname, &sx.st, NULL) < 0)
return 1;
return 3;
if (!(buf = get_backup_name(fname)))
return 0;
/* Try a hard-link or a rename first. Using rename is not atomic, but
* is more efficient than forcing a copy for larger files when no hard-
@@ -244,7 +257,7 @@ int make_backup(const char *fname, BOOL prefer_rename)
/* Fall back to making a copy. */
if (!(file = make_file(fname, NULL, &sx.st, 0, NO_FILTERS)))
return 1; /* the file could have disappeared */
return 3; /* the file could have disappeared */
#ifdef SUPPORT_ACLS
if (preserve_acls && !S_ISLNK(file->mode)) {
@@ -299,7 +312,7 @@ int make_backup(const char *fname, BOOL prefer_rename)
#ifdef SUPPORT_XATTRS
uncache_tmp_xattrs();
#endif
return 2;
return 3;
}
/* Copy to backup tree if a file. */
@@ -323,7 +336,7 @@ int make_backup(const char *fname, BOOL prefer_rename)
save_preserve_xattrs = preserve_xattrs;
preserve_xattrs = 0;
set_file_attrs(buf, file, NULL, fname, 0);
set_file_attrs(buf, file, NULL, fname, ATTRS_ACCURATE_TIME);
preserve_xattrs = save_preserve_xattrs;
unmake_file(file);

166
batch.c
View File

@@ -3,7 +3,7 @@
*
* Copyright (C) 1999 Weiss
* Copyright (C) 2004 Chris Shoemaker
* Copyright (C) 2004-2014 Wayne Davison
* Copyright (C) 2004-2020 Wayne Davison
*
* 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
@@ -37,14 +37,22 @@ extern int always_checksum;
extern int do_compression;
extern int inplace;
extern int append_mode;
extern int write_batch;
extern int xfersum_type;
extern int protocol_version;
extern int raw_argc, cooked_argc;
extern char **raw_argv, **cooked_argv;
extern char *batch_name;
extern const char *checksum_choice;
extern const char *compress_choice;
#ifdef ICONV_OPTION
extern char *iconv_opt;
#endif
extern filter_rule_list filter_list;
int batch_fd = -1;
int batch_sh_fd = -1;
int batch_stream_flags;
static int tweaked_append;
@@ -156,37 +164,45 @@ void check_batch_flags(void)
append_mode = 2;
}
static int write_arg(int fd, char *arg)
static int write_arg(const char *arg)
{
char *x, *s;
int len, ret = 0;
const char *x, *s;
int len, err = 0;
if (*arg == '-' && (x = strchr(arg, '=')) != NULL) {
if (write(fd, arg, x - arg + 1) != x - arg + 1)
ret = -1;
err |= write(batch_sh_fd, arg, x - arg + 1) != x - arg + 1;
arg += x - arg + 1;
}
if (strpbrk(arg, " \"'&;|[]()$#!*?^\\") != NULL) {
if (write(fd, "'", 1) != 1)
ret = -1;
err |= write(batch_sh_fd, "'", 1) != 1;
for (s = arg; (x = strchr(s, '\'')) != NULL; s = x + 1) {
if (write(fd, s, x - s + 1) != x - s + 1
|| write(fd, "'", 1) != 1)
ret = -1;
err |= write(batch_sh_fd, s, x - s + 1) != x - s + 1;
err |= write(batch_sh_fd, "'", 1) != 1;
}
len = strlen(s);
if (write(fd, s, len) != len
|| write(fd, "'", 1) != 1)
ret = -1;
return ret;
err |= write(batch_sh_fd, s, len) != len;
err |= write(batch_sh_fd, "'", 1) != 1;
return err;
}
len = strlen(arg);
if (write(fd, arg, len) != len)
ret = -1;
err |= write(batch_sh_fd, arg, len) != len;
return ret;
return err;
}
/* Writes out a space and then an option (or other string) with an optional "=" + arg suffix. */
static int write_opt(const char *opt, const char *arg)
{
int len = strlen(opt);
int err = write(batch_sh_fd, " ", 1) != 1;
err = write(batch_sh_fd, opt, len) != len ? 1 : 0;
if (arg) {
err |= write(batch_sh_fd, "=", 1) != 1;
err |= write_arg(arg);
}
return err;
}
static void write_filter_rules(int fd)
@@ -208,41 +224,74 @@ static void write_filter_rules(int fd)
write_sbuf(fd, "#E#");
}
/* This sets batch_fd and (for --write-batch) batch_sh_fd. */
void open_batch_files(void)
{
if (write_batch) {
char filename[MAXPATHLEN];
stringjoin(filename, sizeof filename, batch_name, ".sh", NULL);
batch_sh_fd = do_open(filename, O_WRONLY | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR | S_IXUSR);
if (batch_sh_fd < 0) {
rsyserr(FERROR, errno, "Batch file %s open error", full_fname(filename));
exit_cleanup(RERR_FILESELECT);
}
batch_fd = do_open(batch_name, O_WRONLY | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR);
} else if (strcmp(batch_name, "-") == 0)
batch_fd = STDIN_FILENO;
else
batch_fd = do_open(batch_name, O_RDONLY, S_IRUSR | S_IWUSR);
if (batch_fd < 0) {
rsyserr(FERROR, errno, "Batch file %s open error", full_fname(batch_name));
exit_cleanup(RERR_FILEIO);
}
}
/* This routine tries to write out an equivalent --read-batch command
* given the user's --write-batch args. However, it doesn't really
* understand most of the options, so it uses some overly simple
* heuristics to munge the command line into something that will
* (hopefully) work. */
void write_batch_shell_file(int argc, char *argv[], int file_arg_cnt)
void write_batch_shell_file(void)
{
int fd, i, len, err = 0;
char *p, filename[MAXPATHLEN];
stringjoin(filename, sizeof filename,
batch_name, ".sh", NULL);
fd = do_open(filename, O_WRONLY | O_CREAT | O_TRUNC,
S_IRUSR | S_IWUSR | S_IXUSR);
if (fd < 0) {
rsyserr(FERROR, errno, "Batch file %s open error",
filename);
exit_cleanup(RERR_FILESELECT);
}
int i, j, len, err = 0;
char *p, *p2;
/* Write argvs info to BATCH.sh file */
if (write_arg(fd, argv[0]) < 0)
err = 1;
err |= write_arg(raw_argv[0]);
if (filter_list.head) {
if (protocol_version >= 29)
write_sbuf(fd, " --filter=._-");
err |= write_opt("--filter", "._-");
else
write_sbuf(fd, " --exclude-from=-");
err |= write_opt("--exclude-from", "-");
}
for (i = 1; i < argc - file_arg_cnt; i++) {
p = argv[i];
/* We need to make sure that any protocol-based or negotiated choices get accurately
* reflected in the options we save AND that we avoid any need for --read-batch to
* do a string-based negotation (since we don't write them into the file). */
if (do_compression)
err |= write_opt("--compress-choice", compress_choice);
if (strchr(checksum_choice, ',') || xfersum_type != parse_csum_name(NULL, -1))
err |= write_opt("--checksum-choice", checksum_choice);
/* Elide the filename args from the option list, but scan for them in reverse. */
for (i = raw_argc-1, j = cooked_argc-1; i > 0 && j >= 0; i--) {
if (strcmp(raw_argv[i], cooked_argv[j]) == 0) {
raw_argv[i] = NULL;
j--;
}
}
for (i = 1; i < raw_argc; i++) {
if (!(p = raw_argv[i]))
continue;
if (strncmp(p, "--files-from", 12) == 0
|| strncmp(p, "--filter", 8) == 0
|| strncmp(p, "--include", 9) == 0
|| strncmp(p, "--exclude", 9) == 0) {
|| strncmp(p, "--filter", 8) == 0
|| strncmp(p, "--include", 9) == 0
|| strncmp(p, "--exclude", 9) == 0) {
if (strchr(p, '=') == NULL)
i++;
continue;
@@ -251,33 +300,24 @@ void write_batch_shell_file(int argc, char *argv[], int file_arg_cnt)
i++;
continue;
}
if (write(fd, " ", 1) != 1)
err = 1;
if (strncmp(p, "--write-batch", len = 13) == 0
|| strncmp(p, "--only-write-batch", len = 18) == 0) {
if (write(fd, "--read-batch", 12) != 12)
err = 1;
if (p[len] == '=') {
if (write(fd, "=", 1) != 1
|| write_arg(fd, p + len + 1) < 0)
err = 1;
}
} else {
if (write_arg(fd, p) < 0)
err = 1;
|| strncmp(p, "--only-write-batch", len = 18) == 0)
err |= write_opt("--read-batch", p[len] == '=' ? p + len + 1 : NULL);
else {
err |= write(batch_sh_fd, " ", 1) != 1;
err |= write_arg(p);
}
}
if (!(p = check_for_hostspec(argv[argc - 1], &p, &i)))
p = argv[argc - 1];
if (write(fd, " ${1:-", 6) != 6
|| write_arg(fd, p) < 0)
err = 1;
write_byte(fd, '}');
if (!(p = check_for_hostspec(cooked_argv[cooked_argc - 1], &p2, &i)))
p = cooked_argv[cooked_argc - 1];
err |= write_opt("${1:-", NULL);
err |= write_arg(p);
err |= write(batch_sh_fd, "}", 1) != 1;
if (filter_list.head)
write_filter_rules(fd);
if (write(fd, "\n", 1) != 1 || close(fd) < 0 || err) {
rsyserr(FERROR, errno, "Batch file %s write error",
filename);
write_filter_rules(batch_sh_fd);
if (write(batch_sh_fd, "\n", 1) != 1 || close(batch_sh_fd) < 0 || err) {
rsyserr(FERROR, errno, "Batch file %s.sh write error", batch_name);
exit_cleanup(RERR_FILEIO);
}
batch_sh_fd = -1;
}

View File

@@ -2,7 +2,7 @@
* Simple byteorder handling.
*
* Copyright (C) 1992-1995 Andrew Tridgell
* Copyright (C) 2007-2014 Wayne Davison
* Copyright (C) 2007-2020 Wayne Davison
*
* 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
@@ -19,7 +19,6 @@
*/
#undef CAREFUL_ALIGNMENT
#undef AVOID_BYTEORDER_INLINE
/* We know that the x86 can handle misalignment and has the same
* byte order (LSB-first) as the 32-bit numbers we transmit. */
@@ -36,16 +35,36 @@
#if CAREFUL_ALIGNMENT
#define PVAL(buf,pos) (UVAL(buf,pos)|UVAL(buf,(pos)+1)<<8)
#define IVAL(buf,pos) (PVAL(buf,pos)|PVAL(buf,(pos)+2)<<16)
#define IVAL64(buf,pos) (IVAL(buf,pos)|(int64)IVAL(buf,(pos)+4)<<32)
#define SSVALX(buf,pos,val) (CVAL(buf,pos)=(val)&0xFF,CVAL(buf,pos+1)=(val)>>8)
#define SIVALX(buf,pos,val) (SSVALX(buf,pos,val&0xFFFF),SSVALX(buf,pos+2,val>>16))
#define SIVAL(buf,pos,val) SIVALX(buf,pos,(uint32)(val))
#define SIVAL64(buf,pos,val) (SIVAL(buf,pos,val),SIVAL(buf,(pos)+4,(val)>>32))
static inline uint32
IVALu(const uchar *buf, int pos)
{
return UVAL(buf, pos)
| UVAL(buf, pos + 1) << 8
| UVAL(buf, pos + 2) << 16
| UVAL(buf, pos + 3) << 24;
}
#define IVALu(buf,pos) IVAL(buf,pos)
#define SIVALu(buf,pos,val) SIVAL(buf,pos,val)
static inline void
SIVALu(uchar *buf, int pos, uint32 val)
{
CVAL(buf, pos) = val;
CVAL(buf, pos + 1) = val >> 8;
CVAL(buf, pos + 2) = val >> 16;
CVAL(buf, pos + 3) = val >> 24;
}
static inline int64
IVAL64(const char *buf, int pos)
{
return IVALu((uchar*)buf, pos) | (int64)IVALu((uchar*)buf, pos + 4) << 32;
}
static inline void
SIVAL64(char *buf, int pos, int64 val)
{
SIVALu((uchar*)buf, pos, val);
SIVALu((uchar*)buf, pos + 4, val >> 32);
}
#else /* !CAREFUL_ALIGNMENT */
@@ -53,16 +72,6 @@
* WARNING: This section is dependent on the length of an int32 (and thus a uint32)
* being correct (4 bytes)! Set CAREFUL_ALIGNMENT if it is not. */
# ifdef AVOID_BYTEORDER_INLINE
#define IVAL(buf,pos) (*(uint32 *)((char *)(buf) + (pos)))
#define SIVAL(buf,pos,val) IVAL(buf,pos)=((uint32)(val))
#define IVALu(buf,pos) IVAL(buf,pos)
#define SIVALu(buf,pos,val) SIVAL(buf,pos,val)
# else /* !AVOID_BYTEORDER_INLINE */
static inline uint32
IVALu(const uchar *buf, int pos)
{
@@ -85,18 +94,6 @@ SIVALu(uchar *buf, int pos, uint32 val)
*u.num = val;
}
static inline uint32
IVAL(const char *buf, int pos)
{
return IVALu((uchar*)buf, pos);
}
static inline void
SIVAL(char *buf, int pos, uint32 val)
{
SIVALu((uchar*)buf, pos, val);
}
static inline int64
IVAL64(const char *buf, int pos)
{
@@ -119,6 +116,17 @@ SIVAL64(char *buf, int pos, int64 val)
*u.num = val;
}
# endif /* !AVOID_BYTEORDER_INLINE */
#endif /* !CAREFUL_ALIGNMENT */
static inline uint32
IVAL(const char *buf, int pos)
{
return IVALu((uchar*)buf, pos);
}
static inline void
SIVAL(char *buf, int pos, uint32 val)
{
SIVALu((uchar*)buf, pos, val);
}

View File

@@ -1,7 +1,7 @@
/*
* Allow an arbitrary sequence of case labels.
*
* Copyright (C) 2006-2014 Wayne Davison
* Copyright (C) 2006-2020 Wayne Davison
*
* 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
@@ -17,7 +17,7 @@
* with this program; if not, visit the http://fsf.org website.
*/
/* This is included multiple times, once for every segement in a switch statement.
/* This is included multiple times, once for every segment in a switch statement.
* This produces the next "case N:" statement in sequence. */
#if !defined CASE_N_STATE_0
@@ -25,51 +25,67 @@
case 0:
#elif !defined CASE_N_STATE_1
#define CASE_N_STATE_1
/* FALLTHROUGH */
case 1:
#elif !defined CASE_N_STATE_2
#define CASE_N_STATE_2
/* FALLTHROUGH */
case 2:
#elif !defined CASE_N_STATE_3
#define CASE_N_STATE_3
/* FALLTHROUGH */
case 3:
#elif !defined CASE_N_STATE_4
#define CASE_N_STATE_4
/* FALLTHROUGH */
case 4:
#elif !defined CASE_N_STATE_5
#define CASE_N_STATE_5
/* FALLTHROUGH */
case 5:
#elif !defined CASE_N_STATE_6
#define CASE_N_STATE_6
/* FALLTHROUGH */
case 6:
#elif !defined CASE_N_STATE_7
#define CASE_N_STATE_7
/* FALLTHROUGH */
case 7:
#elif !defined CASE_N_STATE_8
#define CASE_N_STATE_8
/* FALLTHROUGH */
case 8:
#elif !defined CASE_N_STATE_9
#define CASE_N_STATE_9
/* FALLTHROUGH */
case 9:
#elif !defined CASE_N_STATE_10
#define CASE_N_STATE_10
/* FALLTHROUGH */
case 10:
#elif !defined CASE_N_STATE_11
#define CASE_N_STATE_11
/* FALLTHROUGH */
case 11:
#elif !defined CASE_N_STATE_12
#define CASE_N_STATE_12
/* FALLTHROUGH */
case 12:
#elif !defined CASE_N_STATE_13
#define CASE_N_STATE_13
/* FALLTHROUGH */
case 13:
#elif !defined CASE_N_STATE_14
#define CASE_N_STATE_14
/* FALLTHROUGH */
case 14:
#elif !defined CASE_N_STATE_15
#define CASE_N_STATE_15
/* FALLTHROUGH */
case 15:
#elif !defined CASE_N_STATE_16
#define CASE_N_STATE_16
/* FALLTHROUGH */
case 16:
#else
#error Need to add more case statements!

View File

@@ -3,13 +3,20 @@
*
* Copyright (C) 1996 Andrew Tridgell
* Copyright (C) 1996 Paul Mackerras
* Copyright (C) 2004-2014 Wayne Davison
* Copyright (C) 2004-2020 Wayne Davison
*
* 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 3 of the License, or
* (at your option) any later version.
*
* In addition, as a special exception, the copyright holders give
* permission to dynamically link rsync with the OpenSSL and xxhash
* libraries when those libraries are being distributed in compliance
* with their license terms, and to distribute a dynamically linked
* combination of rsync and these libraries. This is also considered
* to be covered under the GPL's System Libraries exception.
*
* 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
@@ -20,47 +27,217 @@
*/
#include "rsync.h"
#ifdef SUPPORT_XXHASH
#include "xxhash.h"
#endif
extern int am_server;
extern int whole_file;
extern int checksum_seed;
extern int protocol_version;
extern int proper_seed_order;
extern const char *checksum_choice;
struct name_num_obj valid_checksums = {
"checksum", NULL, NULL, 0, 0, {
#ifdef SUPPORT_XXHASH
{ CSUM_XXH64, "xxh64", NULL },
{ CSUM_XXH64, "xxhash", NULL },
#endif
{ CSUM_MD5, "md5", NULL },
{ CSUM_MD4, "md4", NULL },
{ CSUM_NONE, "none", NULL },
{ 0, NULL, NULL }
}
};
int xfersum_type = 0; /* used for the file transfer checksums */
int checksum_type = 0; /* used for the pre-transfer (--checksum) checksums */
int parse_csum_name(const char *name, int len)
{
struct name_num_item *nni;
if (len < 0 && name)
len = strlen(name);
if (!name || (len == 4 && strncasecmp(name, "auto", 4) == 0)) {
if (protocol_version >= 30)
return CSUM_MD5;
if (protocol_version >= 27)
return CSUM_MD4_OLD;
if (protocol_version >= 21)
return CSUM_MD4_BUSTED;
return CSUM_MD4_ARCHAIC;
}
nni = get_nni_by_name(&valid_checksums, name, len);
if (!nni) {
rprintf(FERROR, "unknown checksum name: %s\n", name);
exit_cleanup(RERR_UNSUPPORTED);
}
return nni->num;
}
static const char *checksum_name(int num)
{
struct name_num_item *nni = get_nni_by_num(&valid_checksums, num);
return nni ? nni->name : num < CSUM_MD4 ? "MD4" : "UNKNOWN";
}
void parse_checksum_choice(int final_call)
{
if (valid_checksums.negotiated_name)
xfersum_type = checksum_type = valid_checksums.negotiated_num;
else {
char *cp = checksum_choice ? strchr(checksum_choice, ',') : NULL;
if (cp) {
xfersum_type = parse_csum_name(checksum_choice, cp - checksum_choice);
checksum_type = parse_csum_name(cp+1, -1);
} else
xfersum_type = checksum_type = parse_csum_name(checksum_choice, -1);
}
if (xfersum_type == CSUM_NONE)
whole_file = 1;
/* Snag the checksum name for both write_batch's option output & the following debug output. */
if (valid_checksums.negotiated_name)
checksum_choice = valid_checksums.negotiated_name;
else if (checksum_choice == NULL)
checksum_choice = checksum_name(xfersum_type);
if (final_call && DEBUG_GTE(NSTR, am_server ? 3 : 1)) {
rprintf(FINFO, "%s%s checksum: %s\n",
am_server ? "Server" : "Client",
valid_checksums.negotiated_name ? " negotiated" : "",
checksum_choice);
}
}
int csum_len_for_type(int cst, BOOL flist_csum)
{
switch (cst) {
case CSUM_NONE:
return 1;
case CSUM_MD4_ARCHAIC:
/* The oldest checksum code is rather weird: the file-list code only sent
* 2-byte checksums, but all other checksums were full MD4 length. */
return flist_csum ? 2 : MD4_DIGEST_LEN;
case CSUM_MD4:
case CSUM_MD4_OLD:
case CSUM_MD4_BUSTED:
return MD4_DIGEST_LEN;
case CSUM_MD5:
return MD5_DIGEST_LEN;
#ifdef SUPPORT_XXHASH
case CSUM_XXH64:
return 64/8;
#endif
default: /* paranoia to prevent missing case values */
exit_cleanup(RERR_UNSUPPORTED);
}
return 0;
}
/* Returns 0 if the checksum is not canonical (i.e. it includes a seed value).
* Returns 1 if the public sum order matches our internal sum order.
* Returns -1 if the public sum order is the reverse of our internal sum order.
*/
int canonical_checksum(int csum_type)
{
switch (csum_type) {
case CSUM_NONE:
case CSUM_MD4_ARCHAIC:
case CSUM_MD4_OLD:
case CSUM_MD4_BUSTED:
break;
case CSUM_MD4:
case CSUM_MD5:
return -1;
#ifdef SUPPORT_XXHASH
case CSUM_XXH64:
return 1;
#endif
default: /* paranoia to prevent missing case values */
exit_cleanup(RERR_UNSUPPORTED);
}
return 0;
}
#ifndef HAVE_SIMD /* See simd-checksum-*.cpp. */
/*
a simple 32 bit checksum that can be upadted from either end
a simple 32 bit checksum that can be updated from either end
(inspired by Mark Adler's Adler-32 checksum)
*/
uint32 get_checksum1(char *buf1, int32 len)
{
int32 i;
uint32 s1, s2;
schar *buf = (schar *)buf1;
int32 i;
uint32 s1, s2;
schar *buf = (schar *)buf1;
s1 = s2 = 0;
for (i = 0; i < (len-4); i+=4) {
s2 += 4*(s1 + buf[i]) + 3*buf[i+1] + 2*buf[i+2] + buf[i+3] +
10*CHAR_OFFSET;
s1 += (buf[i+0] + buf[i+1] + buf[i+2] + buf[i+3] + 4*CHAR_OFFSET);
}
for (; i < len; i++) {
s1 += (buf[i]+CHAR_OFFSET); s2 += s1;
}
return (s1 & 0xffff) + (s2 << 16);
s1 = s2 = 0;
for (i = 0; i < (len-4); i+=4) {
s2 += 4*(s1 + buf[i]) + 3*buf[i+1] + 2*buf[i+2] + buf[i+3] + 10*CHAR_OFFSET;
s1 += (buf[i+0] + buf[i+1] + buf[i+2] + buf[i+3] + 4*CHAR_OFFSET);
}
for (; i < len; i++) {
s1 += (buf[i]+CHAR_OFFSET); s2 += s1;
}
return (s1 & 0xffff) + (s2 << 16);
}
#endif
void get_checksum2(char *buf, int32 len, char *sum)
{
md_context m;
if (protocol_version >= 30) {
switch (xfersum_type) {
#ifdef SUPPORT_XXHASH
case CSUM_XXH64:
SIVAL64(sum, 0, XXH64(buf, len, checksum_seed));
break;
#endif
case CSUM_MD5: {
MD5_CTX m5;
uchar seedbuf[4];
md5_begin(&m);
md5_update(&m, (uchar *)buf, len);
if (checksum_seed) {
SIVALu(seedbuf, 0, checksum_seed);
md5_update(&m, seedbuf, 4);
MD5_Init(&m5);
if (proper_seed_order) {
if (checksum_seed) {
SIVALu(seedbuf, 0, checksum_seed);
MD5_Update(&m5, seedbuf, 4);
}
MD5_Update(&m5, (uchar *)buf, len);
} else {
MD5_Update(&m5, (uchar *)buf, len);
if (checksum_seed) {
SIVALu(seedbuf, 0, checksum_seed);
MD5_Update(&m5, seedbuf, 4);
}
}
md5_result(&m, (uchar *)sum);
} else {
MD5_Final((uchar *)sum, &m5);
break;
}
case CSUM_MD4:
#ifdef USE_OPENSSL
{
MD4_CTX m4;
MD4_Init(&m4);
MD4_Update(&m4, (uchar *)buf, len);
if (checksum_seed) {
uchar seedbuf[4];
SIVALu(seedbuf, 0, checksum_seed);
MD4_Update(&m4, seedbuf, 4);
}
MD4_Final((uchar *)sum, &m4);
break;
}
#endif
case CSUM_MD4_OLD:
case CSUM_MD4_BUSTED:
case CSUM_MD4_ARCHAIC: {
md_context m;
int32 i;
static char *buf1;
static int32 len1;
@@ -91,10 +268,14 @@ void get_checksum2(char *buf, int32 len, char *sum)
* are multiples of 64. This is fixed by calling mdfour_update()
* even when there are no more bytes.
*/
if (len - i > 0 || protocol_version >= 27)
if (len - i > 0 || xfersum_type > CSUM_MD4_BUSTED)
mdfour_update(&m, (uchar *)(buf1+i), len-i);
mdfour_result(&m, (uchar *)sum);
break;
}
default: /* paranoia to prevent missing case values */
exit_cleanup(RERR_UNSUPPORTED);
}
}
@@ -102,7 +283,6 @@ void file_checksum(const char *fname, const STRUCT_STAT *st_p, char *sum)
{
struct map_struct *buf;
OFF_T i, len = st_p->st_size;
md_context m;
int32 remainder;
int fd;
@@ -112,38 +292,86 @@ void file_checksum(const char *fname, const STRUCT_STAT *st_p, char *sum)
if (fd == -1)
return;
buf = map_file(fd, len, MAX_MAP_SIZE, CSUM_CHUNK);
buf = map_file(fd, len, MAX_MAP_SIZE, CHUNK_SIZE);
if (protocol_version >= 30) {
md5_begin(&m);
switch (checksum_type) {
#ifdef SUPPORT_XXHASH
case CSUM_XXH64: {
static XXH64_state_t* state = NULL;
if (!state && !(state = XXH64_createState()))
out_of_memory("file_checksum");
for (i = 0; i + CSUM_CHUNK <= len; i += CSUM_CHUNK) {
md5_update(&m, (uchar *)map_ptr(buf, i, CSUM_CHUNK),
CSUM_CHUNK);
}
XXH64_reset(state, 0);
for (i = 0; i + CHUNK_SIZE <= len; i += CHUNK_SIZE)
XXH64_update(state, (uchar *)map_ptr(buf, i, CHUNK_SIZE), CHUNK_SIZE);
remainder = (int32)(len - i);
if (remainder > 0)
md5_update(&m, (uchar *)map_ptr(buf, i, remainder), remainder);
XXH64_update(state, (uchar *)map_ptr(buf, i, remainder), remainder);
SIVAL64(sum, 0, XXH64_digest(state));
break;
}
#endif
case CSUM_MD5: {
MD5_CTX m5;
MD5_Init(&m5);
for (i = 0; i + CHUNK_SIZE <= len; i += CHUNK_SIZE)
MD5_Update(&m5, (uchar *)map_ptr(buf, i, CHUNK_SIZE), CHUNK_SIZE);
remainder = (int32)(len - i);
if (remainder > 0)
MD5_Update(&m5, (uchar *)map_ptr(buf, i, remainder), remainder);
MD5_Final((uchar *)sum, &m5);
break;
}
case CSUM_MD4:
#ifdef USE_OPENSSL
{
MD4_CTX m4;
MD4_Init(&m4);
for (i = 0; i + CHUNK_SIZE <= len; i += CHUNK_SIZE)
MD4_Update(&m4, (uchar *)map_ptr(buf, i, CHUNK_SIZE), CHUNK_SIZE);
remainder = (int32)(len - i);
if (remainder > 0)
MD4_Update(&m4, (uchar *)map_ptr(buf, i, remainder), remainder);
MD4_Final((uchar *)sum, &m4);
break;
}
#endif
case CSUM_MD4_OLD:
case CSUM_MD4_BUSTED:
case CSUM_MD4_ARCHAIC: {
md_context m;
md5_result(&m, (uchar *)sum);
} else {
mdfour_begin(&m);
for (i = 0; i + CSUM_CHUNK <= len; i += CSUM_CHUNK) {
mdfour_update(&m, (uchar *)map_ptr(buf, i, CSUM_CHUNK),
CSUM_CHUNK);
}
for (i = 0; i + CHUNK_SIZE <= len; i += CHUNK_SIZE)
mdfour_update(&m, (uchar *)map_ptr(buf, i, CHUNK_SIZE), CHUNK_SIZE);
/* Prior to version 27 an incorrect MD4 checksum was computed
* by failing to call mdfour_tail() for block sizes that
* are multiples of 64. This is fixed by calling mdfour_update()
* even when there are no more bytes. */
remainder = (int32)(len - i);
if (remainder > 0 || protocol_version >= 27)
if (remainder > 0 || checksum_type > CSUM_MD4_BUSTED)
mdfour_update(&m, (uchar *)map_ptr(buf, i, remainder), remainder);
mdfour_result(&m, (uchar *)sum);
break;
}
default:
rprintf(FERROR, "Invalid checksum-choice for --checksum: %s (%d)\n",
checksum_name(checksum_type), checksum_type);
exit_cleanup(RERR_UNSUPPORTED);
}
close(fd);
@@ -151,19 +379,57 @@ void file_checksum(const char *fname, const STRUCT_STAT *st_p, char *sum)
}
static int32 sumresidue;
static md_context md;
static union {
md_context md;
#ifdef USE_OPENSSL
MD4_CTX m4;
#endif
MD5_CTX m5;
} ctx;
#ifdef SUPPORT_XXHASH
static XXH64_state_t* xxh64_state;
#endif
static int cursum_type;
void sum_init(int seed)
void sum_init(int csum_type, int seed)
{
char s[4];
if (protocol_version >= 30)
md5_begin(&md);
else {
mdfour_begin(&md);
if (csum_type < 0)
csum_type = parse_csum_name(NULL, 0);
cursum_type = csum_type;
switch (csum_type) {
#ifdef SUPPORT_XXHASH
case CSUM_XXH64:
if (!xxh64_state && !(xxh64_state = XXH64_createState()))
out_of_memory("sum_init");
XXH64_reset(xxh64_state, 0);
break;
#endif
case CSUM_MD5:
MD5_Init(&ctx.m5);
break;
case CSUM_MD4:
#ifdef USE_OPENSSL
MD4_Init(&ctx.m4);
#else
mdfour_begin(&ctx.md);
sumresidue = 0;
#endif
break;
case CSUM_MD4_OLD:
case CSUM_MD4_BUSTED:
case CSUM_MD4_ARCHAIC:
mdfour_begin(&ctx.md);
sumresidue = 0;
SIVAL(s, 0, seed);
sum_update(s, 4);
break;
case CSUM_NONE:
break;
default: /* paranoia to prevent missing case values */
exit_cleanup(RERR_UNSUPPORTED);
}
}
@@ -177,47 +443,90 @@ void sum_init(int seed)
**/
void sum_update(const char *p, int32 len)
{
if (protocol_version >= 30) {
md5_update(&md, (uchar *)p, len);
return;
}
switch (cursum_type) {
#ifdef SUPPORT_XXHASH
case CSUM_XXH64:
XXH64_update(xxh64_state, p, len);
break;
#endif
case CSUM_MD5:
MD5_Update(&ctx.m5, (uchar *)p, len);
break;
case CSUM_MD4:
#ifdef USE_OPENSSL
MD4_Update(&ctx.m4, (uchar *)p, len);
break;
#endif
case CSUM_MD4_OLD:
case CSUM_MD4_BUSTED:
case CSUM_MD4_ARCHAIC:
if (len + sumresidue < CSUM_CHUNK) {
memcpy(ctx.md.buffer + sumresidue, p, len);
sumresidue += len;
break;
}
if (len + sumresidue < CSUM_CHUNK) {
memcpy(md.buffer + sumresidue, p, len);
sumresidue += len;
return;
}
if (sumresidue) {
int32 i = CSUM_CHUNK - sumresidue;
memcpy(ctx.md.buffer + sumresidue, p, i);
mdfour_update(&ctx.md, (uchar *)ctx.md.buffer, CSUM_CHUNK);
len -= i;
p += i;
}
if (sumresidue) {
int32 i = CSUM_CHUNK - sumresidue;
memcpy(md.buffer + sumresidue, p, i);
mdfour_update(&md, (uchar *)md.buffer, CSUM_CHUNK);
len -= i;
p += i;
}
while (len >= CSUM_CHUNK) {
mdfour_update(&ctx.md, (uchar *)p, CSUM_CHUNK);
len -= CSUM_CHUNK;
p += CSUM_CHUNK;
}
while (len >= CSUM_CHUNK) {
mdfour_update(&md, (uchar *)p, CSUM_CHUNK);
len -= CSUM_CHUNK;
p += CSUM_CHUNK;
sumresidue = len;
if (sumresidue)
memcpy(ctx.md.buffer, p, sumresidue);
break;
case CSUM_NONE:
break;
default: /* paranoia to prevent missing case values */
exit_cleanup(RERR_UNSUPPORTED);
}
sumresidue = len;
if (sumresidue)
memcpy(md.buffer, p, sumresidue);
}
/* NOTE: all the callers of sum_end() pass in a pointer to a buffer that is
* MAX_DIGEST_LEN in size, so even if the csum-len is shorter that that (i.e.
* CSUM_MD4_ARCHAIC), we don't have to worry about limiting the data we write
* into the "sum" buffer. */
int sum_end(char *sum)
{
if (protocol_version >= 30) {
md5_result(&md, (uchar *)sum);
return MD5_DIGEST_LEN;
switch (cursum_type) {
#ifdef SUPPORT_XXHASH
case CSUM_XXH64:
SIVAL64(sum, 0, XXH64_digest(xxh64_state));
break;
#endif
case CSUM_MD5:
MD5_Final((uchar *)sum, &ctx.m5);
break;
case CSUM_MD4:
#ifdef USE_OPENSSL
MD4_Final((uchar *)sum, &ctx.m4);
break;
#endif
case CSUM_MD4_OLD:
mdfour_update(&ctx.md, (uchar *)ctx.md.buffer, sumresidue);
mdfour_result(&ctx.md, (uchar *)sum);
break;
case CSUM_MD4_BUSTED:
case CSUM_MD4_ARCHAIC:
if (sumresidue)
mdfour_update(&ctx.md, (uchar *)ctx.md.buffer, sumresidue);
mdfour_result(&ctx.md, (uchar *)sum);
break;
case CSUM_NONE:
*sum = '\0';
break;
default: /* paranoia to prevent missing case values */
exit_cleanup(RERR_UNSUPPORTED);
}
if (sumresidue || protocol_version >= 27)
mdfour_update(&md, (uchar *)md.buffer, sumresidue);
mdfour_result(&md, (uchar *)sum);
return MD4_DIGEST_LEN;
return csum_len_for_type(cursum_type, 0);
}

View File

@@ -2,7 +2,7 @@
* Implement the core of the --chmod option.
*
* Copyright (C) 2002 Scott Howard
* Copyright (C) 2005-2014 Wayne Davison
* Copyright (C) 2005-2020 Wayne Davison
*
* 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
@@ -44,7 +44,7 @@ struct chmod_mode_struct {
#define STATE_OCTAL_NUM 3
/* Parse a chmod-style argument, and break it down into one or more AND/OR
* pairs in a linked list. We return a pointer to new items on succcess
* pairs in a linked list. We return a pointer to new items on success
* (appending the items to the specified list), or NULL on error. */
struct chmod_mode_struct *parse_chmod(const char *modestr,
struct chmod_mode_struct **root_mode_ptr)

View File

@@ -4,7 +4,7 @@
* Copyright (C) 1996-2000 Andrew Tridgell
* Copyright (C) 1996 Paul Mackerras
* Copyright (C) 2002 Martin Pool
* Copyright (C) 2003-2014 Wayne Davison
* Copyright (C) 2003-2020 Wayne Davison
*
* 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
@@ -22,9 +22,11 @@
#include "rsync.h"
extern int dry_run;
extern int am_server;
extern int am_daemon;
extern int am_receiver;
extern int am_sender;
extern int io_error;
extern int keep_partial;
extern int got_xfer_error;
@@ -33,6 +35,7 @@ extern int output_needs_newline;
extern char *partial_dir;
extern char *logfile_name;
int called_from_signal_handler = 0;
BOOL shutting_down = False;
BOOL flush_ok_after_signal = False;
@@ -137,7 +140,6 @@ NORETURN void _exit_cleanup(int code, const char *file, int line)
who_am_i(), code, file, line);
}
/* FALLTHROUGH */
#include "case_N.h"
switch_step++;
@@ -151,7 +153,6 @@ NORETURN void _exit_cleanup(int code, const char *file, int line)
}
}
/* FALLTHROUGH */
#include "case_N.h"
switch_step++;
@@ -171,18 +172,17 @@ NORETURN void _exit_cleanup(int code, const char *file, int line)
const char *fname = cleanup_fname;
cleanup_fname = NULL;
if (!partial_dir) {
/* We don't want to leave a partial file with a modern time or it
* could be skipped via --update. Setting the time to something
* really old also helps it to stand out as unfinished in an ls. */
tweak_modtime = 1;
cleanup_file->modtime = 0;
/* We don't want to leave a partial file with a modern time or it
* could be skipped via --update. Setting the time to something
* really old also helps it to stand out as unfinished in an ls. */
tweak_modtime = 1;
cleanup_file->modtime = 0;
}
finish_transfer(cleanup_new_fname, fname, NULL, NULL,
cleanup_file, tweak_modtime, !partial_dir);
}
}
/* FALLTHROUGH */
#include "case_N.h"
switch_step++;
@@ -194,7 +194,6 @@ NORETURN void _exit_cleanup(int code, const char *file, int line)
if (!exit_code && !code)
io_flush(FULL_FLUSH);
/* FALLTHROUGH */
#include "case_N.h"
switch_step++;
@@ -225,34 +224,38 @@ NORETURN void _exit_cleanup(int code, const char *file, int line)
|| am_daemon || (logfile_name && (am_server || !INFO_GTE(STATS, 1))))
log_exit(exit_code, exit_file, exit_line);
/* FALLTHROUGH */
#include "case_N.h"
switch_step++;
if (DEBUG_GTE(EXIT, 1)) {
rprintf(FINFO,
"[%s] _exit_cleanup(code=%d, file=%s, line=%d): "
"about to call exit(%d)\n",
who_am_i(), first_code, exit_file, exit_line, exit_code);
"about to call exit(%d)%s\n",
who_am_i(), first_code, exit_file, exit_line, exit_code,
dry_run ? " (DRY RUN)" : "");
}
/* FALLTHROUGH */
#include "case_N.h"
switch_step++;
if (exit_code && exit_code != RERR_SOCKETIO && exit_code != RERR_STREAMIO && exit_code != RERR_SIGNAL1
&& exit_code != RERR_TIMEOUT && !shutting_down && (protocol_version >= 31 || am_receiver)) {
if (line > 0) {
if (DEBUG_GTE(EXIT, 3)) {
rprintf(FINFO, "[%s] sending MSG_ERROR_EXIT with exit_code %d\n",
who_am_i(), exit_code);
&& exit_code != RERR_TIMEOUT && !shutting_down) {
if (protocol_version >= 31 || am_receiver) {
if (line > 0) {
if (DEBUG_GTE(EXIT, 3)) {
rprintf(FINFO, "[%s] sending MSG_ERROR_EXIT with exit_code %d\n",
who_am_i(), exit_code);
}
send_msg_int(MSG_ERROR_EXIT, exit_code);
}
send_msg_int(MSG_ERROR_EXIT, exit_code);
if (!am_sender)
io_flush(MSG_FLUSH); /* Be sure to send all messages */
noop_io_until_death();
}
noop_io_until_death();
else if (!am_sender)
io_flush(MSG_FLUSH); /* Be sure to send all messages */
}
/* FALLTHROUGH */
#include "case_N.h"
switch_step++;
@@ -265,6 +268,8 @@ NORETURN void _exit_cleanup(int code, const char *file, int line)
break;
}
if (called_from_signal_handler)
_exit(exit_code);
exit(exit_code);
}

View File

@@ -3,7 +3,7 @@
*
* Copyright (C) 1992-2001 Andrew Tridgell <tridge@samba.org>
* Copyright (C) 2001, 2002 Martin Pool <mbp@samba.org>
* Copyright (C) 2002-2014 Wayne Davison
* Copyright (C) 2002-2020 Wayne Davison
*
* 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
@@ -27,52 +27,60 @@
*/
#include "rsync.h"
#include "itypes.h"
extern int am_daemon;
static const char default_name[] = "UNKNOWN";
extern int am_server;
static const char proxyv2sig[] = "\r\n\r\n\0\r\nQUIT\n";
static char ipaddr_buf[100];
/**
* Return the IP addr of the client as a string
**/
#define PROXY_V2_SIG_SIZE ((int)sizeof proxyv2sig - 1)
#define PROXY_V2_HEADER_SIZE (PROXY_V2_SIG_SIZE + 1 + 1 + 2)
#define CMD_LOCAL 0
#define CMD_PROXY 1
#define PROXY_FAM_TCPv4 0x11
#define PROXY_FAM_TCPv6 0x21
#define GET_SOCKADDR_FAMILY(ss) ((struct sockaddr*)ss)->sa_family
static void client_sockaddr(int fd, struct sockaddr_storage *ss, socklen_t *ss_len);
static int check_name(const char *ipaddr, const struct sockaddr_storage *ss, char *name_buf, size_t name_buf_size);
static int valid_ipaddr(const char *s);
/* Return the IP addr of the client as a string. */
char *client_addr(int fd)
{
static char addr_buf[100];
static int initialised;
struct sockaddr_storage ss;
socklen_t length = sizeof ss;
if (initialised)
return addr_buf;
if (*ipaddr_buf)
return ipaddr_buf;
initialised = 1;
if (am_server) { /* daemon over --rsh mode */
if (am_daemon < 0) { /* daemon over --rsh mode */
char *env_str;
strlcpy(addr_buf, "0.0.0.0", sizeof addr_buf);
strlcpy(ipaddr_buf, "0.0.0.0", sizeof ipaddr_buf);
if ((env_str = getenv("REMOTE_HOST")) != NULL
|| (env_str = getenv("SSH_CONNECTION")) != NULL
|| (env_str = getenv("SSH_CLIENT")) != NULL
|| (env_str = getenv("SSH2_CLIENT")) != NULL) {
char *p;
strlcpy(addr_buf, env_str, sizeof addr_buf);
strlcpy(ipaddr_buf, env_str, sizeof ipaddr_buf);
/* Truncate the value to just the IP address. */
if ((p = strchr(addr_buf, ' ')) != NULL)
if ((p = strchr(ipaddr_buf, ' ')) != NULL)
*p = '\0';
}
} else {
client_sockaddr(fd, &ss, &length);
getnameinfo((struct sockaddr *)&ss, length,
addr_buf, sizeof addr_buf, NULL, 0, NI_NUMERICHOST);
if (valid_ipaddr(ipaddr_buf))
return ipaddr_buf;
}
return addr_buf;
}
client_sockaddr(fd, &ss, &length);
getnameinfo((struct sockaddr *)&ss, length, ipaddr_buf, sizeof ipaddr_buf, NULL, 0, NI_NUMERICHOST);
static int get_sockaddr_family(const struct sockaddr_storage *ss)
{
return ((struct sockaddr *) ss)->sa_family;
return ipaddr_buf;
}
@@ -89,71 +97,216 @@ static int get_sockaddr_family(const struct sockaddr_storage *ss)
* After translation from sockaddr to name we do a forward lookup to
* make sure nobody is spoofing PTR records.
**/
char *client_name(int fd)
char *client_name(const char *ipaddr)
{
static char name_buf[100];
static char port_buf[100];
static int initialised;
char port_buf[100];
struct sockaddr_storage ss;
socklen_t ss_len;
struct addrinfo hint, *answer;
int err;
if (initialised)
if (*name_buf)
return name_buf;
strlcpy(name_buf, default_name, sizeof name_buf);
initialised = 1;
if (strcmp(ipaddr, "0.0.0.0") == 0)
return name_buf;
memset(&ss, 0, sizeof ss);
if (am_server) { /* daemon over --rsh mode */
char *addr = client_addr(fd);
struct addrinfo hint, *answer;
int err;
if (strcmp(addr, "0.0.0.0") == 0)
return name_buf;
memset(&hint, 0, sizeof hint);
memset(&hint, 0, sizeof hint);
#ifdef AI_NUMERICHOST
hint.ai_flags = AI_NUMERICHOST;
hint.ai_flags = AI_NUMERICHOST;
#endif
hint.ai_socktype = SOCK_STREAM;
hint.ai_socktype = SOCK_STREAM;
if ((err = getaddrinfo(addr, NULL, &hint, &answer)) != 0) {
rprintf(FLOG, "malformed address %s: %s\n",
addr, gai_strerror(err));
return name_buf;
}
switch (answer->ai_family) {
case AF_INET:
ss_len = sizeof (struct sockaddr_in);
memcpy(&ss, answer->ai_addr, ss_len);
break;
#ifdef INET6
case AF_INET6:
ss_len = sizeof (struct sockaddr_in6);
memcpy(&ss, answer->ai_addr, ss_len);
break;
#endif
default:
exit_cleanup(RERR_SOCKETIO);
}
freeaddrinfo(answer);
} else {
ss_len = sizeof ss;
client_sockaddr(fd, &ss, &ss_len);
if ((err = getaddrinfo(ipaddr, NULL, &hint, &answer)) != 0) {
rprintf(FLOG, "malformed address %s: %s\n", ipaddr, gai_strerror(err));
return name_buf;
}
if (lookup_name(fd, &ss, ss_len, name_buf, sizeof name_buf,
port_buf, sizeof port_buf) == 0)
check_name(fd, &ss, name_buf, sizeof name_buf);
switch (answer->ai_family) {
case AF_INET:
ss_len = sizeof (struct sockaddr_in);
memcpy(&ss, answer->ai_addr, ss_len);
break;
#ifdef INET6
case AF_INET6:
ss_len = sizeof (struct sockaddr_in6);
memcpy(&ss, answer->ai_addr, ss_len);
break;
#endif
default:
assert(0);
}
freeaddrinfo(answer);
/* reverse lookup */
err = getnameinfo((struct sockaddr*)&ss, ss_len, name_buf, sizeof name_buf,
port_buf, sizeof port_buf, NI_NAMEREQD | NI_NUMERICSERV);
if (err) {
strlcpy(name_buf, default_name, sizeof name_buf);
rprintf(FLOG, "name lookup failed for %s: %s\n", ipaddr, gai_strerror(err));
} else
check_name(ipaddr, &ss, name_buf, sizeof name_buf);
return name_buf;
}
/* Try to read an proxy protocol header (V1 or V2). Returns 1 on success or 0 on failure. */
int read_proxy_protocol_header(int fd)
{
union {
struct {
char line[108];
} v1;
struct {
char sig[PROXY_V2_SIG_SIZE];
char ver_cmd;
char fam;
char len[2];
union {
struct {
char src_addr[4];
char dst_addr[4];
char src_port[2];
char dst_port[2];
} ip4;
struct {
char src_addr[16];
char dst_addr[16];
char src_port[2];
char dst_port[2];
} ip6;
struct {
char src_addr[108];
char dst_addr[108];
} unx;
} addr;
} v2;
} hdr;
read_buf(fd, (char*)&hdr, PROXY_V2_SIG_SIZE);
if (memcmp(hdr.v2.sig, proxyv2sig, PROXY_V2_SIG_SIZE) == 0) { /* Proxy V2 */
int ver, cmd, size;
read_buf(fd, (char*)&hdr + PROXY_V2_SIG_SIZE, PROXY_V2_HEADER_SIZE - PROXY_V2_SIG_SIZE);
ver = (hdr.v2.ver_cmd & 0xf0) >> 4;
cmd = (hdr.v2.ver_cmd & 0x0f);
size = (hdr.v2.len[0] << 8) + hdr.v2.len[1];
if (ver != 2 || size + PROXY_V2_HEADER_SIZE > (int)sizeof hdr)
return 0;
/* Grab all the remaining data in the binary request. */
read_buf(fd, (char*)&hdr + PROXY_V2_HEADER_SIZE, size);
switch (cmd) {
case CMD_PROXY:
switch (hdr.v2.fam) {
case PROXY_FAM_TCPv4:
if (size != sizeof hdr.v2.addr.ip4)
return 0;
inet_ntop(AF_INET, hdr.v2.addr.ip4.src_addr, ipaddr_buf, sizeof ipaddr_buf);
return valid_ipaddr(ipaddr_buf);
case PROXY_FAM_TCPv6:
if (size != sizeof hdr.v2.addr.ip6)
return 0;
inet_ntop(AF_INET6, hdr.v2.addr.ip6.src_addr, ipaddr_buf, sizeof ipaddr_buf);
return valid_ipaddr(ipaddr_buf);
default:
break;
}
/* For an unsupported protocol we'll ignore the proxy data (leaving ipaddr_buf unset)
* and accept the connection, which will get handled as a normal socket addr. */
return 1;
case CMD_LOCAL:
return 1;
default:
break;
}
return 0;
}
if (memcmp(hdr.v1.line, "PROXY", 5) == 0) { /* Proxy V1 */
char *endc, *sp, *p = hdr.v1.line + PROXY_V2_SIG_SIZE;
int port_chk;
*p = '\0';
if (!strchr(hdr.v1.line, '\n')) {
while (1) {
read_buf(fd, p, 1);
if (*p++ == '\n')
break;
if (p - hdr.v1.line >= (int)sizeof hdr.v1.line - 1)
return 0;
}
*p = '\0';
}
endc = strchr(hdr.v1.line, '\r');
if (!endc || endc[1] != '\n' || endc[2])
return 0;
*endc = '\0';
p = hdr.v1.line + 5;
if (!isSpace(p++))
return 0;
if (strncmp(p, "TCP4", 4) == 0)
p += 4;
else if (strncmp(p, "TCP6", 4) == 0)
p += 4;
else if (strncmp(p, "UNKNOWN", 7) == 0)
return 1;
else
return 0;
if (!isSpace(p++))
return 0;
if ((sp = strchr(p, ' ')) == NULL)
return 0;
*sp = '\0';
if (!valid_ipaddr(p))
return 0;
strlcpy(ipaddr_buf, p, sizeof ipaddr_buf); /* It will always fit when valid. */
p = sp + 1;
if ((sp = strchr(p, ' ')) == NULL)
return 0;
*sp = '\0';
if (!valid_ipaddr(p))
return 0;
/* Ignore destination address. */
p = sp + 1;
if ((sp = strchr(p, ' ')) == NULL)
return 0;
*sp = '\0';
port_chk = strtol(p, &endc, 10);
if (*endc || port_chk == 0)
return 0;
/* Ignore source port. */
p = sp + 1;
port_chk = strtol(p, &endc, 10);
if (*endc || port_chk == 0)
return 0;
/* Ignore destination port. */
return 1;
}
return 0;
}
/**
* Get the sockaddr for the client.
@@ -161,9 +314,7 @@ char *client_name(int fd)
* If it comes in as an ipv4 address mapped into IPv6 format then we
* convert it back to a regular IPv4.
**/
void client_sockaddr(int fd,
struct sockaddr_storage *ss,
socklen_t *ss_len)
static void client_sockaddr(int fd, struct sockaddr_storage *ss, socklen_t *ss_len)
{
memset(ss, 0, sizeof *ss);
@@ -174,8 +325,8 @@ void client_sockaddr(int fd,
}
#ifdef INET6
if (get_sockaddr_family(ss) == AF_INET6 &&
IN6_IS_ADDR_V4MAPPED(&((struct sockaddr_in6 *)ss)->sin6_addr)) {
if (GET_SOCKADDR_FAMILY(ss) == AF_INET6
&& IN6_IS_ADDR_V4MAPPED(&((struct sockaddr_in6 *)ss)->sin6_addr)) {
/* OK, so ss is in the IPv6 family, but it is really
* an IPv4 address: something like
* "::ffff:10.130.1.2". If we use it as-is, then the
@@ -198,51 +349,20 @@ void client_sockaddr(int fd,
/* There is a macro to extract the mapped part
* (IN6_V4MAPPED_TO_SINADDR ?), but it does not seem
* to be present in the Linux headers. */
memcpy(&sin->sin_addr, &sin6.sin6_addr.s6_addr[12],
sizeof sin->sin_addr);
memcpy(&sin->sin_addr, &sin6.sin6_addr.s6_addr[12], sizeof sin->sin_addr);
}
#endif
}
/**
* Look up a name from @p ss into @p name_buf.
*
* @param fd file descriptor for client socket.
**/
int lookup_name(int fd, const struct sockaddr_storage *ss,
socklen_t ss_len,
char *name_buf, size_t name_buf_size,
char *port_buf, size_t port_buf_size)
{
int name_err;
/* reverse lookup */
name_err = getnameinfo((struct sockaddr *) ss, ss_len,
name_buf, name_buf_size,
port_buf, port_buf_size,
NI_NAMEREQD | NI_NUMERICSERV);
if (name_err != 0) {
strlcpy(name_buf, default_name, name_buf_size);
rprintf(FLOG, "name lookup failed for %s: %s\n",
client_addr(fd), gai_strerror(name_err));
return name_err;
}
return 0;
}
/**
* Compare an addrinfo from the resolver to a sockinfo.
*
* Like strcmp, returns 0 for identical.
**/
int compare_addrinfo_sockaddr(const struct addrinfo *ai,
const struct sockaddr_storage *ss)
static int compare_addrinfo_sockaddr(const struct addrinfo *ai, const struct sockaddr_storage *ss)
{
int ss_family = get_sockaddr_family(ss);
int ss_family = GET_SOCKADDR_FAMILY(ss);
const char fn[] = "compare_addrinfo_sockaddr";
if (ai->ai_family != ss_family) {
@@ -258,8 +378,7 @@ int compare_addrinfo_sockaddr(const struct addrinfo *ai,
sin1 = (const struct sockaddr_in *) ss;
sin2 = (const struct sockaddr_in *) ai->ai_addr;
return memcmp(&sin1->sin_addr, &sin2->sin_addr,
sizeof sin1->sin_addr);
return memcmp(&sin1->sin_addr, &sin2->sin_addr, sizeof sin1->sin_addr);
}
#ifdef INET6
@@ -275,8 +394,7 @@ int compare_addrinfo_sockaddr(const struct addrinfo *ai,
return 1;
}
if (memcmp(&sin1->sin6_addr, &sin2->sin6_addr,
sizeof sin1->sin6_addr))
if (memcmp(&sin1->sin6_addr, &sin2->sin6_addr, sizeof sin1->sin6_addr))
return 1;
#ifdef HAVE_SOCKADDR_IN6_SCOPE_ID
@@ -302,13 +420,11 @@ int compare_addrinfo_sockaddr(const struct addrinfo *ai,
* because it doesn't seem that it could be spoofed in any way, and
* getaddrinfo on random service names seems to cause problems on AIX.
**/
int check_name(int fd,
const struct sockaddr_storage *ss,
char *name_buf, size_t name_buf_size)
static int check_name(const char *ipaddr, const struct sockaddr_storage *ss, char *name_buf, size_t name_buf_size)
{
struct addrinfo hints, *res, *res0;
int error;
int ss_family = get_sockaddr_family(ss);
int ss_family = GET_SOCKADDR_FAMILY(ss);
memset(&hints, 0, sizeof hints);
hints.ai_family = ss_family;
@@ -339,10 +455,74 @@ int check_name(int fd,
/* We hit the end of the list without finding an
* address that was the same as ss. */
rprintf(FLOG, "%s is not a known address for \"%s\": "
"spoofed address?\n", client_addr(fd), name_buf);
"spoofed address?\n", ipaddr, name_buf);
strlcpy(name_buf, default_name, name_buf_size);
}
freeaddrinfo(res0);
return 0;
}
/* Returns 1 for a valid IPv4 or IPv6 addr, or 0 for a bad one. */
static int valid_ipaddr(const char *s)
{
int i;
if (strchr(s, ':') != NULL) { /* Only IPv6 has a colon. */
int count, saw_double_colon = 0;
int ipv4_at_end = 0;
if (*s == ':') { /* A colon at the start must be a :: */
if (*++s != ':')
return 0;
saw_double_colon = 1;
s++;
}
for (count = 0; count < 8; count++) {
if (!*s)
return saw_double_colon && count < 7;
if (strchr(s, ':') == NULL && strchr(s, '.') != NULL) {
if ((!saw_double_colon && count != 6) || (saw_double_colon && count > 6))
return 0;
ipv4_at_end = 1;
break;
}
if (!isHexDigit(s++)) /* Need 1-4 hex digits */
return 0;
if (isHexDigit(s) && isHexDigit(++s) && isHexDigit(++s) && isHexDigit(++s))
return 0;
if (*s == ':') {
if (!*++s)
return 0;
if (*s == ':') {
if (saw_double_colon)
return 0;
saw_double_colon = 1;
s++;
}
}
}
if (!ipv4_at_end)
return !*s;
}
/* IPv4 */
for (i = 0; i < 4; i++) {
long n;
char *end;
if (i && *s++ != '.')
return 0;
n = strtol(s, &end, 10);
if (n > 255 || n < 0 || end <= s || end > s+3)
return 0;
s = end;
}
return !*s;
}

View File

@@ -3,7 +3,7 @@
*
* Copyright (C) 1998-2001 Andrew Tridgell <tridge@samba.org>
* Copyright (C) 2001-2002 Martin Pool <mbp@samba.org>
* Copyright (C) 2002-2014 Wayne Davison
* Copyright (C) 2002-2020 Wayne Davison
*
* 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
@@ -30,6 +30,7 @@ extern int am_sender;
extern int am_server;
extern int am_daemon;
extern int am_root;
extern int msgs2stderr;
extern int rsync_port;
extern int protect_args;
extern int ignore_errors;
@@ -59,12 +60,13 @@ extern filter_rule_list daemon_filter_list;
extern char *iconv_opt;
extern iconv_t ic_send, ic_recv;
#endif
#define MAX_GID_LIST 32
extern uid_t our_uid;
extern gid_t our_gid;
char *auth_user;
int read_only = 0;
int module_id = -1;
int pid_file_fd = -1;
struct chmod_mode_struct *daemon_chmod_modes;
/* module_dirlen is the length of the module_dir string when in daemon
@@ -81,8 +83,7 @@ static int rl_nulls = 0;
static struct sigaction sigact;
#endif
static gid_t gid_list[MAX_GID_LIST];
static int gid_count = 0;
static item_list gid_list = EMPTY_ITEM_LIST;
/* Used when "reverse lookup" is off. */
const char undetermined_hostname[] = "UNDETERMINED";
@@ -122,8 +123,7 @@ int start_socket_client(char *host, int remote_argc, char *remote_argv[],
*p = '\0';
}
fd = open_socket_out_wrapped(host, rsync_port, bind_address,
default_af_hint);
fd = open_socket_out_wrapped(host, rsync_port, bind_address, default_af_hint);
if (fd == -1)
exit_cleanup(RERR_SOCKETIO);
@@ -348,61 +348,6 @@ int start_inband_exchange(int f_in, int f_out, const char *user, int argc, char
return 0;
}
static char *finish_pre_exec(pid_t pid, int write_fd, int read_fd, char *request,
char **early_argv, char **argv)
{
char buf[BIGPATHBUFLEN], *bp;
int j = 0, status = -1, msglen = sizeof buf - 1;
if (!request)
request = "(NONE)";
write_buf(write_fd, request, strlen(request)+1);
if (early_argv) {
for ( ; *early_argv; early_argv++)
write_buf(write_fd, *early_argv, strlen(*early_argv)+1);
j = 1; /* Skip arg0 name in argv. */
}
for ( ; argv[j]; j++)
write_buf(write_fd, argv[j], strlen(argv[j])+1);
write_byte(write_fd, 0);
close(write_fd);
/* Read the stdout from the pre-xfer exec program. This it is only
* displayed to the user if the script also returns an error status. */
for (bp = buf; msglen > 0; msglen -= j) {
if ((j = read(read_fd, bp, msglen)) <= 0) {
if (j == 0)
break;
if (errno == EINTR)
continue;
break; /* Just ignore the read error for now... */
}
bp += j;
if (j > 1 && bp[-1] == '\n' && bp[-2] == '\r') {
bp--;
j--;
bp[-1] = '\n';
}
}
*bp = '\0';
close(read_fd);
if (wait_process(pid, &status, 0) < 0
|| !WIFEXITED(status) || WEXITSTATUS(status) != 0) {
char *e;
if (asprintf(&e, "pre-xfer exec returned failure (%d)%s%s%s\n%s",
status, status < 0 ? ": " : "",
status < 0 ? strerror(errno) : "",
*buf ? ":" : "", buf) < 0)
return "out_of_memory in finish_pre_exec\n";
return e;
}
return NULL;
}
#ifdef HAVE_PUTENV
static int read_arg_from_pipe(int fd, char *buf, int limit)
{
@@ -426,61 +371,6 @@ static int read_arg_from_pipe(int fd, char *buf, int limit)
}
#endif
static int path_failure(int f_out, const char *dir, BOOL was_chdir)
{
if (was_chdir)
rsyserr(FLOG, errno, "chdir %s failed\n", dir);
else
rprintf(FLOG, "normalize_path(%s) failed\n", dir);
io_printf(f_out, "@ERROR: chdir failed\n");
return -1;
}
static int add_a_group(int f_out, const char *gname)
{
gid_t gid;
if (!group_to_gid(gname, &gid, True)) {
rprintf(FLOG, "Invalid gid %s\n", gname);
io_printf(f_out, "@ERROR: invalid gid %s\n", gname);
return -1;
}
if (gid_count == MAX_GID_LIST) {
rprintf(FLOG, "Too many groups specified via gid parameter.\n");
io_printf(f_out, "@ERROR: too many groups\n");
return -1;
}
gid_list[gid_count++] = gid;
return 0;
}
#ifdef HAVE_GETGROUPLIST
static int want_all_groups(int f_out, uid_t uid)
{
const char *err;
gid_count = MAX_GID_LIST;
if ((err = getallgroups(uid, gid_list, &gid_count)) != NULL) {
rsyserr(FLOG, errno, "%s", err);
io_printf(f_out, "@ERROR: %s\n", err);
return -1;
}
return 0;
}
#elif defined HAVE_INITGROUPS
static struct passwd *want_all_groups(int f_out, uid_t uid)
{
struct passwd *pw;
if ((pw = getpwuid(uid)) == NULL) {
rsyserr(FLOG, errno, "getpwuid failed");
io_printf(f_out, "@ERROR: getpwuid failed\n");
return NULL;
}
/* Start with the default group and initgroups() will add the reset. */
gid_count = 1;
gid_list[0] = pw->pw_gid;
return pw;
}
#endif
static void set_env_str(const char *var, const char *str)
{
#ifdef HAVE_PUTENV
@@ -492,7 +382,7 @@ static void set_env_str(const char *var, const char *str)
}
#ifdef HAVE_PUTENV
static void set_env_num(const char *var, long num)
void set_env_num(const char *var, long num)
{
char *mem;
if (asprintf(&mem, "%s=%ld", var, num) < 0)
@@ -501,6 +391,199 @@ static void set_env_num(const char *var, long num)
}
#endif
/* Used for both early exec & pre-xfer exec */
static pid_t start_pre_exec(const char *cmd, int *arg_fd_ptr, int *error_fd_ptr)
{
int arg_fds[2], error_fds[2], arg_fd, error_fd;
pid_t pid;
if ((error_fd_ptr && pipe(error_fds) < 0) || (arg_fd_ptr && pipe(arg_fds) < 0) || (pid = fork()) < 0)
return (pid_t)-1;
if (pid == 0) {
char buf[BIGPATHBUFLEN];
int j, len, status;
if (error_fd_ptr) {
close(error_fds[0]);
error_fd = error_fds[1];
set_blocking(error_fd);
}
if (arg_fd_ptr) {
close(arg_fds[1]);
arg_fd = arg_fds[0];
set_blocking(arg_fd);
len = read_arg_from_pipe(arg_fd, buf, BIGPATHBUFLEN);
if (len <= 0)
_exit(1);
set_env_str("RSYNC_REQUEST", buf);
for (j = 0; ; j++) {
char *p;
len = read_arg_from_pipe(arg_fd, buf, BIGPATHBUFLEN);
if (len <= 0) {
if (!len)
break;
_exit(1);
}
if (asprintf(&p, "RSYNC_ARG%d=%s", j, buf) >= 0)
putenv(p);
}
close(arg_fd);
}
if (error_fd_ptr) {
close(STDIN_FILENO);
dup2(error_fd, STDOUT_FILENO);
close(error_fd);
}
status = shell_exec(cmd);
if (!WIFEXITED(status))
_exit(1);
_exit(WEXITSTATUS(status));
}
if (error_fd_ptr) {
close(error_fds[1]);
error_fd = *error_fd_ptr = error_fds[0];
set_blocking(error_fd);
}
if (arg_fd_ptr) {
close(arg_fds[0]);
arg_fd = *arg_fd_ptr = arg_fds[1];
set_blocking(arg_fd);
}
return pid;
}
static void write_pre_exec_args(int write_fd, char *request, char **early_argv, char **argv)
{
int j = 0;
if (!request)
request = "(NONE)";
write_buf(write_fd, request, strlen(request)+1);
if (early_argv) {
for ( ; *early_argv; early_argv++)
write_buf(write_fd, *early_argv, strlen(*early_argv)+1);
j = 1; /* Skip arg0 name in argv. */
}
for ( ; argv[j]; j++)
write_buf(write_fd, argv[j], strlen(argv[j])+1);
write_byte(write_fd, 0);
close(write_fd);
}
static char *finish_pre_exec(const char *desc, pid_t pid, int read_fd)
{
char buf[BIGPATHBUFLEN], *bp, *cr;
int j, status = -1, msglen = sizeof buf - 1;
if (read_fd >= 0) {
/* Read the stdout from the program. This it is only displayed
* to the user if the script also returns an error status. */
for (bp = buf, cr = buf; msglen > 0; msglen -= j) {
if ((j = read(read_fd, bp, msglen)) <= 0) {
if (j == 0)
break;
if (errno == EINTR)
continue;
break; /* Just ignore the read error for now... */
}
bp[j] = '\0';
while (1) {
if ((cr = strchr(cr, '\r')) == NULL) {
cr = bp + j;
break;
}
if (!cr[1])
break; /* wait for more data before we decide what to do */
if (cr[1] == '\n') {
memmove(cr, cr+1, j - (cr - bp));
j--;
} else
cr++;
}
bp += j;
}
*bp = '\0';
close(read_fd);
} else
*buf = '\0';
if (wait_process(pid, &status, 0) < 0
|| !WIFEXITED(status) || WEXITSTATUS(status) != 0) {
char *e;
if (asprintf(&e, "%s returned failure (%d)%s%s%s\n%s",
desc, status, status < 0 ? ": " : "",
status < 0 ? strerror(errno) : "",
*buf ? ":" : "", buf) < 0)
return "out_of_memory in finish_pre_exec\n";
return e;
}
return NULL;
}
static int path_failure(int f_out, const char *dir, BOOL was_chdir)
{
if (was_chdir)
rsyserr(FLOG, errno, "chdir %s failed", dir);
else
rprintf(FLOG, "normalize_path(%s) failed\n", dir);
io_printf(f_out, "@ERROR: chdir failed\n");
return -1;
}
static int add_a_group(int f_out, const char *gname)
{
gid_t gid, *gid_p;
if (!group_to_gid(gname, &gid, True)) {
rprintf(FLOG, "Invalid gid %s\n", gname);
io_printf(f_out, "@ERROR: invalid gid %s\n", gname);
return -1;
}
gid_p = EXPAND_ITEM_LIST(&gid_list, gid_t, -32);
*gid_p = gid;
return 0;
}
#ifdef HAVE_GETGROUPLIST
static int want_all_groups(int f_out, uid_t uid)
{
const char *err;
if ((err = getallgroups(uid, &gid_list)) != NULL) {
rsyserr(FLOG, errno, "%s", err);
io_printf(f_out, "@ERROR: %s\n", err);
return -1;
}
return 0;
}
#elif defined HAVE_INITGROUPS
static struct passwd *want_all_groups(int f_out, uid_t uid)
{
struct passwd *pw;
gid_t *gid_p;
if ((pw = getpwuid(uid)) == NULL) {
rsyserr(FLOG, errno, "getpwuid failed");
io_printf(f_out, "@ERROR: getpwuid failed\n");
return NULL;
}
/* Start with the default group and initgroups() will add the rest. */
gid_p = EXPAND_ITEM_LIST(&gid_list, gid_t, -32);
*gid_p = pw->pw_gid;
return pw;
}
#endif
static int rsync_module(int f_in, int f_out, int i, const char *addr, const char *host)
{
int argc;
@@ -531,7 +614,7 @@ static int rsync_module(int f_in, int f_out, int i, const char *addr, const char
/* If reverse lookup is disabled globally but enabled for this module,
* we need to do it now before the access check. */
if (host == undetermined_hostname && lp_reverse_lookup(i))
host = client_name(f_in);
host = client_name(client_addr(f_in));
set_env_str("RSYNC_HOST_NAME", host);
set_env_str("RSYNC_HOST_ADDR", addr);
@@ -548,7 +631,7 @@ static int rsync_module(int f_in, int f_out, int i, const char *addr, const char
return -1;
}
if (am_daemon && am_server) {
if (am_daemon > 0) {
rprintf(FLOG, "rsync allowed access on module %s from %s (%s)\n",
name, host, addr);
}
@@ -599,7 +682,7 @@ static int rsync_module(int f_in, int f_out, int i, const char *addr, const char
} else
set_uid = 0;
p = *lp_gid(i) ? strtok(lp_gid(i), ", ") : NULL;
p = *lp_gid(i) ? conf_strtok(lp_gid(i)) : NULL;
if (p) {
/* The "*" gid must be the first item in the list. */
if (strcmp(p, "*") == 0) {
@@ -616,7 +699,7 @@ static int rsync_module(int f_in, int f_out, int i, const char *addr, const char
#endif
} else if (add_a_group(f_out, p) < 0)
return -1;
while ((p = strtok(NULL, ", ")) != NULL) {
while ((p = conf_strtok(NULL)) != NULL) {
#if defined HAVE_INITGROUPS && !defined HAVE_GETGROUPLIST
if (pw) {
rprintf(FLOG, "This rsync cannot add groups after \"*\".\n");
@@ -671,30 +754,31 @@ static int rsync_module(int f_in, int f_out, int i, const char *addr, const char
p = lp_filter(i);
parse_filter_str(&daemon_filter_list, p, rule_template(FILTRULE_WORD_SPLIT),
XFLG_ABS_IF_SLASH | XFLG_DIR2WILD3);
XFLG_ABS_IF_SLASH | XFLG_DIR2WILD3);
p = lp_include_from(i);
parse_filter_file(&daemon_filter_list, p, rule_template(FILTRULE_INCLUDE),
XFLG_ABS_IF_SLASH | XFLG_DIR2WILD3 | XFLG_OLD_PREFIXES | XFLG_FATAL_ERRORS);
XFLG_ABS_IF_SLASH | XFLG_DIR2WILD3 | XFLG_OLD_PREFIXES | XFLG_FATAL_ERRORS);
p = lp_include(i);
parse_filter_str(&daemon_filter_list, p,
rule_template(FILTRULE_INCLUDE | FILTRULE_WORD_SPLIT),
XFLG_ABS_IF_SLASH | XFLG_DIR2WILD3 | XFLG_OLD_PREFIXES);
rule_template(FILTRULE_INCLUDE | FILTRULE_WORD_SPLIT),
XFLG_ABS_IF_SLASH | XFLG_DIR2WILD3 | XFLG_OLD_PREFIXES);
p = lp_exclude_from(i);
parse_filter_file(&daemon_filter_list, p, rule_template(0),
XFLG_ABS_IF_SLASH | XFLG_DIR2WILD3 | XFLG_OLD_PREFIXES | XFLG_FATAL_ERRORS);
XFLG_ABS_IF_SLASH | XFLG_DIR2WILD3 | XFLG_OLD_PREFIXES | XFLG_FATAL_ERRORS);
p = lp_exclude(i);
parse_filter_str(&daemon_filter_list, p, rule_template(FILTRULE_WORD_SPLIT),
XFLG_ABS_IF_SLASH | XFLG_DIR2WILD3 | XFLG_OLD_PREFIXES);
XFLG_ABS_IF_SLASH | XFLG_DIR2WILD3 | XFLG_OLD_PREFIXES);
log_init(1);
#ifdef HAVE_PUTENV
if (*lp_prexfer_exec(i) || *lp_postxfer_exec(i)) {
int status;
if ((*lp_early_exec(i) || *lp_prexfer_exec(i) || *lp_postxfer_exec(i))
&& !getenv("RSYNC_NO_XFER_EXEC")) {
set_env_num("RSYNC_PID", (long)getpid());
/* For post-xfer exec, fork a new process to run the rsync
* daemon while this process waits for the exit status and
@@ -707,10 +791,10 @@ static int rsync_module(int f_in, int f_out, int i, const char *addr, const char
return -1;
}
if (pid) {
int status;
close(f_in);
if (f_out != f_in)
close(f_out);
set_env_num("RSYNC_PID", (long)pid);
if (wait_process(pid, &status, 0) < 0)
status = -1;
set_env_num("RSYNC_RAW_STATUS", status);
@@ -719,61 +803,38 @@ static int rsync_module(int f_in, int f_out, int i, const char *addr, const char
else
status = -1;
set_env_num("RSYNC_EXIT_STATUS", status);
if (system(lp_postxfer_exec(i)) < 0)
if (shell_exec(lp_postxfer_exec(i)) < 0)
status = -1;
_exit(status);
}
}
/* For early exec, fork a child process to run the indicated
* command and wait for it to exit. */
if (*lp_early_exec(i)) {
pid_t pid = start_pre_exec(lp_early_exec(i), NULL, NULL);
if (pid == (pid_t)-1) {
rsyserr(FLOG, errno, "early exec preparation failed");
io_printf(f_out, "@ERROR: early exec preparation failed\n");
return -1;
}
if (finish_pre_exec("early exec", pid, -1) != NULL) {
rsyserr(FLOG, errno, "early exec failed");
io_printf(f_out, "@ERROR: early exec failed\n");
return -1;
}
}
/* For pre-xfer exec, fork a child process to run the indicated
* command, though it first waits for the parent process to
* send us the user's request via a pipe. */
if (*lp_prexfer_exec(i)) {
int arg_fds[2], error_fds[2];
set_env_num("RSYNC_PID", (long)getpid());
if (pipe(arg_fds) < 0 || pipe(error_fds) < 0 || (pre_exec_pid = fork()) < 0) {
pre_exec_pid = start_pre_exec(lp_prexfer_exec(i), &pre_exec_arg_fd, &pre_exec_error_fd);
if (pre_exec_pid == (pid_t)-1) {
rsyserr(FLOG, errno, "pre-xfer exec preparation failed");
io_printf(f_out, "@ERROR: pre-xfer exec preparation failed\n");
return -1;
}
if (pre_exec_pid == 0) {
char buf[BIGPATHBUFLEN];
int j, len;
close(arg_fds[1]);
close(error_fds[0]);
pre_exec_arg_fd = arg_fds[0];
pre_exec_error_fd = error_fds[1];
set_blocking(pre_exec_arg_fd);
set_blocking(pre_exec_error_fd);
len = read_arg_from_pipe(pre_exec_arg_fd, buf, BIGPATHBUFLEN);
if (len <= 0)
_exit(1);
set_env_str("RSYNC_REQUEST", buf);
for (j = 0; ; j++) {
len = read_arg_from_pipe(pre_exec_arg_fd, buf,
BIGPATHBUFLEN);
if (len <= 0) {
if (!len)
break;
_exit(1);
}
if (asprintf(&p, "RSYNC_ARG%d=%s", j, buf) >= 0)
putenv(p);
}
close(pre_exec_arg_fd);
close(STDIN_FILENO);
dup2(pre_exec_error_fd, STDOUT_FILENO);
close(pre_exec_error_fd);
status = system(lp_prexfer_exec(i));
if (!WIFEXITED(status))
_exit(1);
_exit(WEXITSTATUS(status));
}
close(arg_fds[0]);
close(error_fds[1]);
pre_exec_arg_fd = arg_fds[1];
pre_exec_error_fd = error_fds[0];
set_blocking(pre_exec_arg_fd);
set_blocking(pre_exec_error_fd);
}
}
#endif
@@ -801,7 +862,7 @@ static int rsync_module(int f_in, int f_out, int i, const char *addr, const char
if (!change_dir(module_chdir, CD_NORMAL))
return path_failure(f_out, module_chdir, True);
if (module_dirlen || !use_chroot)
if (module_dirlen || (!use_chroot && !*lp_daemon_chroot()))
sanitize_paths = 1;
if ((munge_symlinks = lp_munge_symlinks(i)) < 0)
@@ -818,15 +879,16 @@ static int rsync_module(int f_in, int f_out, int i, const char *addr, const char
}
}
if (gid_count) {
if (setgid(gid_list[0])) {
rsyserr(FLOG, errno, "setgid %ld failed", (long)gid_list[0]);
if (gid_list.count) {
gid_t *gid_array = gid_list.items;
if (setgid(gid_array[0])) {
rsyserr(FLOG, errno, "setgid %ld failed", (long)gid_array[0]);
io_printf(f_out, "@ERROR: setgid failed\n");
return -1;
}
#ifdef HAVE_SETGROUPS
/* Set the group(s) we want to be active. */
if (setgroups(gid_count, gid_list)) {
if (setgroups(gid_list.count, gid_array)) {
rsyserr(FLOG, errno, "setgroups failed");
io_printf(f_out, "@ERROR: setgroups failed\n");
return -1;
@@ -840,6 +902,7 @@ static int rsync_module(int f_in, int f_out, int i, const char *addr, const char
return -1;
}
#endif
our_gid = MY_GID();
}
if (set_uid) {
@@ -853,7 +916,8 @@ static int rsync_module(int f_in, int f_out, int i, const char *addr, const char
return -1;
}
am_root = (MY_UID() == 0);
our_uid = MY_UID();
am_root = (our_uid == 0);
}
if (lp_temp_dir(i) && *lp_temp_dir(i)) {
@@ -885,10 +949,12 @@ static int rsync_module(int f_in, int f_out, int i, const char *addr, const char
orig_early_argv = NULL;
munge_symlinks = save_munge_symlinks; /* The client mustn't control this. */
if (am_daemon > 0)
msgs2stderr = 0; /* A non-rsh-run daemon doesn't have stderr for msgs. */
if (pre_exec_pid) {
err_msg = finish_pre_exec(pre_exec_pid, pre_exec_arg_fd, pre_exec_error_fd,
request, orig_early_argv, orig_argv);
write_pre_exec_args(pre_exec_arg_fd, request, orig_early_argv, orig_argv);
err_msg = finish_pre_exec("pre-xfer exec", pre_exec_pid, pre_exec_error_fd);
}
if (orig_early_argv)
@@ -929,8 +995,7 @@ static int rsync_module(int f_in, int f_out, int i, const char *addr, const char
limit_output_verbosity(lp_max_verbosity(i));
#endif
if (protocol_version < 23
&& (protocol_version == 22 || am_sender))
if (protocol_version < 23 && (protocol_version == 22 || am_sender))
io_start_multiplex_out(f_out);
else if (!ret || err_msg) {
/* We have to get I/O multiplexing started so that we can
@@ -967,6 +1032,7 @@ static int rsync_module(int f_in, int f_out, int i, const char *addr, const char
}
if (*err_msg)
rprintf(FERROR, "%s\n", err_msg);
io_flush(MSG_FLUSH);
} else
option_error();
msleep(400);
@@ -1030,7 +1096,7 @@ static void send_listing(int fd)
static int load_config(int globals_only)
{
if (!config_file) {
if (am_server && am_root <= 0)
if (am_daemon < 0 && am_root <= 0)
config_file = RSYNCD_USERCONF;
else
config_file = RSYNCD_SYSCONF;
@@ -1045,8 +1111,16 @@ int start_daemon(int f_in, int f_out)
{
char line[1024];
const char *addr, *host;
char *p;
int i;
/* At this point, am_server is only set for a daemon started via rsh.
* Because am_server gets forced on soon, we'll set am_daemon to -1 as
* a flag that can be checked later on to distinguish a normal daemon
* from an rsh-run daemon. */
if (am_server)
am_daemon = -1;
io_set_sock_fds(f_in, f_out);
/* We must load the config file before calling any function that
@@ -1056,11 +1130,50 @@ int start_daemon(int f_in, int f_out)
if (!load_config(0))
exit_cleanup(RERR_SYNTAX);
if (lp_proxy_protocol() && !read_proxy_protocol_header(f_in))
return -1;
p = lp_daemon_chroot();
if (*p) {
log_init(0); /* Make use we've initialized syslog before chrooting. */
if (chroot(p) < 0 || chdir("/") < 0) {
rsyserr(FLOG, errno, "daemon chroot %s failed", p);
return -1;
}
}
p = lp_daemon_gid();
if (*p) {
gid_t gid;
if (!group_to_gid(p, &gid, True)) {
rprintf(FLOG, "Invalid daemon gid: %s\n", p);
return -1;
}
if (setgid(gid) < 0) {
rsyserr(FLOG, errno, "Unable to set group to daemon gid %ld", (long)gid);
return -1;
}
our_gid = MY_GID();
}
p = lp_daemon_uid();
if (*p) {
uid_t uid;
if (!user_to_uid(p, &uid, True)) {
rprintf(FLOG, "Invalid daemon uid: %s\n", p);
return -1;
}
if (setuid(uid) < 0) {
rsyserr(FLOG, errno, "Unable to set user to daemon uid %ld", (long)uid);
return -1;
}
our_uid = MY_UID();
am_root = (our_uid == 0);
}
addr = client_addr(f_in);
host = lp_reverse_lookup(-1) ? client_name(f_in) : undetermined_hostname;
host = lp_reverse_lookup(-1) ? client_name(addr) : undetermined_hostname;
rprintf(FLOG, "connect from %s (%s)\n", host, addr);
if (!am_server) {
if (am_daemon > 0) {
set_socket_options(f_in, "SO_KEEPALIVE");
set_nonblocking(f_in);
}
@@ -1103,26 +1216,65 @@ int start_daemon(int f_in, int f_out)
static void create_pid_file(void)
{
char *pid_file = lp_pid_file();
char pidbuf[16];
pid_t pid = getpid();
int fd, len;
char pidbuf[32];
STRUCT_STAT st1, st2;
char *fail = NULL;
if (!pid_file || !*pid_file)
return;
cleanup_set_pid(pid);
if ((fd = do_open(pid_file, O_WRONLY|O_CREAT|O_EXCL, 0666)) == -1) {
failure:
cleanup_set_pid(0);
fprintf(stderr, "failed to create pid file %s: %s\n", pid_file, strerror(errno));
rsyserr(FLOG, errno, "failed to create pid file %s", pid_file);
#ifdef O_NOFOLLOW
#define SAFE_OPEN_FLAGS (O_CREAT|O_NOFOLLOW)
#else
#define SAFE_OPEN_FLAGS (O_CREAT)
#endif
/* These tests make sure that a temp-style lock dir is handled safely. */
st1.st_mode = 0;
if (do_lstat(pid_file, &st1) == 0 && !S_ISREG(st1.st_mode) && unlink(pid_file) < 0)
fail = "unlink";
else if ((pid_file_fd = do_open(pid_file, O_RDWR|SAFE_OPEN_FLAGS, 0664)) < 0)
fail = S_ISREG(st1.st_mode) ? "open" : "create";
else if (!lock_range(pid_file_fd, 0, 4))
fail = "lock";
else if (do_fstat(pid_file_fd, &st1) < 0)
fail = "fstat opened";
else if (st1.st_size > (int)sizeof pidbuf)
fail = "find small";
else if (do_lstat(pid_file, &st2) < 0)
fail = "lstat";
else if (!S_ISREG(st1.st_mode))
fail = "avoid file overwrite race for";
else if (st1.st_dev != st2.st_dev || st1.st_ino != st2.st_ino)
fail = "verify stat info for";
#ifdef HAVE_FTRUNCATE
else if (do_ftruncate(pid_file_fd, 0) < 0)
fail = "truncate";
#endif
else {
pid_t pid = getpid();
int len = snprintf(pidbuf, sizeof pidbuf, "%d\n", (int)pid);
#ifndef HAVE_FTRUNCATE
/* What can we do with a too-long file and no truncate? I guess we'll add extra newlines. */
while (len < st1.st_size) /* We already verified that st_size chars fits in the buffer. */
pidbuf[len++] = '\n';
/* We don't need the buffer to end in a '\0' (and we may not have room to add it). */
#endif
if (write(pid_file_fd, pidbuf, len) != len)
fail = "write";
cleanup_set_pid(pid); /* Mark the file for removal on exit, even if the write failed. */
}
if (fail) {
char msg[1024];
snprintf(msg, sizeof msg, "failed to %s pid file %s: %s\n",
fail, pid_file, strerror(errno));
fputs(msg, stderr);
rprintf(FLOG, "%s", msg);
exit_cleanup(RERR_FILEIO);
}
snprintf(pidbuf, sizeof pidbuf, "%d\n", (int)pid);
len = strlen(pidbuf);
if (write(fd, pidbuf, len) != len)
goto failure;
close(fd);
/* The file is left open so that the lock remains valid. It is closed in our forked child procs. */
}
/* Become a daemon, discarding the controlling terminal. */

435
compat.c
View File

@@ -3,7 +3,7 @@
*
* Copyright (C) Andrew Tridgell 1996
* Copyright (C) Paul Mackerras 1996
* Copyright (C) 2004-2014 Wayne Davison
* Copyright (C) 2004-2020 Wayne Davison
*
* 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
@@ -21,12 +21,6 @@
#include "rsync.h"
int remote_protocol = 0;
int file_extra_cnt = 0; /* count of file-list extras that everyone gets */
int inc_recurse = 0;
int compat_flags = 0;
int use_safe_inc_flist = 0;
extern int am_server;
extern int am_sender;
extern int local_server;
@@ -38,6 +32,7 @@ extern int preallocate_files;
extern int append_mode;
extern int fuzzy_basis;
extern int read_batch;
extern int write_batch;
extern int delay_updates;
extern int checksum_seed;
extern int basis_dir_cnt;
@@ -46,24 +41,40 @@ extern int protocol_version;
extern int protect_args;
extern int preserve_uid;
extern int preserve_gid;
extern int preserve_atimes;
extern int preserve_acls;
extern int preserve_xattrs;
extern int xfer_flags_as_varint;
extern int need_messages_from_generator;
extern int delete_mode, delete_before, delete_during, delete_after;
extern int do_compression;
extern int do_compression_level;
extern char *shell_cmd;
extern char *partial_dir;
extern char *dest_option;
extern char *files_from;
extern char *filesfrom_host;
extern const char *checksum_choice;
extern const char *compress_choice;
extern filter_rule_list filter_list;
extern int need_unsorted_flist;
#ifdef ICONV_OPTION
extern iconv_t ic_send, ic_recv;
extern char *iconv_opt;
#endif
extern struct name_num_obj valid_checksums;
int remote_protocol = 0;
int file_extra_cnt = 0; /* count of file-list extras that everyone gets */
int inc_recurse = 0;
int compat_flags = 0;
int use_safe_inc_flist = 0;
int want_xattr_optim = 0;
int proper_seed_order = 0;
int inplace_partial = 0;
int do_negotiated_strings = 0;
/* These index values are for the file-list's extra-attribute array. */
int uid_ndx, gid_ndx, acls_ndx, xattrs_ndx, unsort_ndx;
int pathname_ndx, depth_ndx, atimes_ndx, uid_ndx, gid_ndx, acls_ndx, xattrs_ndx, unsort_ndx;
int receiver_symlink_times = 0; /* receiver can set the time on a symlink */
int sender_symlink_iconv = 0; /* sender should convert symlink content */
@@ -72,10 +83,31 @@ int sender_symlink_iconv = 0; /* sender should convert symlink content */
int filesfrom_convert = 0;
#endif
#define MAX_NSTR_STRLEN 256
struct name_num_obj valid_compressions = {
"compress", NULL, NULL, 0, 0, {
#ifdef SUPPORT_ZSTD
{ CPRES_ZSTD, "zstd", NULL },
#endif
#ifdef SUPPORT_LZ4
{ CPRES_LZ4, "lz4", NULL },
#endif
{ CPRES_ZLIBX, "zlibx", NULL },
{ CPRES_ZLIB, "zlib", NULL },
{ CPRES_NONE, "none", NULL },
{ 0, NULL, NULL }
}
};
#define CF_INC_RECURSE (1<<0)
#define CF_SYMLINK_TIMES (1<<1)
#define CF_SYMLINK_ICONV (1<<2)
#define CF_SAFE_FLIST (1<<3)
#define CF_AVOID_XATTR_OPTIM (1<<4)
#define CF_CHKSUM_SEED_FIX (1<<5)
#define CF_INPLACE_PARTIAL_DIR (1<<6)
#define CF_VARINT_FLIST_FLAGS (1<<7)
static const char *client_info;
@@ -130,12 +162,308 @@ void set_allow_inc_recurse(void)
allow_inc_recurse = 0;
}
void parse_compress_choice(int final_call)
{
if (valid_compressions.negotiated_name)
do_compression = valid_compressions.negotiated_num;
else if (compress_choice) {
struct name_num_item *nni = get_nni_by_name(&valid_compressions, compress_choice, -1);
if (!nni) {
rprintf(FERROR, "unknown compress name: %s\n", compress_choice);
exit_cleanup(RERR_UNSUPPORTED);
}
do_compression = nni->num;
} else if (do_compression)
do_compression = CPRES_ZLIB;
else
do_compression = CPRES_NONE;
if (do_compression != CPRES_NONE && final_call)
init_compression_level(); /* There's a chance this might turn compression off! */
if (do_compression == CPRES_NONE)
compress_choice = NULL;
/* Snag the compression name for both write_batch's option output & the following debug output. */
if (valid_compressions.negotiated_name)
compress_choice = valid_compressions.negotiated_name;
else if (compress_choice == NULL) {
struct name_num_item *nni = get_nni_by_num(&valid_compressions, do_compression);
compress_choice = nni ? nni->name : "UNKNOWN";
}
if (final_call && DEBUG_GTE(NSTR, am_server ? 3 : 1)
&& (do_compression != CPRES_NONE || do_compression_level != CLVL_NOT_SPECIFIED)) {
rprintf(FINFO, "%s%s compress: %s (level %d)\n",
am_server ? "Server" : "Client",
valid_compressions.negotiated_name ? " negotiated" : "",
compress_choice, do_compression_level);
}
}
struct name_num_item *get_nni_by_name(struct name_num_obj *nno, const char *name, int len)
{
struct name_num_item *nni;
if (len < 0)
len = strlen(name);
for (nni = nno->list; nni->name; nni++) {
if (strncasecmp(name, nni->name, len) == 0 && nni->name[len] == '\0')
return nni;
}
return NULL;
}
struct name_num_item *get_nni_by_num(struct name_num_obj *nno, int num)
{
struct name_num_item *nni;
for (nni = nno->list; nni->name; nni++) {
if (num == nni->num)
return nni;
}
return NULL;
}
static void init_nno_saw(struct name_num_obj *nno, int val)
{
struct name_num_item *nni;
int cnt;
if (!nno->saw_len) {
for (nni = nno->list; nni->name; nni++) {
if (nni->num >= nno->saw_len)
nno->saw_len = nni->num + 1;
}
}
if (!nno->saw) {
if (!(nno->saw = new_array0(uchar, nno->saw_len)))
out_of_memory("init_nno_saw");
/* We'll take this opportunity to make sure that the main_name values are set right. */
for (cnt = 1, nni = nno->list; nni->name; nni++, cnt++) {
if (nno->saw[nni->num])
nni->main_name = nno->list[nno->saw[nni->num]-1].name;
else
nno->saw[nni->num] = cnt;
}
}
memset(nno->saw, val, nno->saw_len);
}
/* Simplify the user-provided string so that it contains valid names without any duplicates.
* It also sets the "saw" flags to a 1-relative count of which name was seen first. */
static int parse_nni_str(struct name_num_obj *nno, const char *from, char *tobuf, int tobuf_len)
{
char *to = tobuf, *tok = NULL;
int cnt = 0;
while (1) {
if (*from == ' ' || !*from) {
if (tok) {
struct name_num_item *nni = get_nni_by_name(nno, tok, to - tok);
if (nni && !nno->saw[nni->num]) {
nno->saw[nni->num] = ++cnt;
if (nni->main_name) {
to = tok + strlcpy(tok, nni->main_name, tobuf_len - (tok - tobuf));
if (to - tobuf >= tobuf_len) {
to = tok - 1;
break;
}
}
} else
to = tok - (tok != tobuf);
tok = NULL;
}
if (!*from++)
break;
continue;
}
if (!tok) {
if (to != tobuf)
*to++ = ' ';
tok = to;
}
if (to - tobuf >= tobuf_len - 1) {
to = tok - (tok != tobuf);
break;
}
*to++ = *from++;
}
*to = '\0';
return to - tobuf;
}
static void recv_negotiate_str(int f_in, struct name_num_obj *nno, char *tmpbuf, int len)
{
struct name_num_item *ret = NULL;
if (len < 0)
len = read_vstring(f_in, tmpbuf, MAX_NSTR_STRLEN);
if (DEBUG_GTE(NSTR, am_server ? 3 : 2)) {
if (am_server)
rprintf(FINFO, "Client %s list (on server): %s\n", nno->type, tmpbuf);
else
rprintf(FINFO, "Server %s list (on client): %s\n", nno->type, tmpbuf);
}
if (len > 0) {
int best = nno->saw_len; /* We want best == 1 from the client list, so start with a big number. */
char *tok;
if (am_server)
init_nno_saw(nno, 1); /* Since we're parsing client names, anything we parse first is #1. */
for (tok = strtok(tmpbuf, " \t"); tok; tok = strtok(NULL, " \t")) {
struct name_num_item *nni = get_nni_by_name(nno, tok, -1);
if (!nni || !nno->saw[nni->num] || best <= nno->saw[nni->num])
continue;
ret = nni;
best = nno->saw[nni->num];
if (best == 1)
break;
}
if (ret) {
free(nno->saw);
nno->saw = NULL;
nno->negotiated_name = ret->main_name ? ret->main_name : ret->name;
nno->negotiated_num = ret->num;
return;
}
}
if (!am_server)
rprintf(FERROR, "Failed to negotiate a common %s\n", nno->type);
exit_cleanup(RERR_UNSUPPORTED);
}
/* The saw buffer is initialized and used to store ordinal values from 1 to N
* for the order of the args in the array. If dup_markup == '\0', duplicates
* are removed otherwise the char is prefixed to the duplicate term and, if it
* is an opening paren/bracket/brace, the matching closing char is suffixed. */
int get_default_nno_list(struct name_num_obj *nno, char *to_buf, int to_buf_len, char dup_markup)
{
struct name_num_item *nni;
int len = 0, cnt = 0;
char delim = '\0', post_delim;
switch (dup_markup) {
case '(': post_delim = ')'; break;
case '[': post_delim = ']'; break;
case '{': post_delim = '}'; break;
default: post_delim = '\0'; break;
}
init_nno_saw(nno, 0);
for (nni = nno->list, len = 0; nni->name; nni++) {
if (nni->main_name) {
if (!dup_markup)
continue;
delim = dup_markup;
}
if (len)
to_buf[len++]= ' ';
if (delim) {
to_buf[len++]= delim;
delim = post_delim;
}
len += strlcpy(to_buf+len, nni->name, to_buf_len - len);
if (len >= to_buf_len - 3)
exit_cleanup(RERR_UNSUPPORTED); /* IMPOSSIBLE... */
if (delim) {
to_buf[len++]= delim;
delim = '\0';
}
nno->saw[nni->num] = ++cnt;
}
return len;
}
static void send_negotiate_str(int f_out, struct name_num_obj *nno, const char *env_name)
{
char tmpbuf[MAX_NSTR_STRLEN];
const char *list_str = getenv(env_name);
int len, fail_if_empty = list_str && strstr(list_str, "FAIL");
if (!do_negotiated_strings) {
if (!am_server && fail_if_empty) {
rprintf(FERROR, "Remote rsync is too old for %s negotation\n", nno->type);
exit_cleanup(RERR_UNSUPPORTED);
}
return;
}
if (list_str && *list_str && (!am_server || local_server)) {
init_nno_saw(nno, 0);
len = parse_nni_str(nno, list_str, tmpbuf, MAX_NSTR_STRLEN);
if (fail_if_empty && !len)
len = strlcpy(tmpbuf, "FAIL", MAX_NSTR_STRLEN);
list_str = tmpbuf;
} else
list_str = NULL;
if (!list_str || !*list_str)
len = get_default_nno_list(nno, tmpbuf, MAX_NSTR_STRLEN, '\0');
if (DEBUG_GTE(NSTR, am_server ? 3 : 2)) {
if (am_server)
rprintf(FINFO, "Server %s list (on server): %s\n", nno->type, tmpbuf);
else
rprintf(FINFO, "Client %s list (on client): %s\n", nno->type, tmpbuf);
}
if (local_server) {
/* A local server doesn't bother to send/recv the strings, it just constructs
* and parses the same string on both sides. */
recv_negotiate_str(-1, nno, tmpbuf, len);
} else {
/* Each side sends their list of valid names to the other side and then both sides
* pick the first name in the client's list that is also in the server's list. */
write_vstring(f_out, tmpbuf, len);
}
}
static void negotiate_the_strings(int f_in, int f_out)
{
/* We send all the negotiation strings before we start to read them to help avoid a slow startup. */
if (!checksum_choice)
send_negotiate_str(f_out, &valid_checksums, "RSYNC_CHECKSUM_LIST");
if (do_compression && !compress_choice)
send_negotiate_str(f_out, &valid_compressions, "RSYNC_COMPRESS_LIST");
if (valid_checksums.saw) {
char tmpbuf[MAX_NSTR_STRLEN];
recv_negotiate_str(f_in, &valid_checksums, tmpbuf, -1);
}
if (valid_compressions.saw) {
char tmpbuf[MAX_NSTR_STRLEN];
recv_negotiate_str(f_in, &valid_compressions, tmpbuf, -1);
}
}
void setup_protocol(int f_out,int f_in)
{
if (am_sender)
file_extra_cnt += PTR_EXTRA_CNT;
assert(file_extra_cnt == 0);
assert(EXTRA64_CNT == 2 || EXTRA64_CNT == 1);
/* All int64 values must be set first so that they are guaranteed to be
* aligned for direct int64-pointer memory access. */
if (preserve_atimes)
atimes_ndx = (file_extra_cnt += EXTRA64_CNT);
if (am_sender) /* This is most likely in the in64 union as well. */
pathname_ndx = (file_extra_cnt += PTR_EXTRA_CNT);
else
file_extra_cnt++;
depth_ndx = ++file_extra_cnt;
if (preserve_uid)
uid_ndx = ++file_extra_cnt;
if (preserve_gid)
@@ -203,16 +531,16 @@ void setup_protocol(int f_out,int f_in)
append_mode = 2;
if (preserve_acls && !local_server) {
rprintf(FERROR,
"--acls requires protocol 30 or higher"
" (negotiated %d).\n",
protocol_version);
"--acls requires protocol 30 or higher"
" (negotiated %d).\n",
protocol_version);
exit_cleanup(RERR_PROTOCOL);
}
if (preserve_xattrs && !local_server) {
rprintf(FERROR,
"--xattrs requires protocol 30 or higher"
" (negotiated %d).\n",
protocol_version);
"--xattrs requires protocol 30 or higher"
" (negotiated %d).\n",
protocol_version);
exit_cleanup(RERR_PROTOCOL);
}
}
@@ -227,33 +555,33 @@ void setup_protocol(int f_out,int f_in)
if (protocol_version < 29) {
if (fuzzy_basis) {
rprintf(FERROR,
"--fuzzy requires protocol 29 or higher"
" (negotiated %d).\n",
protocol_version);
"--fuzzy requires protocol 29 or higher"
" (negotiated %d).\n",
protocol_version);
exit_cleanup(RERR_PROTOCOL);
}
if (basis_dir_cnt && inplace) {
rprintf(FERROR,
"%s with --inplace requires protocol 29 or higher"
" (negotiated %d).\n",
dest_option, protocol_version);
"%s with --inplace requires protocol 29 or higher"
" (negotiated %d).\n",
alt_dest_opt(0), protocol_version);
exit_cleanup(RERR_PROTOCOL);
}
if (basis_dir_cnt > 1) {
rprintf(FERROR,
"Using more than one %s option requires protocol"
" 29 or higher (negotiated %d).\n",
dest_option, protocol_version);
"Using more than one %s option requires protocol"
" 29 or higher (negotiated %d).\n",
alt_dest_opt(0), protocol_version);
exit_cleanup(RERR_PROTOCOL);
}
if (prune_empty_dirs) {
rprintf(FERROR,
"--prune-empty-dirs requires protocol 29 or higher"
" (negotiated %d).\n",
protocol_version);
"--prune-empty-dirs requires protocol 29 or higher"
" (negotiated %d).\n",
protocol_version);
exit_cleanup(RERR_PROTOCOL);
}
} else if (protocol_version >= 30) {
@@ -267,11 +595,34 @@ void setup_protocol(int f_out,int f_in)
#endif
if (local_server || strchr(client_info, 'f') != NULL)
compat_flags |= CF_SAFE_FLIST;
write_byte(f_out, compat_flags);
} else
compat_flags = read_byte(f_in);
if (local_server || strchr(client_info, 'x') != NULL)
compat_flags |= CF_AVOID_XATTR_OPTIM;
if (local_server || strchr(client_info, 'C') != NULL)
compat_flags |= CF_CHKSUM_SEED_FIX;
if (local_server || strchr(client_info, 'I') != NULL)
compat_flags |= CF_INPLACE_PARTIAL_DIR;
if (local_server || strchr(client_info, 'v') != NULL) {
if (!write_batch || protocol_version >= 30) {
do_negotiated_strings = 1;
compat_flags |= CF_VARINT_FLIST_FLAGS;
}
}
if (strchr(client_info, 'V') != NULL) { /* Support a pre-release 'V' that got superseded */
if (!write_batch)
compat_flags |= CF_VARINT_FLIST_FLAGS;
write_byte(f_out, compat_flags);
} else
write_varint(f_out, compat_flags);
} else { /* read_varint() is compatible with the older write_byte() when the 0x80 bit isn't on. */
compat_flags = read_varint(f_in);
if (compat_flags & CF_VARINT_FLIST_FLAGS)
do_negotiated_strings = 1;
}
/* The inc_recurse var MUST be set to 0 or 1. */
inc_recurse = compat_flags & CF_INC_RECURSE ? 1 : 0;
want_xattr_optim = protocol_version >= 31 && !(compat_flags & CF_AVOID_XATTR_OPTIM);
proper_seed_order = compat_flags & CF_CHKSUM_SEED_FIX ? 1 : 0;
xfer_flags_as_varint = compat_flags & CF_VARINT_FLIST_FLAGS ? 1 : 0;
if (am_sender) {
receiver_symlink_times = am_server
? strchr(client_info, 'L') != NULL
@@ -289,12 +640,14 @@ void setup_protocol(int f_out,int f_in)
if (inc_recurse && !allow_inc_recurse) {
/* This should only be able to happen in a batch. */
fprintf(stderr,
"Incompatible options specified for inc-recursive %s.\n",
read_batch ? "batch file" : "connection");
"Incompatible options specified for inc-recursive %s.\n",
read_batch ? "batch file" : "connection");
exit_cleanup(RERR_SYNTAX);
}
use_safe_inc_flist = (compat_flags & CF_SAFE_FLIST) || protocol_version >= 31;
need_messages_from_generator = 1;
if (compat_flags & CF_INPLACE_PARTIAL_DIR)
inplace_partial = 1;
#ifdef CAN_SET_SYMLINK_TIMES
} else if (!am_sender) {
receiver_symlink_times = 1;
@@ -321,11 +674,21 @@ void setup_protocol(int f_out,int f_in)
}
#endif
negotiate_the_strings(f_in, f_out);
if (am_server) {
if (!checksum_seed)
checksum_seed = time(NULL);
checksum_seed = time(NULL) ^ (getpid() << 6);
write_int(f_out, checksum_seed);
} else {
checksum_seed = read_int(f_in);
}
parse_checksum_choice(1); /* Sets checksum_type & xfersum_type */
parse_compress_choice(1); /* Sets do_compression */
if (write_batch && !am_server)
write_batch_shell_file();
init_flist();
}

View File

@@ -1,20 +1,25 @@
dnl Process this file with autoconf to produce a configure script.
AC_INIT()
AC_INIT([rsync],[3.2.0pre2],[http://rsync.samba.org/bugzilla.html])
AC_CONFIG_MACRO_DIR([m4])
AC_CONFIG_SRCDIR([byteorder.h])
AC_CONFIG_HEADER(config.h)
AC_PREREQ(2.60)
AC_PREREQ([2.69])
RSYNC_VERSION=3.1.1pre2
AC_SUBST(RSYNC_VERSION)
AC_MSG_NOTICE([Configuring rsync $RSYNC_VERSION])
AC_SUBST(RSYNC_VERSION, $PACKAGE_VERSION)
AC_MSG_NOTICE([Configuring rsync $PACKAGE_VERSION])
AC_DEFINE_UNQUOTED(RSYNC_VERSION, ["$RSYNC_VERSION"], [rsync release version])
AC_DEFINE_UNQUOTED(RSYNC_VERSION, ["$PACKAGE_VERSION"], [rsync release version])
LDFLAGS=${LDFLAGS-""}
AC_CANONICAL_HOST
dnl define the directory for replacement function since AC_LIBOBJ does not
dnl officially support subdirs and fails with automake
AC_CONFIG_LIBOBJ_DIR([lib])
# We must decide this before testing the compiler.
# Please allow this to default to yes, so that your users have more
@@ -22,8 +27,7 @@ AC_CANONICAL_HOST
AC_MSG_CHECKING([whether to include debugging symbols])
AC_ARG_ENABLE(debug,
AC_HELP_STRING([--disable-debug],
[disable debugging symbols and features]))
AS_HELP_STRING([--disable-debug],[disable debugging symbols and features]))
if test x"$enable_debug" = x"no"; then
AC_MSG_RESULT(no)
@@ -37,11 +41,13 @@ fi
dnl Checks for programs.
AC_PROG_CC
AC_PROG_CPP
AC_PROG_CXX
AC_PROG_EGREP
AC_PROG_INSTALL
AC_PROG_MKDIR_P
AC_PROG_CC_STDC
AC_SUBST(SHELL)
AC_PATH_PROG([PERL], [perl])
AC_DEFINE([_GNU_SOURCE], 1,
[Define _GNU_SOURCE so that we get all necessary prototypes])
@@ -51,8 +57,7 @@ if test x"$ac_cv_prog_cc_stdc" = x"no"; then
fi
AC_ARG_ENABLE(profile,
AC_HELP_STRING([--enable-profile],
[turn on CPU profiling]))
AS_HELP_STRING([--enable-profile],[turn on CPU profiling]))
if test x"$enable_profile" = x"yes"; then
CFLAGS="$CFLAGS -pg"
fi
@@ -60,8 +65,7 @@ fi
# Specifically, this turns on panic_action handling.
AC_ARG_ENABLE(maintainer-mode,
AC_HELP_STRING([--enable-maintainer-mode],
[turn on extra debug features]))
AS_HELP_STRING([--enable-maintainer-mode],[turn on extra debug features]))
if test x"$enable_maintainer_mode" = x"yes"; then
CFLAGS="$CFLAGS -DMAINTAINER_MODE"
fi
@@ -77,26 +81,26 @@ if test x"$GCC" = x"yes"; then
fi
AC_ARG_WITH(included-popt,
AC_HELP_STRING([--with-included-popt], [use bundled popt library, not from system]))
AS_HELP_STRING([--with-included-popt],[use bundled popt library, not from system]))
AC_ARG_WITH(included-zlib,
AC_HELP_STRING([--with-included-zlib], [use bundled zlib library, not from system]))
AS_HELP_STRING([--with-included-zlib],[use bundled zlib library, not from system]))
AC_ARG_WITH(protected-args,
AC_HELP_STRING([--with-protected-args], [make --protected-args option the default]))
AS_HELP_STRING([--with-protected-args],[make --protected-args option the default]))
if test x"$with_protected_args" = x"yes"; then
AC_DEFINE_UNQUOTED(RSYNC_USE_PROTECTED_ARGS, 1, [Define to 1 if --protected-args should be the default])
fi
AC_ARG_WITH(rsync-path,
AC_HELP_STRING([--with-rsync-path=PATH], [set default --rsync-path to PATH (default: rsync)]),
AS_HELP_STRING([--with-rsync-path=PATH],[set default --rsync-path to PATH (default: rsync)]),
[ RSYNC_PATH="$with_rsync_path" ],
[ RSYNC_PATH="rsync" ])
AC_DEFINE_UNQUOTED(RSYNC_PATH, "$RSYNC_PATH", [location of rsync on remote machine])
AC_ARG_WITH(rsyncd-conf,
AC_HELP_STRING([--with-rsyncd-conf=PATH], [set configuration file for rsync server to PATH (default: /etc/rsyncd.conf)]),
AS_HELP_STRING([--with-rsyncd-conf=PATH],[set configuration file for rsync server to PATH (default: /etc/rsyncd.conf)]),
[ if test ! -z "$with_rsyncd_conf" ; then
case $with_rsyncd_conf in
yes|no)
@@ -117,7 +121,7 @@ AC_ARG_WITH(rsyncd-conf,
AC_DEFINE_UNQUOTED(RSYNCD_SYSCONF, "$RSYNCD_SYSCONF", [location of configuration file for rsync server])
AC_ARG_WITH(rsh,
AC_HELP_STRING([--with-rsh=CMD], [set remote shell command to CMD (default: ssh)]))
AS_HELP_STRING([--with-rsh=CMD],[set remote shell command to CMD (default: ssh)]))
AC_CHECK_PROG(HAVE_REMSH, remsh, 1, 0)
if test x$HAVE_REMSH = x1; then
@@ -131,20 +135,12 @@ else
fi
AC_DEFINE_UNQUOTED(RSYNC_RSH, "$RSYNC_RSH", [default -e command])
AC_CHECK_PROG(HAVE_YODL2MAN, yodl2man, 1, 0)
if test x$HAVE_YODL2MAN = x1; then
MAKE_MAN=man
else
MAKE_MAN=man-copy
fi
# Some programs on solaris are only found in /usr/xpg4/bin (or work better than others versions).
AC_PATH_PROG(SHELL_PATH, sh, /bin/sh, [/usr/xpg4/bin$PATH_SEPARATOR$PATH])
AC_PATH_PROG(FAKEROOT_PATH, fakeroot, /usr/bin/fakeroot, [/usr/xpg4/bin$PATH_SEPARATOR$PATH])
AC_ARG_WITH(nobody-group,
AC_HELP_STRING([--with-nobody-group=GROUP],
[set the default unprivileged group (default nobody or nogroup)]),
AS_HELP_STRING([--with-nobody-group=GROUP],[set the default unprivileged group (default nobody or nogroup)]),
[ NOBODY_GROUP="$with_nobody_group" ])
if test x"$with_nobody_group" = x; then
@@ -162,15 +158,48 @@ fi
AC_DEFINE_UNQUOTED(NOBODY_USER, "nobody", [unprivileged user--e.g. nobody])
AC_DEFINE_UNQUOTED(NOBODY_GROUP, "$NOBODY_GROUP", [unprivileged group for unprivileged user])
# SIMD optimizations
SIMD=
AC_MSG_CHECKING([whether to enable SIMD optimizations])
AC_ARG_ENABLE(simd,
AS_HELP_STRING([--disable-simd],[disable SIMD optimizations (requires g++)]))
if test x"$enable_simd" != x"no"; then
# For x86-64 SIMD, g++ is also required
if test x"$build_cpu" = x"x86_64" && test x"$CXX" = x"g++"; then
SIMD="$SIMD x86_64"
fi
fi
if test x"$SIMD" != x""; then
SIMD=`echo "$SIMD" | sed -e 's/^ *//'`
AC_MSG_RESULT([yes ($SIMD)])
AC_DEFINE(HAVE_SIMD, 1, [Define to 1 to enable SIMD optimizations])
SIMD=`echo "$SIMD" | sed -e 's/[[^ ]]\+/$(SIMD_&)/g'`
else
AC_MSG_RESULT(no)
fi
AC_SUBST(SIMD)
# We only use g++ for its target attribute dispatching, disable unneeded bulky features
if test x"$CXXOBJ" != x""; then
CXXFLAGS="$CXXFLAGS -fno-exceptions -fno-rtti"
fi
# arrgh. libc in some old debian version screwed up the largefile
# stuff, getting byte range locking wrong
AC_CACHE_CHECK([for broken largefile support],rsync_cv_HAVE_BROKEN_LARGEFILE,[
AC_TRY_RUN([
AC_RUN_IFELSE([AC_LANG_SOURCE([[
#define _FILE_OFFSET_BITS 64
#include <stdio.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/wait.h>
#if HAVE_UNISTD_H
#include <unistd.h>
#endif
int main(void)
{
@@ -195,10 +224,9 @@ int main(void)
}
wait(&status);
unlink(tpl);
exit(WEXITSTATUS(status));
return WEXITSTATUS(status);
}
],
rsync_cv_HAVE_BROKEN_LARGEFILE=yes,rsync_cv_HAVE_BROKEN_LARGEFILE=no,rsync_cv_HAVE_BROKEN_LARGEFILE=cross)])
]])],[rsync_cv_HAVE_BROKEN_LARGEFILE=yes],[rsync_cv_HAVE_BROKEN_LARGEFILE=no],[rsync_cv_HAVE_BROKEN_LARGEFILE=cross])])
if test x"$rsync_cv_HAVE_BROKEN_LARGEFILE" != x"yes"; then
AC_SYS_LARGEFILE
fi
@@ -208,8 +236,7 @@ ipv6lib=none
ipv6trylibc=yes
AC_ARG_ENABLE(ipv6,
AC_HELP_STRING([--disable-ipv6],
[do not even try to use IPv6]))
AS_HELP_STRING([--disable-ipv6],[turn off IPv6 support]))
if test x"$enable_ipv6" != x"no"; then
AC_MSG_CHECKING([ipv6 stack type])
for i in inria kame linux-glibc linux-inet6 solaris toshiba v6d zeta cygwin; do
@@ -320,8 +347,7 @@ fi
dnl Do you want to disable use of locale functions
AC_ARG_ENABLE([locale],
AC_HELP_STRING([--disable-locale],
[disable locale features]))
AS_HELP_STRING([--disable-locale],[disable locale features]))
AH_TEMPLATE([CONFIG_LOCALE],
[Undefine if you do not want locale features. By default this is defined.])
if test x"$enable_locale" != x"no"; then
@@ -348,11 +374,59 @@ AC_CHECK_HEADERS(sys/fcntl.h sys/select.h fcntl.h sys/time.h sys/unistd.h \
netdb.h malloc.h float.h limits.h iconv.h libcharset.h langinfo.h \
sys/acl.h acl/libacl.h attr/xattr.h sys/xattr.h sys/extattr.h \
popt.h popt/popt.h linux/falloc.h netinet/in_systm.h netinet/ip.h \
zlib.h)
AC_HEADER_MAJOR
zlib.h xxhash.h openssl/md4.h openssl/md5.h zstd.h lz4.h)
AC_HEADER_MAJOR_FIXED
AC_MSG_CHECKING([whether to enable use of openssl crypto library])
AC_ARG_ENABLE([openssl],
AS_HELP_STRING([--disable-openssl],[disable openssl crypto library]))
AH_TEMPLATE([USE_OPENSSL],
[Undefine if you do not want to use openssl crypto library. By default this is defined.])
if test x"$enable_openssl" != x"no" && test x"$ac_cv_header_openssl_md4_h" = x"yes" && test x"$ac_cv_header_openssl_md5_h" = x"yes"; then
AC_MSG_RESULT(yes)
AC_SEARCH_LIBS(MD5_Init, crypto, [AC_DEFINE(USE_OPENSSL)])
else
AC_MSG_RESULT(no)
fi
AC_MSG_CHECKING([whether to enable xxhash checksum support])
AC_ARG_ENABLE([xxhash],
AS_HELP_STRING([--disable-xxhash],[disable xxhash checksums]))
AH_TEMPLATE([SUPPORT_XXHASH],
[Undefine if you do not want xxhash checksums. By default this is defined.])
if test x"$enable_xxhash" != x"no" && test x"$ac_cv_header_xxhash_h" = x"yes"; then
AC_MSG_RESULT(yes)
AC_SEARCH_LIBS(XXH64_createState, xxhash, [AC_DEFINE(SUPPORT_XXHASH)])
else
AC_MSG_RESULT(no)
fi
AC_MSG_CHECKING([whether to enable zstd compression])
AC_ARG_ENABLE([zstd],
AC_HELP_STRING([--disable-zstd], [disable zstd compression]))
AH_TEMPLATE([SUPPORT_ZSTD],
[Undefine if you do not want zstd compression. By default this is defined.])
if test x"$enable_zstd" != x"no" && test x"$ac_cv_header_zstd_h" = x"yes"; then
AC_MSG_RESULT(yes)
AC_SEARCH_LIBS(ZSTD_minCLevel, zstd, [AC_DEFINE(SUPPORT_ZSTD)])
else
AC_MSG_RESULT(no)
fi
AC_MSG_CHECKING([whether to enable LZ4 compression])
AC_ARG_ENABLE([lz4],
AC_HELP_STRING([--disable-lz4], [disable LZ4 compression]))
AH_TEMPLATE([SUPPORT_LZ4],
[Undefine if you do not want LZ4 compression. By default this is defined.])
if test x"$enable_lz4" != x"no" && test x"$ac_cv_header_lz4_h" = x"yes"; then
AC_MSG_RESULT(yes)
AC_SEARCH_LIBS(LZ4_compress_default, lz4, [AC_DEFINE(SUPPORT_LZ4)])
else
AC_MSG_RESULT(no)
fi
AC_CACHE_CHECK([if makedev takes 3 args],rsync_cv_MAKEDEV_TAKES_3_ARGS,[
AC_TRY_RUN([
AC_RUN_IFELSE([AC_LANG_SOURCE([[
#include <sys/types.h>
#ifdef MAJOR_IN_MKDEV
#include <sys/mkdev.h>
@@ -367,11 +441,10 @@ int main(void)
{
dev_t dev = makedev(0, 5, 7);
if (major(dev) != 5 || minor(dev) != 7)
exit(1);
return 1;
return 0;
}
],
rsync_cv_MAKEDEV_TAKES_3_ARGS=yes,rsync_cv_MAKEDEV_TAKES_3_ARGS=no,rsync_cv_MAKEDEV_TAKES_3_ARGS=no)])
]])],[rsync_cv_MAKEDEV_TAKES_3_ARGS=yes],[rsync_cv_MAKEDEV_TAKES_3_ARGS=no],[rsync_cv_MAKEDEV_TAKES_3_ARGS=no])])
if test x"$rsync_cv_MAKEDEV_TAKES_3_ARGS" = x"yes"; then
AC_DEFINE(MAKEDEV_TAKES_3_ARGS, 1, [Define to 1 if makedev() takes 3 args])
fi
@@ -388,16 +461,22 @@ AC_CHECK_SIZEOF(int64_t)
AC_CHECK_SIZEOF(off_t)
AC_CHECK_SIZEOF(off64_t)
AC_CHECK_SIZEOF(time_t)
AC_CHECK_SIZEOF(char*)
AC_C_INLINE
AC_C_LONG_DOUBLE
AC_TYPE_SIGNAL
AC_TYPE_LONG_DOUBLE_WIDER
ac_cv_c_long_double=$ac_cv_type_long_double_wider
if test $ac_cv_c_long_double = yes; then
AC_DEFINE([HAVE_LONG_DOUBLE],[1],[Define to 1 if the type `long double' works and has more range or precision than `double'.])
fi
AC_TYPE_UID_T
AC_CHECK_TYPES([mode_t,off_t,size_t,pid_t,id_t])
AC_TYPE_GETGROUPS
AC_CHECK_MEMBERS([struct stat.st_rdev,
struct stat.st_mtimensec,
struct stat.st_mtimespec.tv_nsec,
struct stat.st_mtim.tv_nsec],,,[
#ifdef HAVE_SYS_TYPES_H
#include <sys/types.h>
@@ -412,8 +491,7 @@ AC_CHECK_MEMBERS([struct stat.st_rdev,
TYPE_SOCKLEN_T
AC_CACHE_CHECK([for errno in errno.h],rsync_cv_errno, [
AC_TRY_COMPILE([#include <errno.h>],[int i = errno],
rsync_cv_errno=yes,rsync_cv_have_errno_decl=no)])
AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[#include <errno.h>]], [[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, [Define to 1 if errno is declared in errno.h])
fi
@@ -464,7 +542,7 @@ AC_SEARCH_LIBS(libiconv_open, iconv)
AC_MSG_CHECKING([for iconv declaration])
AC_CACHE_VAL(am_cv_proto_iconv, [
AC_TRY_COMPILE([
AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[
#include <stdlib.h>
#include <iconv.h>
extern
@@ -476,7 +554,7 @@ size_t iconv (iconv_t cd, char * *inbuf, size_t *inbytesleft, char * *outbuf, si
#else
size_t iconv();
#endif
], [], am_cv_proto_iconv_arg1="", am_cv_proto_iconv_arg1="const")
]], [[]])],[am_cv_proto_iconv_arg1=""],[am_cv_proto_iconv_arg1="const"])
am_cv_proto_iconv="extern size_t iconv (iconv_t cd, $am_cv_proto_iconv_arg1 char * *inbuf, size_t *inbytesleft, char * *outbuf, size_t *outbytesleft);"])
am_cv_proto_iconv=`echo "[$]am_cv_proto_iconv" | tr -s ' ' | sed -e 's/( /(/'`
AC_MSG_RESULT([$]{ac_t:-
@@ -486,8 +564,7 @@ AC_DEFINE_UNQUOTED(ICONV_CONST, $am_cv_proto_iconv_arg1,
dnl AC_MSG_NOTICE([Looking in libraries: $LIBS])
AC_CHECK_FUNCS(inet_ntop, , [AC_LIBOBJ(lib/inet_ntop)])
AC_CHECK_FUNCS(inet_pton, , [AC_LIBOBJ(lib/inet_pton)])
AC_REPLACE_FUNCS([inet_ntop inet_pton])
AC_HAVE_TYPE([struct addrinfo], [#include <netdb.h>])
AC_HAVE_TYPE([struct sockaddr_storage], [#include <sys/types.h>
@@ -506,23 +583,19 @@ AC_CACHE_CHECK([whether defines needed by getaddrinfo exist],
#endif],
rsync_cv_HAVE_GETADDR_DEFINES=yes,
rsync_cv_HAVE_GETADDR_DEFINES=no)])
if test x"$rsync_cv_HAVE_GETADDR_DEFINES" = x"yes" -a x"$ac_cv_type_struct_addrinfo" = x"yes"; then
AS_IF([test x"$rsync_cv_HAVE_GETADDR_DEFINES" = x"yes" -a x"$ac_cv_type_struct_addrinfo" = x"yes"],[
# Tru64 UNIX has getaddrinfo() but has it renamed in libc as
# something else so we must include <netdb.h> to get the
# redefinition.
AC_CHECK_FUNCS(getaddrinfo, ,
[AC_MSG_CHECKING([for getaddrinfo by including <netdb.h>])
AC_TRY_LINK([#include <sys/types.h>
AC_LINK_IFELSE([AC_LANG_PROGRAM([[#include <sys/types.h>
#include <sys/socket.h>
#include <netdb.h>],[getaddrinfo(NULL, NULL, NULL, NULL);],
[AC_MSG_RESULT([yes])
#include <netdb.h>]], [[getaddrinfo(NULL, NULL, NULL, NULL);]])],[AC_MSG_RESULT([yes])
AC_DEFINE(HAVE_GETADDRINFO, 1,
[Define to 1 if you have the "getaddrinfo" function and required types.])],
[AC_MSG_RESULT([no])
AC_LIBOBJ(lib/getaddrinfo)])])
else
AC_LIBOBJ(lib/getaddrinfo)
fi
[Define to 1 if you have the "getaddrinfo" function and required types.])],[AC_MSG_RESULT([no])
AC_LIBOBJ([getaddrinfo])])])
],[AC_LIBOBJ([getaddrinfo])])
AC_CHECK_MEMBER([struct sockaddr.sa_len],
[ AC_DEFINE(HAVE_SOCKADDR_LEN, 1, [Do we have sockaddr.sa_len?]) ],
@@ -597,12 +670,13 @@ AC_FUNC_UTIME_NULL
AC_FUNC_ALLOCA
AC_CHECK_FUNCS(waitpid wait4 getcwd strdup chown chmod lchmod mknod mkfifo \
fchmod fstat ftruncate strchr readlink link utime utimes lutimes strftime \
chflags getattrlist \
memmove lchown vsnprintf snprintf vasprintf asprintf setsid strpbrk \
strlcat strlcpy strtol mallinfo getgroups setgroups geteuid getegid \
setlocale setmode open64 lseek64 mkstemp64 mtrace va_copy __va_copy \
seteuid strerror putenv iconv_open locale_charset nl_langinfo getxattr \
extattr_get_link sigaction sigprocmask setattrlist getgrouplist \
initgroups utimensat posix_fallocate attropen setvbuf)
initgroups utimensat posix_fallocate attropen setvbuf nanosleep usleep)
dnl cygwin iconv.h defines iconv_open as libiconv_open
if test x"$ac_cv_func_iconv_open" != x"yes"; then
@@ -612,19 +686,46 @@ fi
dnl Preallocation stuff (also fallocate, posix_fallocate function tests above):
AC_CACHE_CHECK([for useable fallocate],rsync_cv_have_fallocate,[
AC_TRY_LINK([#include <fcntl.h>
#include <sys/types.h>],
[fallocate(0, 0, 0, 0);],
rsync_cv_have_fallocate=yes,rsync_cv_have_fallocate=no)])
AC_LINK_IFELSE([AC_LANG_PROGRAM([[#include <fcntl.h>
#include <sys/types.h>]], [[fallocate(0, 0, 0, 0);]])],[rsync_cv_have_fallocate=yes],[rsync_cv_have_fallocate=no])])
if test x"$rsync_cv_have_fallocate" = x"yes"; then
AC_DEFINE(HAVE_FALLOCATE, 1, [Define to 1 if you have the fallocate function and it compiles and links without error])
fi
AC_MSG_CHECKING([for FALLOC_FL_PUNCH_HOLE])
AC_PREPROC_IFELSE([AC_LANG_SOURCE([[
#define _GNU_SOURCE 1
#include <linux/falloc.h>
#ifndef FALLOC_FL_PUNCH_HOLE
#error FALLOC_FL_PUNCH_HOLE is missing
#endif
]])], [
AC_MSG_RESULT([yes])
AC_DEFINE([HAVE_FALLOC_FL_PUNCH_HOLE], [1], [Define if FALLOC_FL_PUNCH_HOLE is available.])
], [
AC_MSG_RESULT([no])
]
)
AC_MSG_CHECKING([for FALLOC_FL_ZERO_RANGE])
AC_PREPROC_IFELSE([AC_LANG_SOURCE([[
#define _GNU_SOURCE 1
#include <linux/falloc.h>
#ifndef FALLOC_FL_ZERO_RANGE
#error FALLOC_FL_ZERO_RANGE is missing
#endif
]])], [
AC_MSG_RESULT([yes])
AC_DEFINE([HAVE_FALLOC_FL_ZERO_RANGE], [1], [Define if FALLOC_FL_ZERO_RANGE is available.])
], [
AC_MSG_RESULT([no])
]
)
AC_CACHE_CHECK([for SYS_fallocate],rsync_cv_have_sys_fallocate,[
AC_TRY_COMPILE([#include <sys/syscall.h>
#include <sys/types.h>],
[syscall(SYS_fallocate, 0, 0, (loff_t)0, (loff_t)0);],
rsync_cv_have_sys_fallocate=yes,rsync_cv_have_sys_fallocate=no)])
AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[#include <sys/syscall.h>
#include <unistd.h>
#include <sys/types.h>]], [[syscall(SYS_fallocate, 0, 0, (loff_t)0, (loff_t)0);]])],[rsync_cv_have_sys_fallocate=yes],[rsync_cv_have_sys_fallocate=no])])
if test x"$rsync_cv_have_sys_fallocate" = x"yes"; then
AC_DEFINE(HAVE_SYS_FALLOCATE, 1, [Define to 1 if you have the SYS_fallocate syscall number])
fi
@@ -651,8 +752,7 @@ if test $ac_cv_func_getpgrp = yes; then
fi
AC_ARG_ENABLE(iconv-open,
AC_HELP_STRING([--disable-iconv-open],
[disable all use of iconv_open() function]),
AS_HELP_STRING([--disable-iconv-open],[disable all use of iconv_open() function]),
[], [enable_iconv_open=$ac_cv_func_iconv_open])
if test x"$enable_iconv_open" != x"no"; then
@@ -660,8 +760,7 @@ if test x"$enable_iconv_open" != x"no"; then
fi
AC_ARG_ENABLE(iconv,
AC_HELP_STRING([--disable-iconv],
[disable rsync's --iconv option]),
AS_HELP_STRING([--disable-iconv],[disable rsync's --iconv option]),
[], [enable_iconv=$enable_iconv_open])
AH_TEMPLATE([ICONV_OPTION],
[Define if you want the --iconv option. Specifing a value will set the
@@ -676,77 +775,78 @@ if test x"$enable_iconv" != x"no"; then
fi
AC_CACHE_CHECK([whether chown() modifies symlinks],rsync_cv_chown_modifies_symlink,[
AC_TRY_RUN([
AC_RUN_IFELSE([AC_LANG_SOURCE([[
#if HAVE_UNISTD_H
# include <unistd.h>
#endif
#include <stdlib.h>
#include <errno.h>
main() {
int main(void) {
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(1);
exit(0);
}],
rsync_cv_chown_modifies_symlink=yes,rsync_cv_chown_modifies_symlink=no,rsync_cv_chown_modifies_symlink=no)])
if (chown(dangling_symlink, getuid(), getgid()) < 0 && errno == ENOENT) return 1;
return 0;
}]])],[rsync_cv_chown_modifies_symlink=yes],[rsync_cv_chown_modifies_symlink=no],[rsync_cv_chown_modifies_symlink=no])])
if test $rsync_cv_chown_modifies_symlink = yes; then
AC_DEFINE(CHOWN_MODIFIES_SYMLINK, 1, [Define to 1 if chown modifies symlinks.])
fi
AC_CACHE_CHECK([whether link() can hard-link symlinks],rsync_cv_can_hardlink_symlink,[
AC_TRY_RUN([
AC_RUN_IFELSE([AC_LANG_SOURCE([[
#if HAVE_UNISTD_H
# include <unistd.h>
#endif
#include <stdlib.h>
#include <errno.h>
#define FILENAME "conftest.dangle"
main() {
int main(void) {
unlink(FILENAME);
if (symlink("conftest.no-such", FILENAME) < 0) abort();
if (link(FILENAME, FILENAME "2") < 0) exit(1);
exit(0);
}],
rsync_cv_can_hardlink_symlink=yes,rsync_cv_can_hardlink_symlink=no,rsync_cv_can_hardlink_symlink=no)])
unlink(FILENAME "2");
if (link(FILENAME, FILENAME "2") < 0) return 1;
return 0;
}]])],[rsync_cv_can_hardlink_symlink=yes],[rsync_cv_can_hardlink_symlink=no],[rsync_cv_can_hardlink_symlink=no])])
if test $rsync_cv_can_hardlink_symlink = yes; then
AC_DEFINE(CAN_HARDLINK_SYMLINK, 1, [Define to 1 if link() can hard-link symlinks.])
fi
AC_CACHE_CHECK([whether link() can hard-link special files],rsync_cv_can_hardlink_special,[
AC_TRY_RUN([
AC_RUN_IFELSE([AC_LANG_SOURCE([[
#if HAVE_UNISTD_H
# include <unistd.h>
#endif
#ifdef HAVE_SYS_STAT_H
#include <sys/stat.h>
#endif
#include <stdlib.h>
#include <errno.h>
#define FILENAME "conftest.fifi"
main() {
int main(void) {
unlink(FILENAME);
if (mkfifo(FILENAME, 0777) < 0) abort();
if (link(FILENAME, FILENAME "2") < 0) exit(1);
exit(0);
}],
rsync_cv_can_hardlink_special=yes,rsync_cv_can_hardlink_special=no,rsync_cv_can_hardlink_special=no)])
unlink(FILENAME "2");
if (link(FILENAME, FILENAME "2") < 0) return 1;
return 0;
}]])],[rsync_cv_can_hardlink_special=yes],[rsync_cv_can_hardlink_special=no],[rsync_cv_can_hardlink_special=no])])
if test $rsync_cv_can_hardlink_special = yes; then
AC_DEFINE(CAN_HARDLINK_SPECIAL, 1, [Define to 1 if link() can hard-link special files.])
fi
AC_CACHE_CHECK([for working socketpair],rsync_cv_HAVE_SOCKETPAIR,[
AC_TRY_RUN([
AC_RUN_IFELSE([AC_LANG_SOURCE([[
#include <sys/types.h>
#include <sys/socket.h>
main() {
int main(void) {
int fd[2];
exit((socketpair(AF_UNIX, SOCK_STREAM, 0, fd) != -1) ? 0 : 1);
}],
rsync_cv_HAVE_SOCKETPAIR=yes,rsync_cv_HAVE_SOCKETPAIR=no,rsync_cv_HAVE_SOCKETPAIR=cross)])
return (socketpair(AF_UNIX, SOCK_STREAM, 0, fd) != -1) ? 0 : 1;
}]])],[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, [Define to 1 if you have the "socketpair" function])
fi
AC_CHECK_FUNCS(getpass, , [AC_LIBOBJ(lib/getpass)])
AC_REPLACE_FUNCS([getpass])
if test x"$with_included_popt" != x"yes"; then
AC_CHECK_LIB(popt, poptGetContext, , [with_included_popt=yes])
@@ -765,7 +865,7 @@ AC_MSG_CHECKING([whether to use included libpopt])
if test x"$with_included_popt" = x"yes"; then
AC_MSG_RESULT($srcdir/popt)
BUILD_POPT='$(popt_OBJS)'
CFLAGS="$CFLAGS -I$srcdir/popt"
CFLAGS="-I$srcdir/popt $CFLAGS"
if test x"$ALLOCA" != x
then
# this can be removed when/if we add an included alloca.c;
@@ -790,56 +890,53 @@ AC_MSG_CHECKING([whether to use included zlib])
if test x"$with_included_zlib" = x"yes"; then
AC_MSG_RESULT($srcdir/zlib)
BUILD_ZLIB='$(zlib_OBJS)'
CFLAGS="$CFLAGS -I$srcdir/zlib"
CFLAGS="-I$srcdir/zlib $CFLAGS"
else
AC_DEFINE(EXTERNAL_ZLIB, 1, [Define to 1 if using external zlib])
AC_MSG_RESULT(no)
fi
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)])
AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[]], [[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,[
AC_TRY_RUN([#include <sys/types.h>
AC_RUN_IFELSE([AC_LANG_SOURCE([[#include <sys/types.h>
#include <dirent.h>
main() { struct dirent *di; DIR *d = opendir("."); di = readdir(d);
int main(void) { struct dirent *di; DIR *d = opendir("."); di = readdir(d);
if (di && di->d_name[-2] == '.' && di->d_name[-1] == 0 &&
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)])
di->d_name[0] == 0) return 0; return 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, [Define to 1 if readdir() is broken])
fi
AC_CACHE_CHECK([for utimbuf],rsync_cv_HAVE_STRUCT_UTIMBUF,[
AC_TRY_COMPILE([#include <sys/types.h>
#include <utime.h>],
[struct utimbuf tbuf; tbuf.actime = 0; tbuf.modtime = 1; exit(utime("foo.c",&tbuf));],
rsync_cv_HAVE_STRUCT_UTIMBUF=yes,rsync_cv_HAVE_STRUCT_UTIMBUF=no)])
AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[#include <sys/types.h>
#include <utime.h>]], [[struct utimbuf tbuf; tbuf.actime = 0; tbuf.modtime = 1; return utime("foo.c",&tbuf);]])],[rsync_cv_HAVE_STRUCT_UTIMBUF=yes],[rsync_cv_HAVE_STRUCT_UTIMBUF=no])])
if test x"$rsync_cv_HAVE_STRUCT_UTIMBUF" = x"yes"; then
AC_DEFINE(HAVE_STRUCT_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_COMPILE([#include <sys/time.h>
#include <unistd.h>],
[struct timeval tv; exit(gettimeofday(&tv, NULL));],
rsync_cv_HAVE_GETTIMEOFDAY_TZ=yes,rsync_cv_HAVE_GETTIMEOFDAY_TZ=no)])
AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[#include <sys/time.h>
#include <unistd.h>]], [[struct timeval tv; return 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, [Define to 1 if gettimeofday() takes a time-zone arg])
fi
AC_CACHE_CHECK([for C99 vsnprintf],rsync_cv_HAVE_C99_VSNPRINTF,[
AC_TRY_RUN([
AC_RUN_IFELSE([AC_LANG_SOURCE([[
#include <sys/types.h>
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
void foo(const char *format, ...) {
va_list ap;
int len;
char buf[5];
static char buf[] = "12345678901234567890";
va_start(ap, format);
len = vsnprintf(0, 0, format, ap);
@@ -847,35 +944,29 @@ void foo(const char *format, ...) {
if (len != 5) exit(1);
if (snprintf(buf, 3, "hello") != 5 || strcmp(buf, "he") != 0) exit(1);
exit(0);
}
main() { foo("hello"); }
],
rsync_cv_HAVE_C99_VSNPRINTF=yes,rsync_cv_HAVE_C99_VSNPRINTF=no,rsync_cv_HAVE_C99_VSNPRINTF=cross)])
int main(void) { foo("hello"); return 0; }
]])],[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, [Define to 1 if vsprintf has a C99-compatible return value])
fi
AC_CACHE_CHECK([for secure mkstemp],rsync_cv_HAVE_SECURE_MKSTEMP,[
AC_TRY_RUN([#include <stdlib.h>
AC_RUN_IFELSE([AC_LANG_SOURCE([[#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
main() {
int main(void) {
struct stat st;
char tpl[20]="/tmp/test.XXXXXX";
int fd = mkstemp(tpl);
if (fd == -1) exit(1);
if (fd == -1) return 1;
unlink(tpl);
if (fstat(fd, &st) != 0) exit(1);
if ((st.st_mode & 0777) != 0600) exit(1);
exit(0);
}],
rsync_cv_HAVE_SECURE_MKSTEMP=yes,
rsync_cv_HAVE_SECURE_MKSTEMP=no,
rsync_cv_HAVE_SECURE_MKSTEMP=cross)])
if (fstat(fd, &st) != 0) return 1;
if ((st.st_mode & 0777) != 0600) return 1;
return 0;
}]])],[rsync_cv_HAVE_SECURE_MKSTEMP=yes],[rsync_cv_HAVE_SECURE_MKSTEMP=no],[rsync_cv_HAVE_SECURE_MKSTEMP=cross])])
if test x"$rsync_cv_HAVE_SECURE_MKSTEMP" = x"yes"; then
case $host_os in
hpux*)
@@ -892,29 +983,33 @@ fi
AC_CACHE_CHECK([if mknod creates FIFOs],rsync_cv_MKNOD_CREATES_FIFOS,[
AC_TRY_RUN([
AC_RUN_IFELSE([AC_LANG_SOURCE([[
#include <stdio.h>
#include <sys/stat.h>
#include <errno.h>
main() { int rc, ec; char *fn = "fifo-test";
#if HAVE_UNISTD_H
# include <unistd.h>
#endif
int main(void) { int rc, ec; char *fn = "fifo-test";
unlink(fn); rc = mknod(fn,S_IFIFO,0600); ec = errno; unlink(fn);
if (rc) {printf("(%d %d) ",rc,ec); return ec;}
return 0;}],
rsync_cv_MKNOD_CREATES_FIFOS=yes,rsync_cv_MKNOD_CREATES_FIFOS=no,rsync_cv_MKNOD_CREATES_FIFOS=cross)])
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([
AC_RUN_IFELSE([AC_LANG_SOURCE([[
#include <stdio.h>
#include <sys/stat.h>
#include <errno.h>
main() { int rc, ec; char *fn = "sock-test";
#if HAVE_UNISTD_H
# include <unistd.h>
#endif
int main(void) { int rc, ec; char *fn = "sock-test";
unlink(fn); rc = mknod(fn,S_IFSOCK,0600); ec = errno; unlink(fn);
if (rc) {printf("(%d %d) ",rc,ec); return ec;}
return 0;}],
rsync_cv_MKNOD_CREATES_SOCKETS=yes,rsync_cv_MKNOD_CREATES_SOCKETS=no,rsync_cv_MKNOD_CREATES_SOCKETS=cross)])
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
@@ -925,7 +1020,7 @@ fi
AC_CACHE_CHECK([whether -c -o works],rsync_cv_DASHC_WORKS_WITH_DASHO,[
rm -rf conftest*
cat > conftest.$ac_ext <<EOF
int main() { return 0; }
int main(void) { return 0; }
EOF
${CC-cc} -c -o conftest..o conftest.$ac_ext
if test -f conftest..o; then
@@ -952,17 +1047,13 @@ AC_SUBST(BUILD_POPT)
AC_SUBST(BUILD_ZLIB)
AC_SUBST(MAKE_MAN)
AC_PATH_PROG([STUNNEL], [stunnel], [stunnel], [$PATH$PATH_SEPARATOR/usr/sbin$PATH_SEPARATOR/sbin])
AC_PATH_PROG([STUNNEL4], [stunnel4], [$STUNNEL], [$PATH$PATH_SEPARATOR/usr/sbin$PATH_SEPARATOR/sbin])
AC_CHECK_FUNCS(_acl __acl _facl __facl)
#################################################
# check for ACL support
AC_MSG_CHECKING([whether to support ACLs])
AC_ARG_ENABLE(acl-support,
AC_HELP_STRING([--disable-acl-support],
[disable ACL support]))
AS_HELP_STRING([--disable-acl-support],[disable ACL support]))
if test x"$enable_acl_support" = x"no"; then
AC_MSG_RESULT(no)
@@ -973,7 +1064,7 @@ else
AC_DEFINE(HAVE_UNIXWARE_ACLS, 1, [true if you have UnixWare ACLs])
AC_DEFINE(SUPPORT_ACLS, 1, [Define to 1 to add support for ACLs])
;;
solaris*|*cygwin*)
solaris*)
AC_MSG_RESULT(Using solaris ACLs)
AC_DEFINE(HAVE_SOLARIS_ACLS, 1, [true if you have solaris ACLs])
AC_DEFINE(SUPPORT_ACLS, 1)
@@ -1008,20 +1099,16 @@ else
AC_MSG_RESULT(running tests:)
AC_CHECK_LIB(acl,acl_get_file)
AC_CACHE_CHECK([for ACL support],samba_cv_HAVE_POSIX_ACLS,[
AC_TRY_LINK([#include <sys/types.h>
#include <sys/acl.h>],
[ acl_t acl; int entry_id; acl_entry_t *entry_p; return acl_get_entry( acl, entry_id, entry_p);],
samba_cv_HAVE_POSIX_ACLS=yes,samba_cv_HAVE_POSIX_ACLS=no)])
AC_LINK_IFELSE([AC_LANG_PROGRAM([[#include <sys/types.h>
#include <sys/acl.h>]], [[ acl_t acl; int entry_id; acl_entry_t *entry_p; return acl_get_entry( acl, entry_id, entry_p);]])],[samba_cv_HAVE_POSIX_ACLS=yes],[samba_cv_HAVE_POSIX_ACLS=no])])
AC_MSG_CHECKING(ACL test results)
if test x"$samba_cv_HAVE_POSIX_ACLS" = x"yes"; then
AC_MSG_RESULT(Using posix ACLs)
AC_DEFINE(HAVE_POSIX_ACLS, 1, [true if you have posix ACLs])
AC_DEFINE(SUPPORT_ACLS, 1)
AC_CACHE_CHECK([for acl_get_perm_np],samba_cv_HAVE_ACL_GET_PERM_NP,[
AC_TRY_LINK([#include <sys/types.h>
#include <sys/acl.h>],
[ acl_permset_t permset_d; acl_perm_t perm; return acl_get_perm_np( permset_d, perm);],
samba_cv_HAVE_ACL_GET_PERM_NP=yes,samba_cv_HAVE_ACL_GET_PERM_NP=no)])
AC_LINK_IFELSE([AC_LANG_PROGRAM([[#include <sys/types.h>
#include <sys/acl.h>]], [[ acl_permset_t permset_d; acl_perm_t perm; return acl_get_perm_np( permset_d, perm);]])],[samba_cv_HAVE_ACL_GET_PERM_NP=yes],[samba_cv_HAVE_ACL_GET_PERM_NP=no])])
if test x"$samba_cv_HAVE_ACL_GET_PERM_NP" = x"yes"; then
AC_DEFINE(HAVE_ACL_GET_PERM_NP, 1, [true if you have acl_get_perm_np])
fi
@@ -1040,8 +1127,7 @@ fi
# check for extended attribute support
AC_MSG_CHECKING(whether to support extended attributes)
AC_ARG_ENABLE(xattr-support,
AC_HELP_STRING([--disable-xattr-support],
[disable extended attributes]),
AS_HELP_STRING([--disable-xattr-support],[disable extended attributes]),
[], [case "$ac_cv_func_getxattr$ac_cv_func_extattr_get_link$ac_cv_func_attropen" in
*yes*) enable_xattr_support=maybe ;;
*) enable_xattr_support=no ;;
@@ -1052,9 +1138,9 @@ if test x"$enable_xattr_support" = x"no"; then
AC_MSG_RESULT(no)
else
case "$host_os" in
*linux*)
*linux*|*netbsd*)
AC_MSG_RESULT(Using Linux xattrs)
AC_DEFINE(HAVE_LINUX_XATTRS, 1, [True if you have Linux xattrs])
AC_DEFINE(HAVE_LINUX_XATTRS, 1, [True if you have Linux xattrs (or equivalent)])
AC_DEFINE(SUPPORT_XATTRS, 1)
AC_DEFINE(NO_SYMLINK_USER_XATTRS, 1, [True if symlinks do not support user xattrs])
AC_CHECK_LIB(attr,getxattr)
@@ -1091,7 +1177,7 @@ if test x"$enable_acl_support" = x"no" -o x"$enable_xattr_support" = x"no" -o x"
AC_MSG_CHECKING([whether $CC supports -Wno-unused-parameter])
OLD_CFLAGS="$CFLAGS"
CFLAGS="$CFLAGS -Wno-unused-parameter"
AC_TRY_LINK([#include <stdio.h>], [printf("hello\n");], [rsync_warn_flag=yes], [rsync_warn_flag=no])
AC_LINK_IFELSE([AC_LANG_PROGRAM([[#include <stdio.h>]], [[printf("hello\n");]])],[rsync_warn_flag=yes],[rsync_warn_flag=no])
AC_MSG_RESULT([$rsync_warn_flag])
if test x"$rsync_warn_flag" = x"no"; then
CFLAGS="$OLD_CFLAGS"
@@ -1110,8 +1196,3 @@ AC_OUTPUT
AC_MSG_RESULT()
AC_MSG_RESULT([ rsync ${RSYNC_VERSION} configuration successful])
AC_MSG_RESULT()
if test x$HAVE_YODL2MAN != x1; then
AC_MSG_RESULT([ Note that yodl2man was not found, so pre-existing manpage files will be])
AC_MSG_RESULT([ used w/o change (if available) -- no .yo file changes will be used.])
AC_MSG_RESULT()
fi

View File

@@ -2,6 +2,7 @@
* Support the max connections option.
*
* Copyright (C) 1998 Andrew Tridgell
* Copyright (C) 2006-2020 Wayne Davison
*
* 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

View File

@@ -4,7 +4,7 @@
* Copyright (C) 1996-2000 Andrew Tridgell
* Copyright (C) 1996 Paul Mackerras
* Copyright (C) 2002 Martin Pool <mbp@samba.org>
* Copyright (C) 2003-2014 Wayne Davison
* Copyright (C) 2003-2020 Wayne Davison
*
* 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
@@ -89,8 +89,8 @@ static enum delret delete_dir_contents(char *fname, uint16 flags)
if (fp->flags & FLAG_MOUNT_DIR && S_ISDIR(fp->mode)) {
if (DEBUG_GTE(DEL, 1)) {
rprintf(FINFO,
"mount point, %s, pins parent directory\n",
f_name(fp, NULL));
"mount point, %s, pins parent directory\n",
f_name(fp, NULL));
}
ret = DR_NOT_EMPTY;
continue;

View File

@@ -126,7 +126,7 @@
<para><option>-P</option>
Display a progress indicator while files are transferred. This should
normally be ommitted if rsync is not run on a terminal.
normally be omitted if rsync is not run on a terminal.
</para>
</section>
@@ -348,4 +348,4 @@ running rsync giving the network directory.
<para><ulink url="http://www.ccp14.ac.uk/ccp14admin/rsync/"></ulink></para>
</appendix>
</book>
</book>

View File

@@ -2,7 +2,7 @@
* Error codes returned by rsync.
*
* Copyright (C) 1998-2000 Andrew Tridgell
* Copyright (C) 2003-2014 Wayne Davison
* Copyright (C) 2003-2019 Wayne Davison
*
* 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

201
exclude.c
View File

@@ -4,7 +4,7 @@
* Copyright (C) 1996-2001 Andrew Tridgell <tridge@samba.org>
* Copyright (C) 1996 Paul Mackerras
* Copyright (C) 2002 Martin Pool
* Copyright (C) 2003-2014 Wayne Davison
* Copyright (C) 2003-2020 Wayne Davison
*
* 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
@@ -44,6 +44,8 @@ filter_rule_list filter_list = { .debug_type = "" };
filter_rule_list cvs_filter_list = { .debug_type = " [global CVS]" };
filter_rule_list daemon_filter_list = { .debug_type = " [daemon]" };
int saw_xattr_filter = 0;
/* Need room enough for ":MODS " prefix plus some room to grow. */
#define MAX_RULE_PREFIX (16)
@@ -100,52 +102,44 @@ static int mergelist_size = 0;
static void teardown_mergelist(filter_rule *ex)
{
int j;
if (!ex->u.mergelist)
return;
if (DEBUG_GTE(FILTER, 2)) {
rprintf(FINFO, "[%s] deactivating mergelist #%d%s\n",
who_am_i(), mergelist_cnt - 1,
ex->u.mergelist->debug_type);
}
/* We should deactivate mergelists in LIFO order. */
assert(mergelist_cnt > 0);
assert(ex == mergelist_parents[mergelist_cnt - 1]);
/* The parent_dirscan filters should have been freed. */
assert(ex->u.mergelist->parent_dirscan_head == NULL);
free(ex->u.mergelist->debug_type);
free(ex->u.mergelist);
mergelist_cnt--;
for (j = 0; j < mergelist_cnt; j++) {
if (mergelist_parents[j] == ex) {
mergelist_parents[j] = NULL;
break;
}
}
while (mergelist_cnt && mergelist_parents[mergelist_cnt-1] == NULL)
mergelist_cnt--;
}
static void free_filter(filter_rule *ex)
{
if (ex->rflags & FILTRULE_PERDIR_MERGE)
teardown_mergelist(ex);
free(ex->pattern);
free(ex);
}
static void free_filters(filter_rule *head)
static void free_filters(filter_rule *ent)
{
filter_rule *rev_head = NULL;
/* Reverse the list so we deactivate mergelists in the proper LIFO
* order. */
while (head) {
filter_rule *next = head->next;
head->next = rev_head;
rev_head = head;
head = next;
}
while (rev_head) {
filter_rule *prev = rev_head->next;
/* Tear down mergelists here, not in free_filter, so that we
* affect only real filter lists and not temporarily allocated
* filters. */
if (rev_head->rflags & FILTRULE_PERDIR_MERGE)
teardown_mergelist(rev_head);
free_filter(rev_head);
rev_head = prev;
while (ent) {
filter_rule *next = ent->next;
free_filter(ent);
ent = next;
}
}
@@ -252,7 +246,10 @@ static void add_rule(filter_rule_list *listp, const char *pat, unsigned int pat_
* add it again. */
for (i = 0; i < mergelist_cnt; i++) {
filter_rule *ex = mergelist_parents[i];
const char *s = strrchr(ex->pattern, '/');
const char *s;
if (!ex)
continue;
s = strrchr(ex->pattern, '/');
if (s)
s++;
else
@@ -264,9 +261,8 @@ static void add_rule(filter_rule_list *listp, const char *pat, unsigned int pat_
}
}
if (!(lp = new_array(filter_rule_list, 1)))
if (!(lp = new_array0(filter_rule_list, 1)))
out_of_memory("add_rule");
lp->head = lp->tail = lp->parent_dirscan_head = NULL;
if (asprintf(&lp->debug_type, " [per-dir %s]", cp) < 0)
out_of_memory("add_rule");
rule->u.mergelist = lp;
@@ -297,16 +293,23 @@ static void add_rule(filter_rule_list *listp, const char *pat, unsigned int pat_
}
}
static void clear_filter_list(filter_rule_list *listp)
/* This frees any non-inherited items, leaving just inherited items on the list. */
static void pop_filter_list(filter_rule_list *listp)
{
if (listp->tail) {
/* Truncate any inherited items from the local list. */
listp->tail->next = NULL;
/* Now free everything that is left. */
free_filters(listp->head);
}
filter_rule *inherited;
listp->head = listp->tail = NULL;
if (!listp->tail)
return;
inherited = listp->tail->next;
/* Truncate any inherited items from the local list. */
listp->tail->next = NULL;
/* Now free everything that is left. */
free_filters(listp->head);
listp->head = inherited;
listp->tail = NULL;
}
/* This returns an expanded (absolute) filename for the merge-file name if
@@ -457,8 +460,6 @@ static BOOL setup_merge_file(int mergelist_num, filter_rule *ex,
strlcpy(y, save, MAXPATHLEN);
while ((*x++ = *y++) != '/') {}
}
/* Save current head for freeing when the mergelist becomes inactive. */
lp->parent_dirscan_head = lp->head;
parent_dirscan = False;
if (DEBUG_GTE(FILTER, 2)) {
rprintf(FINFO, "[%s] completed parent_dirscan for mergelist #%d%s\n",
@@ -501,15 +502,20 @@ void *push_local_filters(const char *dir, unsigned int dirlen)
push->mergelist_cnt = mergelist_cnt;
for (i = 0; i < mergelist_cnt; i++) {
memcpy(&push->mergelists[i], mergelist_parents[i]->u.mergelist,
sizeof (filter_rule_list));
filter_rule *ex = mergelist_parents[i];
if (!ex)
continue;
memcpy(&push->mergelists[i], ex->u.mergelist, sizeof (filter_rule_list));
}
/* Note: parse_filter_file() might increase mergelist_cnt, so keep
* this loop separate from the above loop. */
for (i = 0; i < mergelist_cnt; i++) {
filter_rule *ex = mergelist_parents[i];
filter_rule_list *lp = ex->u.mergelist;
filter_rule_list *lp;
if (!ex)
continue;
lp = ex->u.mergelist;
if (DEBUG_GTE(FILTER, 2)) {
rprintf(FINFO, "[%s] pushing mergelist #%d%s\n",
@@ -553,44 +559,38 @@ void pop_local_filters(void *mem)
for (i = mergelist_cnt; i-- > 0; ) {
filter_rule *ex = mergelist_parents[i];
filter_rule_list *lp = ex->u.mergelist;
filter_rule_list *lp;
if (!ex)
continue;
lp = ex->u.mergelist;
if (DEBUG_GTE(FILTER, 2)) {
rprintf(FINFO, "[%s] popping mergelist #%d%s\n",
who_am_i(), i, lp->debug_type);
}
clear_filter_list(lp);
if (i >= old_mergelist_cnt) {
/* This mergelist does not exist in the state to be
* restored. Free its parent_dirscan list to clean up
* any per-dir mergelists defined there so we don't
* crash trying to restore nonexistent state for them
* below. (Counterpart to setup_merge_file call in
* push_local_filters. Must be done here, not in
* free_filter, for LIFO order.) */
pop_filter_list(lp);
if (i >= old_mergelist_cnt && lp->head) {
/* This mergelist does not exist in the state to be restored, but it
* still has inherited rules. This can sometimes happen if a per-dir
* merge file calls setup_merge_file() in push_local_filters() and that
* leaves some inherited rules that aren't in the pushed list state. */
if (DEBUG_GTE(FILTER, 2)) {
rprintf(FINFO, "[%s] freeing parent_dirscan filters of mergelist #%d%s\n",
who_am_i(), i, ex->u.mergelist->debug_type);
}
free_filters(lp->parent_dirscan_head);
lp->parent_dirscan_head = NULL;
pop_filter_list(lp);
}
}
/* If we cleaned things up properly, the only still-active mergelists
* should be those with a state to be restored. */
assert(mergelist_cnt == old_mergelist_cnt);
if (!pop)
return; /* No state to restore. */
if (!pop) {
/* No state to restore. */
return;
}
for (i = 0; i < mergelist_cnt; i++) {
memcpy(mergelist_parents[i]->u.mergelist, &pop->mergelists[i],
sizeof (filter_rule_list));
for (i = 0; i < old_mergelist_cnt; i++) {
filter_rule *ex = mergelist_parents[i];
if (!ex)
continue;
memcpy(ex->u.mergelist, &pop->mergelists[i], sizeof (filter_rule_list));
}
free(pop);
@@ -624,7 +624,7 @@ void change_local_filter_dir(const char *dname, int dlen, int dir_depth)
filt_array[cur_depth] = push_local_filters(dname, dlen);
}
static int rule_matches(const char *fname, filter_rule *ex, int name_is_dir)
static int rule_matches(const char *fname, filter_rule *ex, int name_flags)
{
int slash_handling, str_cnt = 0, anchored_match = 0;
int ret_match = ex->rflags & FILTRULE_NEGATE ? 0 : 1;
@@ -635,6 +635,9 @@ static int rule_matches(const char *fname, filter_rule *ex, int name_is_dir)
if (!*name)
return 0;
if (!(name_flags & NAME_IS_XATTR) ^ !(ex->rflags & FILTRULE_XATTR))
return 0;
if (!ex->u.slash_cnt && !(ex->rflags & FILTRULE_WILD2)) {
/* If the pattern does not have any slashes AND it does
* not have a "**" (which could match a slash), then we
@@ -652,7 +655,7 @@ static int rule_matches(const char *fname, filter_rule *ex, int name_is_dir)
strings[str_cnt++] = "/";
}
strings[str_cnt++] = name;
if (name_is_dir) {
if (name_flags & NAME_IS_DIR) {
/* Allow a trailing "/"+"***" to match the directory. */
if (ex->rflags & FILTRULE_WILD3_SUFFIX)
strings[str_cnt++] = "/";
@@ -704,7 +707,7 @@ static int rule_matches(const char *fname, filter_rule *ex, int name_is_dir)
static void report_filter_result(enum logcode code, char const *name,
filter_rule const *ent,
int name_is_dir, const char *type)
int name_flags, const char *type)
{
/* If a trailing slash is present to match only directories,
* then it is stripped out by add_rule(). So as a special
@@ -714,17 +717,40 @@ static void report_filter_result(enum logcode code, char const *name,
static char *actions[2][2]
= { {"show", "hid"}, {"risk", "protect"} };
const char *w = who_am_i();
const char *t = name_flags & NAME_IS_XATTR ? "xattr"
: name_flags & NAME_IS_DIR ? "directory"
: "file";
rprintf(code, "[%s] %sing %s %s because of pattern %s%s%s\n",
w, actions[*w!='s'][!(ent->rflags & FILTRULE_INCLUDE)],
name_is_dir ? "directory" : "file", name, ent->pattern,
t, name, ent->pattern,
ent->rflags & FILTRULE_DIRECTORY ? "/" : "", type);
}
}
/* 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
* filter_level is set to either SERVER_FILTERS or ALL_FILTERS. */
int name_is_excluded(const char *fname, int name_flags, int filter_level)
{
if (daemon_filter_list.head && check_filter(&daemon_filter_list, FLOG, fname, name_flags) < 0) {
if (!(name_flags & NAME_IS_XATTR))
errno = ENOENT;
return 1;
}
if (filter_level != ALL_FILTERS)
return 0;
if (filter_list.head && check_filter(&filter_list, FINFO, fname, name_flags) < 0)
return 1;
return 0;
}
/* 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_filter(filter_rule_list *listp, enum logcode code,
const char *name, int name_is_dir)
const char *name, int name_flags)
{
filter_rule *ent;
@@ -732,22 +758,19 @@ int check_filter(filter_rule_list *listp, enum logcode code,
if (ignore_perishable && ent->rflags & FILTRULE_PERISHABLE)
continue;
if (ent->rflags & FILTRULE_PERDIR_MERGE) {
int rc = check_filter(ent->u.mergelist, code, name,
name_is_dir);
int rc = check_filter(ent->u.mergelist, code, name, name_flags);
if (rc)
return rc;
continue;
}
if (ent->rflags & FILTRULE_CVS_IGNORE) {
int rc = check_filter(&cvs_filter_list, code, name,
name_is_dir);
int rc = check_filter(&cvs_filter_list, code, name, name_flags);
if (rc)
return rc;
continue;
}
if (rule_matches(name, ent, name_is_dir)) {
report_filter_result(code, name, ent, name_is_dir,
listp->debug_type);
if (rule_matches(name, ent, name_flags)) {
report_filter_result(code, name, ent, name_flags, listp->debug_type);
return ent->rflags & FILTRULE_INCLUDE ? 1 : -1;
}
}
@@ -872,7 +895,7 @@ static filter_rule *parse_rule_tok(const char **rulestr_ptr,
switch (ch) {
case ':':
rule->rflags |= FILTRULE_PERDIR_MERGE
| FILTRULE_FINISH_SETUP;
| FILTRULE_FINISH_SETUP;
/* FALL THROUGH */
case '.':
rule->rflags |= FILTRULE_MERGE_FILE;
@@ -972,6 +995,10 @@ static filter_rule *parse_rule_tok(const char **rulestr_ptr,
goto invalid;
rule->rflags |= FILTRULE_WORD_SPLIT;
break;
case 'x':
rule->rflags |= FILTRULE_XATTR;
saw_xattr_filter = 1;
break;
}
}
if (*s)
@@ -1093,7 +1120,8 @@ void parse_filter_str(filter_rule_list *listp, const char *rulestr,
"[%s] clearing filter list%s\n",
who_am_i(), listp->debug_type);
}
clear_filter_list(listp);
pop_filter_list(listp);
listp->head = NULL;
goto free_continue;
}
@@ -1258,6 +1286,8 @@ char *get_rule_prefix(filter_rule *rule, const char *pat, int for_xfer,
}
if (rule->rflags & FILTRULE_EXCLUDE_SELF)
*op++ = 'e';
if (rule->rflags & FILTRULE_XATTR)
*op++ = 'x';
if (rule->rflags & FILTRULE_SENDER_SIDE
&& (!for_xfer || protocol_version >= 29))
*op++ = 's';
@@ -1376,8 +1406,7 @@ void recv_filter_list(int f_in)
char line[BIGPATHBUFLEN];
int xflags = protocol_version >= 29 ? 0 : XFLG_OLD_PREFIXES;
int receiver_wants_list = prune_empty_dirs
|| (delete_mode
&& (!delete_excluded || protocol_version >= 29));
|| (delete_mode && (!delete_excluded || protocol_version >= 29));
unsigned int len;
if (!local_server && (am_sender || receiver_wants_list)) {

View File

@@ -3,7 +3,7 @@
*
* Copyright (C) 1998 Andrew Tridgell
* Copyright (C) 2002 Martin Pool
* Copyright (C) 2004-2014 Wayne Davison
* Copyright (C) 2004-2020 Wayne Davison
*
* 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
@@ -26,21 +26,26 @@
#define ENODATA EAGAIN
#endif
/* We want all reads to be aligned on 1K boundries. */
#define ALIGN_BOUNDRY 1024
/* We want all reads to be aligned on 1K boundaries. */
#define ALIGN_BOUNDARY 1024
/* How far past the boundary is an offset? */
#define ALIGNED_OVERSHOOT(oft) ((oft) & (ALIGN_BOUNDRY-1))
#define ALIGNED_OVERSHOOT(oft) ((oft) & (ALIGN_BOUNDARY-1))
/* Round up a length to the next boundary */
#define ALIGNED_LENGTH(len) ((((len) - 1) | (ALIGN_BOUNDRY-1)) + 1)
#define ALIGNED_LENGTH(len) ((((len) - 1) | (ALIGN_BOUNDARY-1)) + 1)
extern int sparse_files;
OFF_T preallocated_len = 0;
static OFF_T sparse_seek = 0;
static OFF_T sparse_past_write = 0;
int sparse_end(int f, OFF_T size)
{
int ret;
sparse_past_write = 0;
if (!sparse_seek)
return 0;
@@ -63,8 +68,10 @@ int sparse_end(int f, OFF_T size)
return ret;
}
static int write_sparse(int f, char *buf, int len)
/* Note that the offset is just the caller letting us know where
* the current file position is in the file. The use_seek arg tells
* us that we should seek over matching data instead of writing it. */
static int write_sparse(int f, int use_seek, OFF_T offset, const char *buf, int len)
{
int l1 = 0, l2 = 0;
int ret;
@@ -77,9 +84,24 @@ static int write_sparse(int f, char *buf, int len)
if (l1 == len)
return len;
if (sparse_seek)
do_lseek(f, sparse_seek, SEEK_CUR);
if (sparse_seek) {
if (sparse_past_write >= preallocated_len) {
if (do_lseek(f, sparse_seek, SEEK_CUR) < 0)
return -1;
} else if (do_punch_hole(f, sparse_past_write, sparse_seek) < 0) {
sparse_seek = 0;
return -1;
}
}
sparse_seek = l2;
sparse_past_write = offset + len - l2;
if (use_seek) {
/* The in-place data already matches. */
if (do_lseek(f, len - (l1+l2), SEEK_CUR) < 0)
return -1;
return len;
}
while ((ret = write(f, buf + l1, len - (l1+l2))) <= 0) {
if (ret < 0 && errno == EINTR)
@@ -96,7 +118,6 @@ static int write_sparse(int f, char *buf, int len)
return len;
}
static char *wf_writeBuf;
static size_t wf_writeBufSize;
static size_t wf_writeBufCnt;
@@ -118,12 +139,10 @@ int flush_write_file(int f)
return ret;
}
/*
* write_file does not allow incomplete writes. It loops internally
* until len bytes are written or errno is set.
*/
int write_file(int f, char *buf, int len)
/* write_file does not allow incomplete writes. It loops internally
* until len bytes are written or errno is set. Note that use_seek and
* offset are only used in sparse processing (see write_sparse()). */
int write_file(int f, int use_seek, OFF_T offset, const char *buf, int len)
{
int ret = 0;
@@ -131,7 +150,8 @@ int write_file(int f, char *buf, int len)
int r1;
if (sparse_files > 0) {
int len1 = MIN(len, SPARSE_WRITE_SIZE);
r1 = write_sparse(f, buf, len1);
r1 = write_sparse(f, use_seek, offset, buf, len1);
offset += r1;
} else {
if (!wf_writeBuf) {
wf_writeBufSize = WRITE_SIZE * 8;
@@ -164,6 +184,30 @@ int write_file(int f, char *buf, int len)
return ret;
}
/* An in-place update found identical data at an identical location. We either
* just seek past it, or (for an in-place sparse update), we give the data to
* the sparse processor with the use_seek flag set. */
int skip_matched(int fd, OFF_T offset, const char *buf, int len)
{
OFF_T pos;
if (sparse_files > 0) {
if (write_file(fd, 1, offset, buf, len) != len)
return -1;
return 0;
}
if (flush_write_file(fd) < 0)
return -1;
if ((pos = do_lseek(fd, len, SEEK_CUR)) != offset + len) {
rsyserr(FERROR_XFER, errno, "lseek returned %s, not %s",
big_num(pos), big_num(offset));
return -1;
}
return 0;
}
/* This provides functionality somewhat similar to mmap() but using read().
* It gives sliding window access to a file. mmap() is not used because of
@@ -271,7 +315,6 @@ char *map_ptr(struct map_struct *map, OFF_T offset, int32 len)
return map->p + align_fudge;
}
int unmap_file(struct map_struct *map)
{
int ret;
@@ -281,7 +324,9 @@ int unmap_file(struct map_struct *map)
map->p = NULL;
}
ret = map->status;
memset(map, 0, sizeof map[0]);
#if 0 /* I don't think we really need this. */
force_memzero(map, sizeof map[0]);
#endif
free(map);
return ret;

297
flist.c
View File

@@ -4,7 +4,7 @@
* Copyright (C) 1996 Andrew Tridgell
* Copyright (C) 1996 Paul Mackerras
* Copyright (C) 2001, 2002 Martin Pool <mbp@samba.org>
* Copyright (C) 2002-2014 Wayne Davison
* Copyright (C) 2002-2020 Wayne Davison
*
* 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
@@ -33,9 +33,11 @@ extern int am_sender;
extern int am_generator;
extern int inc_recurse;
extern int always_checksum;
extern int checksum_type;
extern int module_id;
extern int ignore_errors;
extern int numeric_ids;
extern int quiet;
extern int recurse;
extern int use_qsort;
extern int xfer_dirs;
@@ -53,6 +55,7 @@ extern int preserve_specials;
extern int delete_during;
extern int missing_args;
extern int eol_nulls;
extern int atimes_ndx;
extern int relative_paths;
extern int implied_dirs;
extern int ignore_perishable;
@@ -89,7 +92,7 @@ extern iconv_t ic_send, ic_recv;
#define PTR_SIZE (sizeof (struct file_struct *))
int io_error;
int checksum_len;
int flist_csum_len;
dev_t filesystem_dev; /* used to implement -x */
struct file_list *cur_flist, *first_flist, *dir_flist;
@@ -98,6 +101,7 @@ int flist_cnt = 0; /* how many (non-tmp) file list objects exist */
int file_total = 0; /* total of all active items over all file-lists */
int file_old_total = 0; /* total of active items that will soon be gone */
int flist_eof = 0; /* all the file-lists are now known */
int xfer_flags_as_varint = 0;
#define NORMAL_NAME 0
#define SLASH_ENDING_NAME 1
@@ -127,6 +131,7 @@ static char tmp_sum[MAX_DIGEST_LEN];
static char empty_sum[MAX_DIGEST_LEN];
static int flist_count_offset; /* for --delete --progress */
static int show_filelist_progress;
static void flist_sort_and_clean(struct file_list *flist, int strip_root);
static void output_flist(struct file_list *flist);
@@ -137,18 +142,15 @@ void init_flist(void)
rprintf(FINFO, "FILE_STRUCT_LEN=%d, EXTRA_LEN=%d\n",
(int)FILE_STRUCT_LEN, (int)EXTRA_LEN);
}
checksum_len = protocol_version < 21 ? 2
: protocol_version < 30 ? MD4_DIGEST_LEN
: MD5_DIGEST_LEN;
}
flist_csum_len = csum_len_for_type(checksum_type, 1);
static int show_filelist_p(void)
{
return INFO_GTE(FLIST, 1) && xfer_dirs && !am_server && !inc_recurse;
show_filelist_progress = INFO_GTE(FLIST, 1) && xfer_dirs && !am_server && !inc_recurse;
}
static void start_filelist_progress(char *kind)
{
if (quiet)
return;
rprintf(FCLIENT, "%s ... ", kind);
output_needs_newline = 1;
rflush(FINFO);
@@ -156,23 +158,28 @@ static void start_filelist_progress(char *kind)
static void emit_filelist_progress(int count)
{
if (quiet)
return;
if (output_needs_newline == 2) /* avoid a newline in the middle of this filelist-progress output */
output_needs_newline = 0;
rprintf(FCLIENT, " %d files...\r", count);
output_needs_newline = 2;
}
static void maybe_emit_filelist_progress(int count)
{
if (INFO_GTE(FLIST, 2) && show_filelist_p() && (count % 100) == 0)
if (INFO_GTE(FLIST, 2) && show_filelist_progress && (count % 100) == 0)
emit_filelist_progress(count);
}
static void finish_filelist_progress(const struct file_list *flist)
{
output_needs_newline = 0;
if (INFO_GTE(FLIST, 2)) {
/* This overwrites the progress line */
rprintf(FINFO, "%d file%sto consider\n",
flist->used, flist->used == 1 ? " " : "s ");
} else {
output_needs_newline = 0;
rprintf(FINFO, "done\n");
}
}
@@ -237,16 +244,6 @@ int link_stat(const char *path, STRUCT_STAT *stp, int follow_dirlinks)
#endif
}
static inline int is_daemon_excluded(const char *fname, int is_dir)
{
if (daemon_filter_list.head
&& check_filter(&daemon_filter_list, FLOG, fname, is_dir) < 0) {
errno = ENOENT;
return 1;
}
return 0;
}
static inline int path_is_daemon_excluded(char *path, int ignore_filename)
{
if (daemon_filter_list.head) {
@@ -273,23 +270,9 @@ static inline int path_is_daemon_excluded(char *path, int ignore_filename)
return 0;
}
/* 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
* filter_level is set to either SERVER_FILTERS or ALL_FILTERS. */
static int is_excluded(const char *fname, int is_dir, int filter_level)
static inline int is_excluded(const char *fname, int is_dir, int filter_level)
{
#if 0 /* This currently never happens, so avoid a useless compare. */
if (filter_level == NO_FILTERS)
return 0;
#endif
if (is_daemon_excluded(fname, is_dir))
return 1;
if (filter_level != ALL_FILTERS)
return 0;
if (filter_list.head
&& check_filter(&filter_list, FINFO, fname, is_dir) < 0)
return 1;
return 0;
return name_is_excluded(fname, is_dir ? NAME_IS_DIR : NAME_IS_FILE, filter_level);
}
static void send_directory(int f, struct file_list *flist,
@@ -397,7 +380,7 @@ static void send_file_entry(int f, const char *fname, struct file_struct *file,
#endif
int ndx, int first_ndx)
{
static time_t modtime;
static time_t modtime, atime;
static mode_t mode;
#ifdef SUPPORT_HARD_LINKS
static int64 dev;
@@ -497,14 +480,20 @@ static void send_file_entry(int f, const char *fname, struct file_struct *file,
modtime = file->modtime;
if (NSEC_BUMP(file) && protocol_version >= 31)
xflags |= XMIT_MOD_NSEC;
if (atimes_ndx && !S_ISDIR(mode)) {
if (F_ATIME(file) == atime)
xflags |= XMIT_SAME_ATIME;
else
atime = F_ATIME(file);
}
#ifdef SUPPORT_HARD_LINKS
if (tmp_dev != -1) {
if (protocol_version >= 30) {
struct ht_int64_node *np = idev_find(tmp_dev, tmp_ino);
first_hlink_ndx = (int32)(long)np->data - 1;
first_hlink_ndx = (int32)(long)np->data; /* is -1 when new */
if (first_hlink_ndx < 0) {
np->data = (void*)(long)(first_ndx + ndx + 1);
np->data = (void*)(long)(first_ndx + ndx);
xflags |= XMIT_HLINK_FIRST;
}
if (DEBUG_GTE(HLINK, 1)) {
@@ -539,11 +528,14 @@ static void send_file_entry(int f, const char *fname, struct file_struct *file,
if (l2 > 255)
xflags |= XMIT_LONG_NAME;
/* We must make sure we don't send a zero flag byte or the
* other end will terminate the flist transfer. Note that
* the use of XMIT_TOP_DIR on a non-dir has no meaning, so
* it's harmless way to add a bit to the first flag byte. */
if (protocol_version >= 28) {
/* We must avoid sending a flag value of 0 (or an initial byte of
* 0 for the older xflags protocol) or it will signal the end of
* the list. Note that the use of XMIT_TOP_DIR on a non-dir has
* no meaning, so it's a harmless way to add a bit to the first
* flag byte. */
if (xfer_flags_as_varint)
write_varint(f, xflags ? xflags : XMIT_EXTENDED_FLAGS);
else if (protocol_version >= 28) {
if (!xflags && !S_ISDIR(mode))
xflags |= XMIT_TOP_DIR;
if ((xflags & 0xFF00) || !xflags) {
@@ -583,6 +575,8 @@ static void send_file_entry(int f, const char *fname, struct file_struct *file,
write_varint(f, F_MOD_NSEC(file));
if (!(xflags & XMIT_SAME_MODE))
write_int(f, to_wire_mode(mode));
if (atimes_ndx && !S_ISDIR(mode) && !(xflags & XMIT_SAME_ATIME))
write_varlong(f, atime, 4);
if (preserve_uid && !(xflags & XMIT_SAME_UID)) {
if (protocol_version < 30)
write_int(f, uid);
@@ -656,7 +650,7 @@ static void send_file_entry(int f, const char *fname, struct file_struct *file,
/* Prior to 28, we sent a useless set of nulls. */
sum = empty_sum;
}
write_buf(f, sum, checksum_len);
write_buf(f, sum, flist_csum_len);
}
#ifdef SUPPORT_HARD_LINKS
@@ -670,7 +664,7 @@ static void send_file_entry(int f, const char *fname, struct file_struct *file,
static struct file_struct *recv_file_entry(int f, struct file_list *flist, int xflags)
{
static int64 modtime;
static int64 modtime, atime;
static mode_t mode;
#ifdef SUPPORT_HARD_LINKS
static int64 dev;
@@ -777,8 +771,10 @@ static struct file_struct *recv_file_entry(int f, struct file_list *flist, int x
struct file_struct *first = flist->files[first_hlink_ndx - flist->ndx_start];
file_length = F_LENGTH(first);
modtime = first->modtime;
modtime_nsec = F_MOD_NSEC(first);
modtime_nsec = F_MOD_NSEC_or_0(first);
mode = first->mode;
if (atimes_ndx && !S_ISDIR(mode))
atime = F_ATIME(first);
if (preserve_uid)
uid = F_OWNER(first);
if (preserve_gid)
@@ -817,6 +813,16 @@ static struct file_struct *recv_file_entry(int f, struct file_list *flist, int x
modtime_nsec = 0;
if (!(xflags & XMIT_SAME_MODE))
mode = from_wire_mode(read_int(f));
if (atimes_ndx && !S_ISDIR(mode) && !(xflags & XMIT_SAME_ATIME)) {
atime = read_varlong(f, 4);
#if SIZEOF_TIME_T < SIZEOF_INT64
if (!am_generator && (int64)(time_t)atime != atime) {
rprintf(FERROR_XFER,
"Access time value of %s truncated on receiver.\n",
lastname);
}
#endif
}
if (chmod_modes && !S_ISLNK(mode) && mode)
mode = tweak_mode(mode, chmod_modes);
@@ -913,7 +919,7 @@ static struct file_struct *recv_file_entry(int f, struct file_list *flist, int x
if (file_length > 0xFFFFFFFFu && S_ISREG(mode))
extra_len += EXTRA_LEN;
#endif
#ifdef HAVE_UTIMENSAT
#ifdef CAN_SET_NSEC
if (modtime_nsec)
extra_len += EXTRA_LEN;
#endif
@@ -948,14 +954,21 @@ static struct file_struct *recv_file_entry(int f, struct file_list *flist, int x
memcpy(bp, basename, basename_len);
#ifdef SUPPORT_HARD_LINKS
if (xflags & XMIT_HLINKED)
if (xflags & XMIT_HLINKED
#ifndef CAN_HARDLINK_SYMLINK
&& !S_ISLNK(mode)
#endif
#ifndef CAN_HARDLINK_SPECIAL
&& !IS_SPECIAL(mode) && !IS_DEVICE(mode)
#endif
)
file->flags |= FLAG_HLINKED;
#endif
file->modtime = (time_t)modtime;
#ifdef HAVE_UTIMENSAT
#ifdef CAN_SET_NSEC
if (modtime_nsec) {
file->flags |= FLAG_MOD_NSEC;
OPT_EXTRA(file, 0)->unum = modtime_nsec;
F_MOD_NSEC(file) = modtime_nsec;
}
#endif
file->len32 = (uint32)file_length;
@@ -966,7 +979,7 @@ static struct file_struct *recv_file_entry(int f, struct file_list *flist, int x
exit_cleanup(RERR_UNSUPPORTED);
#else
file->flags |= FLAG_LENGTH64;
OPT_EXTRA(file, NSEC_BUMP(file))->unum = (uint32)(file_length >> 32);
F_HIGH_LEN(file) = (uint32)(file_length >> 32);
#endif
}
#endif
@@ -977,6 +990,8 @@ static struct file_struct *recv_file_entry(int f, struct file_list *flist, int x
F_GROUP(file) = gid;
file->flags |= gid_flags;
}
if (atimes_ndx && !S_ISDIR(mode))
F_ATIME(file) = atime;
if (unsort_ndx)
F_NDX(file) = flist->used + flist->ndx_start;
@@ -1086,10 +1101,10 @@ static struct file_struct *recv_file_entry(int f, struct file_list *flist, int x
ino = read_longint(f);
}
np = idev_find(dev, ino);
ndx = (int32)(long)np->data - 1;
ndx = (int32)(long)np->data; /* is -1 when new */
if (ndx < 0) {
ndx = cnt++;
np->data = (void*)(long)cnt;
ndx = cnt++;
}
F_HL_GNUM(file) = ndx;
}
@@ -1105,9 +1120,9 @@ static struct file_struct *recv_file_entry(int f, struct file_list *flist, int x
}
if (first_hlink_ndx >= flist->ndx_start) {
struct file_struct *first = flist->files[first_hlink_ndx - flist->ndx_start];
memcpy(bp, F_SUM(first), checksum_len);
memcpy(bp, F_SUM(first), flist_csum_len);
} else
read_buf(f, bp, checksum_len);
read_buf(f, bp, flist_csum_len);
}
#ifdef SUPPORT_ACLS
@@ -1357,14 +1372,14 @@ struct file_struct *make_file(const char *fname, struct file_list *flist,
#ifdef ST_MTIME_NSEC
if (st.ST_MTIME_NSEC && protocol_version >= 31) {
file->flags |= FLAG_MOD_NSEC;
OPT_EXTRA(file, 0)->unum = st.ST_MTIME_NSEC;
F_MOD_NSEC(file) = st.ST_MTIME_NSEC;
}
#endif
file->len32 = (uint32)st.st_size;
#if SIZEOF_CAPITAL_OFF_T >= 8
if (st.st_size > 0xFFFFFFFFu && S_ISREG(st.st_mode)) {
file->flags |= FLAG_LENGTH64;
OPT_EXTRA(file, NSEC_BUMP(file))->unum = (uint32)(st.st_size >> 32);
F_HIGH_LEN(file) = (uint32)(st.st_size >> 32);
}
#endif
file->mode = st.st_mode;
@@ -1374,6 +1389,8 @@ struct file_struct *make_file(const char *fname, struct file_list *flist,
F_GROUP(file) = st.st_gid;
if (am_generator && st.st_uid == our_uid)
file->flags |= FLAG_OWNED_BY_US;
if (atimes_ndx && !S_ISDIR(file->mode))
F_ATIME(file) = st.st_atime;
if (basename != thisname)
file->dirname = lastdir;
@@ -1395,7 +1412,7 @@ struct file_struct *make_file(const char *fname, struct file_list *flist,
}
if (sender_keeps_checksum && S_ISREG(st.st_mode))
memcpy(F_SUM(file), tmp_sum, checksum_len);
memcpy(F_SUM(file), tmp_sum, flist_csum_len);
if (unsort_ndx)
F_NDX(file) = stats.num_dirs;
@@ -1403,6 +1420,20 @@ struct file_struct *make_file(const char *fname, struct file_list *flist,
return file;
}
OFF_T get_device_size(int fd, const char *fname)
{
OFF_T off = lseek(fd, 0, SEEK_END);
if (off == (OFF_T) -1) {
rsyserr(FERROR, errno, "failed to get device size via seek: %s", fname);
return 0;
}
if (lseek(fd, 0, SEEK_SET) != 0)
rsyserr(FERROR, errno, "failed to seek device back to start: %s", fname);
return off;
}
/* Only called for temporary file_struct entries created by make_file(). */
void unmake_file(struct file_struct *file)
{
@@ -1647,6 +1678,7 @@ static void add_dirs_to_tree(int parent_ndx, struct file_list *from_flist,
int32 *parent_dp = parent_ndx < 0 ? NULL
: F_DIR_NODE_P(dir_flist->sorted[parent_ndx]);
/* The sending side is adding entries to dir_flist in sorted order, so sorted & files are the same. */
flist_expand(dir_flist, dir_cnt);
dir_flist->sorted = dir_flist->files;
@@ -1714,6 +1746,8 @@ static void send_directory(int f, struct file_list *flist, char *fbuf, int len,
interpret_stat_error(fbuf, True);
return;
}
if (errno == ENOTDIR && (flags & FLAG_PERHAPS_DIR))
return;
io_error |= IOERR_GENERAL;
rsyserr(FERROR_XFER, errno, "opendir %s failed", full_fname(fbuf));
return;
@@ -1952,6 +1986,18 @@ static void send1extra(int f, struct file_struct *file, struct file_list *flist)
free(relname_list);
}
static void write_end_of_flist(int f, int send_io_error)
{
if (xfer_flags_as_varint) {
write_varint(f, 0);
write_varint(f, send_io_error ? io_error : 0);
} else if (send_io_error) {
write_shortint(f, XMIT_EXTENDED_FLAGS|XMIT_IO_ERROR_ENDLIST);
write_varint(f, io_error);
} else
write_byte(f, 0);
}
void send_extra_file_list(int f, int at_least)
{
struct file_list *flist;
@@ -1981,7 +2027,7 @@ void send_extra_file_list(int f, int at_least)
else
dir_ndx = send_dir_ndx;
write_ndx(f, NDX_FLIST_OFFSET - dir_ndx);
flist->parent_ndx = dir_ndx;
flist->parent_ndx = send_dir_ndx; /* the sending side must remember the sorted ndx value */
send1extra(f, file, flist);
prev_flags = file->flags;
@@ -2003,14 +2049,13 @@ void send_extra_file_list(int f, int at_least)
}
if (io_error == save_io_error || ignore_errors)
write_byte(f, 0);
else if (use_safe_inc_flist) {
write_shortint(f, XMIT_EXTENDED_FLAGS|XMIT_IO_ERROR_ENDLIST);
write_varint(f, io_error);
} else {
write_end_of_flist(f, 0);
else if (use_safe_inc_flist)
write_end_of_flist(f, 1);
else {
if (delete_during)
fatal_unsafe_io_error();
write_byte(f, 0);
write_end_of_flist(f, 0);
}
if (need_unsorted_flist) {
@@ -2080,7 +2125,7 @@ struct file_list *send_file_list(int f, int argc, char *argv[])
int implied_dot_dir = 0;
rprintf(FLOG, "building file list\n");
if (show_filelist_p())
if (show_filelist_progress)
start_filelist_progress("building file list");
else if (inc_recurse && INFO_GTE(FLIST, 1) && !am_server)
rprintf(FCLIENT, "sending incremental file list\n");
@@ -2255,7 +2300,7 @@ struct file_list *send_file_list(int f, int argc, char *argv[])
memmove(fbuf, fn, len + 1);
if (link_stat(fbuf, &st, copy_dirlinks || name_type != NORMAL_NAME) != 0
|| (name_type != DOTDIR_NAME && is_daemon_excluded(fbuf, S_ISDIR(st.st_mode)))
|| (name_type != DOTDIR_NAME && is_excluded(fbuf, S_ISDIR(st.st_mode) != 0, SERVER_FILTERS))
|| (relative_paths && path_is_daemon_excluded(fbuf, 1))) {
if (errno != ENOENT || missing_args == 0) {
/* This is a transfer error, but inhibit deletion
@@ -2339,14 +2384,13 @@ struct file_list *send_file_list(int f, int argc, char *argv[])
/* Indicate end of file list */
if (io_error == 0 || ignore_errors)
write_byte(f, 0);
else if (use_safe_inc_flist) {
write_shortint(f, XMIT_EXTENDED_FLAGS|XMIT_IO_ERROR_ENDLIST);
write_varint(f, io_error);
} else {
write_end_of_flist(f, 0);
else if (use_safe_inc_flist)
write_end_of_flist(f, 1);
else {
if (delete_during && inc_recurse)
fatal_unsafe_io_error();
write_byte(f, 0);
write_end_of_flist(f, 0);
}
#ifdef SUPPORT_HARD_LINKS
@@ -2354,7 +2398,7 @@ struct file_list *send_file_list(int f, int argc, char *argv[])
idev_destroy();
#endif
if (show_filelist_p())
if (show_filelist_progress)
finish_filelist_progress(flist);
gettimeofday(&end_tv, NULL);
@@ -2428,14 +2472,15 @@ struct file_list *send_file_list(int f, int argc, char *argv[])
return flist;
}
struct file_list *recv_file_list(int f)
struct file_list *recv_file_list(int f, int dir_ndx)
{
const char *good_dirname = NULL;
struct file_list *flist;
int dstart, flags;
int64 start_read;
if (!first_flist) {
if (show_filelist_p())
if (show_filelist_progress)
start_filelist_progress("receiving file list");
else if (inc_recurse && INFO_GTE(FLIST, 1) && !am_server)
rprintf(FCLIENT, "receiving incremental file list\n");
@@ -2464,27 +2509,56 @@ struct file_list *recv_file_list(int f)
dstart = 0;
}
while ((flags = read_byte(f)) != 0) {
while (1) {
struct file_struct *file;
if (protocol_version >= 28 && (flags & XMIT_EXTENDED_FLAGS))
flags |= read_byte(f) << 8;
if (flags == (XMIT_EXTENDED_FLAGS|XMIT_IO_ERROR_ENDLIST)) {
int err;
if (!use_safe_inc_flist) {
rprintf(FERROR, "Invalid flist flag: %x\n", flags);
exit_cleanup(RERR_PROTOCOL);
if (xfer_flags_as_varint) {
if ((flags = read_varint(f)) == 0) {
int err = read_varint(f);
if (!ignore_errors)
io_error |= err;
break;
}
} else {
if ((flags = read_byte(f)) == 0)
break;
if (protocol_version >= 28 && (flags & XMIT_EXTENDED_FLAGS))
flags |= read_byte(f) << 8;
if (flags == (XMIT_EXTENDED_FLAGS|XMIT_IO_ERROR_ENDLIST)) {
int err;
if (!use_safe_inc_flist) {
rprintf(FERROR, "Invalid flist flag: %x\n", flags);
exit_cleanup(RERR_PROTOCOL);
}
err = read_varint(f);
if (!ignore_errors)
io_error |= err;
break;
}
err = read_varint(f);
if (!ignore_errors)
io_error |= err;
break;
}
flist_expand(flist, 1);
file = recv_file_entry(f, flist, flags);
if (inc_recurse) {
static const char empty_dir[] = "\0";
const char *cur_dir = file->dirname ? file->dirname : empty_dir;
if (relative_paths && *cur_dir == '/')
cur_dir++;
if (cur_dir != good_dirname) {
const char *d = dir_ndx >= 0 ? f_name(dir_flist->files[dir_ndx], NULL) : empty_dir;
if (strcmp(cur_dir, d) != 0) {
rprintf(FERROR,
"ABORTING due to invalid path from sender: %s/%s\n",
cur_dir, file->basename);
exit_cleanup(RERR_PROTOCOL);
}
good_dirname = cur_dir;
}
}
if (S_ISREG(file->mode)) {
/* Already counted */
} else if (S_ISDIR(file->mode)) {
@@ -2514,7 +2588,7 @@ struct file_list *recv_file_list(int f)
if (DEBUG_GTE(FLIST, 2))
rprintf(FINFO, "received %d names\n", flist->used);
if (show_filelist_p())
if (show_filelist_progress)
finish_filelist_progress(flist);
if (need_unsorted_flist) {
@@ -2608,7 +2682,7 @@ void recv_additional_file_list(int f)
rprintf(FINFO, "[%s] receiving flist for dir %d\n",
who_am_i(), ndx);
}
flist = recv_file_list(f);
flist = recv_file_list(f, ndx);
flist->parent_ndx = ndx;
}
}
@@ -2664,6 +2738,34 @@ int flist_find(struct file_list *flist, struct file_struct *f)
return -1;
}
/* Search for a name in the file list. You must specify want_dir_match as:
* 1=match directories, 0=match non-directories, or -1=match either. */
int flist_find_name(struct file_list *flist, const char *fname, int want_dir_match)
{
struct { /* We have to create a temporary file_struct for the search. */
struct file_struct f;
char name_space[MAXPATHLEN];
} t;
char fbuf[MAXPATHLEN];
const char *slash = strrchr(fname, '/');
const char *basename = slash ? slash+1 : fname;
memset(&t.f, 0, FILE_STRUCT_LEN);
memcpy((void *)t.f.basename, basename, strlen(basename)+1);
if (slash) {
strlcpy(fbuf, fname, slash - fname + 1);
t.f.dirname = fbuf;
} else
t.f.dirname = NULL;
t.f.mode = want_dir_match > 0 ? S_IFDIR : S_IFREG;
if (want_dir_match < 0)
return flist_find_ignore_dirness(flist, &t.f);
return flist_find(flist, &t.f);
}
/* Search for an identically-named item in the file list. Differs from
* flist_find in that an item that agrees with "f" in directory-ness is
* preferred but one that does not is still found. */
@@ -2908,8 +3010,7 @@ static void flist_sort_and_clean(struct file_list *flist, int strip_root)
clear_file(fp);
}
prev_depth = F_DEPTH(file);
if (is_excluded(f_name(file, fbuf), 1,
ALL_FILTERS)) {
if (is_excluded(f_name(file, fbuf), 1, ALL_FILTERS)) {
/* Keep dirs through this dir. */
for (j = prev_depth-1; ; j--) {
fp = flist->sorted[prev_i];
@@ -3194,6 +3295,7 @@ struct file_list *get_dirlist(char *dirname, int dlen, int flags)
int save_xfer_dirs = xfer_dirs;
int save_prune_empty_dirs = prune_empty_dirs;
int senddir_fd = flags & GDL_IGNORE_FILTER_RULES ? -2 : -1;
int senddir_flags = FLAG_CONTENT_DIR;
if (dlen < 0) {
dlen = strlcpy(dirbuf, dirname, MAXPATHLEN);
@@ -3204,9 +3306,12 @@ struct file_list *get_dirlist(char *dirname, int dlen, int flags)
dirlist = flist_new(FLIST_TEMP, "get_dirlist");
if (flags & GDL_PERHAPS_DIR)
senddir_flags |= FLAG_PERHAPS_DIR;
recurse = 0;
xfer_dirs = 1;
send_directory(senddir_fd, dirlist, dirname, dlen, FLAG_CONTENT_DIR);
send_directory(senddir_fd, dirlist, dirname, dlen, senddir_flags);
xfer_dirs = save_xfer_dirs;
recurse = save_recurse;
if (INFO_GTE(PROGRESS, 1))

View File

@@ -4,7 +4,7 @@
* Copyright (C) 1996-2000 Andrew Tridgell
* Copyright (C) 1996 Paul Mackerras
* Copyright (C) 2002 Martin Pool <mbp@samba.org>
* Copyright (C) 2003-2014 Wayne Davison
* Copyright (C) 2003-2020 Wayne Davison
*
* 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
@@ -39,6 +39,7 @@ extern int preserve_acls;
extern int preserve_xattrs;
extern int preserve_links;
extern int preserve_devices;
extern int write_devices;
extern int preserve_specials;
extern int preserve_hard_links;
extern int preserve_executability;
@@ -57,6 +58,8 @@ extern int update_only;
extern int human_readable;
extern int ignore_existing;
extern int ignore_non_existing;
extern int want_xattr_optim;
extern int modify_window;
extern int inplace;
extern int append_mode;
extern int make_backups;
@@ -73,11 +76,9 @@ extern int protocol_version;
extern int file_total;
extern int fuzzy_basis;
extern int always_checksum;
extern int checksum_len;
extern int flist_csum_len;
extern char *partial_dir;
extern int compare_dest;
extern int copy_dest;
extern int link_dest;
extern int alt_dest_type;
extern int whole_file;
extern int list_only;
extern int read_batch;
@@ -98,6 +99,7 @@ extern struct file_list *cur_flist, *first_flist, *dir_flist;
extern filter_rule_list filter_list, daemon_filter_list;
int maybe_ATTRS_REPORT = 0;
int maybe_ATTRS_ACCURATE_TIME = 0;
static dev_t dev_zero;
static int deldelay_size = 0, deldelay_cnt = 0;
@@ -111,7 +113,7 @@ static int need_retouch_dir_perms;
static const char *solo_file = NULL;
enum nonregtype {
TYPE_DIR, TYPE_SPECIAL, TYPE_DEVICE, TYPE_SYMLINK
TYPE_DIR, TYPE_SPECIAL, TYPE_DEVICE, TYPE_SYMLINK
};
/* Forward declarations. */
@@ -169,10 +171,8 @@ static int remember_delete(struct file_struct *file, const char *fname, int flag
deldelay_buf[deldelay_cnt++] = '!';
while (1) {
len = snprintf(deldelay_buf + deldelay_cnt,
deldelay_size - deldelay_cnt,
"%x %s%c",
(int)file->mode, fname, '\0');
len = snprintf(deldelay_buf + deldelay_cnt, deldelay_size - deldelay_cnt,
"%x %s%c", (int)file->mode, fname, '\0');
if ((deldelay_cnt += len) <= deldelay_size)
break;
deldelay_cnt -= len;
@@ -209,8 +209,7 @@ static int read_delay_line(char *buf, int *flags_p)
deldelay_size - deldelay_cnt);
if (len == 0) {
if (deldelay_cnt) {
rprintf(FERROR,
"ERROR: unexpected EOF in delete-delay file.\n");
rprintf(FERROR, "ERROR: unexpected EOF in delete-delay file.\n");
}
return -1;
}
@@ -274,6 +273,7 @@ static void do_delayed_deletions(char *delbuf)
static void delete_in_dir(char *fbuf, struct file_struct *file, dev_t *fs_dev)
{
static int already_warned = 0;
static struct hashtable *dev_tbl;
struct file_list *dirlist;
char delbuf[MAXPATHLEN];
int dlen, i;
@@ -302,10 +302,16 @@ static void delete_in_dir(char *fbuf, struct file_struct *file, dev_t *fs_dev)
change_local_filter_dir(fbuf, dlen, F_DEPTH(file));
if (one_file_system) {
if (file->flags & FLAG_TOP_DIR)
if (!dev_tbl)
dev_tbl = hashtable_create(16, HT_KEY64);
if (file->flags & FLAG_TOP_DIR) {
hashtable_find(dev_tbl, *fs_dev+1, "");
filesystem_dev = *fs_dev;
else if (filesystem_dev != *fs_dev)
return;
} else if (filesystem_dev != *fs_dev) {
if (!hashtable_find(dev_tbl, *fs_dev+1, NULL))
return;
filesystem_dev = *fs_dev; /* it's a prior top-dir dev */
}
}
dirlist = get_dirlist(fbuf, dlen, 0);
@@ -381,9 +387,13 @@ static void do_delete_pass(void)
rprintf(FINFO, " \r");
}
static inline int time_differs(struct file_struct *file, stat_x *sxp)
static inline int mtime_differs(STRUCT_STAT *stp, struct file_struct *file)
{
return cmp_time(sxp->st.st_mtime, file->modtime);
#ifdef ST_MTIME_NSEC
return !same_time(stp->st_mtime, stp->ST_MTIME_NSEC, file->modtime, F_MOD_NSEC_or_0(file));
#else
return !same_time(stp->st_mtime, 0, file->modtime, 0);
#endif
}
static inline int perms_differ(struct file_struct *file, stat_x *sxp)
@@ -440,7 +450,7 @@ int unchanged_attrs(const char *fname, struct file_struct *file, stat_x *sxp)
{
if (S_ISLNK(file->mode)) {
#ifdef CAN_SET_SYMLINK_TIMES
if (preserve_times & PRESERVE_LINK_TIMES && time_differs(file, sxp))
if (preserve_times & PRESERVE_LINK_TIMES && mtime_differs(&sxp->st, file))
return 0;
#endif
#ifdef CAN_CHMOD_SYMLINK
@@ -460,7 +470,7 @@ int unchanged_attrs(const char *fname, struct file_struct *file, stat_x *sxp)
return 0;
#endif
} else {
if (preserve_times && time_differs(file, sxp))
if (preserve_times && mtime_differs(&sxp->st, file))
return 0;
if (perms_differ(file, sxp))
return 0;
@@ -495,10 +505,13 @@ void itemize(const char *fnamecmp, struct file_struct *file, int ndx, int statre
if (iflags & ITEM_LOCAL_CHANGE)
iflags |= symlink_timeset_failed_flags;
} else if (keep_time
? cmp_time(file->modtime, sxp->st.st_mtime) != 0
? mtime_differs(&sxp->st, file)
: iflags & (ITEM_TRANSFER|ITEM_LOCAL_CHANGE) && !(iflags & ITEM_MATCHED)
&& (!(iflags & ITEM_XNAME_FOLLOWS) || *xname))
iflags |= ITEM_REPORT_TIME;
if (atimes_ndx && !S_ISDIR(file->mode) && !S_ISLNK(file->mode)
&& !same_time(F_ATIME(file), 0, sxp->st.st_atime, 0))
iflags |= ITEM_REPORT_ATIME;
#if !defined HAVE_LCHMOD && !defined HAVE_SETATTRLIST
if (S_ISLNK(file->mode)) {
;
@@ -512,8 +525,7 @@ void itemize(const char *fnamecmp, struct file_struct *file, int ndx, int statre
iflags |= ITEM_REPORT_PERMS;
if (uid_ndx && am_root && (uid_t)F_OWNER(file) != sxp->st.st_uid)
iflags |= ITEM_REPORT_OWNER;
if (gid_ndx && !(file->flags & FLAG_SKIP_GROUP)
&& sxp->st.st_gid != (gid_t)F_GROUP(file))
if (gid_ndx && !(file->flags & FLAG_SKIP_GROUP) && sxp->st.st_gid != (gid_t)F_GROUP(file))
iflags |= ITEM_REPORT_GROUP;
#ifdef SUPPORT_ACLS
if (preserve_acls && !S_ISLNK(file->mode)) {
@@ -553,7 +565,9 @@ void itemize(const char *fnamecmp, struct file_struct *file, int ndx, int statre
#ifdef SUPPORT_XATTRS
if (preserve_xattrs && do_xfers
&& iflags & (ITEM_REPORT_XATTR|ITEM_TRANSFER)) {
int fd = iflags & ITEM_REPORT_XATTR ? sock_f_out : -1;
int fd = iflags & ITEM_REPORT_XATTR
&& !(want_xattr_optim && BITS_SET(iflags, ITEM_XNAME_FOLLOWS|ITEM_LOCAL_CHANGE))
? sock_f_out : -1;
send_xattr_request(NULL, file, fd);
}
#endif
@@ -576,7 +590,7 @@ int unchanged_file(char *fn, struct file_struct *file, STRUCT_STAT *st)
if (always_checksum > 0 && S_ISREG(st->st_mode)) {
char sum[MAX_DIGEST_LEN];
file_checksum(fn, st, sum);
return memcmp(sum, F_SUM(file), checksum_len) == 0;
return memcmp(sum, F_SUM(file), flist_csum_len) == 0;
}
if (size_only > 0)
@@ -585,7 +599,7 @@ int unchanged_file(char *fn, struct file_struct *file, STRUCT_STAT *st)
if (ignore_times)
return 0;
return cmp_time(st->st_mtime, file->modtime) == 0;
return !mtime_differs(st, file);
}
@@ -630,14 +644,14 @@ static void sum_sizes_sqroot(struct sum_struct *sum, int64 len)
if (c < 0 || c >= max_blength)
blength = max_blength;
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 < (int64)blength * blength)
blength &= ~c;
c >>= 1;
} while (c >= 8); /* round to multiple of 8 */
blength = MAX(blength, BLOCK_SIZE);
}
}
@@ -762,7 +776,7 @@ static struct file_struct *find_fuzzy(struct file_struct *file, struct file_list
if (!S_ISREG(fp->mode) || !F_LENGTH(fp) || fp->flags & FLAG_FILE_SENT)
continue;
if (F_LENGTH(fp) == F_LENGTH(file) && cmp_time(fp->modtime, file->modtime) == 0) {
if (F_LENGTH(fp) == F_LENGTH(file) && same_time(fp->modtime, 0, file->modtime, 0)) {
if (DEBUG_GTE(FUZZY, 2))
rprintf(FINFO, "fuzzy size/modtime match for %s\n", f_name(fp, NULL));
*fnamecmp_type_ptr = FNAMECMP_FUZZY + i;
@@ -868,52 +882,47 @@ static int try_dests_reg(struct file_struct *file, char *fname, int ndx,
pathjoin(cmpbuf, MAXPATHLEN, basis_dir[j], fname);
if (link_stat(cmpbuf, &sxp->st, 0) < 0 || !S_ISREG(sxp->st.st_mode))
continue;
switch (match_level) {
case 0:
if (match_level == 0) {
best_match = j;
match_level = 1;
/* FALL THROUGH */
case 1:
if (!unchanged_file(cmpbuf, file, &sxp->st))
continue;
}
if (!unchanged_file(cmpbuf, file, &sxp->st))
continue;
if (match_level == 1) {
best_match = j;
match_level = 2;
/* FALL THROUGH */
case 2:
if (!unchanged_attrs(cmpbuf, file, sxp)) {
free_stat_x(sxp);
continue;
}
}
if (unchanged_attrs(cmpbuf, file, sxp)) {
best_match = j;
match_level = 3;
break;
}
break;
free_stat_x(sxp);
} while (basis_dir[++j] != NULL);
if (!match_level)
return -1;
goto got_nothing_for_ya;
if (j != best_match) {
j = best_match;
pathjoin(cmpbuf, MAXPATHLEN, basis_dir[j], fname);
if (link_stat(cmpbuf, &sxp->st, 0) < 0)
return -1;
goto got_nothing_for_ya;
}
if (match_level == 3 && !copy_dest) {
if (match_level == 3 && alt_dest_type != COPY_DEST) {
if (find_exact_for_existing) {
if (link_dest && real_st.st_dev == sxp->st.st_dev && real_st.st_ino == sxp->st.st_ino)
if (alt_dest_type == LINK_DEST && real_st.st_dev == sxp->st.st_dev && real_st.st_ino == sxp->st.st_ino)
return -1;
if (do_unlink(fname) < 0 && errno != ENOENT) {
sxp->st = real_st;
return -1;
}
if (do_unlink(fname) < 0 && errno != ENOENT)
goto got_nothing_for_ya;
}
#ifdef SUPPORT_HARD_LINKS
if (link_dest) {
if (alt_dest_type == LINK_DEST) {
if (!hard_link_one(file, fname, cmpbuf, 1))
goto try_a_copy;
if (atimes_ndx)
set_file_attrs(fname, file, sxp, NULL, 0);
if (preserve_hard_links && F_IS_HLINKED(file))
finish_hard_link(file, fname, ndx, &sxp->st, itemizing, code, j);
if (!maybe_ATTRS_REPORT && (INFO_GTE(NAME, 2) || stdout_format_has_i > 1)) {
@@ -932,10 +941,8 @@ static int try_dests_reg(struct file_struct *file, char *fname, int ndx,
return -2;
}
if (find_exact_for_existing) {
sxp->st = real_st;
return -1;
}
if (find_exact_for_existing)
goto got_nothing_for_ya;
if (match_level >= 2) {
#ifdef SUPPORT_HARD_LINKS
@@ -943,7 +950,7 @@ static int try_dests_reg(struct file_struct *file, char *fname, int ndx,
#endif
if (!dry_run && copy_altdest_file(cmpbuf, fname, file) < 0) {
if (find_exact_for_existing) /* Can get here via hard-link failure */
sxp->st = real_st;
goto got_nothing_for_ya;
return -1;
}
if (itemizing)
@@ -963,6 +970,10 @@ static int try_dests_reg(struct file_struct *file, char *fname, int ndx,
}
return FNAMECMP_BASIS_DIR_LOW + j;
got_nothing_for_ya:
sxp->st = real_st;
return -1;
}
/* This is only called for non-regular files. We return -2 if we've finished
@@ -1077,7 +1088,7 @@ static int try_dests_non(struct file_struct *file, char *fname, int ndx,
if (match_level == 3) {
#ifdef SUPPORT_HARD_LINKS
if (link_dest
if (alt_dest_type == LINK_DEST
#ifndef CAN_HARDLINK_SYMLINK
&& !S_ISLNK(file->mode)
#endif
@@ -1098,7 +1109,7 @@ static int try_dests_non(struct file_struct *file, char *fname, int ndx,
match_level = 2;
if (itemizing && stdout_format_has_i
&& (INFO_GTE(NAME, 2) || stdout_format_has_i > 1)) {
int chg = compare_dest && type != TYPE_DIR ? 0
int chg = alt_dest_type == COMPARE_DEST && type != TYPE_DIR ? 0
: ITEM_LOCAL_CHANGE + (match_level == 3 ? ITEM_XNAME_FOLLOWS : 0);
char *lp = match_level == 3 ? "" : NULL;
itemize(cmpbuf, file, ndx, 0, sxp, chg + ITEM_MATCHED, 0, lp);
@@ -1116,35 +1127,40 @@ static int try_dests_non(struct file_struct *file, char *fname, int ndx,
static void list_file_entry(struct file_struct *f)
{
char permbuf[PERMSTRING_SIZE];
int64 len;
int colwidth = human_readable ? 14 : 11;
const char *mtime_str = timestring(f->modtime);
int size_width = human_readable ? 14 : 11;
int mtime_width = 1 + strlen(mtime_str);
int atime_width = atimes_ndx ? mtime_width : 0;
if (!F_IS_ACTIVE(f)) {
/* this can happen if duplicate names were removed */
return;
}
permstring(permbuf, f->mode);
len = F_LENGTH(f);
/* TODO: indicate '+' if the entry has an ACL. */
#ifdef SUPPORT_LINKS
if (preserve_links && S_ISLNK(f->mode)) {
rprintf(FINFO, "%s %*s %s %s -> %s\n",
permbuf, colwidth, human_num(len),
timestring(f->modtime), f_name(f, NULL),
F_SYMLINK(f));
} else
#endif
if (missing_args == 2 && f->mode == 0) {
rprintf(FINFO, "%-*s %s\n",
colwidth + 31, "*missing",
10 + 1 + size_width + mtime_width + atime_width, "*missing",
f_name(f, NULL));
} else {
rprintf(FINFO, "%s %*s %s %s\n",
permbuf, colwidth, human_num(len),
timestring(f->modtime), f_name(f, NULL));
const char *atime_str = atimes_ndx && !S_ISDIR(f->mode) ? timestring(F_ATIME(f)) : "";
const char *arrow, *lnk;
permstring(permbuf, f->mode);
#ifdef SUPPORT_LINKS
if (preserve_links && S_ISLNK(f->mode)) {
arrow = " -> ";
lnk = F_SYMLINK(f);
} else
#endif
arrow = lnk = "";
rprintf(FINFO, "%s %*s %s%*s %s%s%s\n",
permbuf, size_width, human_num(F_LENGTH(f)),
timestring(f->modtime), atime_width, atime_str,
f_name(f, NULL), arrow, lnk);
}
}
@@ -1174,6 +1190,7 @@ static void recv_generator(char *fname, struct file_struct *file, int ndx,
int itemizing, enum logcode code, int f_out)
{
static const char *parent_dirname = "";
static struct file_struct *prior_dir_file = NULL;
/* Missing dir not created due to --dry-run; will still be scanned. */
static struct file_struct *dry_missing_dir = NULL;
/* Missing dir whose contents are skipped altogether due to
@@ -1206,6 +1223,8 @@ static void recv_generator(char *fname, struct file_struct *file, int ndx,
return;
}
maybe_ATTRS_ACCURATE_TIME = always_checksum ? ATTRS_ACCURATE_TIME : 0;
if (skip_dir) {
if (is_below(file, skip_dir)) {
if (is_dir)
@@ -1253,6 +1272,24 @@ static void recv_generator(char *fname, struct file_struct *file, int ndx,
const char *dn = file->dirname ? file->dirname : ".";
dry_missing_dir = NULL;
if (parent_dirname != dn && strcmp(parent_dirname, dn) != 0) {
/* Each parent dir must be in the file list or the flist data is bad.
* Optimization: most of the time the parent dir will be the last dir
* this function was asked to process in the file list. */
if (!inc_recurse
&& (*dn != '.' || dn[1]) /* Avoid an issue with --relative and the "." dir. */
&& (!prior_dir_file || strcmp(dn, f_name(prior_dir_file, NULL)) != 0)
&& flist_find_name(cur_flist, dn, 1) < 0) {
/* The --delete-missing-args option can actually put invalid entries into
* the file list, so if that option was specified, we'll just complain about
* it and allow it. */
if (missing_args == 2 && file->mode == 0)
rprintf(FERROR, "WARNING: parent dir is absent in the file list: %s\n", dn);
else {
rprintf(FERROR, "ABORTING due to invalid path from sender: %s/%s\n",
dn, file->basename);
exit_cleanup(RERR_PROTOCOL);
}
}
if (relative_paths && !implied_dirs
&& do_stat(dn, &sx.st) < 0) {
if (dry_run)
@@ -1280,21 +1317,6 @@ static void recv_generator(char *fname, struct file_struct *file, int ndx,
}
parent_dirname = dn;
if (need_fuzzy_dirlist && S_ISREG(file->mode)) {
int i;
strlcpy(fnamecmpbuf, dn, sizeof fnamecmpbuf);
for (i = 0; i < fuzzy_basis; i++) {
if (i && pathjoin(fnamecmpbuf, MAXPATHLEN, basis_dir[i-1], dn) >= MAXPATHLEN)
continue;
fuzzy_dirlist[i] = get_dirlist(fnamecmpbuf, -1, GDL_IGNORE_FILTER_RULES);
if (fuzzy_dirlist[i] && fuzzy_dirlist[i]->used == 0) {
flist_free(fuzzy_dirlist[i]);
fuzzy_dirlist[i] = NULL;
}
}
need_fuzzy_dirlist = 0;
}
statret = link_stat(fname, &sx.st, keep_dirlinks && is_dir);
stat_errno = errno;
}
@@ -1354,7 +1376,7 @@ static void recv_generator(char *fname, struct file_struct *file, int ndx,
added_perms = 0;
if (is_dir < 0) {
if (!(preserve_times & PRESERVE_DIR_TIMES))
return;
goto cleanup;
/* In inc_recurse mode we want to make sure any missing
* directories get created while we're still processing
* the parent dir (which allows us to touch the parent
@@ -1389,12 +1411,10 @@ static void recv_generator(char *fname, struct file_struct *file, int ndx,
if (file->flags & FLAG_DIR_CREATED)
statret = -1;
if (!preserve_perms) { /* See comment in non-dir code below. */
file->mode = dest_mode(file->mode, sx.st.st_mode,
dflt_perms, statret == 0);
file->mode = dest_mode(file->mode, sx.st.st_mode, dflt_perms, statret == 0);
}
if (statret != 0 && basis_dir[0] != NULL) {
int j = try_dests_non(file, fname, ndx, fnamecmpbuf, &sx,
itemizing, code);
int j = try_dests_non(file, fname, ndx, fnamecmpbuf, &sx, itemizing, code);
if (j == -2) {
itemizing = 0;
code = FNONE;
@@ -1416,8 +1436,7 @@ static void recv_generator(char *fname, struct file_struct *file, int ndx,
"recv_generator: mkdir %s failed",
full_fname(fname));
skipping_dir_contents:
rprintf(FERROR,
"*** Skipping any contents from this failed directory ***\n");
rprintf(FERROR, "*** Skipping any contents from this failed directory ***\n");
skip_dir = file;
file->flags |= FLAG_MISSING_DIR;
goto cleanup;
@@ -1429,7 +1448,7 @@ static void recv_generator(char *fname, struct file_struct *file, int ndx,
copy_xattrs(fnamecmpbuf, fname);
#endif
if (set_file_attrs(fname, file, real_ret ? NULL : &real_sx, NULL, 0)
&& INFO_GTE(NAME, 1) && code != FNONE && f_out != -1)
&& INFO_GTE(NAME, 1) && code != FNONE && f_out != -1)
rprintf(code, "%s/\n", fname);
/* We need to ensure that the dirs in the transfer have both
@@ -1464,6 +1483,7 @@ static void recv_generator(char *fname, struct file_struct *file, int ndx,
else
change_local_filter_dir(fname, strlen(fname), F_DEPTH(file));
}
prior_dir_file = file;
goto cleanup;
}
@@ -1471,8 +1491,7 @@ static void recv_generator(char *fname, struct file_struct *file, int ndx,
* mode based on the local permissions and some heuristics. */
if (!preserve_perms) {
int exists = statret == 0 && !S_ISDIR(sx.st.st_mode);
file->mode = dest_mode(file->mode, sx.st.st_mode, dflt_perms,
exists);
file->mode = dest_mode(file->mode, sx.st.st_mode, dflt_perms, exists);
}
#ifdef SUPPORT_HARD_LINKS
@@ -1495,7 +1514,7 @@ static void recv_generator(char *fname, struct file_struct *file, int ndx,
"ignoring unsafe symlink \"%s\" -> \"%s\"\n",
fname, sl);
}
return;
goto cleanup;
}
if (statret == 0) {
char lnk[MAXPATHLEN];
@@ -1508,7 +1527,7 @@ static void recv_generator(char *fname, struct file_struct *file, int ndx,
set_file_attrs(fname, file, &sx, NULL, maybe_ATTRS_REPORT);
if (itemizing)
itemize(fname, file, ndx, 0, &sx, 0, 0, NULL);
#if defined SUPPORT_HARD_LINKS && defined CAN_HARDLINK_SYMLINK
#ifdef SUPPORT_HARD_LINKS
if (preserve_hard_links && F_IS_HLINKED(file))
finish_hard_link(file, fname, ndx, &sx.st, itemizing, code, -1);
#endif
@@ -1517,15 +1536,14 @@ static void recv_generator(char *fname, struct file_struct *file, int ndx,
goto cleanup;
}
} else if (basis_dir[0] != NULL) {
int j = try_dests_non(file, fname, ndx, fnamecmpbuf, &sx,
itemizing, code);
int j = try_dests_non(file, fname, ndx, fnamecmpbuf, &sx, itemizing, code);
if (j == -2) {
#ifndef CAN_HARDLINK_SYMLINK
if (link_dest) {
if (alt_dest_type == LINK_DEST) {
/* Resort to --copy-dest behavior. */
} else
#endif
if (!copy_dest)
if (alt_dest_type != COPY_DEST)
goto cleanup;
itemizing = 0;
code = FNONE;
@@ -1534,7 +1552,7 @@ static void recv_generator(char *fname, struct file_struct *file, int ndx,
fnamecmp = fnamecmpbuf;
}
}
if (atomic_create(file, fname, sl, MAKEDEV(0, 0), &sx, statret == 0 ? DEL_FOR_SYMLINK : 0)) {
if (atomic_create(file, fname, sl, NULL, MAKEDEV(0, 0), &sx, statret == 0 ? DEL_FOR_SYMLINK : 0)) {
set_file_attrs(fname, file, NULL, NULL, 0);
if (itemizing) {
if (statret == 0 && !S_ISLNK(sx.st.st_mode))
@@ -1593,15 +1611,14 @@ static void recv_generator(char *fname, struct file_struct *file, int ndx,
goto cleanup;
}
} else if (basis_dir[0] != NULL) {
int j = try_dests_non(file, fname, ndx, fnamecmpbuf, &sx,
itemizing, code);
int j = try_dests_non(file, fname, ndx, fnamecmpbuf, &sx, itemizing, code);
if (j == -2) {
#ifndef CAN_HARDLINK_SPECIAL
if (link_dest) {
if (alt_dest_type == LINK_DEST) {
/* Resort to --copy-dest behavior. */
} else
#endif
if (!copy_dest)
if (alt_dest_type != COPY_DEST)
goto cleanup;
itemizing = 0;
code = FNONE;
@@ -1615,7 +1632,7 @@ static void recv_generator(char *fname, struct file_struct *file, int ndx,
fname, (int)file->mode,
(long)major(rdev), (long)minor(rdev));
}
if (atomic_create(file, fname, NULL, rdev, &sx, del_for_flag)) {
if (atomic_create(file, fname, NULL, NULL, rdev, &sx, del_for_flag)) {
set_file_attrs(fname, file, NULL, NULL, 0);
if (itemizing) {
itemize(fnamecmp, file, ndx, statret, &sx,
@@ -1657,8 +1674,7 @@ static void recv_generator(char *fname, struct file_struct *file, int ndx,
goto cleanup;
}
if (update_only > 0 && statret == 0
&& cmp_time(sx.st.st_mtime, file->modtime) > 0) {
if (update_only > 0 && statret == 0 && file->modtime - sx.st.st_mtime <= modify_window) {
if (INFO_GTE(SKIP, 1))
rprintf(FINFO, "%s is newer\n", fname);
#ifdef SUPPORT_HARD_LINKS
@@ -1670,16 +1686,15 @@ static void recv_generator(char *fname, struct file_struct *file, int ndx,
fnamecmp_type = FNAMECMP_FNAME;
if (statret == 0 && !S_ISREG(sx.st.st_mode)) {
if (statret == 0 && !(S_ISREG(sx.st.st_mode) || (write_devices && IS_DEVICE(sx.st.st_mode)))) {
if (delete_item(fname, sx.st.st_mode, del_opts | DEL_FOR_FILE) != 0)
goto cleanup;
statret = -1;
stat_errno = ENOENT;
}
if (basis_dir[0] != NULL && (statret != 0 || !copy_dest)) {
int j = try_dests_reg(file, fname, ndx, fnamecmpbuf, &sx,
statret == 0, itemizing, code);
if (basis_dir[0] != NULL && (statret != 0 || alt_dest_type != COPY_DEST)) {
int j = try_dests_reg(file, fname, ndx, fnamecmpbuf, &sx, statret == 0, itemizing, code);
if (j == -2) {
if (remove_source_files == 1)
goto return_with_success;
@@ -1697,14 +1712,30 @@ static void recv_generator(char *fname, struct file_struct *file, int ndx,
real_ret = statret;
if (partial_dir && (partialptr = partial_dir_fname(fname)) != NULL
&& link_stat(partialptr, &partial_st, 0) == 0
&& S_ISREG(partial_st.st_mode)) {
&& link_stat(partialptr, &partial_st, 0) == 0
&& S_ISREG(partial_st.st_mode)) {
if (statret != 0)
goto prepare_to_open;
} else
partialptr = NULL;
if (statret != 0 && fuzzy_basis) {
if (need_fuzzy_dirlist && S_ISREG(file->mode)) {
const char *dn = file->dirname ? file->dirname : ".";
int i;
strlcpy(fnamecmpbuf, dn, sizeof fnamecmpbuf);
for (i = 0; i < fuzzy_basis; i++) {
if (i && pathjoin(fnamecmpbuf, MAXPATHLEN, basis_dir[i-1], dn) >= MAXPATHLEN)
continue;
fuzzy_dirlist[i] = get_dirlist(fnamecmpbuf, -1, GDL_IGNORE_FILTER_RULES | GDL_PERHAPS_DIR);
if (fuzzy_dirlist[i] && fuzzy_dirlist[i]->used == 0) {
flist_free(fuzzy_dirlist[i]);
fuzzy_dirlist[i] = NULL;
}
}
need_fuzzy_dirlist = 0;
}
/* Sets fnamecmp_type to FNAMECMP_FUZZY or above. */
fuzzy_file = find_fuzzy(file, fuzzy_dirlist, &fnamecmp_type);
if (fuzzy_file) {
@@ -1735,14 +1766,14 @@ static void recv_generator(char *fname, struct file_struct *file, int ndx,
if (fnamecmp_type <= FNAMECMP_BASIS_DIR_HIGH)
;
else if (fnamecmp_type == FNAMECMP_FUZZY)
else if (fnamecmp_type >= FNAMECMP_FUZZY)
;
else if (unchanged_file(fnamecmp, file, &sx.st)) {
if (partialptr) {
do_unlink(partialptr);
handle_partial_dir(partialptr, PDIR_DELETE);
}
set_file_attrs(fname, file, &sx, NULL, maybe_ATTRS_REPORT);
set_file_attrs(fname, file, &sx, NULL, maybe_ATTRS_REPORT | maybe_ATTRS_ACCURATE_TIME);
if (itemizing)
itemize(fnamecmp, file, ndx, statret, &sx, 0, 0, NULL);
#ifdef SUPPORT_HARD_LINKS
@@ -1889,8 +1920,8 @@ static void recv_generator(char *fname, struct file_struct *file, int ndx,
} else {
if (generate_and_send_sums(fd, sx.st.st_size, f_out, f_copy) < 0) {
rprintf(FWARNING,
"WARNING: file is too large for checksum sending: %s\n",
fnamecmp);
"WARNING: file is too large for checksum sending: %s\n",
fnamecmp);
write_sum_head(f_out, NULL);
}
close(fd);
@@ -1920,11 +1951,11 @@ static void recv_generator(char *fname, struct file_struct *file, int ndx,
}
/* If we are replacing an existing hard link, symlink, device, or special file,
* create a temp-name item and rename it into place. Only a symlink or hard
* link puts a non-NULL value into the lnk arg. Only a device puts a non-0
* value into the rdev arg. Specify 0 for the del_for_flag if there is not a
* file to replace. This returns 1 on success and 0 on failure. */
int atomic_create(struct file_struct *file, char *fname, const char *lnk,
* create a temp-name item and rename it into place. A symlimk specifies slnk,
* a hard link specifies hlnk, otherwise we create a device based on rdev.
* Specify 0 for the del_for_flag if there is not a file to replace. This
* returns 1 on success and 0 on failure. */
int atomic_create(struct file_struct *file, char *fname, const char *slnk, const char *hlnk,
dev_t rdev, stat_x *sxp, int del_for_flag)
{
char tmpname[MAXPATHLEN];
@@ -1949,23 +1980,22 @@ int atomic_create(struct file_struct *file, char *fname, const char *lnk,
create_name = skip_atomic ? fname : tmpname;
if (lnk) {
if (slnk) {
#ifdef SUPPORT_LINKS
if (S_ISLNK(file->mode)
#ifdef SUPPORT_HARD_LINKS /* The first symlink in a hard-linked cluster is always created. */
&& (!F_IS_HLINKED(file) || file->flags & FLAG_HLINK_FIRST)
#endif
) {
if (do_symlink(lnk, create_name) < 0) {
rsyserr(FERROR_XFER, errno, "symlink %s -> \"%s\" failed",
full_fname(create_name), lnk);
return 0;
}
} else
#endif
#ifdef SUPPORT_HARD_LINKS
if (!hard_link_one(file, create_name, lnk, 0))
if (do_symlink(slnk, create_name) < 0) {
rsyserr(FERROR_XFER, errno, "symlink %s -> \"%s\" failed",
full_fname(create_name), slnk);
return 0;
}
#else
return 0;
#endif
} else if (hlnk) {
#ifdef SUPPORT_HARD_LINKS
if (!hard_link_one(file, create_name, hlnk, 0))
return 0;
#else
return 0;
#endif
} else {
if (do_mknod(create_name, file->mode, rdev) < 0) {
@@ -2046,9 +2076,13 @@ static void touch_up_dirs(struct file_list *flist, int ndx)
do_chmod(fname, file->mode);
if (need_retouch_dir_times) {
STRUCT_STAT st;
if (link_stat(fname, &st, 0) == 0
&& cmp_time(st.st_mtime, file->modtime) != 0)
set_modtime(fname, file->modtime, F_MOD_NSEC(file), file->mode);
if (link_stat(fname, &st, 0) == 0 && mtime_differs(&st, file)) {
st.st_mtime = file->modtime;
#ifdef ST_MTIME_NSEC
st.ST_MTIME_NSEC = F_MOD_NSEC_or_0(file);
#endif
set_times(fname, &st);
}
}
if (counter >= loopchk_limit) {
if (allowed_lull)

View File

@@ -15,8 +15,7 @@
fprintf(stderr, "Unable to stat `%s'\n", *argv);
exit(1);
}
printf("%ld/%ld\n", (long)major(st.st_dev),
(long)minor(st.st_dev));
printf("%ld/%ld\n", (long)major(st.st_dev), (long)minor(st.st_dev));
}
return 0;

View File

@@ -3,7 +3,7 @@
* `id -G` on Linux, but it's too hard to find a portable equivalent.
*
* Copyright (C) 2002 Martin Pool
* Copyright (C) 2003-2014 Wayne Davison
* Copyright (C) 2003-2019 Wayne Davison
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 3 as

View File

@@ -1,7 +1,7 @@
/*
* Routines to provide a memory-efficient hashtable.
*
* Copyright (C) 2007-2014 Wayne Davison
* Copyright (C) 2007-2020 Wayne Davison
*
* 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
@@ -66,9 +66,19 @@ void hashtable_destroy(struct hashtable *tbl)
free(tbl);
}
/* This returns the node for the indicated key, either newly created or
* already existing. Returns NULL if not allocating and not found. */
void *hashtable_find(struct hashtable *tbl, int64 key, int allocate_if_missing)
/* Returns the node that holds the indicated key if it exists. When it does not
* exist, it returns either NULL (when data_when_new is NULL), or it returns a
* new node with its node->data set to the indicated value.
*
* If your code doesn't know the data value for a new node in advance (usually
* because it doesn't know if a node is new or not) you should pass in a unique
* (non-0) value that you can use to check if the returned node is new. You can
* then overwrite the data with any value you want (even 0) since it only needs
* to be different than whatever data_when_new value you use later on.
*
* This return is a void* just because it might be pointing at a ht_int32_node
* or a ht_int64_node, and that makes the caller's assignment a little easier. */
void *hashtable_find(struct hashtable *tbl, int64 key, void *data_when_new)
{
int key64 = tbl->key64;
struct ht_int32_node *node;
@@ -79,7 +89,7 @@ void *hashtable_find(struct hashtable *tbl, int64 key, int allocate_if_missing)
exit_cleanup(RERR_MESSAGEIO);
}
if (allocate_if_missing && tbl->entries > HASH_LOAD_LIMIT(tbl->size)) {
if (data_when_new && tbl->entries > HASH_LOAD_LIMIT(tbl->size)) {
void *old_nodes = tbl->nodes;
int size = tbl->size * 2;
int i;
@@ -99,8 +109,12 @@ void *hashtable_find(struct hashtable *tbl, int64 key, int allocate_if_missing)
int64 move_key = HT_KEY(move_node, key64);
if (move_key == 0)
continue;
node = hashtable_find(tbl, move_key, 1);
node->data = move_node->data;
if (move_node->data)
hashtable_find(tbl, move_key, move_node->data);
else {
node = hashtable_find(tbl, move_key, "");
node->data = 0;
}
}
free(old_nodes);
@@ -155,7 +169,7 @@ void *hashtable_find(struct hashtable *tbl, int64 key, int allocate_if_missing)
if (nkey == key)
return node;
if (nkey == 0) {
if (!allocate_if_missing)
if (!data_when_new)
return NULL;
break;
}
@@ -167,6 +181,320 @@ void *hashtable_find(struct hashtable *tbl, int64 key, int allocate_if_missing)
((struct ht_int64_node*)node)->key = key;
else
node->key = (int32)key;
node->data = data_when_new;
tbl->entries++;
return node;
}
#ifndef WORDS_BIGENDIAN
# define HASH_LITTLE_ENDIAN 1
# define HASH_BIG_ENDIAN 0
#else
# define HASH_LITTLE_ENDIAN 0
# define HASH_BIG_ENDIAN 1
#endif
/*
-------------------------------------------------------------------------------
lookup3.c, by Bob Jenkins, May 2006, Public Domain.
These are functions for producing 32-bit hashes for hash table lookup.
hash_word(), hashlittle(), hashlittle2(), hashbig(), mix(), and final()
are externally useful functions. Routines to test the hash are included
if SELF_TEST is defined. You can use this free for any purpose. It's in
the public domain. It has no warranty.
You probably want to use hashlittle(). hashlittle() and hashbig()
hash byte arrays. hashlittle() is is faster than hashbig() on
little-endian machines. Intel and AMD are little-endian machines.
On second thought, you probably want hashlittle2(), which is identical to
hashlittle() except it returns two 32-bit hashes for the price of one.
You could implement hashbig2() if you wanted but I haven't bothered here.
If you want to find a hash of, say, exactly 7 integers, do
a = i1; b = i2; c = i3;
mix(a,b,c);
a += i4; b += i5; c += i6;
mix(a,b,c);
a += i7;
final(a,b,c);
then use c as the hash value. If you have a variable length array of
4-byte integers to hash, use hash_word(). If you have a byte array (like
a character string), use hashlittle(). If you have several byte arrays, or
a mix of things, see the comments above hashlittle().
Why is this so big? I read 12 bytes at a time into 3 4-byte integers,
then mix those integers. This is fast (you can do a lot more thorough
mixing with 12*3 instructions on 3 integers than you can with 3 instructions
on 1 byte), but shoehorning those bytes into integers efficiently is messy.
*/
#define hashsize(n) ((uint32_t)1<<(n))
#define hashmask(n) (hashsize(n)-1)
#define rot(x,k) (((x)<<(k)) | ((x)>>(32-(k))))
/*
-------------------------------------------------------------------------------
mix -- mix 3 32-bit values reversibly.
This is reversible, so any information in (a,b,c) before mix() is
still in (a,b,c) after mix().
If four pairs of (a,b,c) inputs are run through mix(), or through
mix() in reverse, there are at least 32 bits of the output that
are sometimes the same for one pair and different for another pair.
This was tested for:
* pairs that differed by one bit, by two bits, in any combination
of top bits of (a,b,c), or in any combination of bottom bits of
(a,b,c).
* "differ" is defined as +, -, ^, or ~^. For + and -, I transformed
the output delta to a Gray code (a^(a>>1)) so a string of 1's (as
is commonly produced by subtraction) look like a single 1-bit
difference.
* the base values were pseudorandom, all zero but one bit set, or
all zero plus a counter that starts at zero.
Some k values for my "a-=c; a^=rot(c,k); c+=b;" arrangement that
satisfy this are
4 6 8 16 19 4
9 15 3 18 27 15
14 9 3 7 17 3
Well, "9 15 3 18 27 15" didn't quite get 32 bits diffing
for "differ" defined as + with a one-bit base and a two-bit delta. I
used http://burtleburtle.net/bob/hash/avalanche.html to choose
the operations, constants, and arrangements of the variables.
This does not achieve avalanche. There are input bits of (a,b,c)
that fail to affect some output bits of (a,b,c), especially of a. The
most thoroughly mixed value is c, but it doesn't really even achieve
avalanche in c.
This allows some parallelism. Read-after-writes are good at doubling
the number of bits affected, so the goal of mixing pulls in the opposite
direction as the goal of parallelism. I did what I could. Rotates
seem to cost as much as shifts on every machine I could lay my hands
on, and rotates are much kinder to the top and bottom bits, so I used
rotates.
-------------------------------------------------------------------------------
*/
#define mix(a,b,c) \
{ \
a -= c; a ^= rot(c, 4); c += b; \
b -= a; b ^= rot(a, 6); a += c; \
c -= b; c ^= rot(b, 8); b += a; \
a -= c; a ^= rot(c,16); c += b; \
b -= a; b ^= rot(a,19); a += c; \
c -= b; c ^= rot(b, 4); b += a; \
}
/*
-------------------------------------------------------------------------------
final -- final mixing of 3 32-bit values (a,b,c) into c
Pairs of (a,b,c) values differing in only a few bits will usually
produce values of c that look totally different. This was tested for
* pairs that differed by one bit, by two bits, in any combination
of top bits of (a,b,c), or in any combination of bottom bits of
(a,b,c).
* "differ" is defined as +, -, ^, or ~^. For + and -, I transformed
the output delta to a Gray code (a^(a>>1)) so a string of 1's (as
is commonly produced by subtraction) look like a single 1-bit
difference.
* the base values were pseudorandom, all zero but one bit set, or
all zero plus a counter that starts at zero.
These constants passed:
14 11 25 16 4 14 24
12 14 25 16 4 14 24
and these came close:
4 8 15 26 3 22 24
10 8 15 26 3 22 24
11 8 15 26 3 22 24
-------------------------------------------------------------------------------
*/
#define final(a,b,c) \
{ \
c ^= b; c -= rot(b,14); \
a ^= c; a -= rot(c,11); \
b ^= a; b -= rot(a,25); \
c ^= b; c -= rot(b,16); \
a ^= c; a -= rot(c,4); \
b ^= a; b -= rot(a,14); \
c ^= b; c -= rot(b,24); \
}
/*
-------------------------------------------------------------------------------
hashlittle() -- hash a variable-length key into a 32-bit value
k : the key (the unaligned variable-length array of bytes)
length : the length of the key, counting by bytes
val2 : IN: can be any 4-byte value OUT: second 32 bit hash.
Returns a 32-bit value. Every bit of the key affects every bit of
the return value. Two keys differing by one or two bits will have
totally different hash values. Note that the return value is better
mixed than val2, so use that first.
The best hash table sizes are powers of 2. There is no need to do
mod a prime (mod is sooo slow!). If you need less than 32 bits,
use a bitmask. For example, if you need only 10 bits, do
h = (h & hashmask(10));
In which case, the hash table should have hashsize(10) elements.
If you are hashing n strings (uint8_t **)k, do it like this:
for (i=0, h=0; i<n; ++i) h = hashlittle( k[i], len[i], h);
By Bob Jenkins, 2006. bob_jenkins@burtleburtle.net. You may use this
code any way you wish, private, educational, or commercial. It's free.
Use for hash table lookup, or anything where one collision in 2^^32 is
acceptable. Do NOT use for cryptographic purposes.
-------------------------------------------------------------------------------
*/
uint32_t hashlittle(const void *key, size_t length)
{
uint32_t a,b,c; /* internal state */
union { const void *ptr; size_t i; } u; /* needed for Mac Powerbook G4 */
/* Set up the internal state */
a = b = c = 0xdeadbeef + ((uint32_t)length);
u.ptr = key;
if (HASH_LITTLE_ENDIAN && ((u.i & 0x3) == 0)) {
const uint32_t *k = (const uint32_t *)key; /* read 32-bit chunks */
const uint8_t *k8;
/*------ all but last block: aligned reads and affect 32 bits of (a,b,c) */
while (length > 12)
{
a += k[0];
b += k[1];
c += k[2];
mix(a,b,c);
length -= 12;
k += 3;
}
/*----------------------------- handle the last (probably partial) block */
k8 = (const uint8_t *)k;
switch(length)
{
case 12: c+=k[2]; b+=k[1]; a+=k[0]; break;
case 11: c+=((uint32_t)k8[10])<<16; /* fall through */
case 10: c+=((uint32_t)k8[9])<<8; /* fall through */
case 9 : c+=k8[8]; /* fall through */
case 8 : b+=k[1]; a+=k[0]; break;
case 7 : b+=((uint32_t)k8[6])<<16; /* fall through */
case 6 : b+=((uint32_t)k8[5])<<8; /* fall through */
case 5 : b+=k8[4]; /* fall through */
case 4 : a+=k[0]; break;
case 3 : a+=((uint32_t)k8[2])<<16; /* fall through */
case 2 : a+=((uint32_t)k8[1])<<8; /* fall through */
case 1 : a+=k8[0]; break;
case 0 : return c;
}
} else if (HASH_LITTLE_ENDIAN && ((u.i & 0x1) == 0)) {
const uint16_t *k = (const uint16_t *)key; /* read 16-bit chunks */
const uint8_t *k8;
/*--------------- all but last block: aligned reads and different mixing */
while (length > 12)
{
a += k[0] + (((uint32_t)k[1])<<16);
b += k[2] + (((uint32_t)k[3])<<16);
c += k[4] + (((uint32_t)k[5])<<16);
mix(a,b,c);
length -= 12;
k += 6;
}
/*----------------------------- handle the last (probably partial) block */
k8 = (const uint8_t *)k;
switch(length)
{
case 12: c+=k[4]+(((uint32_t)k[5])<<16);
b+=k[2]+(((uint32_t)k[3])<<16);
a+=k[0]+(((uint32_t)k[1])<<16);
break;
case 11: c+=((uint32_t)k8[10])<<16; /* fall through */
case 10: c+=k[4];
b+=k[2]+(((uint32_t)k[3])<<16);
a+=k[0]+(((uint32_t)k[1])<<16);
break;
case 9 : c+=k8[8]; /* fall through */
case 8 : b+=k[2]+(((uint32_t)k[3])<<16);
a+=k[0]+(((uint32_t)k[1])<<16);
break;
case 7 : b+=((uint32_t)k8[6])<<16; /* fall through */
case 6 : b+=k[2];
a+=k[0]+(((uint32_t)k[1])<<16);
break;
case 5 : b+=k8[4]; /* fall through */
case 4 : a+=k[0]+(((uint32_t)k[1])<<16);
break;
case 3 : a+=((uint32_t)k8[2])<<16; /* fall through */
case 2 : a+=k[0];
break;
case 1 : a+=k8[0];
break;
case 0 : return c; /* zero length requires no mixing */
}
} else { /* need to read the key one byte at a time */
const uint8_t *k = (const uint8_t *)key;
/*--------------- all but the last block: affect some 32 bits of (a,b,c) */
while (length > 12)
{
a += k[0];
a += ((uint32_t)k[1])<<8;
a += ((uint32_t)k[2])<<16;
a += ((uint32_t)k[3])<<24;
b += k[4];
b += ((uint32_t)k[5])<<8;
b += ((uint32_t)k[6])<<16;
b += ((uint32_t)k[7])<<24;
c += k[8];
c += ((uint32_t)k[9])<<8;
c += ((uint32_t)k[10])<<16;
c += ((uint32_t)k[11])<<24;
mix(a,b,c);
length -= 12;
k += 12;
}
/*-------------------------------- last block: affect all 32 bits of (c) */
switch(length) /* all the case statements fall through */
{
case 12: c+=((uint32_t)k[11])<<24;
/* FALLTHROUGH */
case 11: c+=((uint32_t)k[10])<<16;
/* FALLTHROUGH */
case 10: c+=((uint32_t)k[9])<<8;
/* FALLTHROUGH */
case 9 : c+=k[8];
/* FALLTHROUGH */
case 8 : b+=((uint32_t)k[7])<<24;
/* FALLTHROUGH */
case 7 : b+=((uint32_t)k[6])<<16;
/* FALLTHROUGH */
case 6 : b+=((uint32_t)k[5])<<8;
/* FALLTHROUGH */
case 5 : b+=k[4];
/* FALLTHROUGH */
case 4 : a+=((uint32_t)k[3])<<24;
/* FALLTHROUGH */
case 3 : a+=((uint32_t)k[2])<<16;
/* FALLTHROUGH */
case 2 : a+=((uint32_t)k[1])<<8;
/* FALLTHROUGH */
case 1 : a+=k[0];
break;
case 0 : return c;
}
}
final(a,b,c);
return c;
}

33
help-from-md Executable file
View File

@@ -0,0 +1,33 @@
#!/bin/bash
if [[ "$#" != 2 ]]; then
echo "Usage: $0 MD_FILE HELP_FILE.h"
exit 1
fi
mdfile="$1"
helpfile="$2"
newfile="$helpfile.new"
findfile="${helpfile/./\\.}"
sed -e '1,/^\[comment\].*'"$findfile"'/d' \
-e '1,/^```/d' \
-e '/^```/,$d' \
-e 's/"/\\"/g' \
-e 's/^/ rprintf(F,"/' \
-e 's/$/\\n");/' \
<"$mdfile" >"$newfile"
if [[ ! -s "$newfile" ]]; then
rm "$newfile"
echo "Discarding empty output for $helpfile file from $mdfile"
exit 1
fi
(cat <<EOT
/* DO NOT EDIT THIS FILE! It is auto-generated from the option list in $mdfile! */
EOT
cat "$newfile"
) >"$helpfile"
rm "$newfile"

42
hlink.c
View File

@@ -4,7 +4,7 @@
* Copyright (C) 1996 Andrew Tridgell
* Copyright (C) 1996 Paul Mackerras
* Copyright (C) 2002 Martin Pool <mbp@samba.org>
* Copyright (C) 2004-2014 Wayne Davison
* Copyright (C) 2004-2020 Wayne Davison
*
* 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
@@ -29,7 +29,7 @@ extern int list_only;
extern int am_sender;
extern int inc_recurse;
extern int do_xfers;
extern int link_dest;
extern int alt_dest_type;
extern int preserve_acls;
extern int preserve_xattrs;
extern int protocol_version;
@@ -48,6 +48,8 @@ extern struct file_list *cur_flist;
* we can avoid the pool of dev+inode data. For incremental recursion mode,
* the receiver will use a ndx hash to remember old pathnames. */
static void *data_when_new = "";
static struct hashtable *dev_tbl;
static struct hashtable *prior_hlinks;
@@ -57,32 +59,29 @@ static struct file_list *hlink_flist;
void init_hard_links(void)
{
if (am_sender || protocol_version < 30)
dev_tbl = hashtable_create(16, 1);
dev_tbl = hashtable_create(16, HT_KEY64);
else if (inc_recurse)
prior_hlinks = hashtable_create(1024, 0);
prior_hlinks = hashtable_create(1024, HT_KEY32);
}
struct ht_int64_node *idev_find(int64 dev, int64 ino)
{
static struct ht_int64_node *dev_node = NULL;
struct hashtable *tbl;
/* Note that some OSes have a dev == 0, so increment to avoid storing a 0. */
if (!dev_node || dev_node->key != dev+1) {
/* We keep a separate hash table of inodes for every device. */
dev_node = hashtable_find(dev_tbl, dev+1, 1);
if (!(tbl = dev_node->data)) {
tbl = dev_node->data = hashtable_create(512, 1);
dev_node = hashtable_find(dev_tbl, dev+1, data_when_new);
if (dev_node->data == data_when_new) {
dev_node->data = hashtable_create(512, HT_KEY64);
if (DEBUG_GTE(HLINK, 3)) {
rprintf(FINFO,
"[%s] created hashtable for dev %s\n",
who_am_i(), big_num(dev));
rprintf(FINFO, "[%s] created hashtable for dev %s\n",
who_am_i(), big_num(dev));
}
}
} else
tbl = dev_node->data;
}
return hashtable_find(tbl, ino, 1);
return hashtable_find(dev_node->data, ino, (void*)-1L);
}
void idev_destroy(void)
@@ -118,15 +117,14 @@ static void match_gnums(int32 *ndx_list, int ndx_count)
struct ht_int32_node *node = NULL;
int32 gnum, gnum_next;
qsort(ndx_list, ndx_count, sizeof ndx_list[0],
(int (*)()) hlink_compare_gnum);
qsort(ndx_list, ndx_count, sizeof ndx_list[0], (int (*)()) hlink_compare_gnum);
for (from = 0; from < ndx_count; from++) {
file = hlink_flist->sorted[ndx_list[from]];
gnum = F_HL_GNUM(file);
if (inc_recurse) {
node = hashtable_find(prior_hlinks, gnum, 1);
if (!node->data) {
node = hashtable_find(prior_hlinks, gnum, data_when_new);
if (node->data == data_when_new) {
if (!(node->data = new_array0(char, 5)))
out_of_memory("match_gnums");
assert(gnum >= hlink_flist->ndx_start);
@@ -231,7 +229,7 @@ static int maybe_hard_link(struct file_struct *file, int ndx,
}
}
if (atomic_create(file, fname, oldname, MAKEDEV(0, 0), sxp, statret == 0 ? DEL_FOR_FILE : 0)) {
if (atomic_create(file, fname, NULL, oldname, MAKEDEV(0, 0), sxp, statret == 0 ? DEL_FOR_FILE : 0)) {
if (itemizing) {
itemize(fname, file, ndx, statret, sxp,
ITEM_LOCAL_CHANGE | ITEM_XNAME_FOLLOWS, 0,
@@ -269,7 +267,7 @@ static char *check_prior(struct file_struct *file, int gnum,
}
if (inc_recurse
&& (node = hashtable_find(prior_hlinks, gnum, 0)) != NULL) {
&& (node = hashtable_find(prior_hlinks, gnum, NULL)) != NULL) {
assert(node->data != NULL);
if (CVAL(node->data, 0) != 0) {
*prev_ndx_p = -1;
@@ -396,7 +394,7 @@ int hard_link_check(struct file_struct *file, int ndx, char *fname,
pathjoin(cmpbuf, MAXPATHLEN, basis_dir[j], fname);
if (link_stat(cmpbuf, &alt_sx.st, 0) < 0)
continue;
if (link_dest) {
if (alt_dest_type == LINK_DEST) {
if (prev_st.st_dev != alt_sx.st.st_dev
|| prev_st.st_ino != alt_sx.st.st_ino)
continue;
@@ -528,7 +526,7 @@ void finish_hard_link(struct file_struct *file, const char *fname, int fin_ndx,
if (inc_recurse) {
int gnum = F_HL_GNUM(file);
struct ht_int32_node *node = hashtable_find(prior_hlinks, gnum, 0);
struct ht_int32_node *node = hashtable_find(prior_hlinks, gnum, NULL);
if (node == NULL) {
rprintf(FERROR, "Unable to find a hlink node for %d (%s)\n", gnum, f_name(file, prev_name));
exit_cleanup(RERR_MESSAGEIO);

View File

@@ -1,6 +1,6 @@
/* Inline functions for rsync.
*
* Copyright (C) 2007-2014 Wayne Davison
* Copyright (C) 2007-2019 Wayne Davison
*
* 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

View File

@@ -1,6 +1,6 @@
/* Inline functions for rsync.
*
* Copyright (C) 2008-2014 Wayne Davison
* Copyright (C) 2008-2019 Wayne Davison
*
* 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

60
io.c
View File

@@ -4,7 +4,7 @@
* Copyright (C) 1996-2001 Andrew Tridgell
* Copyright (C) 1996 Paul Mackerras
* Copyright (C) 2001, 2002 Martin Pool <mbp@samba.org>
* Copyright (C) 2003-2014 Wayne Davison
* Copyright (C) 2003-2020 Wayne Davison
*
* 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
@@ -44,6 +44,7 @@ extern int am_generator;
extern int msgs2stderr;
extern int inc_recurse;
extern int io_error;
extern int batch_fd;
extern int eol_nulls;
extern int flist_eof;
extern int file_total;
@@ -67,7 +68,6 @@ extern iconv_t ic_send, ic_recv;
int csum_length = SHORT_SUM_LENGTH; /* initial value */
int allowed_lull = 0;
int batch_fd = -1;
int msgdone_cnt = 0;
int forward_flist_data = 0;
BOOL flist_receiving_enabled = False;
@@ -251,8 +251,7 @@ static size_t safe_read(int fd, char *buf, size_t len)
cnt = select(fd+1, &r_fds, NULL, &e_fds, &tv);
if (cnt <= 0) {
if (cnt < 0 && errno == EBADF) {
rsyserr(FERROR, errno, "safe_read select failed [%s]",
who_am_i());
rsyserr(FERROR, errno, "safe_read select failed");
exit_cleanup(RERR_FILEIO);
}
check_timeout(1, MSK_ALLOW_FLUSH);
@@ -271,8 +270,7 @@ static size_t safe_read(int fd, char *buf, size_t len)
if (n < 0) {
if (errno == EINTR)
continue;
rsyserr(FERROR, errno, "safe_read failed to read %ld bytes [%s]",
(long)len, who_am_i());
rsyserr(FERROR, errno, "safe_read failed to read %ld bytes", (long)len);
exit_cleanup(RERR_STREAMIO);
}
if ((got += (size_t)n) == len)
@@ -315,8 +313,8 @@ static void safe_write(int fd, const char *buf, size_t len)
if (errno != EINTR && errno != EWOULDBLOCK && errno != EAGAIN) {
write_failed:
rsyserr(FERROR, errno,
"safe_write failed to write %ld bytes to %s [%s]",
(long)len, what_fd_is(fd), who_am_i());
"safe_write failed to write %ld bytes to %s",
(long)len, what_fd_is(fd));
exit_cleanup(RERR_STREAMIO);
}
} else {
@@ -337,8 +335,7 @@ static void safe_write(int fd, const char *buf, size_t len)
cnt = select(fd + 1, NULL, &w_fds, NULL, &tv);
if (cnt <= 0) {
if (cnt < 0 && errno == EBADF) {
rsyserr(FERROR, errno, "safe_write select failed on %s [%s]",
what_fd_is(fd), who_am_i());
rsyserr(FERROR, errno, "safe_write select failed on %s", what_fd_is(fd));
exit_cleanup(RERR_FILEIO);
}
if (io_timeout)
@@ -815,7 +812,7 @@ static char *perform_io(size_t needed, int flags)
msgs2stderr = 1;
iobuf.out_fd = -2;
iobuf.out.len = iobuf.msg.len = iobuf.raw_flushing_ends_before = 0;
rsyserr(FERROR_SOCKET, errno, "[%s] write error", who_am_i());
rsyserr(FERROR_SOCKET, errno, "write error");
drain_multiplex_messages();
exit_cleanup(RERR_SOCKETIO);
}
@@ -915,7 +912,7 @@ void noop_io_until_death(void)
{
char buf[1024];
if (!iobuf.in.buf || !iobuf.out.buf || iobuf.in_fd < 0 || iobuf.out_fd < 0 || kluge_around_eof)
if (!iobuf.in.buf || !iobuf.out.buf || iobuf.in_fd < 0 || iobuf.out_fd < 0 || kluge_around_eof || msgs2stderr)
return;
kluge_around_eof = 2;
@@ -954,8 +951,17 @@ int send_msg(enum msgcode code, const char *buf, size_t len, int convert)
} else
#endif
needed = len + 4 + 3;
if (iobuf.msg.len + needed > iobuf.msg.size)
perform_io(needed, PIO_NEED_MSGROOM);
if (iobuf.msg.len + needed > iobuf.msg.size) {
if (!am_receiver)
perform_io(needed, PIO_NEED_MSGROOM);
else { /* We allow the receiver to increase their iobuf.msg size to avoid a deadlock. */
size_t old_size = iobuf.msg.size;
restore_iobuf_size(&iobuf.msg);
realloc_xbuf(&iobuf.msg, iobuf.msg.size * 2);
if (iobuf.msg.pos + iobuf.msg.len > old_size)
memcpy(iobuf.msg.buf + old_size, iobuf.msg.buf, iobuf.msg.pos + iobuf.msg.len - old_size);
}
}
pos = iobuf.msg.pos + iobuf.msg.len; /* Must be set after any flushing. */
if (pos >= iobuf.msg.size)
@@ -1113,8 +1119,7 @@ static void check_for_d_option_error(const char *msg)
}
if (saw_d) {
rprintf(FWARNING,
"*** Try using \"--old-d\" if remote rsync is <= 2.6.3 ***\n");
rprintf(FWARNING, "*** Try using \"--old-d\" if remote rsync is <= 2.6.3 ***\n");
}
}
@@ -1176,7 +1181,7 @@ int read_line(int fd, char *buf, size_t bufsiz, int flags)
#ifdef ICONV_OPTION
if (flags & RL_CONVERT && iconv_buf.size < bufsiz)
realloc_xbuf(&iconv_buf, bufsiz + 1024);
realloc_xbuf(&iconv_buf, ROUND_UP_1024(bufsiz) + 1024);
#endif
start:
@@ -1685,7 +1690,7 @@ void wait_for_receiver(void)
rprintf(FINFO, "[%s] receiving flist for dir %d\n",
who_am_i(), ndx);
}
flist = recv_file_list(iobuf.in_fd);
flist = recv_file_list(iobuf.in_fd, ndx);
flist->parent_ndx = ndx;
#ifdef SUPPORT_HARD_LINKS
if (preserve_hard_links)
@@ -1982,13 +1987,14 @@ static void sleep_for_bwlimit(int bytes_written)
total_written = (sleep_usec - elapsed_usec) * bwlimit / (ONE_SEC/1024);
}
void io_flush(int flush_it_all)
void io_flush(int flush_type)
{
if (iobuf.out.len > iobuf.out_empty_len) {
if (flush_it_all) /* FULL_FLUSH: flush everything in the output buffers */
if (flush_type == FULL_FLUSH) /* flush everything in the output buffers */
perform_io(iobuf.out.size - iobuf.out_empty_len, PIO_NEED_OUTROOM);
else /* NORMAL_FLUSH: flush at least 1 byte */
else if (flush_type == NORMAL_FLUSH) /* flush at least 1 byte */
perform_io(iobuf.out.size - iobuf.out.len + 1, PIO_NEED_OUTROOM);
/* MSG_FLUSH: flush iobuf.msg only */
}
if (iobuf.msg.len)
perform_io(iobuf.msg.size, PIO_NEED_MSGROOM);
@@ -2013,20 +2019,20 @@ void write_varint(int f, int32 x)
{
char b[5];
uchar bit;
int cnt = 4;
int cnt;
SIVAL(b, 1, x);
while (cnt > 1 && b[cnt] == 0)
cnt--;
for (cnt = 4; cnt > 1 && b[cnt] == 0; cnt--) {}
bit = ((uchar)1<<(7-cnt+1));
if (CVAL(b, cnt) >= bit) {
cnt++;
*b = ~(bit-1);
} else if (cnt > 1)
*b = b[cnt] | ~(bit*2-1);
else
*b = b[cnt];
*b = b[1];
write_buf(f, b, cnt);
}
@@ -2283,7 +2289,7 @@ void io_printf(int fd, const char *format, ...)
if (len < 0)
exit_cleanup(RERR_PROTOCOL);
if (len > (int)sizeof buf) {
if (len >= (int)sizeof buf) {
rprintf(FERROR, "io_printf() was too long for the buffer.\n");
exit_cleanup(RERR_PROTOCOL);
}
@@ -2368,7 +2374,7 @@ void start_write_batch(int fd)
* is involved. */
write_int(batch_fd, protocol_version);
if (protocol_version >= 30)
write_byte(batch_fd, compat_flags);
write_varint(batch_fd, compat_flags);
write_int(batch_fd, checksum_seed);
if (am_sender)

2
io.h
View File

@@ -1,5 +1,5 @@
/*
* Copyright (C) 2007-2014 Wayne Davison
* Copyright (C) 2007-2019 Wayne Davison
*
* 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

View File

@@ -1,6 +1,6 @@
/* Inline functions for rsync.
*
* Copyright (C) 2007-2014 Wayne Davison
* Copyright (C) 2007-2020 Wayne Davison
*
* 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
@@ -22,6 +22,12 @@ isDigit(const char *ptr)
return isdigit(*(unsigned char *)ptr);
}
static inline int
isHexDigit(const char *ptr)
{
return isxdigit(*(unsigned char *)ptr);
}
static inline int
isPrint(const char *ptr)
{

1
latest-year.h Normal file
View File

@@ -0,0 +1 @@
#define LATEST_YEAR "2020"

View File

@@ -3,7 +3,7 @@
*
* Copyright (C) 1998 Andrew Tridgell
* Copyright (C) 2002 Martin Pool
* Copyright (C) 2004-2014 Wayne Davison
* Copyright (C) 2004-2020 Wayne Davison
*
* 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
@@ -79,7 +79,7 @@ static char number_separator;
#ifndef HAVE_STRPBRK
/**
* Find the first ocurrence in @p s of any character in @p accept.
* Find the first occurrence in @p s of any character in @p accept.
*
* Derived from glibc
**/

693
lib/md5-asm-x86_64.s Normal file
View File

@@ -0,0 +1,693 @@
/*
* x86-64 optimized assembler MD5 implementation
*
* Author: Marc Bevand, 2004
*
* This code was placed in the public domain by the author. The original
* publication can be found at:
*
* https://www.zorinaq.com/papers/md5-amd64.html
*/
/*
* No modifications were made aside from changing the function and file names.
* The MD5_CTX structure as expected here (from OpenSSL) is binary compatible
* with the md_context used by rsync, for the fields accessed.
*
* Benchmarks (in MB/s) C ASM
* - Intel Atom D2700 302 334
* - Intel i7-7700hq 351 376
* - AMD ThreadRipper 2950x 728 784
*
* The original code was also incorporated into OpenSSL. It has since been
* modified there. Those changes have not been made here due to licensing
* incompatibilities. Benchmarks of those changes on the above CPUs did not
* show any significant difference in performance, though.
*/
.text
.align 16
.globl md5_process_asm
.type md5_process_asm,@function
md5_process_asm:
push %rbp
push %rbx
push %r12
push %r13 # not really useful (r13 is unused)
push %r14
push %r15
# rdi = arg #1 (ctx, MD5_CTX pointer)
# rsi = arg #2 (ptr, data pointer)
# rdx = arg #3 (nbr, number of 16-word blocks to process)
mov %rdi, %rbp # rbp = ctx
shl $6, %rdx # rdx = nbr in bytes
lea (%rsi,%rdx), %rdi # rdi = end
mov 0*4(%rbp), %eax # eax = ctx->A
mov 1*4(%rbp), %ebx # ebx = ctx->B
mov 2*4(%rbp), %ecx # ecx = ctx->C
mov 3*4(%rbp), %edx # edx = ctx->D
# end is 'rdi'
# ptr is 'rsi'
# A is 'eax'
# B is 'ebx'
# C is 'ecx'
# D is 'edx'
cmp %rdi, %rsi # cmp end with ptr
je 1f # jmp if ptr == end
# BEGIN of loop over 16-word blocks
2: # save old values of A, B, C, D
mov %eax, %r8d
mov %ebx, %r9d
mov %ecx, %r14d
mov %edx, %r15d
mov 0*4(%rsi), %r10d /* (NEXT STEP) X[0] */
mov %edx, %r11d /* (NEXT STEP) z' = %edx */
xor %ecx, %r11d /* y ^ ... */
lea -680876936(%eax,%r10d),%eax /* Const + dst + ... */
and %ebx, %r11d /* x & ... */
xor %edx, %r11d /* z ^ ... */
mov 1*4(%rsi),%r10d /* (NEXT STEP) X[1] */
add %r11d, %eax /* dst += ... */
rol $7, %eax /* dst <<< s */
mov %ecx, %r11d /* (NEXT STEP) z' = %ecx */
add %ebx, %eax /* dst += x */
xor %ebx, %r11d /* y ^ ... */
lea -389564586(%edx,%r10d),%edx /* Const + dst + ... */
and %eax, %r11d /* x & ... */
xor %ecx, %r11d /* z ^ ... */
mov 2*4(%rsi),%r10d /* (NEXT STEP) X[2] */
add %r11d, %edx /* dst += ... */
rol $12, %edx /* dst <<< s */
mov %ebx, %r11d /* (NEXT STEP) z' = %ebx */
add %eax, %edx /* dst += x */
xor %eax, %r11d /* y ^ ... */
lea 606105819(%ecx,%r10d),%ecx /* Const + dst + ... */
and %edx, %r11d /* x & ... */
xor %ebx, %r11d /* z ^ ... */
mov 3*4(%rsi),%r10d /* (NEXT STEP) X[3] */
add %r11d, %ecx /* dst += ... */
rol $17, %ecx /* dst <<< s */
mov %eax, %r11d /* (NEXT STEP) z' = %eax */
add %edx, %ecx /* dst += x */
xor %edx, %r11d /* y ^ ... */
lea -1044525330(%ebx,%r10d),%ebx /* Const + dst + ... */
and %ecx, %r11d /* x & ... */
xor %eax, %r11d /* z ^ ... */
mov 4*4(%rsi),%r10d /* (NEXT STEP) X[4] */
add %r11d, %ebx /* dst += ... */
rol $22, %ebx /* dst <<< s */
mov %edx, %r11d /* (NEXT STEP) z' = %edx */
add %ecx, %ebx /* dst += x */
xor %ecx, %r11d /* y ^ ... */
lea -176418897(%eax,%r10d),%eax /* Const + dst + ... */
and %ebx, %r11d /* x & ... */
xor %edx, %r11d /* z ^ ... */
mov 5*4(%rsi),%r10d /* (NEXT STEP) X[5] */
add %r11d, %eax /* dst += ... */
rol $7, %eax /* dst <<< s */
mov %ecx, %r11d /* (NEXT STEP) z' = %ecx */
add %ebx, %eax /* dst += x */
xor %ebx, %r11d /* y ^ ... */
lea 1200080426(%edx,%r10d),%edx /* Const + dst + ... */
and %eax, %r11d /* x & ... */
xor %ecx, %r11d /* z ^ ... */
mov 6*4(%rsi),%r10d /* (NEXT STEP) X[6] */
add %r11d, %edx /* dst += ... */
rol $12, %edx /* dst <<< s */
mov %ebx, %r11d /* (NEXT STEP) z' = %ebx */
add %eax, %edx /* dst += x */
xor %eax, %r11d /* y ^ ... */
lea -1473231341(%ecx,%r10d),%ecx /* Const + dst + ... */
and %edx, %r11d /* x & ... */
xor %ebx, %r11d /* z ^ ... */
mov 7*4(%rsi),%r10d /* (NEXT STEP) X[7] */
add %r11d, %ecx /* dst += ... */
rol $17, %ecx /* dst <<< s */
mov %eax, %r11d /* (NEXT STEP) z' = %eax */
add %edx, %ecx /* dst += x */
xor %edx, %r11d /* y ^ ... */
lea -45705983(%ebx,%r10d),%ebx /* Const + dst + ... */
and %ecx, %r11d /* x & ... */
xor %eax, %r11d /* z ^ ... */
mov 8*4(%rsi),%r10d /* (NEXT STEP) X[8] */
add %r11d, %ebx /* dst += ... */
rol $22, %ebx /* dst <<< s */
mov %edx, %r11d /* (NEXT STEP) z' = %edx */
add %ecx, %ebx /* dst += x */
xor %ecx, %r11d /* y ^ ... */
lea 1770035416(%eax,%r10d),%eax /* Const + dst + ... */
and %ebx, %r11d /* x & ... */
xor %edx, %r11d /* z ^ ... */
mov 9*4(%rsi),%r10d /* (NEXT STEP) X[9] */
add %r11d, %eax /* dst += ... */
rol $7, %eax /* dst <<< s */
mov %ecx, %r11d /* (NEXT STEP) z' = %ecx */
add %ebx, %eax /* dst += x */
xor %ebx, %r11d /* y ^ ... */
lea -1958414417(%edx,%r10d),%edx /* Const + dst + ... */
and %eax, %r11d /* x & ... */
xor %ecx, %r11d /* z ^ ... */
mov 10*4(%rsi),%r10d /* (NEXT STEP) X[10] */
add %r11d, %edx /* dst += ... */
rol $12, %edx /* dst <<< s */
mov %ebx, %r11d /* (NEXT STEP) z' = %ebx */
add %eax, %edx /* dst += x */
xor %eax, %r11d /* y ^ ... */
lea -42063(%ecx,%r10d),%ecx /* Const + dst + ... */
and %edx, %r11d /* x & ... */
xor %ebx, %r11d /* z ^ ... */
mov 11*4(%rsi),%r10d /* (NEXT STEP) X[11] */
add %r11d, %ecx /* dst += ... */
rol $17, %ecx /* dst <<< s */
mov %eax, %r11d /* (NEXT STEP) z' = %eax */
add %edx, %ecx /* dst += x */
xor %edx, %r11d /* y ^ ... */
lea -1990404162(%ebx,%r10d),%ebx /* Const + dst + ... */
and %ecx, %r11d /* x & ... */
xor %eax, %r11d /* z ^ ... */
mov 12*4(%rsi),%r10d /* (NEXT STEP) X[12] */
add %r11d, %ebx /* dst += ... */
rol $22, %ebx /* dst <<< s */
mov %edx, %r11d /* (NEXT STEP) z' = %edx */
add %ecx, %ebx /* dst += x */
xor %ecx, %r11d /* y ^ ... */
lea 1804603682(%eax,%r10d),%eax /* Const + dst + ... */
and %ebx, %r11d /* x & ... */
xor %edx, %r11d /* z ^ ... */
mov 13*4(%rsi),%r10d /* (NEXT STEP) X[13] */
add %r11d, %eax /* dst += ... */
rol $7, %eax /* dst <<< s */
mov %ecx, %r11d /* (NEXT STEP) z' = %ecx */
add %ebx, %eax /* dst += x */
xor %ebx, %r11d /* y ^ ... */
lea -40341101(%edx,%r10d),%edx /* Const + dst + ... */
and %eax, %r11d /* x & ... */
xor %ecx, %r11d /* z ^ ... */
mov 14*4(%rsi),%r10d /* (NEXT STEP) X[14] */
add %r11d, %edx /* dst += ... */
rol $12, %edx /* dst <<< s */
mov %ebx, %r11d /* (NEXT STEP) z' = %ebx */
add %eax, %edx /* dst += x */
xor %eax, %r11d /* y ^ ... */
lea -1502002290(%ecx,%r10d),%ecx /* Const + dst + ... */
and %edx, %r11d /* x & ... */
xor %ebx, %r11d /* z ^ ... */
mov 15*4(%rsi),%r10d /* (NEXT STEP) X[15] */
add %r11d, %ecx /* dst += ... */
rol $17, %ecx /* dst <<< s */
mov %eax, %r11d /* (NEXT STEP) z' = %eax */
add %edx, %ecx /* dst += x */
xor %edx, %r11d /* y ^ ... */
lea 1236535329(%ebx,%r10d),%ebx /* Const + dst + ... */
and %ecx, %r11d /* x & ... */
xor %eax, %r11d /* z ^ ... */
mov 0*4(%rsi),%r10d /* (NEXT STEP) X[0] */
add %r11d, %ebx /* dst += ... */
rol $22, %ebx /* dst <<< s */
mov %edx, %r11d /* (NEXT STEP) z' = %edx */
add %ecx, %ebx /* dst += x */
mov 1*4(%rsi), %r10d /* (NEXT STEP) X[1] */
mov %edx, %r11d /* (NEXT STEP) z' = %edx */
mov %edx, %r12d /* (NEXT STEP) z' = %edx */
not %r11d /* not z */
lea -165796510(%eax,%r10d),%eax /* Const + dst + ... */
and %ebx, %r12d /* x & z */
and %ecx, %r11d /* y & (not z) */
mov 6*4(%rsi),%r10d /* (NEXT STEP) X[6] */
or %r11d, %r12d /* (y & (not z)) | (x & z) */
mov %ecx, %r11d /* (NEXT STEP) z' = %ecx */
add %r12d, %eax /* dst += ... */
mov %ecx, %r12d /* (NEXT STEP) z' = %ecx */
rol $5, %eax /* dst <<< s */
add %ebx, %eax /* dst += x */
not %r11d /* not z */
lea -1069501632(%edx,%r10d),%edx /* Const + dst + ... */
and %eax, %r12d /* x & z */
and %ebx, %r11d /* y & (not z) */
mov 11*4(%rsi),%r10d /* (NEXT STEP) X[11] */
or %r11d, %r12d /* (y & (not z)) | (x & z) */
mov %ebx, %r11d /* (NEXT STEP) z' = %ebx */
add %r12d, %edx /* dst += ... */
mov %ebx, %r12d /* (NEXT STEP) z' = %ebx */
rol $9, %edx /* dst <<< s */
add %eax, %edx /* dst += x */
not %r11d /* not z */
lea 643717713(%ecx,%r10d),%ecx /* Const + dst + ... */
and %edx, %r12d /* x & z */
and %eax, %r11d /* y & (not z) */
mov 0*4(%rsi),%r10d /* (NEXT STEP) X[0] */
or %r11d, %r12d /* (y & (not z)) | (x & z) */
mov %eax, %r11d /* (NEXT STEP) z' = %eax */
add %r12d, %ecx /* dst += ... */
mov %eax, %r12d /* (NEXT STEP) z' = %eax */
rol $14, %ecx /* dst <<< s */
add %edx, %ecx /* dst += x */
not %r11d /* not z */
lea -373897302(%ebx,%r10d),%ebx /* Const + dst + ... */
and %ecx, %r12d /* x & z */
and %edx, %r11d /* y & (not z) */
mov 5*4(%rsi),%r10d /* (NEXT STEP) X[5] */
or %r11d, %r12d /* (y & (not z)) | (x & z) */
mov %edx, %r11d /* (NEXT STEP) z' = %edx */
add %r12d, %ebx /* dst += ... */
mov %edx, %r12d /* (NEXT STEP) z' = %edx */
rol $20, %ebx /* dst <<< s */
add %ecx, %ebx /* dst += x */
not %r11d /* not z */
lea -701558691(%eax,%r10d),%eax /* Const + dst + ... */
and %ebx, %r12d /* x & z */
and %ecx, %r11d /* y & (not z) */
mov 10*4(%rsi),%r10d /* (NEXT STEP) X[10] */
or %r11d, %r12d /* (y & (not z)) | (x & z) */
mov %ecx, %r11d /* (NEXT STEP) z' = %ecx */
add %r12d, %eax /* dst += ... */
mov %ecx, %r12d /* (NEXT STEP) z' = %ecx */
rol $5, %eax /* dst <<< s */
add %ebx, %eax /* dst += x */
not %r11d /* not z */
lea 38016083(%edx,%r10d),%edx /* Const + dst + ... */
and %eax, %r12d /* x & z */
and %ebx, %r11d /* y & (not z) */
mov 15*4(%rsi),%r10d /* (NEXT STEP) X[15] */
or %r11d, %r12d /* (y & (not z)) | (x & z) */
mov %ebx, %r11d /* (NEXT STEP) z' = %ebx */
add %r12d, %edx /* dst += ... */
mov %ebx, %r12d /* (NEXT STEP) z' = %ebx */
rol $9, %edx /* dst <<< s */
add %eax, %edx /* dst += x */
not %r11d /* not z */
lea -660478335(%ecx,%r10d),%ecx /* Const + dst + ... */
and %edx, %r12d /* x & z */
and %eax, %r11d /* y & (not z) */
mov 4*4(%rsi),%r10d /* (NEXT STEP) X[4] */
or %r11d, %r12d /* (y & (not z)) | (x & z) */
mov %eax, %r11d /* (NEXT STEP) z' = %eax */
add %r12d, %ecx /* dst += ... */
mov %eax, %r12d /* (NEXT STEP) z' = %eax */
rol $14, %ecx /* dst <<< s */
add %edx, %ecx /* dst += x */
not %r11d /* not z */
lea -405537848(%ebx,%r10d),%ebx /* Const + dst + ... */
and %ecx, %r12d /* x & z */
and %edx, %r11d /* y & (not z) */
mov 9*4(%rsi),%r10d /* (NEXT STEP) X[9] */
or %r11d, %r12d /* (y & (not z)) | (x & z) */
mov %edx, %r11d /* (NEXT STEP) z' = %edx */
add %r12d, %ebx /* dst += ... */
mov %edx, %r12d /* (NEXT STEP) z' = %edx */
rol $20, %ebx /* dst <<< s */
add %ecx, %ebx /* dst += x */
not %r11d /* not z */
lea 568446438(%eax,%r10d),%eax /* Const + dst + ... */
and %ebx, %r12d /* x & z */
and %ecx, %r11d /* y & (not z) */
mov 14*4(%rsi),%r10d /* (NEXT STEP) X[14] */
or %r11d, %r12d /* (y & (not z)) | (x & z) */
mov %ecx, %r11d /* (NEXT STEP) z' = %ecx */
add %r12d, %eax /* dst += ... */
mov %ecx, %r12d /* (NEXT STEP) z' = %ecx */
rol $5, %eax /* dst <<< s */
add %ebx, %eax /* dst += x */
not %r11d /* not z */
lea -1019803690(%edx,%r10d),%edx /* Const + dst + ... */
and %eax, %r12d /* x & z */
and %ebx, %r11d /* y & (not z) */
mov 3*4(%rsi),%r10d /* (NEXT STEP) X[3] */
or %r11d, %r12d /* (y & (not z)) | (x & z) */
mov %ebx, %r11d /* (NEXT STEP) z' = %ebx */
add %r12d, %edx /* dst += ... */
mov %ebx, %r12d /* (NEXT STEP) z' = %ebx */
rol $9, %edx /* dst <<< s */
add %eax, %edx /* dst += x */
not %r11d /* not z */
lea -187363961(%ecx,%r10d),%ecx /* Const + dst + ... */
and %edx, %r12d /* x & z */
and %eax, %r11d /* y & (not z) */
mov 8*4(%rsi),%r10d /* (NEXT STEP) X[8] */
or %r11d, %r12d /* (y & (not z)) | (x & z) */
mov %eax, %r11d /* (NEXT STEP) z' = %eax */
add %r12d, %ecx /* dst += ... */
mov %eax, %r12d /* (NEXT STEP) z' = %eax */
rol $14, %ecx /* dst <<< s */
add %edx, %ecx /* dst += x */
not %r11d /* not z */
lea 1163531501(%ebx,%r10d),%ebx /* Const + dst + ... */
and %ecx, %r12d /* x & z */
and %edx, %r11d /* y & (not z) */
mov 13*4(%rsi),%r10d /* (NEXT STEP) X[13] */
or %r11d, %r12d /* (y & (not z)) | (x & z) */
mov %edx, %r11d /* (NEXT STEP) z' = %edx */
add %r12d, %ebx /* dst += ... */
mov %edx, %r12d /* (NEXT STEP) z' = %edx */
rol $20, %ebx /* dst <<< s */
add %ecx, %ebx /* dst += x */
not %r11d /* not z */
lea -1444681467(%eax,%r10d),%eax /* Const + dst + ... */
and %ebx, %r12d /* x & z */
and %ecx, %r11d /* y & (not z) */
mov 2*4(%rsi),%r10d /* (NEXT STEP) X[2] */
or %r11d, %r12d /* (y & (not z)) | (x & z) */
mov %ecx, %r11d /* (NEXT STEP) z' = %ecx */
add %r12d, %eax /* dst += ... */
mov %ecx, %r12d /* (NEXT STEP) z' = %ecx */
rol $5, %eax /* dst <<< s */
add %ebx, %eax /* dst += x */
not %r11d /* not z */
lea -51403784(%edx,%r10d),%edx /* Const + dst + ... */
and %eax, %r12d /* x & z */
and %ebx, %r11d /* y & (not z) */
mov 7*4(%rsi),%r10d /* (NEXT STEP) X[7] */
or %r11d, %r12d /* (y & (not z)) | (x & z) */
mov %ebx, %r11d /* (NEXT STEP) z' = %ebx */
add %r12d, %edx /* dst += ... */
mov %ebx, %r12d /* (NEXT STEP) z' = %ebx */
rol $9, %edx /* dst <<< s */
add %eax, %edx /* dst += x */
not %r11d /* not z */
lea 1735328473(%ecx,%r10d),%ecx /* Const + dst + ... */
and %edx, %r12d /* x & z */
and %eax, %r11d /* y & (not z) */
mov 12*4(%rsi),%r10d /* (NEXT STEP) X[12] */
or %r11d, %r12d /* (y & (not z)) | (x & z) */
mov %eax, %r11d /* (NEXT STEP) z' = %eax */
add %r12d, %ecx /* dst += ... */
mov %eax, %r12d /* (NEXT STEP) z' = %eax */
rol $14, %ecx /* dst <<< s */
add %edx, %ecx /* dst += x */
not %r11d /* not z */
lea -1926607734(%ebx,%r10d),%ebx /* Const + dst + ... */
and %ecx, %r12d /* x & z */
and %edx, %r11d /* y & (not z) */
mov 0*4(%rsi),%r10d /* (NEXT STEP) X[0] */
or %r11d, %r12d /* (y & (not z)) | (x & z) */
mov %edx, %r11d /* (NEXT STEP) z' = %edx */
add %r12d, %ebx /* dst += ... */
mov %edx, %r12d /* (NEXT STEP) z' = %edx */
rol $20, %ebx /* dst <<< s */
add %ecx, %ebx /* dst += x */
mov 5*4(%rsi), %r10d /* (NEXT STEP) X[5] */
mov %ecx, %r11d /* (NEXT STEP) y' = %ecx */
lea -378558(%eax,%r10d),%eax /* Const + dst + ... */
mov 8*4(%rsi),%r10d /* (NEXT STEP) X[8] */
xor %edx, %r11d /* z ^ ... */
xor %ebx, %r11d /* x ^ ... */
add %r11d, %eax /* dst += ... */
rol $4, %eax /* dst <<< s */
mov %ebx, %r11d /* (NEXT STEP) y' = %ebx */
add %ebx, %eax /* dst += x */
lea -2022574463(%edx,%r10d),%edx /* Const + dst + ... */
mov 11*4(%rsi),%r10d /* (NEXT STEP) X[11] */
xor %ecx, %r11d /* z ^ ... */
xor %eax, %r11d /* x ^ ... */
add %r11d, %edx /* dst += ... */
rol $11, %edx /* dst <<< s */
mov %eax, %r11d /* (NEXT STEP) y' = %eax */
add %eax, %edx /* dst += x */
lea 1839030562(%ecx,%r10d),%ecx /* Const + dst + ... */
mov 14*4(%rsi),%r10d /* (NEXT STEP) X[14] */
xor %ebx, %r11d /* z ^ ... */
xor %edx, %r11d /* x ^ ... */
add %r11d, %ecx /* dst += ... */
rol $16, %ecx /* dst <<< s */
mov %edx, %r11d /* (NEXT STEP) y' = %edx */
add %edx, %ecx /* dst += x */
lea -35309556(%ebx,%r10d),%ebx /* Const + dst + ... */
mov 1*4(%rsi),%r10d /* (NEXT STEP) X[1] */
xor %eax, %r11d /* z ^ ... */
xor %ecx, %r11d /* x ^ ... */
add %r11d, %ebx /* dst += ... */
rol $23, %ebx /* dst <<< s */
mov %ecx, %r11d /* (NEXT STEP) y' = %ecx */
add %ecx, %ebx /* dst += x */
lea -1530992060(%eax,%r10d),%eax /* Const + dst + ... */
mov 4*4(%rsi),%r10d /* (NEXT STEP) X[4] */
xor %edx, %r11d /* z ^ ... */
xor %ebx, %r11d /* x ^ ... */
add %r11d, %eax /* dst += ... */
rol $4, %eax /* dst <<< s */
mov %ebx, %r11d /* (NEXT STEP) y' = %ebx */
add %ebx, %eax /* dst += x */
lea 1272893353(%edx,%r10d),%edx /* Const + dst + ... */
mov 7*4(%rsi),%r10d /* (NEXT STEP) X[7] */
xor %ecx, %r11d /* z ^ ... */
xor %eax, %r11d /* x ^ ... */
add %r11d, %edx /* dst += ... */
rol $11, %edx /* dst <<< s */
mov %eax, %r11d /* (NEXT STEP) y' = %eax */
add %eax, %edx /* dst += x */
lea -155497632(%ecx,%r10d),%ecx /* Const + dst + ... */
mov 10*4(%rsi),%r10d /* (NEXT STEP) X[10] */
xor %ebx, %r11d /* z ^ ... */
xor %edx, %r11d /* x ^ ... */
add %r11d, %ecx /* dst += ... */
rol $16, %ecx /* dst <<< s */
mov %edx, %r11d /* (NEXT STEP) y' = %edx */
add %edx, %ecx /* dst += x */
lea -1094730640(%ebx,%r10d),%ebx /* Const + dst + ... */
mov 13*4(%rsi),%r10d /* (NEXT STEP) X[13] */
xor %eax, %r11d /* z ^ ... */
xor %ecx, %r11d /* x ^ ... */
add %r11d, %ebx /* dst += ... */
rol $23, %ebx /* dst <<< s */
mov %ecx, %r11d /* (NEXT STEP) y' = %ecx */
add %ecx, %ebx /* dst += x */
lea 681279174(%eax,%r10d),%eax /* Const + dst + ... */
mov 0*4(%rsi),%r10d /* (NEXT STEP) X[0] */
xor %edx, %r11d /* z ^ ... */
xor %ebx, %r11d /* x ^ ... */
add %r11d, %eax /* dst += ... */
rol $4, %eax /* dst <<< s */
mov %ebx, %r11d /* (NEXT STEP) y' = %ebx */
add %ebx, %eax /* dst += x */
lea -358537222(%edx,%r10d),%edx /* Const + dst + ... */
mov 3*4(%rsi),%r10d /* (NEXT STEP) X[3] */
xor %ecx, %r11d /* z ^ ... */
xor %eax, %r11d /* x ^ ... */
add %r11d, %edx /* dst += ... */
rol $11, %edx /* dst <<< s */
mov %eax, %r11d /* (NEXT STEP) y' = %eax */
add %eax, %edx /* dst += x */
lea -722521979(%ecx,%r10d),%ecx /* Const + dst + ... */
mov 6*4(%rsi),%r10d /* (NEXT STEP) X[6] */
xor %ebx, %r11d /* z ^ ... */
xor %edx, %r11d /* x ^ ... */
add %r11d, %ecx /* dst += ... */
rol $16, %ecx /* dst <<< s */
mov %edx, %r11d /* (NEXT STEP) y' = %edx */
add %edx, %ecx /* dst += x */
lea 76029189(%ebx,%r10d),%ebx /* Const + dst + ... */
mov 9*4(%rsi),%r10d /* (NEXT STEP) X[9] */
xor %eax, %r11d /* z ^ ... */
xor %ecx, %r11d /* x ^ ... */
add %r11d, %ebx /* dst += ... */
rol $23, %ebx /* dst <<< s */
mov %ecx, %r11d /* (NEXT STEP) y' = %ecx */
add %ecx, %ebx /* dst += x */
lea -640364487(%eax,%r10d),%eax /* Const + dst + ... */
mov 12*4(%rsi),%r10d /* (NEXT STEP) X[12] */
xor %edx, %r11d /* z ^ ... */
xor %ebx, %r11d /* x ^ ... */
add %r11d, %eax /* dst += ... */
rol $4, %eax /* dst <<< s */
mov %ebx, %r11d /* (NEXT STEP) y' = %ebx */
add %ebx, %eax /* dst += x */
lea -421815835(%edx,%r10d),%edx /* Const + dst + ... */
mov 15*4(%rsi),%r10d /* (NEXT STEP) X[15] */
xor %ecx, %r11d /* z ^ ... */
xor %eax, %r11d /* x ^ ... */
add %r11d, %edx /* dst += ... */
rol $11, %edx /* dst <<< s */
mov %eax, %r11d /* (NEXT STEP) y' = %eax */
add %eax, %edx /* dst += x */
lea 530742520(%ecx,%r10d),%ecx /* Const + dst + ... */
mov 2*4(%rsi),%r10d /* (NEXT STEP) X[2] */
xor %ebx, %r11d /* z ^ ... */
xor %edx, %r11d /* x ^ ... */
add %r11d, %ecx /* dst += ... */
rol $16, %ecx /* dst <<< s */
mov %edx, %r11d /* (NEXT STEP) y' = %edx */
add %edx, %ecx /* dst += x */
lea -995338651(%ebx,%r10d),%ebx /* Const + dst + ... */
mov 0*4(%rsi),%r10d /* (NEXT STEP) X[0] */
xor %eax, %r11d /* z ^ ... */
xor %ecx, %r11d /* x ^ ... */
add %r11d, %ebx /* dst += ... */
rol $23, %ebx /* dst <<< s */
mov %ecx, %r11d /* (NEXT STEP) y' = %ecx */
add %ecx, %ebx /* dst += x */
mov 0*4(%rsi), %r10d /* (NEXT STEP) X[0] */
mov $0xffffffff, %r11d
xor %edx, %r11d /* (NEXT STEP) not z' = not %edx*/
lea -198630844(%eax,%r10d),%eax /* Const + dst + ... */
or %ebx, %r11d /* x | ... */
xor %ecx, %r11d /* y ^ ... */
add %r11d, %eax /* dst += ... */
mov 7*4(%rsi),%r10d /* (NEXT STEP) X[7] */
mov $0xffffffff, %r11d
rol $6, %eax /* dst <<< s */
xor %ecx, %r11d /* (NEXT STEP) not z' = not %ecx */
add %ebx, %eax /* dst += x */
lea 1126891415(%edx,%r10d),%edx /* Const + dst + ... */
or %eax, %r11d /* x | ... */
xor %ebx, %r11d /* y ^ ... */
add %r11d, %edx /* dst += ... */
mov 14*4(%rsi),%r10d /* (NEXT STEP) X[14] */
mov $0xffffffff, %r11d
rol $10, %edx /* dst <<< s */
xor %ebx, %r11d /* (NEXT STEP) not z' = not %ebx */
add %eax, %edx /* dst += x */
lea -1416354905(%ecx,%r10d),%ecx /* Const + dst + ... */
or %edx, %r11d /* x | ... */
xor %eax, %r11d /* y ^ ... */
add %r11d, %ecx /* dst += ... */
mov 5*4(%rsi),%r10d /* (NEXT STEP) X[5] */
mov $0xffffffff, %r11d
rol $15, %ecx /* dst <<< s */
xor %eax, %r11d /* (NEXT STEP) not z' = not %eax */
add %edx, %ecx /* dst += x */
lea -57434055(%ebx,%r10d),%ebx /* Const + dst + ... */
or %ecx, %r11d /* x | ... */
xor %edx, %r11d /* y ^ ... */
add %r11d, %ebx /* dst += ... */
mov 12*4(%rsi),%r10d /* (NEXT STEP) X[12] */
mov $0xffffffff, %r11d
rol $21, %ebx /* dst <<< s */
xor %edx, %r11d /* (NEXT STEP) not z' = not %edx */
add %ecx, %ebx /* dst += x */
lea 1700485571(%eax,%r10d),%eax /* Const + dst + ... */
or %ebx, %r11d /* x | ... */
xor %ecx, %r11d /* y ^ ... */
add %r11d, %eax /* dst += ... */
mov 3*4(%rsi),%r10d /* (NEXT STEP) X[3] */
mov $0xffffffff, %r11d
rol $6, %eax /* dst <<< s */
xor %ecx, %r11d /* (NEXT STEP) not z' = not %ecx */
add %ebx, %eax /* dst += x */
lea -1894986606(%edx,%r10d),%edx /* Const + dst + ... */
or %eax, %r11d /* x | ... */
xor %ebx, %r11d /* y ^ ... */
add %r11d, %edx /* dst += ... */
mov 10*4(%rsi),%r10d /* (NEXT STEP) X[10] */
mov $0xffffffff, %r11d
rol $10, %edx /* dst <<< s */
xor %ebx, %r11d /* (NEXT STEP) not z' = not %ebx */
add %eax, %edx /* dst += x */
lea -1051523(%ecx,%r10d),%ecx /* Const + dst + ... */
or %edx, %r11d /* x | ... */
xor %eax, %r11d /* y ^ ... */
add %r11d, %ecx /* dst += ... */
mov 1*4(%rsi),%r10d /* (NEXT STEP) X[1] */
mov $0xffffffff, %r11d
rol $15, %ecx /* dst <<< s */
xor %eax, %r11d /* (NEXT STEP) not z' = not %eax */
add %edx, %ecx /* dst += x */
lea -2054922799(%ebx,%r10d),%ebx /* Const + dst + ... */
or %ecx, %r11d /* x | ... */
xor %edx, %r11d /* y ^ ... */
add %r11d, %ebx /* dst += ... */
mov 8*4(%rsi),%r10d /* (NEXT STEP) X[8] */
mov $0xffffffff, %r11d
rol $21, %ebx /* dst <<< s */
xor %edx, %r11d /* (NEXT STEP) not z' = not %edx */
add %ecx, %ebx /* dst += x */
lea 1873313359(%eax,%r10d),%eax /* Const + dst + ... */
or %ebx, %r11d /* x | ... */
xor %ecx, %r11d /* y ^ ... */
add %r11d, %eax /* dst += ... */
mov 15*4(%rsi),%r10d /* (NEXT STEP) X[15] */
mov $0xffffffff, %r11d
rol $6, %eax /* dst <<< s */
xor %ecx, %r11d /* (NEXT STEP) not z' = not %ecx */
add %ebx, %eax /* dst += x */
lea -30611744(%edx,%r10d),%edx /* Const + dst + ... */
or %eax, %r11d /* x | ... */
xor %ebx, %r11d /* y ^ ... */
add %r11d, %edx /* dst += ... */
mov 6*4(%rsi),%r10d /* (NEXT STEP) X[6] */
mov $0xffffffff, %r11d
rol $10, %edx /* dst <<< s */
xor %ebx, %r11d /* (NEXT STEP) not z' = not %ebx */
add %eax, %edx /* dst += x */
lea -1560198380(%ecx,%r10d),%ecx /* Const + dst + ... */
or %edx, %r11d /* x | ... */
xor %eax, %r11d /* y ^ ... */
add %r11d, %ecx /* dst += ... */
mov 13*4(%rsi),%r10d /* (NEXT STEP) X[13] */
mov $0xffffffff, %r11d
rol $15, %ecx /* dst <<< s */
xor %eax, %r11d /* (NEXT STEP) not z' = not %eax */
add %edx, %ecx /* dst += x */
lea 1309151649(%ebx,%r10d),%ebx /* Const + dst + ... */
or %ecx, %r11d /* x | ... */
xor %edx, %r11d /* y ^ ... */
add %r11d, %ebx /* dst += ... */
mov 4*4(%rsi),%r10d /* (NEXT STEP) X[4] */
mov $0xffffffff, %r11d
rol $21, %ebx /* dst <<< s */
xor %edx, %r11d /* (NEXT STEP) not z' = not %edx */
add %ecx, %ebx /* dst += x */
lea -145523070(%eax,%r10d),%eax /* Const + dst + ... */
or %ebx, %r11d /* x | ... */
xor %ecx, %r11d /* y ^ ... */
add %r11d, %eax /* dst += ... */
mov 11*4(%rsi),%r10d /* (NEXT STEP) X[11] */
mov $0xffffffff, %r11d
rol $6, %eax /* dst <<< s */
xor %ecx, %r11d /* (NEXT STEP) not z' = not %ecx */
add %ebx, %eax /* dst += x */
lea -1120210379(%edx,%r10d),%edx /* Const + dst + ... */
or %eax, %r11d /* x | ... */
xor %ebx, %r11d /* y ^ ... */
add %r11d, %edx /* dst += ... */
mov 2*4(%rsi),%r10d /* (NEXT STEP) X[2] */
mov $0xffffffff, %r11d
rol $10, %edx /* dst <<< s */
xor %ebx, %r11d /* (NEXT STEP) not z' = not %ebx */
add %eax, %edx /* dst += x */
lea 718787259(%ecx,%r10d),%ecx /* Const + dst + ... */
or %edx, %r11d /* x | ... */
xor %eax, %r11d /* y ^ ... */
add %r11d, %ecx /* dst += ... */
mov 9*4(%rsi),%r10d /* (NEXT STEP) X[9] */
mov $0xffffffff, %r11d
rol $15, %ecx /* dst <<< s */
xor %eax, %r11d /* (NEXT STEP) not z' = not %eax */
add %edx, %ecx /* dst += x */
lea -343485551(%ebx,%r10d),%ebx /* Const + dst + ... */
or %ecx, %r11d /* x | ... */
xor %edx, %r11d /* y ^ ... */
add %r11d, %ebx /* dst += ... */
mov 0*4(%rsi),%r10d /* (NEXT STEP) X[0] */
mov $0xffffffff, %r11d
rol $21, %ebx /* dst <<< s */
xor %edx, %r11d /* (NEXT STEP) not z' = not %edx */
add %ecx, %ebx /* dst += x */
# add old values of A, B, C, D
add %r8d, %eax
add %r9d, %ebx
add %r14d, %ecx
add %r15d, %edx
# loop control
add $64, %rsi # ptr += 64
cmp %rdi, %rsi # cmp end with ptr
jb 2b # jmp if ptr < end
# END of loop over 16-word blocks
1:
mov %eax, 0*4(%rbp) # ctx->A = A
mov %ebx, 1*4(%rbp) # ctx->B = B
mov %ecx, 2*4(%rbp) # ctx->C = C
mov %edx, 3*4(%rbp) # ctx->D = D
pop %r15
pop %r14
pop %r13 # not really useful (r13 is unused)
pop %r12
pop %rbx
pop %rbp
ret
.L_md5_process_asm_end:
.size md5_process_asm,.L_md5_process_asm_end-md5_process_asm

View File

@@ -2,6 +2,7 @@
* RFC 1321 compliant MD5 implementation
*
* Copyright (C) 2001-2003 Christophe Devine
* Copyright (C) 2007-2020 Wayne Davison
*
* 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
@@ -19,6 +20,7 @@
#include "rsync.h"
#ifndef USE_OPENSSL
void md5_begin(md_context *ctx)
{
ctx->A = 0x67452301;
@@ -146,6 +148,10 @@ static void md5_process(md_context *ctx, const uchar data[CSUM_CHUNK])
ctx->D += D;
}
#if defined(HAVE_SIMD) && (CSUM_CHUNK == 64)
extern void md5_process_asm(md_context *ctx, const void *data, size_t num);
#endif
void md5_update(md_context *ctx, const uchar *input, uint32 length)
{
uint32 left, fill;
@@ -170,11 +176,20 @@ void md5_update(md_context *ctx, const uchar *input, uint32 length)
left = 0;
}
#if defined(HAVE_SIMD) && (CSUM_CHUNK == 64)
if (length >= CSUM_CHUNK) {
uint32 chunks = length / CSUM_CHUNK;
md5_process_asm(ctx, input, chunks);
length -= chunks * CSUM_CHUNK;
input += chunks * CSUM_CHUNK;
}
#else
while (length >= CSUM_CHUNK) {
md5_process(ctx, input);
length -= CSUM_CHUNK;
input += CSUM_CHUNK;
}
#endif
if (length)
memcpy(ctx->buffer + left, input, length);
@@ -206,6 +221,9 @@ void md5_result(md_context *ctx, uchar digest[MD5_DIGEST_LEN])
SIVALu(digest, 8, ctx->C);
SIVALu(digest, 12, ctx->D);
}
#endif
#ifdef TEST_MD5
void get_md5(uchar *out, const uchar *input, int n)
{
@@ -215,8 +233,6 @@ void get_md5(uchar *out, const uchar *input, int n)
md5_result(&ctx, out);
}
#ifdef TEST_MD5
#include <stdlib.h>
#include <stdio.h>

View File

@@ -4,7 +4,7 @@
* An implementation of MD4 designed for use in the SMB authentication protocol.
*
* Copyright (C) 1997-1998 Andrew Tridgell
* Copyright (C) 2005-2014 Wayne Davison
* Copyright (C) 2005-2020 Wayne Davison
*
* 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
@@ -193,6 +193,8 @@ void mdfour_result(md_context *md, uchar digest[MD4_DIGEST_LEN])
copy4(digest+12, m->D);
}
#ifdef TEST_MDFOUR
void mdfour(uchar digest[MD4_DIGEST_LEN], uchar *in, int length)
{
md_context md;
@@ -201,7 +203,6 @@ void mdfour(uchar digest[MD4_DIGEST_LEN], uchar *in, int length)
mdfour_result(&md, digest);
}
#ifdef TEST_MDFOUR
int protocol_version = 28;
static void file_checksum1(char *fname)

View File

@@ -1,11 +1,24 @@
/* The include file for both the MD4 and MD5 routines. */
#ifdef USE_OPENSSL
#include "openssl/md4.h"
#include "openssl/md5.h"
#endif
#define MD4_DIGEST_LEN 16
#define MD5_DIGEST_LEN 16
#define MAX_DIGEST_LEN MD5_DIGEST_LEN
#define CSUM_CHUNK 64
#define CSUM_NONE 0
#define CSUM_MD4_ARCHAIC 1
#define CSUM_MD4_BUSTED 2
#define CSUM_MD4_OLD 3
#define CSUM_MD4 4
#define CSUM_MD5 5
#define CSUM_XXH64 6
typedef struct {
uint32 A, B, C, D;
uint32 totalN; /* bit count, lower 32 bits */
@@ -17,10 +30,13 @@ void mdfour_begin(md_context *md);
void mdfour_update(md_context *md, const uchar *in, uint32 length);
void mdfour_result(md_context *md, uchar digest[MD4_DIGEST_LEN]);
void get_mdfour(uchar digest[MD4_DIGEST_LEN], const uchar *in, int length);
#ifndef USE_OPENSSL
#define MD5_CTX md_context
#define MD5_Init md5_begin
#define MD5_Update md5_update
#define MD5_Final(digest, cptr) md5_result(cptr, digest)
void md5_begin(md_context *ctx);
void md5_update(md_context *ctx, const uchar *input, uint32 length);
void md5_result(md_context *ctx, uchar digest[MD5_DIGEST_LEN]);
void get_md5(uchar digest[MD5_DIGEST_LEN], const uchar *input, int n);
#endif

View File

@@ -4,7 +4,7 @@
* Copyright (C) 1996 Andrew Tridgell
* Copyright (C) 1996 Paul Mackerras
* Copyright (C) 2001 Martin Pool <mbp@samba.org>
* Copyright (C) 2003-2014 Wayne Davison
* Copyright (C) 2003-2019 Wayne Davison
*
* 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

View File

@@ -49,15 +49,15 @@ pool_create(size_t size, size_t quantum, void (*bomb)(const char *), int flags)
{
struct alloc_pool *pool;
if (!(pool = new0(struct alloc_pool)))
return NULL;
if ((MINALIGN & (MINALIGN - 1)) != 0) {
if (bomb)
(*bomb)("Compiler error: MINALIGN is not a power of 2\n");
return NULL;
}
if (!(pool = new0(struct alloc_pool)))
return NULL;
if (!size)
size = POOL_DEF_EXTENT;
if (!quantum)

View File

@@ -34,7 +34,7 @@
* probably requires libm on most operating systems. Don't yet
* support the exponent (e,E) and sigfig (g,G). Also, fmtint()
* was pretty badly broken, it just wasn't being exercised in ways
* which showed it, so that's been fixed. Also, formated the code
* which showed it, so that's been fixed. Also, formatted the code
* to mutt conventions, and removed dead code left over from the
* original. Also, there is now a builtin-test, just compile with:
* gcc -I.. -DTEST_SNPRINTF -o snprintf snprintf.c -lm
@@ -77,7 +77,7 @@
* Fix incorrect zpadlen handling in fmtfp.
* Thanks to Ollie Oldham <ollie.oldham@metro-optix.com> for spotting it.
* few mods to make it easier to compile the tests.
* addedd the "Ollie" test to the floating point ones.
* added 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

View File

@@ -2,7 +2,7 @@
* Unix SMB/CIFS implementation.
* Based on the Samba ACL support code.
* Copyright (C) Jeremy Allison 2000.
* Copyright (C) 2007-2014 Wayne Davison
* Copyright (C) 2007-2020 Wayne Davison
*
* The permission functions have been changed to get/set all bits via
* one call. Some functions that rsync doesn't need were also removed.
@@ -450,7 +450,7 @@ SMB_ACL_T sys_acl_get_file(const char *path_p, SMB_ACL_TYPE_T type)
*
* Note: we assume that the acl() system call returned a
* well formed ACL which is sorted so that all of the
* access ACL entries preceed any default ACL entries
* access ACL entries precede any default ACL entries
*/
for (naccess = 0; naccess < count; naccess++) {
if (acl_d->acl[naccess].a_type & ACL_DEFAULT)
@@ -932,7 +932,7 @@ SMB_ACL_T sys_acl_get_file(const char *path_p, SMB_ACL_TYPE_T type)
*
* Note: we assume that the acl() system call returned a
* well formed ACL which is sorted so that all of the
* access ACL entries preceed any default ACL entries
* access ACL entries precede any default ACL entries
*/
for (naccess = 0; naccess < count; naccess++) {
if (acl_d->acl[naccess].a_type & ACL_DEFAULT)
@@ -1095,7 +1095,7 @@ struct hpux_acl_types {
* structures.
* Inputs:
*
* acl_count - Count of ACLs in the array of ACL strucutres.
* acl_count - Count of ACLs in the array of ACL structures.
* aclp - Array of ACL structures.
* acl_type_count - Pointer to acl_types structure. Should already be
* allocated.
@@ -1256,7 +1256,7 @@ static int hpux_acl_sort(int acl_count, int calclass, struct acl *aclp)
{
#if !defined(HAVE_HPUX_ACLSORT)
/*
* The aclsort() system call is availabe on the latest HPUX General
* The aclsort() system call is available on the latest HPUX General
* Patch Bundles. So for HPUX, we developed our version of acl_sort
* function. Because, we don't want to update to a new
* HPUX GR bundle just for aclsort() call.
@@ -1311,7 +1311,7 @@ or DEF_USER_OBJ or DEF_GROUP_OBJ or DEF_OTHER_OBJ\n"));
* Sorting crieteria - First sort by ACL type. If there are multiple entries of
* same ACL type, sort by ACL id.
*
* I am using the trival kind of sorting method here because, performance isn't
* I am using the trivial kind of sorting method here because, performance isn't
* really effected by the ACLs feature. More over there aren't going to be more
* than 17 entries on HPUX.
*/

View File

@@ -3,7 +3,7 @@
* Version 2.2.x
* Portable SMB ACL interface
* Copyright (C) Jeremy Allison 2000
* Copyright (C) 2007-2014 Wayne Davison
* Copyright (C) 2007-2019 Wayne Davison
*
* 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

View File

@@ -2,7 +2,7 @@
* Extended attribute support for rsync.
*
* Copyright (C) 2004 Red Hat, Inc.
* Copyright (C) 2003-2014 Wayne Davison
* Copyright (C) 2003-2019 Wayne Davison
* Written by Jay Fenlason.
*
* This program is free software; you can redistribute it and/or modify

View File

@@ -11,13 +11,12 @@
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, visit the http://fsf.org website.
*/
/* This is based on loadparm.c from Samba, written by Andrew Tridgell
*
* This is based on loadparm.c from Samba, written by Andrew Tridgell
* and Karl Auer. Some of the changes are:
*
* Copyright (C) 2001, 2002 Martin Pool <mbp@samba.org>
* Copyright (C) 2003-2014 Wayne Davison <wayned@samba.org>
* Copyright (C) 2003-2020 Wayne Davison
*/
/* Load parameters.
@@ -31,7 +30,7 @@
* 1) add it to the global_vars or local_vars structure definition
* 2) add it to the parm_table
* 3) add it to the list of available functions (eg: using FN_GLOBAL_STRING())
* 4) initialise it in the Defaults static stucture
* 4) initialise it in the Defaults static structure
*
* Notes:
* The configuration file is processed sequentially for speed. For this
@@ -55,7 +54,8 @@ extern item_list dparam_list;
#define DEFAULT_DONT_COMPRESS "*.gz *.zip *.z *.rpm *.deb *.iso *.bz2" \
" *.t[gb]z *.7z *.mp[34] *.mov *.avi *.ogg *.jpg *.jpeg *.png" \
" *.lzo *.rzip *.lzma *.rar *.ace *.gpg *.xz *.txz *.lz *.tlz"
" *.lzo *.rzip *.lzma *.rar *.ace *.gpg *.xz *.txz *.lz *.tlz" \
" *.ogv *.web[mp] *.squashfs"
/* the following are used by loadparm for option lists */
typedef enum {
@@ -93,23 +93,38 @@ struct parm_struct {
/* This structure describes global (ie., server-wide) parameters. */
typedef struct {
char *bind_address;
char *daemon_chroot;
char *daemon_gid;
char *daemon_uid;
char *motd_file;
char *pid_file;
char *socket_options;
/* Each _EXP var tracks if the associated char* var has been expanded yet or not. */
BOOL bind_address_EXP;
BOOL daemon_chroot_EXP;
BOOL daemon_gid_EXP;
BOOL daemon_uid_EXP;
BOOL motd_file_EXP;
BOOL pid_file_EXP;
BOOL socket_options_EXP;
int listen_backlog;
int rsync_port;
BOOL proxy_protocol;
} global_vars;
/* This structure describes a single section. Their order must match the
* initializers below, which you can accomplish by keeping each sub-section
* sorted. (e.g. in vim, just visually select each subsection and use !sort.)
* NOTE: the char* variables MUST all remain at the start of the stuct! */
* NOTE: the char* variables MUST all remain at the start of the struct! */
typedef struct {
char *auth_users;
char *charset;
char *comment;
char *dont_compress;
char *early_exec;
char *exclude;
char *exclude_from;
char *filter;
@@ -129,10 +144,38 @@ typedef struct {
char *prexfer_exec;
char *refuse_options;
char *secrets_file;
char *syslog_tag;
char *temp_dir;
char *uid;
/* NOTE: update this macro if the last char* variable changes! */
#define LOCAL_STRING_COUNT() (offsetof(local_vars, uid) / sizeof (char*) + 1)
/* Each _EXP var tracks if the associated char* var has been expanded yet or not. */
BOOL auth_users_EXP;
BOOL charset_EXP;
BOOL comment_EXP;
BOOL dont_compress_EXP;
BOOL early_exec_EXP;
BOOL exclude_EXP;
BOOL exclude_from_EXP;
BOOL filter_EXP;
BOOL gid_EXP;
BOOL hosts_allow_EXP;
BOOL hosts_deny_EXP;
BOOL include_EXP;
BOOL include_from_EXP;
BOOL incoming_chmod_EXP;
BOOL lock_file_EXP;
BOOL log_file_EXP;
BOOL log_format_EXP;
BOOL name_EXP;
BOOL outgoing_chmod_EXP;
BOOL path_EXP;
BOOL postxfer_exec_EXP;
BOOL prexfer_exec_EXP;
BOOL refuse_options_EXP;
BOOL secrets_file_EXP;
BOOL syslog_tag_EXP;
BOOL temp_dir_EXP;
BOOL uid_EXP;
int max_connections;
int max_verbosity;
@@ -172,12 +215,25 @@ static const all_vars Defaults = {
/* ==== global_vars ==== */
{
/* bind_address; */ NULL,
/* daemon_chroot; */ NULL,
/* daemon_gid; */ NULL,
/* daemon_uid; */ NULL,
/* motd_file; */ NULL,
/* pid_file; */ NULL,
/* socket_options; */ NULL,
/* bind_address_EXP; */ False,
/* daemon_chroot_EXP; */ False,
/* daemon_gid_EXP; */ False,
/* daemon_uid_EXP; */ False,
/* motd_file_EXP; */ False,
/* pid_file_EXP; */ False,
/* socket_options_EXP; */ False,
/* listen_backlog; */ 5,
/* rsync_port; */ 0,
/* proxy_protocol; */ False,
},
/* ==== local_vars ==== */
@@ -186,7 +242,8 @@ static const all_vars Defaults = {
/* charset; */ NULL,
/* comment; */ NULL,
/* dont_compress; */ DEFAULT_DONT_COMPRESS,
/* exclude; */ NULL,
/* early_exec; */ NULL,
/* exclude; */ NULL,
/* exclude_from; */ NULL,
/* filter; */ NULL,
/* gid; */ NULL,
@@ -205,9 +262,38 @@ static const all_vars Defaults = {
/* prexfer_exec; */ NULL,
/* refuse_options; */ NULL,
/* secrets_file; */ NULL,
/* syslog_tag; */ "rsyncd",
/* temp_dir; */ NULL,
/* uid; */ NULL,
/* auth_users_EXP; */ False,
/* charset_EXP; */ False,
/* comment_EXP; */ False,
/* dont_compress_EXP; */ False,
/* early_exec_EXP; */ False,
/* exclude_EXP; */ False,
/* exclude_from_EXP; */ False,
/* filter_EXP; */ False,
/* gid_EXP; */ False,
/* hosts_allow_EXP; */ False,
/* hosts_deny_EXP; */ False,
/* include_EXP; */ False,
/* include_from_EXP; */ False,
/* incoming_chmod_EXP; */ False,
/* lock_file_EXP; */ False,
/* log_file_EXP; */ False,
/* log_format_EXP; */ False,
/* name_EXP; */ False,
/* outgoing_chmod_EXP; */ False,
/* path_EXP; */ False,
/* postxfer_exec_EXP; */ False,
/* prexfer_exec_EXP; */ False,
/* refuse_options_EXP; */ False,
/* secrets_file_EXP; */ False,
/* syslog_tag_EXP; */ False,
/* temp_dir_EXP; */ False,
/* uid_EXP; */ False,
/* max_connections; */ 0,
/* max_verbosity; */ 1,
/* syslog_facility; */ LOG_DAEMON,
@@ -313,16 +399,21 @@ static struct enum_list enum_facilities[] = {
static struct parm_struct parm_table[] =
{
{"address", P_STRING, P_GLOBAL,&Vars.g.bind_address, NULL,0},
{"daemon chroot", P_STRING, P_GLOBAL,&Vars.g.daemon_chroot, NULL,0},
{"daemon gid", P_STRING, P_GLOBAL,&Vars.g.daemon_gid, NULL,0},
{"daemon uid", P_STRING, P_GLOBAL,&Vars.g.daemon_uid, NULL,0},
{"listen backlog", P_INTEGER,P_GLOBAL,&Vars.g.listen_backlog, NULL,0},
{"motd file", P_STRING, P_GLOBAL,&Vars.g.motd_file, NULL,0},
{"pid file", P_STRING, P_GLOBAL,&Vars.g.pid_file, NULL,0},
{"port", P_INTEGER,P_GLOBAL,&Vars.g.rsync_port, NULL,0},
{"proxy protocol", P_BOOL, P_LOCAL, &Vars.g.proxy_protocol, NULL,0},
{"socket options", P_STRING, P_GLOBAL,&Vars.g.socket_options, NULL,0},
{"auth users", P_STRING, P_LOCAL, &Vars.l.auth_users, NULL,0},
{"charset", P_STRING, P_LOCAL, &Vars.l.charset, NULL,0},
{"comment", P_STRING, P_LOCAL, &Vars.l.comment, NULL,0},
{"dont compress", P_STRING, P_LOCAL, &Vars.l.dont_compress, NULL,0},
{"early exec", P_STRING, P_LOCAL, &Vars.l.early_exec, NULL,0},
{"exclude from", P_STRING, P_LOCAL, &Vars.l.exclude_from, NULL,0},
{"exclude", P_STRING, P_LOCAL, &Vars.l.exclude, NULL,0},
{"fake super", P_BOOL, P_LOCAL, &Vars.l.fake_super, NULL,0},
@@ -357,6 +448,7 @@ static struct parm_struct parm_table[] =
{"secrets file", P_STRING, P_LOCAL, &Vars.l.secrets_file, NULL,0},
{"strict modes", P_BOOL, P_LOCAL, &Vars.l.strict_modes, NULL,0},
{"syslog facility", P_ENUM, P_LOCAL, &Vars.l.syslog_facility, enum_facilities,0},
{"syslog tag", P_STRING, P_LOCAL, &Vars.l.syslog_tag, NULL,0},
{"temp dir", P_PATH, P_LOCAL, &Vars.l.temp_dir, NULL,0},
{"timeout", P_INTEGER,P_LOCAL, &Vars.l.timeout, NULL,0},
{"transfer logging", P_BOOL, P_LOCAL, &Vars.l.transfer_logging, NULL,0},
@@ -367,7 +459,7 @@ static struct parm_struct parm_table[] =
};
/* Initialise the Default all_vars structure. */
static void reset_all_vars(void)
void reset_daemon_vars(void)
{
memcpy(&Vars, &Defaults, sizeof Vars);
}
@@ -379,7 +471,7 @@ static char *expand_vars(char *str)
char *buf, *t, *f;
int bufsize;
if (strchr(str, '%') == NULL)
if (!str || !strchr(str, '%'))
return str;
bufsize = strlen(str) + 2048;
@@ -422,20 +514,23 @@ static char *expand_vars(char *str)
return buf;
}
/* NOTE: use this function and all the FN_{GLOBAL,LOCAL} ones WITHOUT a trailing semicolon! */
#define RETURN_EXPANDED(val) {if (!val ## _EXP) {val = expand_vars(val); val ## _EXP = True;} return val ? val : "";}
/* In this section all the functions that are used to access the
* parameters from the rest of the program are defined. */
#define FN_GLOBAL_STRING(fn_name, ptr) \
char *fn_name(void) {return expand_vars(*(char **)(ptr) ? *(char **)(ptr) : "");}
#define FN_GLOBAL_BOOL(fn_name, ptr) \
BOOL fn_name(void) {return *(BOOL *)(ptr);}
#define FN_GLOBAL_CHAR(fn_name, ptr) \
char fn_name(void) {return *(char *)(ptr);}
#define FN_GLOBAL_INTEGER(fn_name, ptr) \
int fn_name(void) {return *(int *)(ptr);}
#define FN_GLOBAL_STRING(fn_name, val) \
char *fn_name(void) RETURN_EXPANDED(Vars.g.val)
#define FN_GLOBAL_BOOL(fn_name, val) \
BOOL fn_name(void) {return Vars.g.val;}
#define FN_GLOBAL_CHAR(fn_name, val) \
char fn_name(void) {return Vars.g.val;}
#define FN_GLOBAL_INTEGER(fn_name, val) \
int fn_name(void) {return Vars.g.val;}
#define FN_LOCAL_STRING(fn_name, val) \
char *fn_name(int i) {return expand_vars(LP_SNUM_OK(i) && iSECTION(i).val ? iSECTION(i).val : Vars.l.val ? Vars.l.val : "");}
char *fn_name(int i) {if (LP_SNUM_OK(i) && iSECTION(i).val) RETURN_EXPANDED(iSECTION(i).val) else RETURN_EXPANDED(Vars.l.val)}
#define FN_LOCAL_BOOL(fn_name, val) \
BOOL fn_name(int i) {return LP_SNUM_OK(i)? iSECTION(i).val : Vars.l.val;}
#define FN_LOCAL_CHAR(fn_name, val) \
@@ -443,18 +538,24 @@ static char *expand_vars(char *str)
#define FN_LOCAL_INTEGER(fn_name, val) \
int fn_name(int i) {return LP_SNUM_OK(i)? iSECTION(i).val : Vars.l.val;}
FN_GLOBAL_STRING(lp_bind_address, &Vars.g.bind_address)
FN_GLOBAL_STRING(lp_motd_file, &Vars.g.motd_file)
FN_GLOBAL_STRING(lp_pid_file, &Vars.g.pid_file)
FN_GLOBAL_STRING(lp_socket_options, &Vars.g.socket_options)
FN_GLOBAL_STRING(lp_bind_address, bind_address)
FN_GLOBAL_STRING(lp_daemon_chroot, daemon_chroot)
FN_GLOBAL_STRING(lp_daemon_gid, daemon_gid)
FN_GLOBAL_STRING(lp_daemon_uid, daemon_uid)
FN_GLOBAL_STRING(lp_motd_file, motd_file)
FN_GLOBAL_STRING(lp_pid_file, pid_file)
FN_GLOBAL_STRING(lp_socket_options, socket_options)
FN_GLOBAL_INTEGER(lp_listen_backlog, &Vars.g.listen_backlog)
FN_GLOBAL_INTEGER(lp_rsync_port, &Vars.g.rsync_port)
FN_GLOBAL_INTEGER(lp_listen_backlog, listen_backlog)
FN_GLOBAL_INTEGER(lp_rsync_port, rsync_port)
FN_GLOBAL_BOOL(lp_proxy_protocol, proxy_protocol)
FN_LOCAL_STRING(lp_auth_users, auth_users)
FN_LOCAL_STRING(lp_charset, charset)
FN_LOCAL_STRING(lp_comment, comment)
FN_LOCAL_STRING(lp_dont_compress, dont_compress)
FN_LOCAL_STRING(lp_early_exec, early_exec)
FN_LOCAL_STRING(lp_exclude, exclude)
FN_LOCAL_STRING(lp_exclude_from, exclude_from)
FN_LOCAL_STRING(lp_filter, filter)
@@ -474,6 +575,7 @@ FN_LOCAL_STRING(lp_postxfer_exec, postxfer_exec)
FN_LOCAL_STRING(lp_prexfer_exec, prexfer_exec)
FN_LOCAL_STRING(lp_refuse_options, refuse_options)
FN_LOCAL_STRING(lp_secrets_file, secrets_file)
FN_LOCAL_STRING(lp_syslog_tag, syslog_tag)
FN_LOCAL_STRING(lp_temp_dir, temp_dir)
FN_LOCAL_STRING(lp_uid, uid)
@@ -509,19 +611,10 @@ static inline void string_set(char **s, const char *v)
out_of_memory("string_set");
}
/* Copy the local_vars, strdup'ing any strings. NOTE: this depends on
* the structure starting with a contiguous list of the char* variables,
* and having an accurate count in the LOCAL_STRING_COUNT() macro. */
/* Copy local_vars into a new section. No need to strdup since we don't free. */
static void copy_section(local_vars *psectionDest, local_vars *psectionSource)
{
int count = LOCAL_STRING_COUNT();
char **strings = (char**)psectionDest;
memcpy(psectionDest, psectionSource, sizeof psectionDest[0]);
while (count--) {
if (strings[count] && !(strings[count] = strdup(strings[count])))
out_of_memory("copy_section");
}
}
/* Initialise a section to the defaults. */
@@ -664,10 +757,10 @@ static BOOL do_parameter(char *parmname, char *parmvalue)
switch (parm_table[parmnum].type) {
case P_PATH:
case P_STRING:
/* delay expansion of vars */
/* delay expansion of %VAR% strings */
break;
default:
/* expand any %VARS% now */
/* expand any %VAR% strings now */
parmvalue = expand_vars(parmvalue);
break;
}
@@ -792,7 +885,7 @@ int lp_load(char *pszFname, int globals_only)
{
bInGlobalSection = True;
reset_all_vars();
reset_daemon_vars();
/* We get sections first, so have to start 'behind' to make up. */
iSectionIndex = -1;

199
log.c
View File

@@ -3,7 +3,7 @@
*
* Copyright (C) 1998-2001 Andrew Tridgell <tridge@samba.org>
* Copyright (C) 2000-2001 Martin Pool <mbp@samba.org>
* Copyright (C) 2003-2014 Wayne Davison
* Copyright (C) 2003-2020 Wayne Davison
*
* 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
@@ -31,12 +31,13 @@ extern int am_generator;
extern int local_server;
extern int quiet;
extern int module_id;
extern int checksum_len;
extern int allow_8bit_chars;
extern int protocol_version;
extern int always_checksum;
extern int preserve_times;
extern int msgs2stderr;
extern int xfersum_type;
extern int checksum_type;
extern int stdout_format_has_i;
extern int stdout_format_has_o_or_i;
extern int logfile_format_has_i;
@@ -74,8 +75,8 @@ static int64 initial_data_written;
static int64 initial_data_read;
struct {
int code;
char const *name;
int code;
char const *name;
} const rerr_names[] = {
{ RERR_SYNTAX , "syntax or usage error" },
{ RERR_PROTOCOL , "protocol incompatibility" },
@@ -132,21 +133,16 @@ static void logit(int priority, const char *buf)
static void syslog_init()
{
static int been_here = 0;
int options = LOG_PID;
if (been_here)
return;
been_here = 1;
#ifdef LOG_NDELAY
options |= LOG_NDELAY;
#endif
#ifdef LOG_DAEMON
openlog("rsyncd", options, lp_syslog_facility(module_id));
openlog(lp_syslog_tag(module_id), options, lp_syslog_facility(module_id));
#else
openlog("rsyncd", options);
openlog(lp_syslog_tag(module_id), options);
#endif
#ifndef LOG_NDELAY
@@ -166,14 +162,16 @@ static void logfile_open(void)
rsyserr(FERROR, fopen_errno,
"failed to open log-file %s", logfile_name);
rprintf(FINFO, "Ignoring \"log file\" setting.\n");
logfile_name = "";
}
}
void log_init(int restart)
{
if (log_initialised) {
if (!restart)
if (!restart) /* Note: a restart only happens with am_daemon */
return;
assert(logfile_name); /* all am_daemon procs got at least an empty string */
if (strcmp(logfile_name, lp_log_file(module_id)) != 0) {
if (logfile_fp) {
fclose(logfile_fp);
@@ -183,7 +181,8 @@ void log_init(int restart)
logfile_name = NULL;
} else if (*logfile_name)
return; /* unchanged, non-empty "log file" names */
else if (lp_syslog_facility(-1) != lp_syslog_facility(module_id))
else if (lp_syslog_facility(-1) != lp_syslog_facility(module_id)
|| strcmp(lp_syslog_tag(-1), lp_syslog_tag(module_id)) != 0)
closelog();
else
return; /* unchanged syslog settings */
@@ -205,6 +204,7 @@ void log_init(int restart)
syslog_init();
}
/* Note that this close & reopen idiom intentionally ignores syslog logging. */
void logfile_close(void)
{
if (logfile_fp) {
@@ -222,25 +222,26 @@ void logfile_reopen(void)
}
}
static void filtered_fwrite(FILE *f, const char *buf, int len, int use_isprint)
static void filtered_fwrite(FILE *f, const char *in_buf, int in_len, int use_isprint, char end_char)
{
const char *s, *end = buf + len;
for (s = buf; s < end; s++) {
if ((s < end - 4
&& *s == '\\' && s[1] == '#'
&& isDigit(s + 2)
&& isDigit(s + 3)
&& isDigit(s + 4))
|| (*s != '\t'
&& ((use_isprint && !isPrint(s))
|| *(uchar*)s < ' '))) {
if (s != buf && fwrite(buf, s - buf, 1, f) != 1)
char outbuf[1024], *ob = outbuf;
const char *end = in_buf + in_len;
while (in_buf < end) {
if (ob - outbuf >= (int)sizeof outbuf - 10) {
if (fwrite(outbuf, ob - outbuf, 1, f) != 1)
exit_cleanup(RERR_MESSAGEIO);
fprintf(f, "\\#%03o", *(uchar*)s);
buf = s + 1;
ob = outbuf;
}
if ((in_buf < end - 4 && *in_buf == '\\' && in_buf[1] == '#'
&& isDigit(in_buf + 2) && isDigit(in_buf + 3) && isDigit(in_buf + 4))
|| (*in_buf != '\t' && ((use_isprint && !isPrint(in_buf)) || *(uchar*)in_buf < ' ')))
ob += snprintf(ob, 6, "\\#%03o", *(uchar*)in_buf++);
else
*ob++ = *in_buf++;
}
if (buf != end && fwrite(buf, end - buf, 1, f) != 1)
if (end_char) /* The "- 10" above means that there is always room for one more char here. */
*ob++ = end_char;
if (ob != outbuf && fwrite(outbuf, ob - outbuf, 1, f) != 1)
exit_cleanup(RERR_MESSAGEIO);
}
@@ -249,7 +250,7 @@ static void filtered_fwrite(FILE *f, const char *buf, int len, int use_isprint)
* can happen with certain fatal conditions. */
void rwrite(enum logcode code, const char *buf, int len, int is_utf8)
{
int trailing_CR_or_NL;
char trailing_CR_or_NL;
FILE *f = msgs2stderr ? stderr : stdout;
#ifdef ICONV_OPTION
iconv_t ic = is_utf8 && ic_recv != (iconv_t)-1 ? ic_recv : ic_chck;
@@ -263,14 +264,13 @@ void rwrite(enum logcode code, const char *buf, int len, int is_utf8)
exit_cleanup(RERR_MESSAGEIO);
if (msgs2stderr) {
if (!am_daemon) {
if (code == FLOG)
return;
goto output_msg;
}
if (code == FCLIENT)
return;
code = FLOG;
/* A normal daemon can get msgs2stderr set if the socket is busted, so we
* change the message destination into an FLOG message in order to try to
* get some info about an abnormal-exit into the log file. An rsh daemon
* can have this set via user request, so we'll leave the code alone so
* that the msg gets logged and then sent to stderr after that. */
if (am_daemon > 0 && code != FCLIENT)
code = FLOG;
} else if (send_msgs_to_gen) {
assert(!is_utf8);
/* Pass the message to our sibling in native charset. */
@@ -306,10 +306,28 @@ void rwrite(enum logcode code, const char *buf, int len, int is_utf8)
} else if (code == FLOG)
return;
if (quiet && code == FINFO)
return;
switch (code) {
case FERROR_XFER:
got_xfer_error = 1;
/* FALL THROUGH */
case FERROR:
case FWARNING:
f = stderr;
break;
case FINFO:
if (quiet)
return;
break;
/*case FLOG:*/
/*case FCLIENT:*/
/*case FERROR_UTF8:*/
/*case FERROR_SOCKET:*/
default:
fprintf(stderr, "Bad logcode in rwrite(): %d [%s]\n", (int)code, who_am_i());
exit_cleanup(RERR_MESSAGEIO);
}
if (am_server) {
if (am_server && !msgs2stderr) {
enum msgcode msg = (enum msgcode)code;
if (protocol_version < 30) {
if (msg == MSG_ERROR)
@@ -320,33 +338,13 @@ void rwrite(enum logcode code, const char *buf, int len, int is_utf8)
/* Pass the message to the non-server side. */
if (send_msg(msg, buf, len, !is_utf8))
return;
if (am_daemon) {
if (am_daemon > 0) {
/* TODO: can we send the error to the user somehow? */
return;
}
f = stderr;
}
output_msg:
switch (code) {
case FERROR_XFER:
got_xfer_error = 1;
/* FALL THROUGH */
case FERROR:
case FERROR_UTF8:
case FERROR_SOCKET:
case FWARNING:
f = stderr;
break;
case FLOG:
case FINFO:
case FCLIENT:
break;
default:
fprintf(stderr, "Unknown logcode in rwrite(): %d [%s]\n", (int)code, who_am_i());
exit_cleanup(RERR_MESSAGEIO);
}
if (output_needs_newline) {
fputc('\n', f);
output_needs_newline = 0;
@@ -374,21 +372,28 @@ output_msg:
iconvbufs(ic, &inbuf, &outbuf, inbuf.pos ? 0 : ICB_INIT);
ierrno = errno;
if (outbuf.len) {
filtered_fwrite(f, convbuf, outbuf.len, 0);
filtered_fwrite(f, convbuf, outbuf.len, 0, 0);
outbuf.len = 0;
}
if (!ierrno || ierrno == E2BIG)
continue;
fprintf(f, "\\#%03o", CVAL(inbuf.buf, inbuf.pos++));
inbuf.len--;
/* Log one byte of illegal/incomplete sequence and continue with
* the next character. Check that the buffer is non-empty for the
* sake of robustness. */
if ((ierrno == EILSEQ || ierrno == EINVAL) && inbuf.len) {
fprintf(f, "\\#%03o", CVAL(inbuf.buf, inbuf.pos++));
inbuf.len--;
}
}
if (trailing_CR_or_NL) {
fputc(trailing_CR_or_NL, f);
fflush(f);
}
} else
#endif
filtered_fwrite(f, buf, len, !allow_8bit_chars);
if (trailing_CR_or_NL) {
fputc(trailing_CR_or_NL, f);
fflush(f);
{
filtered_fwrite(f, buf, len, !allow_8bit_chars, trailing_CR_or_NL);
if (trailing_CR_or_NL)
fflush(f);
}
}
@@ -447,8 +452,7 @@ void rsyserr(enum logcode code, int errcode, const char *format, ...)
char buf[BIGPATHBUFLEN];
size_t len;
strlcpy(buf, RSYNC_NAME ": ", sizeof buf);
len = (sizeof RSYNC_NAME ": ") - 1;
len = snprintf(buf, sizeof buf, RSYNC_NAME ": [%s] ", who_am_i());
va_start(ap, format);
len += vsnprintf(buf + len, sizeof buf - len, format, ap);
@@ -656,21 +660,10 @@ static void log_formatted(enum logcode code, const char *format, const char *op,
n = auth_user;
break;
case 'b':
if (!(iflags & ITEM_TRANSFER))
b = 0;
else if (am_sender)
b = total_data_written - initial_data_written;
else
b = total_data_read - initial_data_read;
strlcat(fmt, "s", sizeof fmt);
snprintf(buf2, sizeof buf2, fmt,
do_big_num(b, humanize, NULL));
n = buf2;
break;
case 'c':
if (!(iflags & ITEM_TRANSFER))
b = 0;
else if (!am_sender)
else if ((!!am_sender) ^ (*p == 'c'))
b = total_data_written - initial_data_written;
else
b = total_data_read - initial_data_read;
@@ -680,15 +673,18 @@ static void log_formatted(enum logcode code, const char *format, const char *op,
n = buf2;
break;
case 'C':
if (protocol_version >= 30
&& (iflags & ITEM_TRANSFER
|| (always_checksum && S_ISREG(file->mode)))) {
const char *sum = iflags & ITEM_TRANSFER
? sender_file_sum : F_SUM(file);
n = sum_as_hex(sum);
} else {
memset(buf2, ' ', checksum_len*2);
buf2[checksum_len*2] = '\0';
n = NULL;
if (S_ISREG(file->mode)) {
if (always_checksum)
n = sum_as_hex(checksum_type, F_SUM(file), 1);
else if (iflags & ITEM_TRANSFER)
n = sum_as_hex(xfersum_type, sender_file_sum, 0);
}
if (!n) {
int sum_len = csum_len_for_type(always_checksum ? checksum_type : xfersum_type,
always_checksum);
memset(buf2, ' ', sum_len*2);
buf2[sum_len*2] = '\0';
n = buf2;
}
break;
@@ -699,7 +695,7 @@ static void log_formatted(enum logcode code, const char *format, const char *op,
}
n = c = buf2 + MAXPATHLEN - 32;
c[0] = iflags & ITEM_LOCAL_CHANGE
? iflags & ITEM_XNAME_FOLLOWS ? 'h' : 'c'
? iflags & ITEM_XNAME_FOLLOWS ? 'h' : 'c'
: !(iflags & ITEM_TRANSFER) ? '.'
: !local_server && *op == 's' ? '<' : '>';
if (S_ISLNK(file->mode)) {
@@ -720,7 +716,8 @@ static void log_formatted(enum logcode code, const char *format, const char *op,
c[5] = !(iflags & ITEM_REPORT_PERMS) ? '.' : 'p';
c[6] = !(iflags & ITEM_REPORT_OWNER) ? '.' : 'o';
c[7] = !(iflags & ITEM_REPORT_GROUP) ? '.' : 'g';
c[8] = !(iflags & ITEM_REPORT_ATIME) ? '.' : 'u';
c[8] = !(iflags & ITEM_REPORT_ATIME) ? '.'
: S_ISLNK(file->mode) ? 'U' : 'u';
c[9] = !(iflags & ITEM_REPORT_ACL) ? '.' : 'a';
c[10] = !(iflags & ITEM_REPORT_XATTR) ? '.' : 'x';
c[11] = '\0';
@@ -817,8 +814,7 @@ void log_item(enum logcode code, struct file_struct *file, int iflags, const cha
log_formatted(FLOG, logfile_format, s_or_r, file, NULL, iflags, hlink);
}
void maybe_log_item(struct file_struct *file, int iflags, int itemizing,
const char *buf)
void maybe_log_item(struct file_struct *file, int iflags, int itemizing, const char *buf)
{
int significant_flags = iflags & SIGNIFICANT_ITEM_FLAGS;
int see_item = itemizing && (significant_flags || *buf
@@ -872,12 +868,15 @@ void log_delete(const char *fname, int mode)
*/
void log_exit(int code, const char *file, int line)
{
if (code == 0) {
/* The receiving side's stats are split between 2 procs until the
* end of the run, so only the sender can output non-final info. */
if (code == 0 || am_sender) {
rprintf(FLOG,"sent %s bytes received %s bytes total size %s\n",
big_num(stats.total_written),
big_num(stats.total_read),
big_num(stats.total_size));
} else if (am_server != 2) {
}
if (code != 0 && am_server != 2) {
const char *name;
name = rerr_name(code);

22
m4/have_type.m4 Normal file
View File

@@ -0,0 +1,22 @@
dnl AC_HAVE_TYPE(TYPE,INCLUDES)
AC_DEFUN([AC_HAVE_TYPE], [
AC_REQUIRE([AC_HEADER_STDC])
cv=`echo "$1" | sed 'y%./+- %__p__%'`
AC_MSG_CHECKING(for $1)
AC_CACHE_VAL([ac_cv_type_$cv],
AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[
AC_INCLUDES_DEFAULT
$2]],
[[$1 foo;]])],
[eval "ac_cv_type_$cv=yes"],
[eval "ac_cv_type_$cv=no"]))dnl
ac_foo=`eval echo \\$ac_cv_type_$cv`
AC_MSG_RESULT($ac_foo)
if test "$ac_foo" = yes; then
ac_tr_hdr=HAVE_`echo $1 | sed 'y%abcdefghijklmnopqrstuvwxyz./- %ABCDEFGHIJKLMNOPQRSTUVWXYZ____%'`
if false; then
AC_CHECK_TYPES($1)
fi
AC_DEFINE_UNQUOTED($ac_tr_hdr, 1, [Define if you have type `$1'])
fi
])

27
m4/header_major_fixed.m4 Normal file
View File

@@ -0,0 +1,27 @@
AC_DEFUN([AC_HEADER_MAJOR_FIXED],
[AC_CACHE_CHECK(whether sys/types.h defines makedev,
ac_cv_header_sys_types_h_makedev,
[AC_LINK_IFELSE([AC_LANG_PROGRAM([[@%:@include <sys/types.h>]],
[[return makedev(0, 0);]])],
[if grep sys/sysmacros.h conftest.err >/dev/null; then
ac_cv_header_sys_types_h_makedev=no
else
ac_cv_header_sys_types_h_makedev=yes
fi],
[ac_cv_header_sys_types_h_makedev=no])
])
if test $ac_cv_header_sys_types_h_makedev = no; then
AC_CHECK_HEADER(sys/mkdev.h,
[AC_DEFINE(MAJOR_IN_MKDEV, 1,
[Define to 1 if `major', `minor', and `makedev' are
declared in <mkdev.h>.])])
if test $ac_cv_header_sys_mkdev_h = no; then
AC_CHECK_HEADER(sys/sysmacros.h,
[AC_DEFINE(MAJOR_IN_SYSMACROS, 1,
[Define to 1 if `major', `minor', and `makedev'
are declared in <sysmacros.h>.])])
fi
fi
])

45
m4/socklen_t.m4 Normal file
View File

@@ -0,0 +1,45 @@
dnl Check for socklen_t: historically on BSD it is an int, and in
dnl POSIX 1g it is a type of its own, but some platforms use different
dnl types for the argument to getsockopt, getpeername, etc. So we
dnl have to test to find something that will work.
dnl This is no good, because passing the wrong pointer on C compilers is
dnl likely to only generate a warning, not an error. We don't call this at
dnl the moment.
AC_DEFUN([TYPE_SOCKLEN_T],
[
AC_CHECK_TYPE([socklen_t], ,[
AC_MSG_CHECKING([for socklen_t equivalent])
AC_CACHE_VAL([rsync_cv_socklen_t_equiv],
[
# Systems have either "struct sockaddr *" or
# "void *" as the second argument to getpeername
rsync_cv_socklen_t_equiv=
for arg2 in "struct sockaddr" void; do
for t in int size_t unsigned long "unsigned long"; do
AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[
#include <sys/types.h>
#include <sys/socket.h>
int getpeername (int, $arg2 *, $t *);
]],[[
$t len;
getpeername(0,0,&len);
]])],[
rsync_cv_socklen_t_equiv="$t"
break
])
done
done
if test "x$rsync_cv_socklen_t_equiv" = x; then
AC_MSG_ERROR([Cannot find a type to use in place of socklen_t])
fi
])
AC_MSG_RESULT($rsync_cv_socklen_t_equiv)
AC_DEFINE_UNQUOTED(socklen_t, $rsync_cv_socklen_t_equiv,
[type to use in place of socklen_t if not defined])],
[#include <sys/types.h>
#include <sys/socket.h>])
])

View File

@@ -0,0 +1,23 @@
dnl AC_VALIDATE_CACHE_SYSTEM_TYPE[(cmd)]
dnl if the cache file is inconsistent with the current host,
dnl target and build system types, execute CMD or print a default
dnl error message.
AC_DEFUN([AC_VALIDATE_CACHE_SYSTEM_TYPE], [
AC_REQUIRE([AC_CANONICAL_SYSTEM])
AC_MSG_CHECKING([config.cache system type])
if { test x"${ac_cv_host_system_type+set}" = x"set" &&
test x"$ac_cv_host_system_type" != x"$host"; } ||
{ test x"${ac_cv_build_system_type+set}" = x"set" &&
test x"$ac_cv_build_system_type" != x"$build"; } ||
{ test x"${ac_cv_target_system_type+set}" = x"set" &&
test x"$ac_cv_target_system_type" != x"$target"; }; then
AC_MSG_RESULT([different])
ifelse($#, 1, [$1],
[AC_MSG_ERROR(["you must remove config.cache and restart configure"])])
else
AC_MSG_RESULT([same])
fi
ac_cv_host_system_type="$host"
ac_cv_build_system_type="$build"
ac_cv_target_system_type="$target"
])

306
main.c
View File

@@ -4,7 +4,7 @@
* Copyright (C) 1996-2001 Andrew Tridgell <tridge@samba.org>
* Copyright (C) 1996 Paul Mackerras
* Copyright (C) 2001, 2002 Martin Pool <mbp@samba.org>
* Copyright (C) 2003-2014 Wayne Davison
* Copyright (C) 2003-2020 Wayne Davison
*
* 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
@@ -26,6 +26,7 @@
#if defined CONFIG_LOCALE && defined HAVE_LOCALE_H
#include <locale.h>
#endif
#include <popt.h>
extern int dry_run;
extern int list_only;
@@ -39,6 +40,7 @@ extern int blocking_io;
extern int always_checksum;
extern int remove_source_files;
extern int output_needs_newline;
extern int called_from_signal_handler;
extern int need_messages_from_generator;
extern int kluge_around_eof;
extern int got_xfer_error;
@@ -75,19 +77,21 @@ extern pid_t cleanup_child_pid;
extern size_t bwlimit_writemax;
extern unsigned int module_dirlen;
extern BOOL flist_receiving_enabled;
extern BOOL want_progress_now;
extern BOOL shutting_down;
extern int backup_dir_len;
extern int basis_dir_cnt;
extern int default_af_hint;
extern struct stats stats;
extern char *stdout_format;
extern char *logfile_format;
extern char *filesfrom_host;
extern char *partial_dir;
extern char *dest_option;
extern char *rsync_path;
extern char *shell_cmd;
extern char *batch_name;
extern char *password_file;
extern char *backup_dir;
extern char *copy_as;
extern char curr_dir[MAXPATHLEN];
extern char backup_dir_buf[MAXPATHLEN];
extern char *basis_dir[MAX_BASIS_DIRS+1];
@@ -103,6 +107,8 @@ int daemon_over_rsh = 0;
mode_t orig_umask = 0;
int batch_gen_fd = -1;
int sender_keeps_checksum = 0;
int raw_argc, cooked_argc;
char **raw_argv, **cooked_argv;
/* There's probably never more than at most 2 outstanding child processes,
* but set it higher, just in case. */
@@ -153,6 +159,27 @@ pid_t wait_process(pid_t pid, int *status_ptr, int flags)
return waited_pid;
}
int shell_exec(const char *cmd)
{
char *shell = getenv("RSYNC_SHELL");
int status;
pid_t pid;
if (!shell)
return system(cmd);
if ((pid = fork()) < 0)
return -1;
if (pid == 0) {
execlp(shell, shell, "-c", cmd, NULL);
_exit(1);
}
int ret = wait_process(pid, &status, 0);
return ret < 0 ? -1 : status;
}
/* Wait for a process to exit, calling io_flush while waiting. */
static void wait_process_with_flush(pid_t pid, int *exit_code_ptr)
{
@@ -209,6 +236,74 @@ void read_del_stats(int f)
stats.deleted_files += stats.deleted_specials = read_varint(f);
}
static void become_copy_as_user()
{
char *gname;
uid_t uid;
gid_t gid;
if (!copy_as)
return;
if (DEBUG_GTE(CMD, 2))
rprintf(FINFO, "[%s] copy_as=%s\n", who_am_i(), copy_as);
if ((gname = strchr(copy_as, ':')) != NULL)
*gname++ = '\0';
if (!user_to_uid(copy_as, &uid, True)) {
rprintf(FERROR, "Invalid copy-as user: %s\n", copy_as);
exit_cleanup(RERR_SYNTAX);
}
if (gname) {
if (!group_to_gid(gname, &gid, True)) {
rprintf(FERROR, "Invalid copy-as group: %s\n", gname);
exit_cleanup(RERR_SYNTAX);
}
} else {
struct passwd *pw;
if ((pw = getpwuid(uid)) == NULL) {
rsyserr(FERROR, errno, "getpwuid failed");
exit_cleanup(RERR_SYNTAX);
}
gid = pw->pw_gid;
}
if (setgid(gid) < 0) {
rsyserr(FERROR, errno, "setgid failed");
exit_cleanup(RERR_SYNTAX);
}
#ifdef HAVE_SETGROUPS
if (setgroups(1, &gid)) {
rsyserr(FERROR, errno, "setgroups failed");
exit_cleanup(RERR_SYNTAX);
}
#endif
#ifdef HAVE_INITGROUPS
if (!gname && initgroups(copy_as, gid) < 0) {
rsyserr(FERROR, errno, "initgroups failed");
exit_cleanup(RERR_SYNTAX);
}
#endif
if (setuid(uid) < 0
#ifdef HAVE_SETEUID
|| seteuid(uid) < 0
#endif
) {
rsyserr(FERROR, errno, "setuid failed");
exit_cleanup(RERR_SYNTAX);
}
our_uid = MY_UID();
our_gid = MY_GID();
am_root = (our_uid == 0);
if (gname)
gname[-1] = ':';
}
/* This function gets called from all 3 processes. We want the client side
* to actually output the text, but the sender is the only process that has
* all the stats we need. So, if we're a client sender, we do the report.
@@ -301,6 +396,13 @@ static void output_itemized_counts(const char *prefix, int *counts)
rprintf(FINFO, "%s: %s%s\n", prefix, comma_num(total), buf);
}
static const char *bytes_per_sec_human_dnum(void)
{
if (starttime == (time_t)-1 || endtime == (time_t)-1)
return "UNKNOWN";
return human_dnum((total_written + total_read) / (0.5 + (endtime - starttime)), 2);
}
static void output_summary(void)
{
if (INFO_GTE(STATS, 2)) {
@@ -341,7 +443,7 @@ static void output_summary(void)
rprintf(FINFO,
"sent %s bytes received %s bytes %s bytes/sec\n",
human_num(total_written), human_num(total_read),
human_dnum((total_written + total_read)/(0.5 + (endtime - starttime)), 2));
bytes_per_sec_human_dnum());
rprintf(FINFO, "total size is %s speedup is %s%s\n",
human_num(stats.total_size),
comma_dnum((double)stats.total_size / (total_written+total_read), 2),
@@ -424,8 +526,8 @@ static pid_t do_cmd(char *cmd, char *machine, char *user, char **remote_argv, in
if (!*f) {
if (in_quote) {
rprintf(FERROR,
"Missing trailing-%c in remote-shell command.\n",
in_quote);
"Missing trailing-%c in remote-shell command.\n",
in_quote);
exit_cleanup(RERR_SYNTAX);
}
f--;
@@ -446,8 +548,13 @@ static pid_t do_cmd(char *cmd, char *machine, char *user, char **remote_argv, in
*t++ = '\0';
}
/* check to see if we've already been given '-l user' in
* the remote-shell command */
/* NOTE: must preserve t == start of command name until the end of the args handling! */
if ((t = strrchr(cmd, '/')) != NULL)
t++;
else
t = cmd;
/* Check to see if we've already been given '-l user' in the remote-shell command. */
for (i = 0; i < argc-1; i++) {
if (!strcmp(args[i], "-l") && args[i+1][0] != '-')
dash_l_set = 1;
@@ -465,22 +572,23 @@ static pid_t do_cmd(char *cmd, char *machine, char *user, char **remote_argv, in
args[argc++] = "-l";
args[argc++] = user;
}
#ifdef AF_INET
if (default_af_hint == AF_INET && strcmp(t, "ssh") == 0)
args[argc++] = "-4"; /* we're using ssh so we can add a -4 option */
#endif
#ifdef AF_INET6
if (default_af_hint == AF_INET6 && strcmp(t, "ssh") == 0)
args[argc++] = "-6"; /* we're using ssh so we can add a -6 option */
#endif
args[argc++] = machine;
#endif
args[argc++] = rsync_path;
if (blocking_io < 0) {
char *cp;
if ((cp = strrchr(cmd, '/')) != NULL)
cp++;
else
cp = cmd;
if (strcmp(cp, "rsh") == 0 || strcmp(cp, "remsh") == 0)
blocking_io = 1;
}
if (blocking_io < 0 && (strcmp(t, "rsh") == 0 || strcmp(t, "remsh") == 0))
blocking_io = 1;
server_options(args,&argc);
server_options(args, &argc);
if (argc >= MAX_ARGS - 2)
goto arg_overflow;
@@ -584,7 +692,7 @@ static char *get_local_name(struct file_list *flist, char *dest_path)
/* Treat an empty string as a copy into the current directory. */
if (!*dest_path)
dest_path = ".";
dest_path = ".";
if (daemon_filter_list.head) {
char *slash = strrchr(dest_path, '/');
@@ -645,8 +753,7 @@ static char *get_local_name(struct file_list *flist, char *dest_path)
*cp = '\0';
if (statret == 0) {
rprintf(FERROR,
"ERROR: destination path is not a directory\n");
rprintf(FERROR, "ERROR: destination path is not a directory\n");
exit_cleanup(RERR_SYNTAX);
}
@@ -720,21 +827,21 @@ static void check_alt_basis_dirs(void)
if (!new)
out_of_memory("check_alt_basis_dirs");
if (slash && strncmp(bdir, "../", 3) == 0) {
/* We want to remove only one leading "../" prefix for
* the directory we couldn't create in dry-run mode:
* this ensures that any other ".." references get
* evaluated the same as they would for a live copy. */
*slash = '\0';
pathjoin(new, len, curr_dir, bdir + 3);
*slash = '/';
/* We want to remove only one leading "../" prefix for
* the directory we couldn't create in dry-run mode:
* this ensures that any other ".." references get
* evaluated the same as they would for a live copy. */
*slash = '\0';
pathjoin(new, len, curr_dir, bdir + 3);
*slash = '/';
} else
pathjoin(new, len, curr_dir, bdir);
pathjoin(new, len, curr_dir, bdir);
basis_dir[j] = bdir = new;
}
if (do_stat(bdir, &st) < 0)
rprintf(FWARNING, "%s arg does not exist: %s\n", dest_option, bdir);
rprintf(FWARNING, "%s arg does not exist: %s\n", alt_dest_opt(0), bdir);
else if (!S_ISDIR(st.st_mode))
rprintf(FWARNING, "%s arg is not a dir: %s\n", dest_option, bdir);
rprintf(FWARNING, "%s arg is not a dir: %s\n", alt_dest_opt(0), bdir);
}
}
@@ -775,7 +882,7 @@ static void read_final_goodbye(int f_in, int f_out)
static void do_server_sender(int f_in, int f_out, int argc, char *argv[])
{
struct file_list *flist;
char *dir = argv[0];
char *dir;
if (DEBUG_GTE(SEND, 1))
rprintf(FINFO, "server_sender starting pid=%d\n", (int)getpid());
@@ -783,16 +890,21 @@ static void do_server_sender(int f_in, int f_out, int argc, char *argv[])
if (am_daemon && lp_write_only(module_id)) {
rprintf(FERROR, "ERROR: module is write only\n");
exit_cleanup(RERR_SYNTAX);
return;
}
if (am_daemon && read_only && remove_source_files) {
rprintf(FERROR,
"ERROR: --remove-%s-files cannot be used with a read-only module\n",
remove_source_files == 1 ? "source" : "sent");
"ERROR: --remove-%s-files cannot be used with a read-only module\n",
remove_source_files == 1 ? "source" : "sent");
exit_cleanup(RERR_SYNTAX);
}
if (argc < 1) {
rprintf(FERROR, "ERROR: do_server_sender called without args\n");
exit_cleanup(RERR_SYNTAX);
return;
}
become_copy_as_user();
dir = argv[0];
if (!relative_paths) {
if (!change_dir(dir, CD_NORMAL)) {
rsyserr(FERROR, errno, "change_dir#3 %s failed",
@@ -850,13 +962,26 @@ static int do_recv(int f_in, int f_out, char *local_name)
}
if (backup_dir) {
int ret = make_path(backup_dir_buf, MKP_DROP_NAME); /* drops trailing slash */
if (ret < 0)
exit_cleanup(RERR_SYNTAX);
if (ret)
rprintf(FINFO, "Created backup_dir %s\n", backup_dir_buf);
else if (INFO_GTE(BACKUP, 1))
STRUCT_STAT st;
int ret;
if (backup_dir_len > 1)
backup_dir_buf[backup_dir_len-1] = '\0';
ret = do_stat(backup_dir_buf, &st);
if (ret != 0 || !S_ISDIR(st.st_mode)) {
if (ret == 0) {
rprintf(FERROR, "The backup-dir is not a directory: %s\n", backup_dir_buf);
exit_cleanup(RERR_SYNTAX);
}
if (errno != ENOENT) {
rprintf(FERROR, "Failed to stat %s: %s\n", backup_dir_buf, strerror(errno));
exit_cleanup(RERR_FILEIO);
}
if (INFO_GTE(BACKUP, 1))
rprintf(FINFO, "(new) backup_dir is %s\n", backup_dir_buf);
} else if (INFO_GTE(BACKUP, 1))
rprintf(FINFO, "backup_dir is %s\n", backup_dir_buf);
if (backup_dir_len > 1)
backup_dir_buf[backup_dir_len-1] = '/';
}
io_flush(FULL_FLUSH);
@@ -982,6 +1107,8 @@ static void do_server_recv(int f_in, int f_out, int argc, char *argv[])
return;
}
become_copy_as_user();
if (argc > 0) {
char *dir = argv[0];
argc--;
@@ -1009,7 +1136,7 @@ static void do_server_recv(int f_in, int f_out, int argc, char *argv[])
filesfrom_fd = -1;
}
flist = recv_file_list(f_in);
flist = recv_file_list(f_in, -1);
if (!flist) {
rprintf(FERROR,"server_recv: recv_file_list error\n");
exit_cleanup(RERR_FILESELECT);
@@ -1048,8 +1175,7 @@ static void do_server_recv(int f_in, int f_out, int argc, char *argv[])
if (partial_dir && *partial_dir == '/'
&& check_filter(elp, FLOG, partial_dir + module_dirlen, 1) < 0) {
options_rejected:
rprintf(FERROR,
"Your options have been rejected by the server.\n");
rprintf(FERROR, "Your options have been rejected by the server.\n");
exit_cleanup(RERR_SYNTAX);
}
}
@@ -1141,6 +1267,9 @@ int client_run(int f_in, int f_out, pid_t pid, int argc, char *argv[])
if (write_batch && !am_server)
start_write_batch(f_out);
become_copy_as_user();
flist = send_file_list(f_out, argc, argv);
if (DEBUG_GTE(FLIST, 3))
rprintf(FINFO,"file list sent\n");
@@ -1174,6 +1303,8 @@ int client_run(int f_in, int f_out, pid_t pid, int argc, char *argv[])
io_start_buffering_out(f_out);
}
become_copy_as_user();
send_filter_list(read_batch ? -1 : f_out);
if (filesfrom_fd >= 0) {
@@ -1183,7 +1314,7 @@ int client_run(int f_in, int f_out, pid_t pid, int argc, char *argv[])
if (write_batch && !am_server)
start_write_batch(f_in);
flist = recv_file_list(f_in);
flist = recv_file_list(f_in, -1);
if (inc_recurse && file_total == 1)
recv_additional_file_list(f_in);
@@ -1234,7 +1365,7 @@ static int start_client(int argc, char *argv[])
{
char *p, *shell_machine = NULL, *shell_user = NULL;
char **remote_argv;
int remote_argc;
int remote_argc, env_port = rsync_port;
int f_in, f_out;
int ret;
pid_t pid;
@@ -1263,8 +1394,7 @@ static int start_client(int argc, char *argv[])
remote_argc--; /* don't count dest */
argc = 1;
}
if (filesfrom_host && *filesfrom_host
&& strcmp(filesfrom_host, shell_machine) != 0) {
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);
@@ -1286,8 +1416,7 @@ static int start_client(int argc, char *argv[])
remote_argc = 1;
path = check_for_hostspec(p, &shell_machine, &rsync_port);
if (path && filesfrom_host && *filesfrom_host
&& strcmp(filesfrom_host, shell_machine) != 0) {
if (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);
@@ -1300,6 +1429,7 @@ static int start_client(int argc, char *argv[])
exit_cleanup(RERR_SYNTAX);
}
shell_machine = NULL;
rsync_port = 0;
} else { /* hostspec was found, so dest is remote */
argv[argc] = path;
if (rsync_port)
@@ -1314,6 +1444,7 @@ static int start_client(int argc, char *argv[])
}
remote_argv = argv += argc - 1;
remote_argc = argc = 1;
rsync_port = 0;
}
if (!rsync_port && remote_argc && !**remote_argv) /* Turn an empty arg into a dot dir. */
@@ -1360,6 +1491,11 @@ static int start_client(int argc, char *argv[])
}
}
if (rsync_port < 0)
rsync_port = RSYNC_PORT;
else
env_port = rsync_port;
if (daemon_over_rsh < 0)
return start_socket_client(shell_machine, remote_argc, remote_argv, argc, argv);
@@ -1390,8 +1526,12 @@ static int start_client(int argc, char *argv[])
NS(remote_argv[0]));
}
pid = do_cmd(shell_cmd, shell_machine, shell_user, remote_argv, remote_argc,
&f_in, &f_out);
#ifdef HAVE_PUTENV
if (daemon_over_rsh)
set_env_num("RSYNC_PORT", env_port);
#endif
pid = do_cmd(shell_cmd, shell_machine, shell_user, remote_argv, remote_argc, &f_in, &f_out);
/* if we're running an rsync server on the remote host over a
* remote shell command, we need to do the RSYNCD protocol first */
@@ -1411,12 +1551,13 @@ static int start_client(int argc, char *argv[])
}
static RETSIGTYPE sigusr1_handler(UNUSED(int val))
static void sigusr1_handler(UNUSED(int val))
{
called_from_signal_handler = 1;
exit_cleanup(RERR_SIGNAL1);
}
static RETSIGTYPE sigusr2_handler(UNUSED(int val))
static void sigusr2_handler(UNUSED(int val))
{
if (!am_server)
output_summary();
@@ -1426,7 +1567,13 @@ static RETSIGTYPE sigusr2_handler(UNUSED(int val))
_exit(0);
}
RETSIGTYPE remember_children(UNUSED(int val))
static void siginfo_handler(UNUSED(int val))
{
if (!am_server && !INFO_GTE(PROGRESS, 1))
want_progress_now = True;
}
void remember_children(UNUSED(int val))
{
#ifdef WNOHANG
int cnt, status;
@@ -1473,9 +1620,7 @@ const char *get_panic_action(void)
if (cmd_fmt)
return cmd_fmt;
else
return "xterm -display :0 -T Panic -n Panic "
"-e gdb /proc/%d/exe %d";
return "xterm -display :0 -T Panic -n Panic -e gdb /proc/%d/exe %d";
}
@@ -1487,7 +1632,7 @@ const char *get_panic_action(void)
* should just look at the environment variable, but I'm a bit leery
* of a signal sending us into a busy loop.
**/
static RETSIGTYPE rsync_panic_handler(UNUSED(int whatsig))
static void rsync_panic_handler(UNUSED(int whatsig))
{
char cmd_buf[300];
int ret, pid_int = getpid();
@@ -1496,7 +1641,7 @@ static RETSIGTYPE rsync_panic_handler(UNUSED(int whatsig))
/* Unless we failed to execute gdb, we allow the process to
* continue. I'm not sure if that's right. */
ret = system(cmd_buf);
ret = shell_exec(cmd_buf);
if (ret)
_exit(ret);
}
@@ -1506,8 +1651,10 @@ static RETSIGTYPE rsync_panic_handler(UNUSED(int whatsig))
int main(int argc,char *argv[])
{
int ret;
int orig_argc = argc;
char **orig_argv = argv;
raw_argc = argc;
raw_argv = argv;
#ifdef HAVE_SIGACTION
# ifdef HAVE_SIGPROCMASK
sigset_t sigmask;
@@ -1525,6 +1672,12 @@ int main(int argc,char *argv[])
SIGACTMASK(SIGABRT, rsync_panic_handler);
SIGACTMASK(SIGBUS, rsync_panic_handler);
#endif
#ifdef SIGINFO
SIGACTMASK(SIGINFO, siginfo_handler);
#endif
#ifdef SIGVTALRM
SIGACTMASK(SIGVTALRM, siginfo_handler);
#endif
starttime = time(NULL);
our_uid = MY_UID();
@@ -1533,6 +1686,10 @@ int main(int argc,char *argv[])
memset(&stats, 0, sizeof(stats));
/* Even a non-daemon runs needs the default config values to be set, e.g.
* lp_dont_compress() is queried when no --skip-compress option is set. */
reset_daemon_vars();
if (argc < 2) {
usage(FERROR);
exit_cleanup(RERR_SYNTAX);
@@ -1548,11 +1705,12 @@ int main(int argc,char *argv[])
#endif
if (!parse_arguments(&argc, (const char ***) &argv)) {
/* FIXME: We ought to call the same error-handling
* code here, rather than relying on getopt. */
option_error();
exit_cleanup(RERR_SYNTAX);
}
if (write_batch
&& poptDupArgv(argc, (const char **)argv, &cooked_argc, (const char ***)&cooked_argv) != 0)
out_of_memory("main");
SIGACTMASK(SIGINT, sig_int);
SIGACTMASK(SIGHUP, sig_int);
@@ -1574,24 +1732,8 @@ int main(int argc,char *argv[])
* that implement getcwd that way "pwd" can't be found after chroot. */
change_dir(NULL, CD_NORMAL);
init_flist();
if ((write_batch || read_batch) && !am_server) {
if (write_batch)
write_batch_shell_file(orig_argc, orig_argv, argc);
if (read_batch && strcmp(batch_name, "-") == 0)
batch_fd = STDIN_FILENO;
else {
batch_fd = do_open(batch_name,
write_batch ? O_WRONLY | O_CREAT | O_TRUNC
: O_RDONLY, S_IRUSR | S_IWUSR);
}
if (batch_fd < 0) {
rsyserr(FERROR, errno, "Batch file %s open error",
full_fname(batch_name));
exit_cleanup(RERR_FILEIO);
}
open_batch_files(); /* sets batch_fd */
if (read_batch)
read_stream_flags(batch_fd);
else

35
match.c
View File

@@ -3,7 +3,7 @@
*
* Copyright (C) 1996 Andrew Tridgell
* Copyright (C) 1996 Paul Mackerras
* Copyright (C) 2003-2014 Wayne Davison
* Copyright (C) 2003-2020 Wayne Davison
*
* 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
@@ -24,7 +24,7 @@
extern int checksum_seed;
extern int append_mode;
extern int checksum_len;
extern int xfersum_type;
int updating_basis_file;
char sender_file_sum[MAX_DIGEST_LEN];
@@ -102,8 +102,7 @@ static OFF_T last_match;
* If i >= 0, the number of a matched token. If < 0, indicates we have
* only literal data. A -1 will send a 0-token-int too, and a -2 sends
* only literal data, w/o any token-int. */
static void matched(int f, struct sum_struct *s, struct map_struct *buf,
OFF_T offset, int32 i)
static void matched(int f, struct sum_struct *s, struct map_struct *buf, OFF_T offset, int32 i)
{
int32 n = (int32)(offset - last_match); /* max value: block_size (int32) */
int32 j;
@@ -207,7 +206,7 @@ static void hash_search(int f,struct sum_struct *s,
* either >= our offset or identical data at that offset.
* Remove any bypassed entries that we can never use. */
if (updating_basis_file && s->sums[i].offset < offset
&& !(s->sums[i].flags & SUMFLG_SAME_OFFSET)) {
&& !(s->sums[i].flags & SUMFLG_SAME_OFFSET)) {
*prev = s->sums[i].chain;
continue;
}
@@ -288,10 +287,10 @@ static void hash_search(int f,struct sum_struct *s,
/* 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
&& (!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) {
&& (!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) {
/* we've found an adjacent match - the RLL coder
* will be happy */
i = want_i;
@@ -317,8 +316,7 @@ static void hash_search(int f,struct sum_struct *s,
/* Trim off the first byte from the checksum */
more = offset + k < len;
map = (schar *)map_ptr(buf, offset - backup, k + more + backup)
+ backup;
map = (schar *)map_ptr(buf, offset - backup, k + more + backup) + backup;
s1 -= map[0] + CHAR_OFFSET;
s2 -= k * (map[0]+CHAR_OFFSET);
@@ -360,13 +358,15 @@ static void hash_search(int f,struct sum_struct *s,
**/
void match_sums(int f, struct sum_struct *s, struct map_struct *buf, OFF_T len)
{
int sum_len;
last_match = 0;
false_alarms = 0;
hash_hits = 0;
matches = 0;
data_transfer = 0;
sum_init(checksum_seed);
sum_init(xfersum_type, checksum_seed);
if (append_mode > 0) {
if (append_mode == 2) {
@@ -407,23 +407,22 @@ void match_sums(int f, struct sum_struct *s, struct map_struct *buf, OFF_T len)
matched(f, s, buf, len, -1);
}
if (sum_end(sender_file_sum) != checksum_len)
overflow_exit("checksum_len"); /* Impossible... */
sum_len = sum_end(sender_file_sum);
/* If we had a read error, send a bad checksum. We use all bits
* off as long as the checksum doesn't happen to be that, in
* which case we turn the last 0 bit into a 1. */
if (buf && buf->status != 0) {
int i;
for (i = 0; i < checksum_len && sender_file_sum[i] == 0; i++) {}
memset(sender_file_sum, 0, checksum_len);
if (i == checksum_len)
for (i = 0; i < sum_len && sender_file_sum[i] == 0; i++) {}
memset(sender_file_sum, 0, sum_len);
if (i == sum_len)
sender_file_sum[i-1]++;
}
if (DEBUG_GTE(DELTASUM, 2))
rprintf(FINFO,"sending file_sum\n");
write_buf(f, sender_file_sum, checksum_len);
write_buf(f, sender_file_sum, sum_len);
if (DEBUG_GTE(DELTASUM, 2)) {
rprintf(FINFO, "false_alarms=%d hash_hits=%d matches=%d\n",

40
maybe-make-man Executable file
View File

@@ -0,0 +1,40 @@
#!/bin/sh
if [ x"$2" = x ]; then
echo "Usage: $0 SRC_DIR NAME.NUM.md" 1>&2
exit 1
fi
srcdir="$1"
inname="$2"
flagfile="$srcdir/.md2man-works"
if [ ! -d "$srcdir" ]; then
echo "The specified SRC_DIR is not a directory: $srcdir" 1>&2
exit 1
fi
if [ ! -f "$flagfile" ]; then
# We test our smallest manpage just to see if the python setup works.
if "$srcdir/md2man" --test "$srcdir/rsync-ssl.1.md" >/dev/null 2>&1; then
touch $flagfile
else
outname=`echo "$inname" | sed 's/\.md$//'`
if [ -f "$outname" ]; then
exit 0
elif [ -f "$srcdir/$outname" ]; then
echo "Copying $srcdir/$outname"
cp -p "$srcdir/$outname" .
exit 0
else
echo "ERROR: $outname cannot be created."
if [ -f "$HOME/build_farm/build_test.fns" ]; then
exit 0 # No exit errorno to avoid a build failure in the samba build farm
else
exit 1
fi
fi
fi
fi
"$srcdir/md2man" "$srcdir/$inname"

369
md2man Executable file
View File

@@ -0,0 +1,369 @@
#!/usr/bin/python3
# This script takes a manpage written in markdown and turns it into an html web
# page and a nroff man page. The input file must have the name of the program
# and the section in this format: NAME.NUM.md. The output files are written
# into the current directory named NAME.NUM.html and NAME.NUM. The input
# format has one extra extension: if a numbered list starts at 0, it is turned
# into a description list. The dl's dt tag is taken from the contents of the
# first tag inside the li, which is usually a p, code, or strong tag. The
# cmarkgfm or commonmark lib is used to transforms the input file into html.
# The html.parser is used as a state machine that both tweaks the html and
# outputs the nroff data based on the html tags.
#
# Copyright (C) 2020 Wayne Davison
#
# This program is freely redistributable.
import sys, os, re, argparse, subprocess, time
from html.parser import HTMLParser
CONSUMES_TXT = set('h1 h2 p li pre'.split())
HTML_START = """\
<html><head>
<title>%s</title>
<link href="https://fonts.googleapis.com/css2?family=Roboto&family=Roboto+Mono&display=swap" rel="stylesheet">
<style>
body {
max-width: 50em;
margin: auto;
}
body, b, strong, u {
font-family: 'Roboto', sans-serif;
}
code {
font-family: 'Roboto Mono', monospace;
font-weight: bold;
}
pre code {
display: block;
font-weight: normal;
}
blockquote pre code {
background: #f1f1f1;
}
dd p:first-of-type {
margin-block-start: 0em;
}
</style>
</head><body>
"""
HTML_END = """\
<div style="float: right"><p><i>%s</i></p></div>
</body></html>
"""
MAN_START = r"""
.TH "%s" "%s" "%s" "%s" "User Commands"
""".lstrip()
MAN_END = """\
"""
NORM_FONT = ('\1', r"\fP")
BOLD_FONT = ('\2', r"\fB")
ULIN_FONT = ('\3', r"\fI")
md_parser = None
def main():
fi = re.match(r'^(?P<fn>(?P<srcdir>.+/)?(?P<name>(?P<prog>[^/]+)\.(?P<sect>\d+))\.md)$', args.mdfile)
if not fi:
die('Failed to parse NAME.NUM.md out of input file:', args.mdfile)
fi = argparse.Namespace(**fi.groupdict())
if not fi.srcdir:
fi.srcdir = './'
fi.title = fi.prog + '(' + fi.sect + ') man page'
fi.mtime = None
if os.path.lexists(fi.srcdir + '.git'):
fi.mtime = int(subprocess.check_output('git log -1 --format=%at'.split()))
chk_files = 'NEWS.md Makefile'.split()
for fn in chk_files:
try:
st = os.lstat(fi.srcdir + fn)
except:
die('Failed to find', fi.srcdir + fn)
if not fi.mtime:
fi.mtime = st.st_mtime
fi.date = time.strftime('%d %b %Y', time.localtime(fi.mtime))
env_subs = { 'prefix': os.environ.get('RSYNC_OVERRIDE_PREFIX', None) }
with open(fi.srcdir + 'Makefile', 'r', encoding='utf-8') as fh:
for line in fh:
m = re.match(r'^(\w+)=(.+)', line)
if not m:
continue
var, val = (m[1], m[2])
if var == 'prefix' and env_subs[var] is not None:
continue
while re.search(r'\$\{', val):
val = re.sub(r'\$\{(\w+)\}', lambda m: env_subs[m[1]], val)
env_subs[var] = val
if var == 'VERSION':
break
with open(fi.fn, 'r', encoding='utf-8') as fh:
txt = fh.read()
txt = re.sub(r'@VERSION@', env_subs['VERSION'], txt)
txt = re.sub(r'@LIBDIR@', env_subs['libdir'], txt)
fi.html_in = md_parser(txt)
txt = None
fi.man_headings = (fi.prog, fi.sect, fi.date, fi.prog + ' ' + env_subs['VERSION'])
HtmlToManPage(fi)
if args.test:
print("The test was successful.")
return
for fn, txt in ((fi.name + '.html', fi.html_out), (fi.name, fi.man_out)):
print("Wrote:", fn)
with open(fn, 'w', encoding='utf-8') as fh:
fh.write(txt)
def html_via_cmarkgfm(txt):
return cmarkgfm.markdown_to_html(txt)
def html_via_commonmark(txt):
return commonmark.HtmlRenderer().render(commonmark.Parser().parse(txt))
class HtmlToManPage(HTMLParser):
def __init__(self, fi):
HTMLParser.__init__(self, convert_charrefs=True)
st = self.state = argparse.Namespace(
list_state = [ ],
p_macro = ".P\n",
at_first_tag_in_li = False,
at_first_tag_in_dd = False,
dt_from = None,
in_pre = False,
in_code = False,
html_out = [ HTML_START % fi.title ],
man_out = [ MAN_START % fi.man_headings ],
txt = '',
)
self.feed(fi.html_in)
fi.html_in = None
st.html_out.append(HTML_END % fi.date)
st.man_out.append(MAN_END)
fi.html_out = ''.join(st.html_out)
st.html_out = None
fi.man_out = ''.join(st.man_out)
st.man_out = None
def handle_starttag(self, tag, attrs_list):
st = self.state
if args.debug:
self.output_debug('START', (tag, attrs_list))
if st.at_first_tag_in_li:
if st.list_state[-1] == 'dl':
st.dt_from = tag
if tag == 'p':
tag = 'dt'
else:
st.html_out.append('<dt>')
st.at_first_tag_in_li = False
if tag == 'p':
if not st.at_first_tag_in_dd:
st.man_out.append(st.p_macro)
elif tag == 'li':
st.at_first_tag_in_li = True
lstate = st.list_state[-1]
if lstate == 'dl':
return
if lstate == 'o':
st.man_out.append(".IP o\n")
else:
st.man_out.append(".IP " + str(lstate) + ".\n")
st.list_state[-1] += 1
elif tag == 'blockquote':
st.man_out.append(".RS 4\n")
elif tag == 'pre':
st.in_pre = True
st.man_out.append(st.p_macro + ".nf\n")
elif tag == 'code' and not st.in_pre:
st.in_code = True
st.txt += BOLD_FONT[0]
elif tag == 'strong' or tag == 'b':
st.txt += BOLD_FONT[0]
elif tag == 'em' or tag == 'i':
tag = 'u' # Change it into underline to be more like the man page
st.txt += ULIN_FONT[0]
elif tag == 'ol':
start = 1
for var, val in attrs_list:
if var == 'start':
start = int(val) # We only support integers.
break
if st.list_state:
st.man_out.append(".RS\n")
if start == 0:
tag = 'dl'
attrs_list = [ ]
st.list_state.append('dl')
else:
st.list_state.append(start)
st.man_out.append(st.p_macro)
st.p_macro = ".IP\n"
elif tag == 'ul':
st.man_out.append(st.p_macro)
if st.list_state:
st.man_out.append(".RS\n")
st.p_macro = ".IP\n"
st.list_state.append('o')
st.html_out.append('<' + tag + ''.join(' ' + var + '="' + htmlify(val) + '"' for var, val in attrs_list) + '>')
st.at_first_tag_in_dd = False
def handle_endtag(self, tag):
st = self.state
if args.debug:
self.output_debug('END', (tag,))
if tag in CONSUMES_TXT or st.dt_from == tag:
txt = st.txt.strip()
st.txt = ''
else:
txt = None
add_to_txt = None
if tag == 'h1':
st.man_out.append(st.p_macro + '.SH "' + manify(txt) + '"\n')
elif tag == 'h2':
st.man_out.append(st.p_macro + '.SS "' + manify(txt) + '"\n')
elif tag == 'p':
if st.dt_from == 'p':
tag = 'dt'
st.man_out.append('.IP "' + manify(txt) + '"\n')
st.dt_from = None
elif txt != '':
st.man_out.append(manify(txt) + "\n")
elif tag == 'li':
if st.list_state[-1] == 'dl':
if st.at_first_tag_in_li:
die("Invalid 0. -> td translation")
tag = 'dd'
if txt != '':
st.man_out.append(manify(txt) + "\n")
st.at_first_tag_in_li = False
elif tag == 'blockquote':
st.man_out.append(".RE\n")
elif tag == 'pre':
st.in_pre = False
st.man_out.append(manify(txt) + "\n.fi\n")
elif (tag == 'code' and not st.in_pre):
st.in_code = False
add_to_txt = NORM_FONT[0]
elif tag == 'strong' or tag == 'b':
add_to_txt = NORM_FONT[0]
elif tag == 'em' or tag == 'i':
tag = 'u' # Change it into underline to be more like the man page
add_to_txt = NORM_FONT[0]
elif tag == 'ol' or tag == 'ul':
if st.list_state.pop() == 'dl':
tag = 'dl'
if st.list_state:
st.man_out.append(".RE\n")
else:
st.p_macro = ".P\n"
st.at_first_tag_in_dd = False
st.html_out.append('</' + tag + '>')
if add_to_txt:
if txt is None:
st.txt += add_to_txt
else:
txt += add_to_txt
if st.dt_from == tag:
st.man_out.append('.IP "' + manify(txt) + '"\n')
st.html_out.append('</dt><dd>')
st.at_first_tag_in_dd = True
st.dt_from = None
elif tag == 'dt':
st.html_out.append('<dd>')
st.at_first_tag_in_dd = True
def handle_data(self, data):
st = self.state
if args.debug:
self.output_debug('DATA', (data,))
if st.in_code:
data = re.sub(r'\s', '\xa0', data) # nbsp in non-pre code
data = re.sub(r'\s--\s', '\xa0-- ', data)
st.html_out.append(htmlify(data))
st.txt += data
def output_debug(self, event, extra):
import pprint
st = self.state
if args.debug < 2:
st = argparse.Namespace(**vars(st))
if len(st.html_out) > 2:
st.html_out = ['...'] + st.html_out[-2:]
if len(st.man_out) > 2:
st.man_out = ['...'] + st.man_out[-2:]
print(event, extra)
pprint.PrettyPrinter(indent=2).pprint(vars(st))
def manify(txt):
return re.sub(r"^(['.])", r'\&\1', txt.replace('\\', '\\\\')
.replace("\xa0", r'\ ') # non-breaking space
.replace('--', r'\-\-') # non-breaking double dash
.replace(NORM_FONT[0], NORM_FONT[1])
.replace(BOLD_FONT[0], BOLD_FONT[1])
.replace(ULIN_FONT[0], ULIN_FONT[1]), flags=re.M)
def htmlify(txt):
return re.sub(r'(\W)-', r'\1&#8209;',
txt.replace('&', '&amp;').replace('<', '&lt;').replace('>', '&gt;').replace('"', '&quot;')
.replace('--', '&#8209;&#8209;').replace("\xa0-", '&nbsp;&#8209;').replace("\xa0", '&nbsp;'))
def warn(*msg):
print(*msg, file=sys.stderr)
def die(*msg):
warn(*msg)
sys.exit(1)
if __name__ == '__main__':
parser = argparse.ArgumentParser(description='Transform a NAME.NUM.md markdown file into a NAME.NUM.html web page & a NAME.NUM man page.', add_help=False)
parser.add_argument('--test', action='store_true', help='Test if we can parse the input w/o updating any files.')
parser.add_argument('--debug', '-D', action='count', default=0, help='Output copious info on the html parsing. Repeat for even more.')
parser.add_argument("--help", "-h", action="help", help="Output this help message and exit.")
parser.add_argument('mdfile', help="The NAME.NUM.md file to parse.")
args = parser.parse_args()
try:
import cmarkgfm
md_parser = html_via_cmarkgfm
except:
try:
import commonmark
md_parser = html_via_commonmark
except:
die("Failed to find cmarkgfm or commonmark for python3.")
main()

39
mkproto.awk Normal file
View File

@@ -0,0 +1,39 @@
#!/usr/bin/awk -f
BEGIN {
while ((getline i < "proto.h") > 0) old_protos = old_protos ? old_protos "\n" i : i
protos = "/* This file is automatically generated with \"make proto\". DO NOT EDIT */\n"
}
inheader {
protos = protos "\n" ((inheader = /\)[ \t]*$/ ? 0 : 1) ? $0 : $0 ";")
next
}
/^FN_(LOCAL|GLOBAL)_[^(]+\([^,()]+/ {
local = /^FN_LOCAL/
gsub(/^FN_(LOC|GLOB)AL_|,.*$/, "")
sub(/^BOOL\(/, "BOOL ")
sub(/^CHAR\(/, "char ")
sub(/^INTEGER\(/, "int ")
sub(/^STRING\(/, "char *")
protos = protos "\n" $0 (local ? "(int module_id);" : "(void);")
next
}
/^static|^extern|;/||!/^[A-Za-z][A-Za-z0-9_]* / { next }
/\(.*\)[ \t]*$/ {
protos = protos "\n" $0 ";"
next
}
/\(/ {
inheader = 1
protos = protos "\n" $0
}
END {
if (old_protos != protos) print protos > "proto.h"
printf "" > "proto.h-tstamp"
}

View File

@@ -1,48 +0,0 @@
# generate prototypes for rsync
$old_protos = '';
if (open(IN, 'proto.h')) {
$old_protos = join('', <IN>);
close IN;
}
%FN_MAP = (
BOOL => 'BOOL ',
CHAR => 'char ',
INTEGER => 'int ',
STRING => 'char *',
);
$inheader = 0;
$protos = qq|/* This file is automatically generated with "make proto". DO NOT EDIT */\n\n|;
while (<>) {
if ($inheader) {
if (/[)][ \t]*$/) {
$inheader = 0;
s/$/;/;
}
$protos .= $_;
} elsif (/^FN_(LOCAL|GLOBAL)_([^(]+)\(([^,()]+)/) {
$ret = $FN_MAP{$2};
$func = $3;
$arg = $1 eq 'LOCAL' ? 'int module_id' : 'void';
$protos .= "$ret$func($arg);\n";
} elsif (/^static|^extern/ || /[;]/ || !/^[A-Za-z][A-Za-z0-9_]* /) {
;
} elsif (/[(].*[)][ \t]*$/) {
s/$/;/;
$protos .= $_;
} elsif (/[(]/) {
$inheader = 1;
$protos .= $_;
}
}
if ($old_protos ne $protos) {
open(OUT, '>proto.h') or die $!;
print OUT $protos;
close OUT;
}
open(OUT, '>proto.h-tstamp') and close OUT;

921
options.c
View File

File diff suppressed because it is too large Load Diff

View File

@@ -1,6 +0,0 @@
#!/bin/sh -e
# This script gets git to run gpg with a --passphrase-file option.
PATH=`echo $PATH | sed 's/^[^:]*://'`
gpg --batch --passphrase-file=$GPG_PASSFILE "${@}"

View File

@@ -1,180 +1,174 @@
#!/usr/bin/perl
#!/usr/bin/python3 -B
use strict;
use warnings;
use Getopt::Long;
# This script turns one or more diff files in the patches dir (which is
# expected to be a checkout of the rsync-patches git repo) into a branch
# in the main rsync git checkout. This allows the applied patch to be
# merged with the latest rsync changes and tested. To update the diff
# with the resulting changes, see the patch-update script.
&Getopt::Long::Configure('bundling');
&usage if !&GetOptions(
'branch|b=s' => \( my $master_branch = 'master' ),
'skip-check' => \( my $skip_branch_check ),
'delete' => \( my $delete_local_branches ),
'help|h' => \( my $help_opt ),
);
&usage if $help_opt;
import os, sys, re, argparse, glob
require 'packaging/git-status.pl';
check_git_state($master_branch, !$skip_branch_check, 1);
sys.path = ['packaging'] + sys.path
my %local_branch;
open PIPE, '-|', 'git branch -l' or die "Unable to fork: $!\n";
while (<PIPE>) {
if (m# patch/\Q$master_branch\E/(.*)#o) {
$local_branch{$1} = 1;
}
}
close PIPE;
from pkglib import *
if ($delete_local_branches) {
foreach my $name (sort keys %local_branch) {
my $branch = "patch/$master_branch/$name";
system 'git', 'branch', '-D', $branch and exit 1;
}
%local_branch = ( );
}
def main():
global created, info, local_branch
my @patch_list;
foreach (@ARGV) {
if (!-f $_) {
die "File not found: $_\n";
}
die "Filename is not a .diff file: $_\n" unless /\.diff$/;
push @patch_list, $_;
}
cur_branch, args.base_branch = check_git_state(args.base_branch, not args.skip_check, args.patches_dir)
exit unless @patch_list;
local_branch = get_patch_branches(args.base_branch)
my(%scanned, %created, %info);
if args.delete_local_branches:
for name in sorted(local_branch):
branch = f"patch/{args.base_branch}/{name}"
cmd_chk(['git', 'branch', '-D', branch])
local_branch = set()
foreach my $patch (@patch_list) {
my($where, $name) = $patch =~ m{^(.*?)([^/]+)\.diff$};
next if $scanned{$name}++;
if args.add_missing:
for fn in sorted(glob.glob(f"{args.patches_dir}/*.diff")):
name = re.sub(r'\.diff$', '', re.sub(r'.+/', '', fn))
if name not in local_branch and fn not in args.patch_files:
args.patch_files.append(fn)
open IN, '<', $patch or die "Unable to open $patch: $!\n";
if not args.patch_files:
return
my $info = '';
my $commit;
while (<IN>) {
if (m#^based-on: (\S+)#) {
$commit = $1;
last;
}
last if m#^index .*\.\..* \d#;
last if m#^diff --git #;
last if m#^--- (old|a)/#;
$info .= $_;
}
close IN;
for fn in args.patch_files:
if not fn.endswith('.diff'):
die(f"Filename is not a .diff file: {fn}")
if not os.path.isfile(fn):
die(f"File not found: {fn}")
$info =~ s/\s+\Z/\n/;
scanned = set()
info = { }
my $parent = $master_branch;
my @patches = $info =~ m#patch -p1 <patches/(\S+)\.diff#g;
if (@patches) {
if ($patches[-1] eq $name) {
pop @patches;
} else {
warn "No identity patch line in $patch\n";
}
if (@patches) {
$parent = pop @patches;
if (!$scanned{$parent}) {
unless (-f "$where$parent.diff") {
die "Unknown parent of $patch: $parent\n";
}
# Add parent to @patch_list so that we will look for the
# parent's parent. Any duplicates will just be ignored.
push @patch_list, "$where$parent.diff";
}
}
} else {
warn "No patch lines found in $patch\n";
}
patch_list = [ ]
for fn in args.patch_files:
m = re.match(r'^(?P<dir>.*?)(?P<name>[^/]+)\.diff$', fn)
patch = argparse.Namespace(**m.groupdict())
if patch.name in scanned:
continue
patch.fn = fn
$info{$name} = [ $parent, $info, $commit ];
}
lines = [ ]
commit_hash = None
with open(patch.fn, 'r', encoding='utf-8') as fh:
for line in fh:
m = re.match(r'^based-on: (\S+)', line)
if m:
commit_hash = m[1]
break
if (re.match(r'^index .*\.\..* \d', line)
or re.match(r'^diff --git ', line)
or re.match(r'^--- (old|a)/', line)):
break
lines.append(re.sub(r'\s*\Z', "\n", line, 1))
info_txt = ''.join(lines).strip() + "\n"
lines = None
foreach my $patch (@patch_list) {
create_branch($patch);
}
parent = args.base_branch
patches = re.findall(r'patch -p1 <%s/(\S+)\.diff' % args.patches_dir, info_txt)
if patches:
last = patches.pop()
if last != patch.name:
warn(f"No identity patch line in {patch.fn}")
patches.append(last)
if patches:
parent = patches.pop()
if parent not in scanned:
diff_fn = patch.dir + parent + '.diff'
if not os.path.isfile(diff_fn):
die(f"Failed to find parent of {patch.fn}: {parent}")
# Add parent to args.patch_files so that we will look for the
# parent's parent. Any duplicates will be ignored.
args.patch_files.append(diff_fn)
else:
warn(f"No patch lines found in {patch.fn}")
system 'git', 'checkout', $master_branch and exit 1;
info[patch.name] = [ parent, info_txt, commit_hash ]
exit;
patch_list.append(patch)
sub create_branch
{
my($patch) = @_;
my($where, $name) = $patch =~ m{^(.*?)([^/]+)\.diff$};
created = set()
for patch in patch_list:
create_branch(patch)
return if $created{$name}++;
cmd_chk(['git', 'checkout', args.base_branch])
my $ref = $info{$name};
my($parent, $info, $commit) = @$ref;
my $parent_branch;
if ($parent eq $master_branch) {
$parent_branch = $master_branch;
$parent_branch = $commit if defined $commit;
} else {
create_branch("$where/$parent.diff");
$parent_branch = "patch/$master_branch/$parent";
}
def create_branch(patch):
if patch.name in created:
return
created.add(patch.name)
my $branch = "patch/$master_branch/$name";
print "\n", '=' x 64, "\nProcessing $branch ($parent_branch)\n";
parent, info_txt, commit_hash = info[patch.name]
parent = argparse.Namespace(dir=patch.dir, name=parent, fn=patch.dir + parent + '.diff')
if ($local_branch{$name}) {
system 'git', 'branch', '-D', $branch and exit 1;
}
if parent.name == args.base_branch:
parent_branch = commit_hash if commit_hash else args.base_branch
else:
create_branch(parent)
parent_branch = '/'.join(['patch', args.base_branch, parent.name])
system 'git', 'checkout', '-b', $branch, $parent_branch and exit 1;
branch = '/'.join(['patch', args.base_branch, patch.name])
print("\n" + '=' * 64)
print(f"Processing {branch} ({parent_branch})")
open OUT, '>', "PATCH.$name" or die $!;
print OUT $info;
close OUT;
system 'git', 'add', "PATCH.$name" and exit 1;
if patch.name in local_branch:
cmd_chk(['git', 'branch', '-D', branch])
open IN, '<', $patch or die "Unable to open $patch: $!\n";
$_ = join('', <IN>);
close IN;
cmd_chk(['git', 'checkout', '-b', branch, parent_branch])
open PIPE, '|-', 'patch -p1' or die $!;
print PIPE $_;
close PIPE;
info_fn = 'PATCH.' + patch.name
with open(info_fn, 'w', encoding='utf-8') as fh:
fh.write(info_txt)
cmd_chk(['git', 'add', info_fn])
system 'rm -f *.orig */*.orig';
with open(patch.fn, 'r', encoding='utf-8') as fh:
patch_txt = fh.read()
while (m#\nnew file mode (\d+)\s+--- /dev/null\s+\Q+++\E b/(.*)#g) {
chmod oct($1), $2;
system 'git', 'add', $2;
}
cmd_run('patch -p1'.split(), input=patch_txt)
while (1) {
system 'git status';
print 'Press Enter to commit, Ctrl-C to abort, or type a wild-name to add a new file: ';
$_ = <STDIN>;
last if /^$/;
chomp;
system "git add $_";
}
for fn in glob.glob('*.orig') + glob.glob('*/*.orig'):
os.unlink(fn)
while (system 'git', 'commit', '-a', '-m', "Creating branch from $name.diff.") {
exit 1 if system '/bin/zsh';
}
}
pos = 0
new_file_re = re.compile(r'\nnew file mode (?P<mode>\d+)\s+--- /dev/null\s+\+\+\+ b/(?P<fn>.+)')
while True:
m = new_file_re.search(patch_txt, pos)
if not m:
break
os.chmod(m['fn'], int(m['mode'], 8))
cmd_chk(['git', 'add', m['fn']])
pos = m.end()
sub usage
{
die <<EOT;
Usage branch-from-patch [OPTIONS] patches/DIFF...
while True:
cmd_chk('git status'.split())
ans = input('Press Enter to commit, Ctrl-C to abort, or type a wild-name to add a new file: ')
if ans == '':
break
cmd_chk("git add " + ans, shell=True)
Options:
-b, --branch=BRANCH Create branches relative to BRANCH if no "based-on"
header was found in the patch file.
--skip-check Skip the check that ensures starting with a clean branch.
--delete Delete all the local patch/BASE/* branches, not just the ones
that are being recreated.
-h, --help Output this help message.
EOT
}
while True:
s = cmd_run(['git', 'commit', '-a', '-m', f"Creating branch from {patch.name}.diff."])
if not s.returncode:
break
s = cmd_run(['/bin/zsh'])
if s.returncode:
die('Aborting due to shell error code')
if __name__ == '__main__':
parser = argparse.ArgumentParser(description="Create a git patch branch from an rsync patch file.", add_help=False)
parser.add_argument('--branch', '-b', dest='base_branch', metavar='BASE_BRANCH', default='master', help="The branch the patch is based on. Default: master.")
parser.add_argument('--add-missing', '-a', action='store_true', help="Add a branch for every patches/*.diff that doesn't have a branch.")
parser.add_argument('--skip-check', action='store_true', help="Skip the check that ensures starting with a clean branch.")
parser.add_argument('--delete', dest='delete_local_branches', action='store_true', help="Delete all the local patch/BASE/* branches, not just the ones that are being recreated.")
parser.add_argument('--patches-dir', '-p', metavar='DIR', default='patches', help="Override the location of the rsync-patches dir. Default: patches.")
parser.add_argument('patch_files', metavar='patches/DIFF_FILE', nargs='*', help="Specify what patch diff files to process. Default: all of them.")
parser.add_argument("--help", "-h", action="help", help="Output this help message and exit.")
args = parser.parse_args()
main()
# vim: sw=4 et

View File

@@ -5,13 +5,25 @@
use strict;
our %short_no_arg;
our %short_with_num;
our %long_opt = (
our %short_with_num = ( '@' => 1 );
our %long_opt = ( # These include some extra long-args that BackupPC uses:
'block-size' => 1,
'daemon' => -1,
'debug' => 1,
'fake-super' => 0,
'fuzzy' => 0,
'group' => 0,
'hard-links' => 0,
'ignore-times' => 0,
'info' => 1,
'links' => 0,
'log-file' => 3,
'one-file-system' => 0,
'owner' => 0,
'perms' => 0,
'recursive' => 0,
'times' => 0,
'write-devices' => -1,
);
our $last_long_opt;
@@ -28,13 +40,13 @@ while (<IN>) {
$last_long_opt = $1;
$long_opt{$1} = 0 unless exists $long_opt{$1};
} elsif (defined($last_long_opt)
&& /\Qargs[ac++]\E = ([^["\s]+);/ && $1 ne 'dest_option') {
&& /\Qargs[ac++]\E = ([^["\s]+);/) {
$long_opt{$last_long_opt} = 2;
undef $last_long_opt;
} elsif (/dest_option = "--([^"]+)"/) {
} elsif (/return "--([^"]+-dest)";/) {
$long_opt{$1} = 2;
undef $last_long_opt;
} elsif (/\Qasprintf(\E[^,]+, "--([^"=]+)=/ || /\Qargs[ac++]\E = "--([^"=]+)=/) {
} elsif (/\Qasprintf(\E[^,]+, "--([^"=]+)=/ || /\Qargs[ac++]\E = "--([^"=]+)=/ || /fmt = .*: "--([^"=]+)=/) {
$long_opt{$1} = 1;
undef $last_long_opt;
}
@@ -65,7 +77,8 @@ foreach my $opt (sort keys %long_opt) {
my $val = $long_opt{$opt};
$val = 1 if $opt =~ /^(max-|min-)/;
$val = 3 if $opt eq 'files-from';
$val = '$ro ? -1 : ' . $val if $opt =~ /^remove-/;
$val = q"$only eq 'r' ? -1 : " . $val if $opt =~ /^(remove-|log-file)/;
$val = q"$only eq 'w' ? -1 : " . $val if $opt eq 'sender';
print " '$opt' => $val,\n";
}

View File

@@ -1,51 +0,0 @@
# Do some git-status checking for the current dir and (optionally)
# the patches dir.
sub check_git_state
{
my($master_branch, $fatal_unless_clean, $check_patches_dir) = @_;
my($cur_branch) = check_git_status($fatal_unless_clean);
(my $branch = $cur_branch) =~ s{^patch/([^/]+)/[^/]+$}{$1}; # change patch/BRANCH/PATCH_NAME into BRANCH
if ($branch ne $master_branch) {
print "The checkout is not on the $master_branch branch.\n";
exit 1 if $master_branch ne 'master';
print "Do you want me to continue with --branch=$branch? [n] ";
$_ = <STDIN>;
exit 1 unless /^y/i;
$_[0] = $master_branch = $branch; # Updates caller's $master_branch too.
}
if ($check_patches_dir && -d 'patches/.git') {
($branch) = check_git_status($fatal_unless_clean, 'patches');
if ($branch ne $master_branch) {
print "The *patches* checkout is on branch $branch, not branch $master_branch.\n";
print "Do you want to change it to branch $master_branch? [n] ";
$_ = <STDIN>;
exit 1 unless /^y/i;
system "cd patches && git checkout '$master_branch'";
}
}
return $cur_branch;
}
sub check_git_status
{
my($fatal_unless_clean, $subdir) = @_;
$subdir = '.' unless defined $subdir;
my $status = `cd '$subdir' && git status`;
my $is_clean = $status =~ /\nnothing to commit \(working directory clean\)/;
my($cur_branch) = $status =~ /^# On branch (.+)\n/;
if ($fatal_unless_clean && !$is_clean) {
if ($subdir eq '.') {
$subdir = '';
} else {
$subdir = " *$subdir*";
}
die "The$subdir checkout is not clean:\n", $status;
}
($cur_branch, $is_clean, $status);
}
1;

View File

@@ -1,6 +1,6 @@
Summary: A fast, versatile, remote (and local) file-copying tool
Name: rsync
Version: 3.1.1
Version: 3.2.0
%define fullversion %{version}pre2
Release: 0.1.pre2
%define srcdir src-previews
@@ -13,11 +13,6 @@ URL: http://rsync.samba.org/
Prefix: %{_prefix}
BuildRoot: /var/tmp/%{name}-root
%package ssl-client
Summary: Provides rsync-ssl
Group: Applications/Internet
Requires: rsync, stunnel >= 4
%package ssl-daemon
Summary: An stunnel config file to support ssl rsync daemon connections.
Group: Applications/Internet
@@ -34,11 +29,6 @@ differences between the source files and the existing files in the
destination. Rsync is widely used for backups and mirroring and as an
improved copy command for everyday use.
%description ssl-client
Provides the rsync-ssl script that makes use of stunnel 4 to open an ssl
connection to an rsync daemon (on port 874). This setup does NOT require
any local stunnel daemon to be running to connect to the remote ssl rsyncd.
%description ssl-daemon
Provides a config file for stunnel that will (if you start your stunnel
service) cause stunnel to listen for ssl rsync-daemon connections and run
@@ -66,7 +56,7 @@ make
%install
rm -rf $RPM_BUILD_ROOT
make install install-ssl-client install-ssl-daemon DESTDIR=$RPM_BUILD_ROOT
make install install-ssl-daemon DESTDIR=$RPM_BUILD_ROOT
mkdir -p $RPM_BUILD_ROOT/etc/xinetd.d $RPM_BUILD_ROOT/etc/rsync-ssl/certs
install -m 644 packaging/lsb/rsync.xinetd $RPM_BUILD_ROOT/etc/xinetd.d/rsync
@@ -76,23 +66,21 @@ rm -rf $RPM_BUILD_ROOT
%files
%defattr(-,root,root)
%doc COPYING NEWS OLDNEWS README support/ tech_report.tex
%doc COPYING NEWS.md OLDNEWS.md README.md support/ tech_report.tex
%config(noreplace) /etc/xinetd.d/rsync
%{_prefix}/bin/rsync
%{_mandir}/man1/rsync.1*
%{_mandir}/man5/rsyncd.conf.5*
%files ssl-client
%{_prefix}/bin/rsync-ssl
%{_prefix}/bin/stunnel-rsync
%{_mandir}/man1/rsync.1*
%{_mandir}/man1/rsync-ssl.1*
%{_mandir}/man5/rsyncd.conf.5*
%files ssl-daemon
%config(noreplace) /etc/stunnel/rsyncd.conf
%dir /etc/rsync-ssl/certs
%changelog
* Mon May 26 2014 Wayne Davison <wayned@samba.org>
Released 3.1.1pre2.
* Mon Jun 15 2020 Wayne Davison <wayned@samba.org>
Released 3.2.0pre2.
* Fri Mar 21 2008 Wayne Davison <wayned@samba.org>
Added installation of /etc/xinetd.d/rsync file and some commented-out

96
packaging/md2html Executable file
View File

@@ -0,0 +1,96 @@
#!/usr/bin/python3
# Copyright (C) 2020 Wayne Davison
#
# This program is freely redistributable.
import re, argparse
HTML_START = """\
<html><head>
<title>%s</title>
<link href="https://fonts.googleapis.com/css2?family=Roboto&family=Roboto+Mono&display=swap" rel="stylesheet">
<style>
body {
max-width: 50em;
margin: auto;
}
body, b, strong, u {
font-family: 'Roboto', sans-serif;
}
code {
font-family: 'Roboto Mono', monospace;
font-weight: bold;
}
pre code {
display: block;
font-weight: normal;
}
blockquote pre code {
background: #f1f1f1;
}
dd p:first-of-type {
margin-block-start: 0em;
}
</style>
</head><body>
"""
HTML_END = """\
</body></html>
"""
md_parser = None
def main():
for mdfn in args.mdfiles:
if not mdfn.endswith('.md'):
print('Ignoring non-md input file:', mdfn)
continue
title = re.sub(r'.*/', '', mdfn).replace('.md', '')
htfn = mdfn.replace('.md', '.html')
print("Parsing", mdfn, '->', htfn)
with open(mdfn, 'r', encoding='utf-8') as fh:
txt = fh.read()
txt = re.sub(r'\s--\s', '\xa0-- ', txt)
html = md_parser(txt)
html = re.sub(r'(<code>)([\s\S]*?)(</code>)', lambda m: m[1] + re.sub(r'\s', '\xa0', m[2]) + m[3], html)
html = html.replace('--', '&#8209;&#8209;').replace("\xa0-", '&nbsp;&#8209;').replace("\xa0", '&nbsp;')
html = re.sub(r'(\W)-', r'\1&#8209;', html)
with open(htfn, 'w', encoding='utf-8') as fh:
fh.write(HTML_START % title)
fh.write(html)
fh.write(HTML_END)
def html_via_cmarkgfm(txt):
return cmarkgfm.markdown_to_html(txt)
def html_via_commonmark(txt):
return commonmark.HtmlRenderer().render(commonmark.Parser().parse(txt))
if __name__ == '__main__':
parser = argparse.ArgumentParser(description='Output html for md pages.', add_help=False)
parser.add_argument("--help", "-h", action="help", help="Output this help message and exit.")
parser.add_argument("mdfiles", nargs='+', help="The .md files to turn into .html files.")
args = parser.parse_args()
try:
import cmarkgfm
md_parser = html_via_cmarkgfm
except:
try:
import commonmark
md_parser = html_via_commonmark
except:
die("Failed to find cmarkgfm or commonmark for python3.")
main()

View File

@@ -1,173 +1,106 @@
#!/usr/bin/perl
use strict;
#!/usr/bin/python3 -B
# This script expects the directory ~/samba-rsync-ftp to exist and to be a
# copy of the /home/ftp/pub/rsync dir on samba.org. It also requires a
# git checkout of rsync (feel free to use your normal rsync build dir as
# long as it doesn't have any uncommitted changes).
#
# If this is run with -ctu, it will make an updated "nightly" tar file in
# If this is run with -tu, it will make an updated "nightly" tar file in
# the nightly dir. It will also remove any old tar files, regenerate the
# HTML man pages in the nightly dir, and then rsync the changes to the
# samba.org server.
use Getopt::Long;
use Date::Format;
import os, sys, re, argparse, glob
from datetime import datetime, timezone
from getpass import getpass
sys.path = ['packaging'] + sys.path
from pkglib import *
# Where the local copy of /home/ftp/pub/rsync/dev/nightly should be updated.
our $dest = $ENV{HOME} . '/samba-rsync-ftp/dev/nightly';
our $nightly_symlink = "$dest/rsync-HEAD.tar.gz";
dest = os.environ['HOME'] + '/samba-rsync-ftp/dev/nightly'
samba_host = os.environ['SAMBA_HOST']
nightly_symlink = f"{dest}/rsync-HEAD.tar.gz"
our($make_tar, $upload, $help_opt);
&Getopt::Long::Configure('bundling');
&usage if !&GetOptions(
'make-tar|t' => \$make_tar,
'upload|u' => \$upload,
'help|h' => \$help_opt,
) || $help_opt;
def main():
now = datetime.now(timezone.utc)
name = now.strftime('rsync-HEAD-%Y%m%d-%H%MGMT')
ztoday = now.strftime('%d %b %Y')
today = ztoday.lstrip('0')
gen_target = 'gensend' if args.upload else 'gen'
our $name = time2str('rsync-HEAD-%Y%m%d-%H%M%Z', time, 'GMT');
our $ztoday = time2str('%d %b %Y', time);
our $today = $ztoday;
our $gen_target = $upload ? 'gensend' : 'gen';
if not os.path.isdir(dest):
die("$dest does not exist")
if not os.path.isdir('.git'):
die("There is no .git dir in the current directory.")
if not os.path.exists('rsyncd.conf.5.md'):
die("There is no rsync checkout in the current directory.")
die "$dest does not exist\n" unless -d $dest;
die "There is no .git dir in the current directory.\n" unless -d '.git';
die "There is no rsync checkout in the current directory.\n" unless -f 'rsyncd.conf.yo';
mandate_gensend_hook()
if ($make_tar) {
open(IN, '-|', 'git status') or die $!;
my $status = join('', <IN>);
close IN;
die "The checkout is not clean:\n", $status unless $status =~ /\nnothing to commit \(working directory clean\)/;
die "The checkout is not on the master branch.\n" unless $status =~ /^# On branch master\n/;
system "make $gen_target" and die "make $gen_target failed!\n";
if args.make_tar:
check_git_state('master')
cmd_chk(['touch', 'NEWS.md'])
cmd_chk(['make', gen_target])
cmd_chk(['rsync', '-a', *glob.glob('*.[1-9].html'), dest])
my @extra_files;
open(IN, '<', 'Makefile.in') or die "Couldn't open Makefile.in: $!\n";
while (<IN>) {
if (s/^GENFILES=//) {
while (s/\\$//) {
$_ .= <IN>;
}
@extra_files = split(' ', $_);
last;
}
}
close IN;
gen_files = get_gen_files()
my $confversion;
open(IN, '<', 'configure.ac') or die "Unable to open configure.ac: $!\n";
while (<IN>) {
if (/^RSYNC_VERSION=(.*)/) {
$confversion = $1;
last;
}
}
close IN;
die "Unable to find RSYNC_VERSION in configure.ac\n" unless defined $confversion;
confversion = get_configure_version()
open(IN, '<', 'OLDNEWS') or die "Unable to open OLDNEWS: $!\n";
$_ = <IN>;
my($lastversion) = /(\d+\.\d+\.\d+)/;
my $last_protocol_version;
while (<IN>) {
if (my($ver,$pdate,$pver) = /^\s+\S\S\s\S\S\S\s\d\d\d\d\s+(\d+\.\d+\.\d+)\s+(\d\d \w\w\w \d\d\d\d\s+)?(\d+)$/) {
$last_protocol_version = $pver if $ver eq $lastversion;
}
}
close IN;
die "Unable to determine protocol_version for $lastversion.\n" unless defined $last_protocol_version;
# All version values are strings!
last_version, last_protocol_version = get_OLDNEWS_version_info()
protocol_version, subprotocol_version = get_protocol_versions()
my($protocol_version,$subprotocol_version);
open(IN, '<', 'rsync.h') or die "Unable to open rsync.h: $!\n";
while (<IN>) {
if (/^#define\s+PROTOCOL_VERSION\s+(\d+)/) {
$protocol_version = $1;
} elsif (/^#define\s+SUBPROTOCOL_VERSION\s+(\d+)/) {
$subprotocol_version = $1;
}
}
close IN;
die "Unable to determine the current PROTOCOL_VERSION.\n" unless defined $protocol_version;
die "Unable to determine the current SUBPROTOCOL_VERSION.\n" unless defined $subprotocol_version;
if 'dev' in confversion or 'pre' in confversion:
if last_protocol_version != protocol_version:
if subprotocol_version == '0':
die("SUBPROTOCOL_VERSION must not be 0 for a non-final release with a changed PROTOCOL_VERSION.")
elif subprotocol_version != '0':
die("SUBPROTOCOL_VERSION must be 0 when the PROTOCOL_VERSION hasn't changed from the last release.")
elif subprotocol_version != '0':
die("SUBPROTOCOL_VERSION must be 0 for a final release.")
if ($confversion =~ /dev|pre/) {
if ($last_protocol_version ne $protocol_version) {
if ($subprotocol_version == 0) {
die "SUBPROTOCOL_VERSION must not be 0 for a non-final release with a changed PROTOCOL_VERSION.\n";
}
} else {
if ($subprotocol_version != 0) {
die "SUBPROTOCOL_VERSION must be 0 when the PROTOCOL_VERSION hasn't changed from the last release.\n";
}
}
} else {
if ($subprotocol_version != 0) {
die "SUBPROTOCOL_VERSION must be 0 for a final release.\n";
}
}
name_slash = name + '/'
tar_name = f"{name}.tar.gz"
print "Creating $name.tar.gz\n";
system "rsync -a @extra_files $name/";
system "git archive --format=tar --prefix=$name/ HEAD | tar xf -";
system "support/git-set-file-times --prefix=$name/";
system "fakeroot tar czf $dest/$name.tar.gz $name; rm -rf $name";
print('Creating', tar_name)
unlink($nightly_symlink);
symlink("$name.tar.gz", $nightly_symlink);
}
cmd_chk(['rsync', '-a', *gen_files, name_slash])
cmd_chk(f"git archive --format=tar --prefix={name}/ HEAD | tar xf -")
cmd_chk(['support/git-set-file-times', '--quiet', '--prefix', name_slash])
cmd_chk(['fakeroot', 'tar', 'czf', os.path.join(dest, tar_name), name])
cmd_chk(['rm', '-rf', name])
foreach my $fn (qw( rsync.yo rsyncd.conf.yo )) {
my $yo_tmp = "$dest/$fn";
(my $html_fn = "$dest/$fn") =~ s/\.yo/.html/;
if os.path.lexists(nightly_symlink):
os.unlink(nightly_symlink)
os.symlink(tar_name, nightly_symlink)
open(IN, '<', $fn) or die $!;
undef $/; $_ = <IN>; $/ = "\n";
close IN;
os.chdir(dest)
s/^(manpage\([^)]+\)\(\d+\)\()[^)]+(\).*)/$1$today$2/m;
#s/^(This man ?page is current for version) \S+ (of rsync)/$1 $version $2/m;
tar_files = list(reversed(sorted(glob.glob('rsync-HEAD-*'))))
if len(tar_files) > 10:
for fn in tar_files[10:]:
print('Removing', fn)
os.unlink(fn)
open(OUT, '>', $yo_tmp) or die $!;
print OUT $_;
close OUT;
cmd_run('ls -ltr'.split())
system 'yodl2html', '-o', $html_fn, $yo_tmp;
if args.upload:
cmd = 'rsync -aivHP --delete-after'.split()
partial_dir = os.environ.get('RSYNC_PARTIAL_DIR', None)
if partial_dir:
cmd.append('-fR ' + partial_dir)
cmd_chk([*cmd, '.', f"{samba_host}:/home/ftp/pub/rsync/dev/nightly"])
unlink($yo_tmp);
}
chdir($dest) or die $!;
if __name__ == '__main__':
parser = argparse.ArgumentParser(description='A helper script for "nightly" tar files.', add_help=False)
parser.add_argument('--make-tar', '-t', action='store_true', help=f"Create a new tar file in {dest}.")
parser.add_argument('--upload', '-u', action='store_true', help="Upload the revised nightly dir to {samba_host}.")
parser.add_argument("--help", "-h", action="help", help="Output this help message and exit.")
args = parser.parse_args()
main()
my $cnt = 0;
open(PIPE, '-|', 'ls -1t rsync-HEAD-*') or die $!;
while (<PIPE>) {
chomp;
next if $cnt++ < 10;
unlink($_);
}
close PIPE;
system 'ls -ltr';
if ($upload) {
my $opt = '';
if (defined $ENV{RSYNC_PARTIAL_DIR}) {
$opt = " -f 'R $ENV{RSYNC_PARTIAL_DIR}'";
}
system "rsync$opt -aviHP --delete-after . samba.org:/home/ftp/pub/rsync/dev/nightly";
}
exit;
sub usage
{
die <<EOT;
Usage: nightly-rsync [OPTIONS]
-t, --make-tar create a new tar file in $dest
-u, --upload upload the revised nightly dir to samba.org
-h, --help display this help
EOT
}
# vim: sw=4 et

View File

@@ -1,240 +1,210 @@
#!/usr/bin/perl
#!/usr/bin/python3 -B
# This script is used to turn one or more of the "patch/BASE/*" branches
# into one or more diffs in the "patches" directory. Pass the option
# --gen if you want generated files in the diffs. Pass the name of
# one or more diffs if you want to just update a subset of all the
# diffs.
use strict;
use warnings;
use Getopt::Long;
import os, sys, re, argparse, time, shutil
my $patches_dir = 'patches';
my $tmp_dir = "patches.$$";
my $make_gen_cmd = 'make -f prepare-source.mak conf && ./config.status && make gen';
sys.path = ['packaging'] + sys.path
&Getopt::Long::Configure('bundling');
&usage if !&GetOptions(
'branch|b=s' => \( my $master_branch = 'master' ),
'skip-check' => \( my $skip_branch_check ),
'shell|s' => \( my $launch_shell ),
'gen:s' => \( my $incl_generated_files ),
'help|h' => \( my $help_opt ),
);
&usage if $help_opt;
from pkglib import *
if (defined $incl_generated_files) {
$patches_dir = $incl_generated_files if $incl_generated_files ne '';
$incl_generated_files = 1;
}
MAKE_GEN_CMDS = [
'make -f prepare-source.mak conf'.split(),
'./config.status'.split(),
'make gen'.split(),
]
TMP_DIR = "patches.gen"
die "No '$patches_dir' directory was found.\n" unless -d $patches_dir;
die "No '.git' directory present in the current dir.\n" unless -d '.git';
os.environ['GIT_MERGE_AUTOEDIT'] = 'no'
require 'packaging/git-status.pl';
my $starting_branch = check_git_state($master_branch, !$skip_branch_check, 1);
def main():
global master_commit, parent_patch, description, completed, last_touch
my $master_commit;
open PIPE, '-|', "git log -1 --no-color $master_branch" or die $!;
while (<PIPE>) {
if (/^commit (\S+)/) {
$master_commit = $1;
last;
}
}
close PIPE;
die "Unable to determine commit hash for master branch: $master_branch\n" unless defined $master_commit;
if not os.path.isdir(args.patches_dir):
die(f'No "{args.patches_dir}" directory was found.')
if not os.path.isdir('.git'):
die('No ".git" directory present in the current dir.')
if ($incl_generated_files) {
my @extra_files = get_extra_files();
die "'$tmp_dir' must not exist in the current directory.\n" if -e $tmp_dir;
mkdir($tmp_dir, 0700) or die "Unable to mkdir($tmp_dir): $!\n";
system "$make_gen_cmd && rsync -a @extra_files $tmp_dir/master/" and exit 1;
}
our $last_touch = time;
starting_branch, args.base_branch = check_git_state(args.base_branch, not args.skip_check, args.patches_dir)
my %patches;
master_commit = latest_git_hash(args.base_branch)
# Start by finding all patches so that we can load all possible parents.
open(PIPE, '-|', 'git', 'branch', '-l') or die $!;
while (<PIPE>) {
if (m# patch/\Q$master_branch\E/(.*)#o) {
$patches{$1} = 1;
}
}
close PIPE;
if args.gen:
if os.path.lexists(TMP_DIR):
die(f'"{TMP_DIR}" must not exist in the current directory.')
gen_files = get_gen_files()
os.mkdir(TMP_DIR, 0o700)
for cmd in MAKE_GEN_CMDS:
cmd_chk(cmd)
cmd_chk(['rsync', '-a', *gen_files, f'{TMP_DIR}/master/'])
my @patches = sort keys %patches;
last_touch = time.time()
my(%parent, %description);
foreach my $patch (@patches) {
my $branch = "patch/$master_branch/$patch";
my $desc = '';
open(PIPE, '-|', 'git', 'diff', '-U1000', "$master_branch...$branch", '--', "PATCH.$patch") or die $!;
while (<PIPE>) {
last if /^@@ /;
}
while (<PIPE>) {
next unless s/^[ +]//;
if (m#patch -p1 <patches/(\S+)\.diff# && $1 ne $patch) {
my $parent = $parent{$patch} = $1;
if (!$patches{$parent}) {
die "Parent of $patch is not a local branch: $parent\n";
}
}
$desc .= $_;
}
close PIPE;
$description{$patch} = $desc;
}
# Start by finding all patches so that we can load all possible parents.
patches = sorted(list(get_patch_branches(args.base_branch)))
if (@ARGV) {
# Limit the list of patches to actually process based on @ARGV.
@patches = ( );
foreach (@ARGV) {
s{^patch(es)?/} {};
s{\.diff$} {};
if (!$patches{$_}) {
die "Local branch not available for patch: $_\n";
}
push(@patches, $_);
}
}
parent_patch = { }
description = { }
my %completed;
foreach my $patch (@patches) {
next if $completed{$patch}++;
last unless update_patch($patch);
}
for patch in patches:
branch = f"patch/{args.base_branch}/{patch}"
desc = ''
proc = cmd_pipe(['git', 'diff', '-U1000', f"{args.base_branch}...{branch}", '--', f"PATCH.{patch}"])
in_diff = False
for line in proc.stdout:
if in_diff:
if not re.match(r'^[ +]', line):
continue
line = line[1:]
m = re.search(r'patch -p1 <patches/(\S+)\.diff', line)
if m and m[1] != patch:
parpat = parent_patch[patch] = m[1]
if not parpat in patches:
die(f"Parent of {patch} is not a local branch: {parpat}")
desc += line
elif re.match(r'^@@ ', line):
in_diff = True
description[patch] = desc
proc.communicate()
if ($incl_generated_files) {
system "rm -rf $tmp_dir";
}
if args.patch_files: # Limit the list of patches to actually process
valid_patches = patches
patches = [ ]
for fn in args.patch_files:
name = re.sub(r'\.diff$', '', re.sub(r'.+/', '', fn))
if name not in valid_patches:
die(f"Local branch not available for patch: {name}")
patches.append(name)
sleep 1 while $last_touch >= time;
system "git checkout $starting_branch" and exit 1;
completed = set()
exit;
for patch in patches:
if patch in completed:
continue
if not update_patch(patch):
break
if args.gen:
shutil.rmtree(TMP_DIR)
while last_touch >= time.time():
time.sleep(1)
cmd_chk(['git', 'checkout', starting_branch])
sub update_patch
{
my($patch) = @_;
def update_patch(patch):
global last_touch
my $parent = $parent{$patch};
my $based_on;
if (defined $parent) {
unless ($completed{$parent}++) {
update_patch($parent);
}
$based_on = $parent = "patch/$master_branch/$parent";
} else {
$parent = $master_branch;
$based_on = $master_commit;
}
completed.add(patch) # Mark it as completed early to short-circuit any (bogus) dependency loops.
print "======== $patch ========\n";
parent = parent_patch.get(patch, None)
if parent:
if parent not in completed:
if not update_patch(parent):
return 0
based_on = parent = f"patch/{args.base_branch}/{parent}"
else:
parent = args.base_branch
based_on = master_commit
sleep 1 while $incl_generated_files && $last_touch >= time;
system "git checkout patch/$master_branch/$patch" and return 0;
print(f"======== {patch} ========")
my $ok = system("git merge $based_on") == 0;
if (!$ok || $launch_shell) {
my($parent_dir) = $parent =~ m{([^/]+)$};
print qq|"git merge $based_on" incomplete -- please fix.\n| if !$ok;
$ENV{PS1} = "[$parent_dir] $patch: ";
while (1) {
if (system($ENV{SHELL}) != 0) {
print "Abort? [n/y] ";
$_ = <STDIN>;
next unless /^y/i;
return 0;
}
my($cur_branch, $is_clean, $status) = check_git_status(0);
last if $is_clean;
print $status;
}
}
while args.gen and last_touch >= time.time():
time.sleep(1)
s = cmd_run(f"git checkout patch/{args.base_branch}/{patch}".split())
if s.returncode != 0:
return 0
open(OUT, '>', "$patches_dir/$patch.diff") or die $!;
print OUT $description{$patch}, "\nbased-on: $based_on\n";
s = cmd_run(['git', 'merge', based_on])
ok = s.returncode == 0
if not ok or args.shell:
m = re.search(r'([^/]+)$', parent)
parent_dir = m[1]
if not ok:
print(f'"git merge {based_on}" incomplete -- please fix.')
os.environ['PS1'] = f"[{parent_dir}] {patch}: "
while True:
s = cmd_run([os.environ.get('SHELL', '/bin/sh')])
if s.returncode != 0:
ans = input("Abort? [n/y] ")
if re.match(r'^y', ans, flags=re.I):
return 0
continue
cur_branch, is_clean, status_txt = check_git_status(0)
if is_clean:
break
print(status_txt, end='')
my @extra_files;
if ($incl_generated_files) {
@extra_files = get_extra_files();
system "$make_gen_cmd && rsync -a @extra_files $tmp_dir/$patch/" and exit 1;
}
$last_touch = time;
with open(f"{args.patches_dir}/{patch}.diff", 'w', encoding='utf-8') as fh:
fh.write(description[patch])
fh.write(f"\nbased-on: {based_on}\n")
open(PIPE, '-|', 'git', 'diff', $based_on) or die $!;
DIFF: while (<PIPE>) {
while (m{^diff --git a/PATCH}) {
while (<PIPE>) {
last if m{^diff --git a/};
}
last DIFF if !defined $_;
}
next if /^index /;
print OUT $_;
}
close PIPE;
if args.gen:
gen_files = get_gen_files()
for cmd in MAKE_GEN_CMDS:
cmd_chk(cmd)
cmd_chk(['rsync', '-a', *gen_files, f"{TMP_DIR}/{patch}/"])
else:
gen_files = [ ]
last_touch = time.time()
if ($incl_generated_files) {
my $parent_dir;
if ($parent eq $master_branch) {
$parent_dir = 'master';
} else {
($parent_dir) = $parent =~ m{([^/]+)$};
}
open(PIPE, '-|', 'diff', '-Nurp', "$tmp_dir/$parent_dir", "$tmp_dir/$patch") or die $!;
while (<PIPE>) {
s#^(diff -Nurp) $tmp_dir/[^/]+/(.*?) $tmp_dir/[^/]+/(.*)#$1 a/$2 b/$3#o;
s#^\Q---\E $tmp_dir/[^/]+/([^\t]+)\t.*#--- a/$1#o;
s#^\Q+++\E $tmp_dir/[^/]+/([^\t]+)\t.*#+++ b/$1#o;
print OUT $_;
}
close PIPE;
unlink @extra_files;
}
proc = cmd_pipe(['git', 'diff', based_on])
skipping = False
for line in proc.stdout:
if skipping:
if not re.match(r'^diff --git a/', line):
continue
skipping = False
elif re.match(r'^diff --git a/PATCH', line):
skipping = True
continue
if not re.match(r'^index ', line):
fh.write(line)
proc.communicate()
close OUT;
if args.gen:
e_tmp_dir = re.escape(TMP_DIR)
diff_re = re.compile(r'^(diff -Nurp) %s/[^/]+/(.*?) %s/[^/]+/(.*)' % (e_tmp_dir, e_tmp_dir))
minus_re = re.compile(r'^\-\-\- %s/[^/]+/([^\t]+)\t.*' % e_tmp_dir)
plus_re = re.compile(r'^\+\+\+ %s/[^/]+/([^\t]+)\t.*' % e_tmp_dir)
1;
}
if parent == args.base_branch:
parent_dir = 'master'
else:
m = re.search(r'([^/]+)$', parent)
parent_dir = m[1]
exit;
proc = cmd_pipe(['diff', '-Nurp', f"{TMP_DIR}/{parent_dir}", f"{TMP_DIR}/{patch}"])
for line in proc.stdout:
line = diff_re.sub(r'\1 a/\2 b/\3', line)
line = minus_re.sub(r'--- a/\1', line)
line = plus_re.sub(r'+++ b/\1', line)
fh.write(line)
proc.communicate()
for fn in gen_files:
os.unlink(fn)
sub get_extra_files
{
my @extras;
return 1
open(IN, '<', 'Makefile.in') or die "Couldn't open Makefile.in: $!\n";
while (<IN>) {
if (s/^GENFILES=//) {
while (s/\\$//) {
$_ .= <IN>;
}
@extras = split(' ', $_);
last;
}
}
close IN;
return @extras;
}
if __name__ == '__main__':
parser = argparse.ArgumentParser(description="Turn a git branch back into a diff files in the patches dir.", add_help=False)
parser.add_argument('--branch', '-b', dest='base_branch', metavar='BASE_BRANCH', default='master', help="The branch the patch is based on. Default: master.")
parser.add_argument('--skip-check', action='store_true', help="Skip the check that ensures starting with a clean branch.")
parser.add_argument('--shell', '-s', action='store_true', help="Launch a shell for every patch/BASE/* branch updated, not just when a conflict occurs.")
parser.add_argument('--gen', metavar='DIR', nargs='?', const='', help='Include generated files. Optional DIR value overrides the default of using the "patches" dir.')
parser.add_argument('--patches-dir', '-p', metavar='DIR', default='patches', help="Override the location of the rsync-patches dir. Default: patches.")
parser.add_argument('patch_files', metavar='patches/DIFF_FILE', nargs='*', help="Specify what patch diff files to process. Default: all of them.")
parser.add_argument("--help", "-h", action="help", help="Output this help message and exit.")
args = parser.parse_args()
if args.gen == '':
args.gen = args.patches_dir
elif args.gen is not None:
args.patches_dir = args.gen
main()
sub usage
{
die <<EOT;
Usage: patch-update [OPTIONS] [patches/DIFF...]
Options:
-b, --branch=BRANCH The master branch to merge into the patch/BASE/* branches.
--gen[=DIR] Include generated files. Optional destination DIR
arg overrides the default of using the "patches" dir.
--skip-check Skip the check that ensures starting with a clean branch.
-s, --shell Launch a shell for every patch/BASE/* branch updated, not
just when a conflict occurs.
-h, --help Output this help message.
EOT
}
# vim: sw=4 et

261
packaging/pkglib.py Normal file
View File

@@ -0,0 +1,261 @@
import os, sys, re, subprocess
# This python3 library provides a few helpful routines that are
# used by the latest packaging scripts.
default_encoding = 'utf-8'
# Output the msg args to stderr. Accepts all the args that print() accepts.
def warn(*msg):
print(*msg, file=sys.stderr)
# Output the msg args to stderr and die with a non-zero return-code.
# Accepts all the args that print() accepts.
def die(*msg):
warn(*msg)
sys.exit(1)
# Set this to an encoding name or set it to None to avoid the default encoding idiom.
def set_default_encoding(enc):
default_encoding = enc
# Set shell=True if the cmd is a string; sets a default encoding unless raw=True was specified.
def _tweak_opts(cmd, opts, **maybe_set):
# This sets any maybe_set value that isn't already set AND creates a copy of opts for us.
opts = {**maybe_set, **opts}
if type(cmd) == str:
opts = {'shell': True, **opts}
want_raw = opts.pop('raw', False)
if default_encoding and not want_raw:
opts = {'encoding': default_encoding, **opts}
capture = opts.pop('capture', None)
if capture:
if capture == 'stdout':
opts = {'stdout': subprocess.PIPE, **opts}
elif capture == 'stderr':
opts = {'stderr': subprocess.PIPE, **opts}
elif capture == 'output':
opts = {'stdout': subprocess.PIPE, 'stderr': subprocess.PIPE, **opts}
elif capture == 'combined':
opts = {'stdout': subprocess.PIPE, 'stderr': subprocess.STDOUT, **opts}
discard = opts.pop('discard', None)
if discard:
# We DO want to override any already set stdout|stderr values (unlike above).
if discard == 'stdout' or discard == 'output':
opts['stdout'] = subprocess.DEVNULL
if discard == 'stderr' or discard == 'output':
opts['stderr'] = subprocess.DEVNULL
return opts
# This does a normal subprocess.run() with some auto-args added to make life easier.
def cmd_run(cmd, **opts):
return subprocess.run(cmd, **_tweak_opts(cmd, opts))
# Like cmd_run() with a default check=True specified.
def cmd_chk(cmd, **opts):
return subprocess.run(cmd, **_tweak_opts(cmd, opts, check=True))
# Capture stdout in a string and return the (output, return_code) tuple.
# Use capture='combined' opt to get both stdout and stderr together.
def cmd_txt_status(cmd, **opts):
input = opts.pop('input', None)
if input is not None:
opts['stdin'] = subprocess.PIPE
proc = subprocess.Popen(cmd, **_tweak_opts(cmd, opts, capture='stdout'))
out = proc.communicate(input=input)[0]
return (out, proc.returncode)
# Like cmd_txt_status() but just return the output.
def cmd_txt(cmd, **opts):
return cmd_txt_status(cmd, **opts)[0]
# Capture stdout in a string and return the output if the command has a 0 return code.
# Otherwise it throws an exception that indicates the return code and the output.
def cmd_txt_chk(cmd, **opts):
out, rc = cmd_txt_status(cmd, **opts)
if rc != 0:
cmd_err = f'Command "{cmd}" returned non-zero exit status "{rc}" and output:\n{out}'
raise Exception(cmd_err)
return out
# Starts a piped-output command of stdout (by default) and leaves it up to you to read
# the output and call communicate() on the returned object.
def cmd_pipe(cmd, **opts):
return subprocess.Popen(cmd, **_tweak_opts(cmd, opts, capture='stdout'))
# Runs a "git status" command and dies if the checkout is not clean (the
# arg fatal_unless_clean can be used to make that non-fatal. Returns a
# tuple of the current branch, the is_clean flag, and the status text.
def check_git_status(fatal_unless_clean=True, subdir='.'):
status_txt = cmd_txt_chk(f"cd '{subdir}' && git status")
is_clean = re.search(r'\nnothing to commit.+working (directory|tree) clean', status_txt) != None
if not is_clean and fatal_unless_clean:
if subdir == '.':
subdir = ''
else:
subdir = f" *{subdir}*"
die(f"The{subdir} checkout is not clean:\n" + status_txt)
m = re.match(r'^(?:# )?On branch (.+)\n', status_txt)
cur_branch = m[1] if m else None
return (cur_branch, is_clean, status_txt)
# Calls check_git_status() on the current git checkout and (optionally) a subdir path's
# checkout. Use fatal_unless_clean to indicate if an unclean checkout is fatal or not.
# The master_branch arg indicates what branch we want both checkouts to be using, and
# if the branch is wrong the user is given the option of either switching to the right
# branch or aborting.
def check_git_state(master_branch, fatal_unless_clean=True, check_extra_dir=None):
cur_branch = check_git_status(fatal_unless_clean)[0]
branch = re.sub(r'^patch/([^/]+)/[^/]+$', r'\1', cur_branch) # change patch/BRANCH/PATCH_NAME into BRANCH
if branch != master_branch:
print(f"The checkout is not on the {master_branch} branch.")
if master_branch != 'master':
sys.exit(1)
ans = input(f"Do you want me to continue with --branch={branch}? [n] ")
if not ans or not re.match(r'^y', ans, flags=re.I):
sys.exit(1)
master_branch = branch
if check_extra_dir and os.path.isdir(os.path.join(check_extra_dir, '.git')):
branch = check_git_status(fatal_unless_clean, check_extra_dir)[0]
if branch != master_branch:
print(f"The *{check_extra_dir}* checkout is on branch {branch}, not branch {master_branch}.")
ans = input(f"Do you want to change it to branch {master_branch}? [n] ")
if not ans or not re.match(r'^y', ans, flags=re.I):
sys.exit(1)
subdir.check_call(f"cd {check_extra_dir} && git checkout '{master_branch}'", shell=True)
return (cur_branch, master_branch)
# Return the git hash of the most recent commit.
def latest_git_hash(branch):
out = cmd_txt_chk(['git', 'log', '-1', '--no-color', branch])
m = re.search(r'^commit (\S+)', out, flags=re.M)
if not m:
die(f"Unable to determine commit hash for master branch: {branch}")
return m[1]
# Return a set of all branch names that have the format "patch/BASE_BRANCH/NAME"
# for the given base_branch string. Just the NAME portion is put into the set.
def get_patch_branches(base_branch):
branches = set()
proc = cmd_pipe('git branch -l'.split())
for line in proc.stdout:
m = re.search(r' patch/([^/]+)/(.+)', line)
if m and m[1] == base_branch:
branches.add(m[2])
proc.communicate()
return branches
def mandate_gensend_hook():
hook = '.git/hooks/pre-push'
if not os.path.exists(hook):
print('Creating hook file:', hook)
cmd_chk(['./rsync', '-a', 'packaging/pre-push', hook])
else:
out, rc = cmd_txt_status(['fgrep', 'make gensend', hook], discard='output')
if rc:
die('Please add a "make gensend" into your', hook, 'script.')
# Snag the GENFILES values out of the Makefile.in file and return them as a list.
def get_gen_files():
cont_re = re.compile(r'\\\n')
extras = [ ]
with open('Makefile.in', 'r', encoding='utf-8') as fh:
for line in fh:
if not extras:
chk = re.sub(r'^GENFILES=', '', line)
if line == chk:
continue
line = chk
m = re.search(r'\\$', line)
line = re.sub(r'^\s+|\s*\\\n?$|\s+$', '', line)
extras += line.split()
if not m:
break
return extras
def get_configure_version():
with open('configure.ac', 'r', encoding='utf-8') as fh:
for line in fh:
m = re.match(r'^AC_INIT\(\[rsync\],\s*\[(\d.+?)\]', line)
if m:
return m[1]
die("Unable to find AC_INIT with version in configure.ac")
def get_OLDNEWS_version_info():
rel_re = re.compile(r'^\| \d{2} \w{3} \d{4}\s+\|\s+(?P<ver>\d+\.\d+\.\d+)\s+\|\s+(?P<pdate>\d{2} \w{3} \d{4}\s+)?\|\s+(?P<pver>\d+)\s+\|')
last_version = last_protocol_version = None
pdate = { }
with open('OLDNEWS.md', 'r', encoding='utf-8') as fh:
for line in fh:
if not last_version:
m = re.search(r'(\d+\.\d+\.\d+)', line)
if m:
last_version = m[1]
m = rel_re.match(line)
if m:
if m['pdate']:
pdate[m['ver']] = m['pdate']
if m['ver'] == last_version:
last_protocol_version = m['pver']
break
if not last_protocol_version:
die(f"Unable to determine protocol_version for {last_version}.")
return last_version, last_protocol_version
def get_protocol_versions():
protocol_version = subprotocol_version = None
with open('rsync.h', 'r', encoding='utf-8') as fh:
for line in fh:
m = re.match(r'^#define\s+PROTOCOL_VERSION\s+(\d+)', line)
if m:
protocol_version = m[1]
continue
m = re.match(r'^#define\s+SUBPROTOCOL_VERSION\s+(\d+)', line)
if m:
subprotocol_version = m[1]
break
if not protocol_version:
die("Unable to determine the current PROTOCOL_VERSION.")
if not subprotocol_version:
die("Unable to determine the current SUBPROTOCOL_VERSION.")
return protocol_version, subprotocol_version
# vim: sw=4 et

3
packaging/pre-push Executable file
View File

@@ -0,0 +1,3 @@
#!/bin/sh
cat >/dev/null # Just discard stdin data
make gensend

View File

@@ -1,421 +1,394 @@
#!/usr/bin/perl
#!/usr/bin/python3 -B
# This script expects the directory ~/samba-rsync-ftp to exist and to be a
# copy of the /home/ftp/pub/rsync dir on samba.org. When the script is done,
# the git repository in the current directory will be updated, and the local
# ~/samba-rsync-ftp dir will be ready to be rsynced to samba.org.
use strict;
use warnings;
use Cwd;
use Getopt::Long;
use Term::ReadKey;
use Date::Format;
import os, sys, re, argparse, glob, shutil, signal
from datetime import datetime
from getpass import getpass
my $dest = $ENV{HOME} . '/samba-rsync-ftp';
my $passfile = $ENV{HOME} . '/.rsyncpass';
my $path = $ENV{PATH};
my $make_gen_cmd = 'make -f prepare-source.mak conf && ./config.status && make gen';
sys.path = ['packaging'] + sys.path
&Getopt::Long::Configure('bundling');
&usage if !&GetOptions(
'branch|b=s' => \( my $master_branch = 'master' ),
'help|h' => \( my $help_opt ),
);
&usage if $help_opt;
from pkglib import *
my $now = time;
my $cl_today = time2str('* %a %b %d %Y', $now);
my $year = time2str('%Y', $now);
my $ztoday = time2str('%d %b %Y', $now);
(my $today = $ztoday) =~ s/^0//;
dest = os.environ['HOME'] + '/samba-rsync-ftp'
ORIGINAL_PATH = os.environ['PATH']
my $curdir = Cwd::cwd;
def main():
now = datetime.now()
cl_today = now.strftime('* %a %b %d %Y')
year = now.strftime('%Y')
ztoday = now.strftime('%d %b %Y')
today = ztoday.lstrip('0')
END {
unlink($passfile);
}
mandate_gensend_hook()
my @extra_files;
open(IN, '<', 'Makefile.in') or die "Couldn't open Makefile.in: $!\n";
while (<IN>) {
if (s/^GENFILES=//) {
while (s/\\$//) {
$_ .= <IN>;
}
@extra_files = split(' ', $_);
last;
}
}
close IN;
curdir = os.getcwd()
my $break = <<EOT;
==========================================================================
EOT
signal.signal(signal.SIGINT, signal_handler)
print $break, <<EOT, $break, "\n";
gen_files = get_gen_files()
dash_line = '=' * 74
print(f"""\
{dash_line}
== This will release a new version of rsync onto an unsuspecting world. ==
EOT
{dash_line}
""")
die "$dest does not exist\n" unless -d $dest;
die "There is no .git dir in the current directory.\n" unless -d '.git';
die "'a' must not exist in the current directory.\n" if -e 'a';
die "'b' must not exist in the current directory.\n" if -e 'b';
if not os.path.isdir(dest):
die(dest, "dest does not exist")
if not os.path.isdir('.git'):
die("There is no .git dir in the current directory.")
if os.path.lexists('a'):
die('"a" must not exist in the current directory.')
if os.path.lexists('b'):
die('"b" must not exist in the current directory.')
if os.path.lexists('patches.gen'):
die('"patches.gen" must not exist in the current directory.')
require 'packaging/git-status.pl';
check_git_state($master_branch, 1, 1);
check_git_state(args.master_branch, True, 'patches')
my $confversion;
open(IN, '<', 'configure.ac') or die $!;
while (<IN>) {
if (/^RSYNC_VERSION=(.*)/) {
$confversion = $1;
last;
}
}
close IN;
die "Unable to find RSYNC_VERSION in configure.ac\n" unless defined $confversion;
confversion = get_configure_version()
open(IN, '<', 'OLDNEWS') or die $!;
$_ = <IN>;
my($lastversion) = /(\d+\.\d+\.\d+)/;
my($last_protocol_version, %pdate);
while (<IN>) {
if (my($ver,$pdate,$pver) = /^\s+\S\S\s\S\S\S\s\d\d\d\d\s+(\d+\.\d+\.\d+)\s+(\d\d \w\w\w \d\d\d\d\s+)?(\d+)$/) {
$pdate{$ver} = $pdate if defined $pdate;
$last_protocol_version = $pver if $ver eq $lastversion;
}
}
close IN;
die "Unable to determine protocol_version for $lastversion.\n" unless defined $last_protocol_version;
# All version values are strings!
lastversion, last_protocol_version = get_OLDNEWS_version_info()
protocol_version, subprotocol_version = get_protocol_versions()
my $protocol_version;
open(IN, '<', 'rsync.h') or die $!;
while (<IN>) {
if (/^#define\s+PROTOCOL_VERSION\s+(\d+)/) {
$protocol_version = $1;
last;
}
}
close IN;
die "Unable to determine the current PROTOCOL_VERSION.\n" unless defined $protocol_version;
version = confversion
m = re.search(r'pre(\d+)', version)
if m:
version = re.sub(r'pre\d+', 'pre' + str(int(m[1]) + 1), version)
else:
version = version.replace('dev', 'pre1')
my $version = $confversion;
$version =~ s/dev/pre1/ || $version =~ s/pre(\d+)/ 'pre' . ($1 + 1) /e;
ans = input(f"Please enter the version number of this release: [{version}] ")
if ans == '.':
version = re.sub(r'pre\d+', '', version)
elif ans != '':
version = ans
if not re.match(r'^[\d.]+(pre\d+)?$', version):
die(f'Invalid version: "{version}"')
print "Please enter the version number of this release: [$version] ";
chomp($_ = <STDIN>);
if ($_ eq '.') {
$version =~ s/pre\d+//;
} elsif ($_ ne '') {
$version = $_;
}
die "Invalid version: `$version'\n" unless $version =~ /^[\d.]+(pre\d+)?$/;
v_ver = 'v' + version
rsync_ver = 'rsync-' + version
if (`git tag -l v$version` ne '') {
print "Tag v$version already exists.\n\nDelete tag or quit? [q/del] ";
$_ = <STDIN>;
exit 1 unless /^del/i;
system "git tag -d v$version";
}
if os.path.lexists(rsync_ver):
die(f'"{rsync_ver}" must not exist in the current directory.')
if ($version =~ s/[-.]*pre[-.]*/pre/ && $confversion !~ /dev$/) {
$lastversion = $confversion;
}
out = cmd_txt_chk(['git', 'tag', '-l', v_ver])
if out != '':
print(f"Tag {v_ver} already exists.")
ans = input("\nDelete tag or quit? [Q/del] ")
if not re.match(r'^del', ans, flags=re.I):
die("Aborted")
cmd_chk(['git', 'tag', '-d', v_ver])
print "Enter the previous version to produce a patch against: [$lastversion] ";
chomp($_ = <STDIN>);
$lastversion = $_ if $_ ne '';
$lastversion =~ s/[-.]*pre[-.]*/pre/;
version = re.sub(r'[-.]*pre[-.]*', 'pre', version)
if 'pre' in version and not confversion.endswith('dev'):
lastversion = confversion
my $pre = $version =~ /(pre\d+)/ ? $1 : '';
ans = input(f"Enter the previous version to produce a patch against: [{lastversion}] ")
if ans != '':
lastversion = ans
lastversion = re.sub(r'[-.]*pre[-.]*', 'pre', lastversion)
my $release = $pre ? '0.1' : '1';
print "Please enter the RPM release number of this release: [$release] ";
chomp($_ = <STDIN>);
$release = $_ if $_ ne '';
$release .= ".$pre" if $pre;
rsync_lastver = 'rsync-' + lastversion
if os.path.lexists(rsync_lastver):
die(f'"{rsync_lastver}" must not exist in the current directory.')
(my $finalversion = $version) =~ s/pre\d+//;
my($proto_changed,$proto_change_date);
if ($protocol_version eq $last_protocol_version) {
$proto_changed = 'unchanged';
$proto_change_date = "\t\t";
} else {
$proto_changed = 'changed';
if (!defined($proto_change_date = $pdate{$finalversion})) {
while (1) {
print "On what date did the protocol change to $protocol_version get checked in? (dd Mmm yyyy) ";
chomp($_ = <STDIN>);
last if /^\d\d \w\w\w \d\d\d\d$/;
}
$proto_change_date = "$_\t";
}
}
m = re.search(r'(pre\d+)', version)
pre = m[1] if m else ''
my($srcdir,$srcdiffdir,$lastsrcdir,$skipping);
if ($lastversion =~ /pre/) {
if (!$pre) {
die "You should not diff a release version against a pre-release version.\n";
}
$srcdir = $srcdiffdir = $lastsrcdir = 'src-previews';
$skipping = ' ** SKIPPING **';
} elsif ($pre) {
$srcdir = $srcdiffdir = 'src-previews';
$lastsrcdir = 'src';
$skipping = ' ** SKIPPING **';
} else {
$srcdir = $lastsrcdir = 'src';
$srcdiffdir = 'src-diffs';
$skipping = '';
}
release = '0.1' if pre else '1'
ans = input(f"Please enter the RPM release number of this release: [{release}] ")
if ans != '':
release = ans
if pre:
release += '.' + pre
print "\n", $break, <<EOT;
\$version is "$version"
\$lastversion is "$lastversion"
\$dest is "$dest"
\$curdir is "$curdir"
\$srcdir is "$srcdir"
\$srcdiffdir is "$srcdiffdir"
\$lastsrcdir is "$lastsrcdir"
\$release is "$release"
finalversion = re.sub(r'pre\d+', '', version)
if protocol_version == last_protocol_version:
proto_changed = 'unchanged'
proto_change_date = ' ' * 11
else:
proto_changed = 'changed'
if finalversion in pdate:
proto_change_date = pdate[finalversion]
else:
while True:
ans = input("On what date did the protocol change to {protocol_version} get checked in? (dd Mmm yyyy) ")
if re.match(r'^\d\d \w\w\w \d\d\d\d$', ans):
break
proto_change_date = ans
if 'pre' in lastversion:
if not pre:
die("You should not diff a release version against a pre-release version.")
srcdir = srcdiffdir = lastsrcdir = 'src-previews'
skipping = ' ** SKIPPING **'
elif pre:
srcdir = srcdiffdir = 'src-previews'
lastsrcdir = 'src'
skipping = ' ** SKIPPING **'
else:
srcdir = lastsrcdir = 'src'
srcdiffdir = 'src-diffs'
skipping = ''
print(f"""
{dash_line}
version is "{version}"
lastversion is "{lastversion}"
dest is "{dest}"
curdir is "{curdir}"
srcdir is "{srcdir}"
srcdiffdir is "{srcdiffdir}"
lastsrcdir is "{lastsrcdir}"
release is "{release}"
About to:
- tweak SUBPROTOCOL_VERSION in rsync.h, if needed
- tweak the version in configure.ac and the spec files
- tweak NEWS and OLDNEWS to ensure header values are correct
- tweak the date in the *.yo files and generate the manpages
- tweak NEWS.md and OLDNEWS.md to ensure header values are correct
- generate configure.sh, config.h.in, and proto.h
- page through the differences
""")
ans = input("<Press Enter to continue> ")
EOT
print "<Press Enter to continue> ";
$_ = <STDIN>;
specvars = {
'Version:': finalversion,
'Release:': release,
'%define fullversion': f'%{{version}}{pre}',
'Released': version + '.',
'%define srcdir': srcdir,
}
my %specvars = ( 'Version:' => $finalversion, 'Release:' => $release,
'%define fullversion' => "\%{version}$pre", 'Released' => "$version.",
'%define srcdir' => $srcdir );
my @tweak_files = ( glob('packaging/*.spec'), glob('packaging/*/*.spec'), glob('*.yo'),
qw( configure.ac rsync.h NEWS OLDNEWS options.c ) );
tweak_files = 'configure.ac rsync.h NEWS.md OLDNEWS.md'.split()
tweak_files += glob.glob('packaging/*.spec')
tweak_files += glob.glob('packaging/*/*.spec')
foreach my $fn (@tweak_files) {
open(IN, '<', $fn) or die $!;
undef $/; $_ = <IN>; $/ = "\n";
close IN;
if ($fn =~ /configure/) {
s/^RSYNC_VERSION=.*/RSYNC_VERSION=$version/m
or die "Unable to update RSYNC_VERSION in $fn\n";
} elsif ($fn =~ /\.spec/) {
while (my($str, $val) = each %specvars) {
s/^\Q$str\E .*/$str $val/m
or die "Unable to update $str in $fn\n";
}
s/^\* \w\w\w \w\w\w \d\d \d\d\d\d (.*)/$cl_today $1/m
or die "Unable to update ChangeLog header in $fn\n";
} elsif ($fn =~ /\.yo/) {
s/^(manpage\([^)]+\)\(\d+\)\()[^)]+(\).*)/$1$today$2/m
or die "Unable to update date in manpage() header in $fn\n";
s/^(This man ?page is current for version) \S+ (of rsync)/$1 $version $2/m
or die "Unable to update current version info in $fn\n";
} elsif ($fn eq 'rsync.h') {
s{(#define\s+SUBPROTOCOL_VERSION)\s+(\d+)}
{ $1 . ' ' . get_subprotocol_version($2) }e
or die "Unable to find SUBPROTOCOL_VERSION define in $fn\n";
} elsif ($fn eq 'NEWS') {
s{^(NEWS for rsync \Q$finalversion\E )(\(UNRELEASED\))\s*(\nProtocol: )(\d+) (\([^)]+\))\n}
{ $1 . ($pre ? $2 : "($today)") . "$3$protocol_version ($proto_changed)\n" }ei
or die "The first 2 lines of $fn are not in the right format. They must be:\n"
. "NEWS for rsync $finalversion (UNRELEASED)\n"
. "Protocol: $protocol_version ($proto_changed)\n";
} elsif ($fn eq 'OLDNEWS') {
s{^(\t\S\S\s\S\S\S\s\d\d\d\d)(\t\Q$finalversion\E\t).*}
{ ($pre ? $1 : "\t$ztoday") . $2 . $proto_change_date . $protocol_version }em
or die "Unable to find \"?? ??? $year\t$finalversion\" line in $fn\n";
} elsif ($fn eq 'options.c') {
if (s/(Copyright \(C\) 2002-)(\d+)( Wayne Davison)/$1$year$3/
&& $2 ne $year) {
die "Copyright comments need to be updated to $year in all files!\n";
}
# Adjust the year in the --version output.
s/(rprintf\(f, "Copyright \(C\) 1996-)(\d+)/$1$year/
or die "Unable to find Copyright string in --version output of $fn\n";
next if $2 eq $year;
} else {
die "Unrecognized file in \@tweak_files: $fn\n";
}
open(OUT, '>', $fn) or die $!;
print OUT $_;
close OUT;
}
for fn in tweak_files:
with open(fn, 'r', encoding='utf-8') as fh:
old_txt = txt = fh.read()
if 'configure' in fn:
x_re = re.compile(r'^(AC_INIT\(\[rsync\],\s*\[)\d.+?(\])', re.M)
txt = replace_or_die(x_re, r'\g<1>%s\2' % version, txt, f"Unable to update AC_INIT with version in {fn}")
elif '.spec' in fn:
for var, val in specvars.items():
x_re = re.compile(r'^%s .*' % re.escape(var), re.M)
txt = replace_or_die(x_re, var + ' ' + val, txt, f"Unable to update {var} in {fn}")
x_re = re.compile(r'^\* \w\w\w \w\w\w \d\d \d\d\d\d (.*)', re.M)
txt = replace_or_die(x_re, r'%s \1' % cl_today, txt, f"Unable to update ChangeLog header in {fn}")
elif fn == 'rsync.h':
x_re = re.compile('(#define\s+SUBPROTOCOL_VERSION)\s+(\d+)')
repl = lambda m: m[1] + ' ' + '0' if not pre or proto_changed != 'changed' else 1 if m[2] == '0' else m[2]
txt = replace_or_die(x_re, repl, txt, f"Unable to find SUBPROTOCOL_VERSION define in {fn}")
elif fn == 'NEWS.md':
x_re = re.compile(
r'^(# NEWS for rsync %s )(\(UNRELEASED\))\s*(\n\nProtocol: )(\d+) (\([^)]+\))\n' % re.escape(finalversion),
re.I)
repl = lambda m: m[1] + (m[2] if pre else f"({today})") + m[3] + f"{protocol_version} ({proto_changed})\n"
msg = (f"The first 3 lines of {fn} are not in the right format. They must be:\n"
+ f"# NEWS for rsync {finalversion} (UNRELEASED)\n\n"
+ f"Protocol: {protocol_version} ({proto_changed})")
txt = replace_or_die(x_re, repl, txt, msg)
elif fn == 'OLDNEWS.md':
efv = re.escape(finalversion)
x_re = re.compile(r'^(\| )(\S{2} \S{3} \d{4})(\s+\|\s+%s\s+\| ).{11}(\s+\| )\S{2}(\s+\|+)$' % efv, re.M)
repl = lambda m: m[1] + (m[2] if pre else ztoday) + m[3] + proto_change_date + m[4] + protocol_version + m[5]
txt = replace_or_die(x_re, repl, txt, f'Unable to find "| ?? ??? {year} | {finalversion} | ... |" line in {fn}')
else:
die(f"Unrecognized file in tweak_files: {fn}")
print $break;
system "git diff --color | less -p '^diff .*'";
if txt != old_txt:
print(f"Updating {fn}")
with open(fn, 'w', encoding='utf-8') as fh:
fh.write(txt)
my $srctar_name = "rsync-$version.tar.gz";
my $pattar_name = "rsync-patches-$version.tar.gz";
my $diff_name = "rsync-$lastversion-$version.diffs.gz";
my $srctar_file = "$dest/$srcdir/$srctar_name";
my $pattar_file = "$dest/$srcdir/$pattar_name";
my $diff_file = "$dest/$srcdiffdir/$diff_name";
my $news_file = "$dest/$srcdir/rsync-$version-NEWS";
my $lasttar_file = "$dest/$lastsrcdir/rsync-$lastversion.tar.gz";
cmd_chk(['packaging/year-tweak'])
print $break, <<EOT;
print(dash_line)
cmd_run("git diff --color | less -p '^diff .*'")
srctar_name = f"{rsync_ver}.tar.gz"
pattar_name = f"rsync-patches-{version}.tar.gz"
diff_name = f"{rsync_lastver}-{version}.diffs.gz"
srctar_file = f"{dest}/{srcdir}/{srctar_name}"
pattar_file = f"{dest}/{srcdir}/{pattar_name}"
diff_file = f"{dest}/{srcdiffdir}/{diff_name}"
news_file = f"{dest}/{srcdir}/{rsync_ver}-NEWS.md"
lasttar_file = f"{dest}/{lastsrcdir}/{rsync_lastver}.tar.gz"
print(f"""\
{dash_line}
About to:
- commit all version changes
- merge the $master_branch branch into the patch/$master_branch/* branches
- git commit all changes
- generate the manpages
- merge the {args.master_branch} branch into the patch/{args.master_branch}/* branches
- update the files in the "patches" dir and OPTIONALLY
(if you type 'y') to launch a shell for each patch
""")
ans = input("<Press Enter OR 'y' to continue> ")
EOT
print "<Press Enter OR 'y' to continue> ";
my $ans = <STDIN>;
s = cmd_run(['git', 'commit', '-a', '-m', f'Preparing for release of {version}'])
if s.returncode:
die('Aborting')
system "git commit -a -m 'Preparing for release of $version'" and exit 1;
cmd_chk('make reconfigure ; make gen')
cmd_chk(['rsync', '-a', *gen_files, 'SaVeDiR/'])
print "Updating files in \"patches\" dir ...\n";
system "packaging/patch-update --branch=$master_branch";
print(f'Creating any missing patch branches.')
s = cmd_run(f'packaging/branch-from-patch --branch={args.master_branch} --add-missing')
if s.returncode:
die('Aborting')
if ($ans =~ /^y/i) {
print "\nVisiting all \"patch/$master_branch/*\" branches ...\n";
system "packaging/patch-update --branch=$master_branch --skip-check --shell";
}
print('Updating files in "patches" dir ...')
s = cmd_run(f'packaging/patch-update --branch={args.master_branch}')
if s.returncode:
die('Aborting')
if (-d 'patches/.git') {
system "cd patches && git commit -a -m 'The patches for $version.'" and exit 1;
}
if re.match(r'^y', ans, re.I):
print(f'\nVisiting all "patch/{args.master_branch}/*" branches ...')
cmd_run(f"packaging/patch-update --branch={args.master_branch} --skip-check --shell")
print $break, <<EOT;
cmd_run("rm -f *.[o15] *.html")
cmd_chk('rsync -a SaVeDiR/ .'.split())
if os.path.isdir('patches/.git'):
s = cmd_run(f"cd patches && git commit -a -m 'The patches for {version}.'")
if s.returncode:
die('Aborting')
print(f"""\
{dash_line}
About to:
- create signed tag for this release: v$version
- create release diffs, "$diff_name"
- create release tar, "$srctar_name"
- generate rsync-$version/patches/* files
- create patches tar, "$pattar_name"
- update top-level README, *NEWS, TODO, and ChangeLog
- create signed tag for this release: {v_ver}
- create release diffs, "{diff_name}"
- create release tar, "{srctar_name}"
- generate {rsync_ver}/patches/* files
- create patches tar, "{pattar_name}"
- update top-level README.md, *NEWS.md, TODO, and ChangeLog
- update top-level rsync*.html manpages
- gpg-sign the release files
- update hard-linked top-level release files$skipping
- update hard-linked top-level release files{skipping}
""")
ans = input("<Press Enter to continue> ")
EOT
print "<Press Enter to continue> ";
$_ = <STDIN>;
# TODO: is there a better way to ensure that our passphrase is in the agent?
cmd_run("touch TeMp; gpg --sign TeMp; rm TeMp*")
# We want to use our passphrase-providing "gpg" script, so modify the PATH.
$ENV{PATH} = "$curdir/packaging/bin:$path";
out = cmd_txt(f"git tag -s -m 'Version {version}.' {v_ver}", capture='combined')
print(out, end='')
if 'bad passphrase' in out or 'failed' in out:
die('Aborting')
my $passphrase;
while (1) {
ReadMode('noecho');
print "\nEnter your GPG pass-phrase: ";
chomp($passphrase = <STDIN>);
ReadMode(0);
print "\n";
if os.path.isdir('patches/.git'):
out = cmd_txt(f"cd patches && git tag -s -m 'Version {version}.' {v_ver}", capture='combined')
print(out, end='')
if 'bad passphrase' in out or 'failed' in out:
die('Aborting')
# Briefly create a temp file with the passphrase for git's tagging use.
my $oldmask = umask 077;
unlink($passfile);
open(OUT, '>', $passfile) or die $!;
print OUT $passphrase, "\n";
close OUT;
umask $oldmask;
$ENV{'GPG_PASSFILE'} = $passfile;
os.environ['PATH'] = ORIGINAL_PATH
$_ = `git tag -s -m 'Version $version.' v$version 2>&1`;
print $_;
next if /bad passphrase/;
exit 1 if /failed/;
# Extract the generated files from the old tar.
tweaked_gen_files = [ f"{rsync_lastver}/{x}" for x in gen_files ]
cmd_run(['tar', 'xzf', lasttar_file, *tweaked_gen_files])
os.rename(rsync_lastver, 'a')
if (-d 'patches/.git') {
$_ = `cd patches && git tag -s -m 'Version $version.' v$version 2>&1`;
print $_;
exit 1 if /bad passphrase|failed/;
}
print(f"Creating {diff_file} ...")
cmd_chk(['rsync', '-a', *gen_files, 'b/'])
unlink($passfile);
last;
}
sed_script = r's:^((---|\+\+\+) [ab]/[^\t]+)\t.*:\1:' # CAUTION: must not contain any single quotes!
cmd_chk(f"(git diff v{lastversion} {v_ver} -- ':!.github'; diff -upN a b | sed -r '{sed_script}') | gzip -9 >{diff_file}")
shutil.rmtree('a')
os.rename('b', rsync_ver)
$ENV{PATH} = $path;
print(f"Creating {srctar_file} ...")
cmd_chk(f"git archive --format=tar --prefix={rsync_ver}/ {v_ver} | tar xf -")
cmd_chk(f"support/git-set-file-times --quiet --prefix={rsync_ver}/")
cmd_chk(['fakeroot', 'tar', 'czf', srctar_file, '--exclude=.github', rsync_ver])
shutil.rmtree(rsync_ver)
# Extract the generated files from the old tar.
@_ = @extra_files;
map { s#^#rsync-$lastversion/# } @_;
system "tar xzf $lasttar_file @_";
rename("rsync-$lastversion", 'a');
print(f'Updating files in "{rsync_ver}/patches" dir ...')
os.mkdir(rsync_ver, 0o755)
os.mkdir(f"{rsync_ver}/patches", 0o755)
cmd_chk(f"packaging/patch-update --skip-check --branch={args.master_branch} --gen={rsync_ver}/patches".split())
print "Creating $diff_file ...\n";
system "$make_gen_cmd && rsync -a @extra_files b/" and exit 1;
my $sed_script = 's:^((---|\+\+\+) [ab]/[^\t]+)\t.*:\1:';
system "(git diff v$lastversion v$version; diff -upN a b | sed -r '$sed_script') | gzip -9 >$diff_file";
system "rm -rf a";
rename('b', "rsync-$version");
cmd_run("rm -f *.[o15] *.html")
cmd_chk('rsync -a SaVeDiR/ .'.split())
shutil.rmtree('SaVeDiR')
cmd_chk('make gen'.split())
print "Creating $srctar_file ...\n";
system "git archive --format=tar --prefix=rsync-$version/ v$version | tar xf -";
system "support/git-set-file-times --prefix=rsync-$version/";
system "fakeroot tar czf $srctar_file rsync-$version; rm -rf rsync-$version";
print(f"Creating {pattar_file} ...")
cmd_chk(['fakeroot', 'tar', 'chzf', pattar_file, rsync_ver + '/patches'])
shutil.rmtree(rsync_ver)
print "Updating files in \"rsync-$version/patches\" dir ...\n";
mkdir("rsync-$version", 0755);
mkdir("rsync-$version/patches", 0755);
system "packaging/patch-update --skip-check --branch=$master_branch --gen=rsync-$version/patches";
print(f"Updating the other files in {dest} ...")
md_files = 'README.md NEWS.md OLDNEWS.md'.split()
html_files = [ fn for fn in gen_files if fn.endswith('.html') ]
cmd_chk(['rsync', '-a', *md_files, *html_files, dest])
cmd_chk(["packaging/md2html"] + [ dest +'/'+ fn for fn in md_files ])
print "Creating $pattar_file ...\n";
system "fakeroot tar chzf $pattar_file rsync-$version/patches; rm -rf rsync-$version";
for topfn, verfn in (('NEWS.md', news_file), ('NEWS.html', news_file.replace('.md', '.html'))):
topfn = dest + '/' + topfn
if os.path.lexists(verfn):
os.unlink(verfn)
os.link(topfn, verfn)
print "Updating the other files in $dest ...\n";
system "rsync -a README NEWS OLDNEWS TODO $dest";
unlink($news_file);
link("$dest/NEWS", $news_file);
system "git log --name-status | gzip -9 >$dest/ChangeLog.gz";
cmd_chk(f"git log --name-status | gzip -9 >{dest}/ChangeLog.gz")
system "yodl2html -o $dest/rsync.html rsync.yo";
system "yodl2html -o $dest/rsyncd.conf.html rsyncd.conf.yo";
for fn in (srctar_file, pattar_file, diff_file):
asc_fn = fn + '.asc'
if os.path.lexists(asc_fn):
os.unlink(asc_fn)
res = cmd_run(['gpg', '--batch', '-ba', fn])
if res.returncode != 0 and res.returncode != 2:
die("gpg signing failed")
foreach my $fn ($srctar_file, $pattar_file, $diff_file) {
unlink("$fn.asc");
open(GPG, '|-', "gpg --batch --passphrase-fd=0 -ba $fn") or die $!;
print GPG $passphrase, "\n";
close GPG;
}
if not pre:
for find in f'{dest}/rsync-*.gz {dest}/rsync-*.asc {dest}/rsync-*-NEWS.md {dest}/src-previews/rsync-*diffs.gz*'.split():
for fn in glob.glob(find):
os.unlink(fn)
top_link = [
srctar_file, f"{srctar_file}.asc",
pattar_file, f"{pattar_file}.asc",
diff_file, f"{diff_file}.asc",
news_file,
]
for fn in top_link:
os.link(fn, re.sub(r'/src(-\w+)?/', '/', fn))
if (!$pre) {
system "rm $dest/rsync-*.gz $dest/rsync-*.asc $dest/rsync-*-NEWS $dest/src-previews/rsync-*diffs.gz*";
foreach my $fn ($srctar_file, "$srctar_file.asc",
$pattar_file, "$pattar_file.asc",
$diff_file, "$diff_file.asc", $news_file) {
(my $top_fn = $fn) =~ s#/src(-\w+)?/#/#;
link($fn, $top_fn);
}
}
print $break, <<'EOT';
print(f"""\
{dash_line}
Local changes are done. When you're satisfied, push the git repository
and rsync the release files. Remember to announce the release on *BOTH*
rsync-announce@lists.samba.org and rsync@lists.samba.org (and the web)!
EOT
""")
exit;
sub get_subprotocol_version
{
my($subver) = @_;
if ($pre && $proto_changed eq 'changed') {
return $subver == 0 ? 1 : $subver;
}
0;
}
def replace_or_die(regex, repl, txt, die_msg):
m = regex.search(txt)
if not m:
die(die_msg)
return regex.sub(repl, txt, 1)
sub usage
{
die <<EOT;
Usage: release-rsync [OPTIONS]
-b, --branch=BRANCH The branch to release (default: master)
-h, --help Display this help message
EOT
}
def signal_handler(sig, frame):
die("\nAborting due to SIGINT.")
if __name__ == '__main__':
parser = argparse.ArgumentParser(description="Prepare a new release of rsync in the git repo & ftp dir.", add_help=False)
parser.add_argument('--branch', '-b', dest='master_branch', default='master', help="The branch to release. Default: master.")
parser.add_argument("--help", "-h", action="help", help="Output this help message and exit.")
args = parser.parse_args()
main()
# vim: sw=4 et

View File

@@ -41,7 +41,7 @@ mkdir -p $FAKE_ROOT/man/man5
cp ../../../rsync $FAKE_ROOT/bin/rsync
cp ../../../rsync.1 $FAKE_ROOT/man/man1/rsync.1
cp ../../../rsyncd.conf.5 $FAKE_ROOT/man/man5/rsyncd.conf.5
cp ../../../README $FAKE_ROOT/doc/rsync/README
cp ../../../README.md $FAKE_ROOT/doc/rsync/README.md
cp ../../../COPYING $FAKE_ROOT/doc/rsync/COPYING
cp ../../../tech_report.pdf $FAKE_ROOT/doc/rsync/tech_report.pdf
cp ../../../COPYING $FAKE_ROOT/COPYING
@@ -68,7 +68,7 @@ d none bin 0755 bin bin
f none bin/rsync 0755 bin bin
d none doc 0755 bin bin
d none doc/$NAME 0755 bin bin
f none doc/$NAME/README 0644 bin bin
f none doc/$NAME/README.md 0644 bin bin
f none doc/$NAME/COPYING 0644 bin bin
f none doc/$NAME/tech_report.pdf 0644 bin bin
d none man 0755 bin bin

View File

@@ -1,83 +1,87 @@
#!/usr/bin/perl
#!/usr/bin/python3 -B
# This script checks the *.c files for extraneous "extern" variables,
# for vars that are defined but not used, and for inconsistent array
# sizes. Run it from inside the main rsync directory.
use strict;
use warnings;
import re, argparse, glob
my %add_syscall_c = map { $_ => 1 } qw( t_stub.c t_unsafe.c tls.c trimslash.c );
my %add_compat_c = map { $_ => 1 } qw( t_stub.c tls.c trimslash.c wildtest.c );
my %add_util_c = map { $_ => 1 } qw( t_stub.c t_unsafe.c );
my %sizes;
VARS_RE = re.compile(r'^(?!(?:extern|enum)\s)([a-zA-Z]\S*\s+.*);', re.M)
EXTERNS_RE = re.compile(r'^extern\s+(.*);', re.M)
open(IN, '<', 'syscall.c') or die $!;
undef $/; my $syscall_c = <IN>; $/ = "\n";
close IN;
$syscall_c =~ s/^extern\s.*//mg;
sizes = { }
open(IN, '<', 'lib/compat.c') or die $!;
undef $/; my $compat_c = <IN>; $/ = "\n";
close IN;
$compat_c =~ s/^extern\s.*//mg;
def main():
add_syscall_c = set('t_stub.c t_unsafe.c tls.c trimslash.c'.split())
add_util_c = set('t_stub.c t_unsafe.c'.split())
open(IN, '<', 'util.c') or die $!;
undef $/; my $util_c = <IN>; $/ = "\n";
close IN;
$util_c =~ s/^extern\s.*//mg;
syscall_c = slurp_file('syscall.c', True)
util_c = slurp_file('util.c', True)
my @files = glob('*.c');
for fn in sorted(glob.glob('*.c')):
txt = slurp_file(fn)
foreach my $fn (@files) {
open(IN, '<', $fn) or die $!;
undef $/; $_ = <IN>; $/ = "\n";
close IN;
var_list = parse_vars(fn, VARS_RE.findall(txt))
extern_list = parse_vars(fn, EXTERNS_RE.findall(txt))
if not var_list and not extern_list:
continue
my @vars = /^(?!(?:extern|enum)\s)([a-zA-Z]\S*\s+.*);/mg;
my @externs = /^extern\s+(.*);/mg;
if fn in add_syscall_c:
txt += syscall_c
if fn in add_util_c:
txt += util_c
$_ .= $syscall_c if $add_syscall_c{$fn};
$_ .= $compat_c if $add_compat_c{$fn};
$_ .= $util_c if $add_util_c{$fn};
s/INFO_GTE/info_levels/g;
s/DEBUG_GTE/debug_levels/g;
txt = re.sub(r'INFO_GTE', 'info_levels ', txt)
txt = re.sub(r'DEBUG_GTE', 'debug_levels ', txt)
txt = re.sub(r'SIGACTION\(', 'sigact (', txt)
check_vars($fn, 'var', @vars);
check_vars($fn, 'extern', @externs);
}
find = '|'.join([ re.escape(x) for x in var_list + extern_list ])
var_re = re.compile(r'(?<!\sstruct )\b(%s)(?!\w)' % find)
exit;
found = { x: 0 for x in var_list + extern_list }
for var in var_re.findall(txt):
found[var] += 1
# The file's contents are in $_.
sub check_vars
{
my $fn = shift;
my $type = shift;
for var in sorted(var_list + extern_list):
if found[var] == 1:
vtype = 'var' if var in var_list else 'extern'
print(fn, f'has extraneous {vtype}: "{var}"')
foreach my $line (@_) {
$line =~ s/\s*\{.*\}//;
$line =~ s/\s*\(.*\)//;
foreach my $item (split(/\s*,\s*/, $line)) {
$item =~ s/\s*=.*//;
my $sz = $item =~ s/(\[.*?\])// ? $1 : '';
my($var) = $item =~ /([^*\s]+)$/;
if (!defined $var) {
print "Bogus match? ($item)\n";
next;
}
if ($sz) {
if (defined $sizes{$var}) {
if ($sizes{$var} ne $sz) {
print $fn, ' has inconsistent size for "', $var,
"\": $sizes{$var} vs $sz\n";
}
} else {
$sizes{$var} = $sz;
}
}
my @matches = /(?<!\sstruct )\b(\Q$var\E)(?!\w)/g;
push(@matches, /(\QSIGACTION(\E)/g) if $var eq 'sigact';
print $fn, " has extraneous $type: \"", $var, "\"\n" if @matches == 1;
}
}
}
def slurp_file(fn, drop_externs=False):
with open(fn, 'r', encoding='utf-8') as fh:
txt = fh.read()
if drop_externs:
txt = EXTERNS_RE.sub('', txt)
return txt
def parse_vars(fn, lines):
ret = [ ]
for line in lines:
line = re.sub(r'\s*\{.*\}', '', line)
line = re.sub(r'\s*\(.*\)', '', line)
for item in re.split(r'\s*,\s*', line):
item = re.sub(r'\s*=.*', '', item)
m = re.search(r'(?P<var>\w+)(?P<sz>\[.*?\])?$', item)
if not m:
print(f"Bogus match? ({item})")
continue
if m['sz']:
if m['var'] in sizes:
if sizes[m['var']] != m['sz']:
var = m['var']
print(fn, f'has inconsistent size for "{var}":', m['sz'], 'vs', sizes[var])
else:
sizes[m['var']] = m['sz']
ret.append(m['var'])
return ret
if __name__ == '__main__':
parser = argparse.ArgumentParser(description='Check the *.c files for extraneous extern vars.', add_help=False)
parser.add_argument("--help", "-h", action="help", help="Output this help message and exit.")
args = parser.parse_args()
main()
# vim: sw=4 et

94
packaging/year-tweak Executable file
View File

@@ -0,0 +1,94 @@
#!/usr/bin/python3
# This uses the output from "support/git-set-file-times --list" to discern
# the last-modified year of each *.c & *.h file and updates the copyright
# year if it isn't set right.
import sys, os, re, argparse, subprocess
from datetime import datetime
MAINTAINER_NAME = 'Wayne Davison'
MAINTAINER_SUF = ' ' + MAINTAINER_NAME + "\n"
def main():
latest_year = '2000'
proc = subprocess.Popen('support/git-set-file-times --list'.split(), stdout=subprocess.PIPE, encoding='utf-8')
for line in proc.stdout:
m = re.match(r'^\S\s+(?P<year>\d\d\d\d)\S+\s+\S+\s+(?P<fn>.+)', line)
if not m:
print("Failed to parse line from git-set-file-times:", line)
sys.exit(1)
m = argparse.Namespace(**m.groupdict())
if m.year > latest_year:
latest_year = m.year
if m.fn.startswith('zlib/') or m.fn.startswith('popt/'):
continue
if re.search(r'\.(c|h|sh|test)$', m.fn):
maybe_edit_copyright_year(m.fn, m.year)
proc.communicate()
fn = 'latest-year.h'
with open(fn, 'r', encoding='utf-8') as fh:
old_txt = fh.read()
txt = f'#define LATEST_YEAR "{latest_year}"\n'
if txt != old_txt:
print(f"Updating {fn} with year {latest_year}")
with open(fn, 'w', encoding='utf-8') as fh:
fh.write(txt)
def maybe_edit_copyright_year(fn, year):
opening_lines = [ ]
copyright_line = None
with open(fn, 'r', encoding='utf-8') as fh:
for lineno, line in enumerate(fh):
opening_lines.append(line)
if lineno > 3 and not re.search(r'\S', line):
break
m = re.match(r'^(?P<pre>.*Copyright\s+\S+\s+)(?P<year>\d\d\d\d(?:-\d\d\d\d)?(,\s+\d\d\d\d)*)(?P<suf>.+)', line)
if not m:
continue
copyright_line = argparse.Namespace(**m.groupdict())
copyright_line.lineno = len(opening_lines)
copyright_line.is_maintainer_line = MAINTAINER_NAME in copyright_line.suf
copyright_line.txt = line
if copyright_line.is_maintainer_line:
break
if not copyright_line:
return
if copyright_line.is_maintainer_line:
cyears = copyright_line.year.split('-')
if year == cyears[0]:
cyears = [ year ]
else:
cyears = [ cyears[0], year ]
txt = copyright_line.pre + '-'.join(cyears) + MAINTAINER_SUF
if txt == copyright_line.txt:
return
opening_lines[copyright_line.lineno - 1] = txt
else:
if fn.startswith('lib/') or fn.startswith('testsuite/'):
return
txt = copyright_line.pre + year + MAINTAINER_SUF
opening_lines[copyright_line.lineno - 1] += txt
remaining_txt = fh.read()
print(f"Updating {fn} with year {year}")
with open(fn, 'w', encoding='utf-8') as fh:
fh.write(''.join(opening_lines))
fh.write(remaining_txt)
if __name__ == '__main__':
parser = argparse.ArgumentParser(description="Grab the year of last mod for our c & h files and make sure the Copyright comment is up-to-date.")
args = parser.parse_args()
main()
# vim: sw=4 et

View File

@@ -1,5 +1,5 @@
/* This modules is based on the params.c module from Samba, written by Karl Auer
and much modifed by Christopher Hertel. */
and much modified by Christopher Hertel. */
/*
* This program is free software; you can redistribute it and/or modify
@@ -59,7 +59,7 @@
* beginning with either a semicolon (';') or a pound sign ('#').
*
* All whitespace in section names and parameter names is compressed
* to single spaces. Leading and trailing whitespace is stipped from
* to single spaces. Leading and trailing whitespace is stripped from
* both names and values.
*
* Only the first equals sign in a parameter line is significant.
@@ -153,7 +153,7 @@ static int EatComment( FILE *InFile )
static int Continuation( char *line, int pos )
/* ------------------------------------------------------------------------ **
* Scan backards within a string to discover if the last non-whitespace
* Scan backwards within a string to discover if the last non-whitespace
* character is a line-continuation character ('\\').
*
* Input: line - A pointer to a buffer containing the string to be

24
pipe.c
View File

@@ -4,7 +4,7 @@
* Copyright (C) 1996-2000 Andrew Tridgell
* Copyright (C) 1996 Paul Mackerras
* Copyright (C) 2001, 2002 Martin Pool <mbp@samba.org>
* Copyright (C) 2004-2014 Wayne Davison
* Copyright (C) 2004-2020 Wayne Davison
*
* 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
@@ -66,10 +66,10 @@ pid_t piped_child(char **command, int *f_in, int *f_out)
}
if (pid == 0) {
if (dup2(to_child_pipe[0], STDIN_FILENO) < 0 ||
close(to_child_pipe[1]) < 0 ||
close(from_child_pipe[0]) < 0 ||
dup2(from_child_pipe[1], STDOUT_FILENO) < 0) {
if (dup2(to_child_pipe[0], STDIN_FILENO) < 0
|| close(to_child_pipe[1]) < 0
|| close(from_child_pipe[0]) < 0
|| dup2(from_child_pipe[1], STDOUT_FILENO) < 0) {
rsyserr(FERROR, errno, "Failed to dup/close");
exit_cleanup(RERR_IPC);
}
@@ -116,8 +116,7 @@ pid_t local_child(int argc, char **argv, int *f_in, int *f_out,
/* The parent process is always the sender for a local rsync. */
assert(am_sender);
if (fd_pair(to_child_pipe) < 0 ||
fd_pair(from_child_pipe) < 0) {
if (fd_pair(to_child_pipe) < 0 || fd_pair(from_child_pipe) < 0) {
rsyserr(FERROR, errno, "pipe");
exit_cleanup(RERR_IPC);
}
@@ -150,10 +149,10 @@ pid_t local_child(int argc, char **argv, int *f_in, int *f_out,
}
}
if (dup2(to_child_pipe[0], STDIN_FILENO) < 0 ||
close(to_child_pipe[1]) < 0 ||
close(from_child_pipe[0]) < 0 ||
dup2(from_child_pipe[1], STDOUT_FILENO) < 0) {
if (dup2(to_child_pipe[0], STDIN_FILENO) < 0
|| close(to_child_pipe[1]) < 0
|| close(from_child_pipe[0]) < 0
|| dup2(from_child_pipe[1], STDOUT_FILENO) < 0) {
rsyserr(FERROR, errno, "Failed to dup/close");
exit_cleanup(RERR_IPC);
}
@@ -167,8 +166,7 @@ pid_t local_child(int argc, char **argv, int *f_in, int *f_out,
child_main(argc, argv);
}
if (close(from_child_pipe[1]) < 0 ||
close(to_child_pipe[0]) < 0) {
if (close(from_child_pipe[1]) < 0 || close(to_child_pipe[0]) < 0) {
rsyserr(FERROR, errno, "Failed to close");
exit_cleanup(RERR_IPC);
}

View File

@@ -626,7 +626,7 @@ expandNextArg(/*@special@*/ poptContext con, const char * s)
pos = te - t;
t = realloc(t, tn);
te = t + pos;
strncpy(te, a, alen); te += alen;
memcpy(te, a, alen+1); te += alen;
continue;
/*@notreached@*/ /*@switchbreak@*/ break;
default:

View File

@@ -12,8 +12,8 @@
# The script stops after the first successful action.
dir=`dirname $0`
if test x"$dir" != x -a x"$dir" != x.; then
cd "$dir"
if test x"$dir" = x; then
dir=.
fi
if test $# = 0; then
@@ -23,21 +23,20 @@ fi
for action in "${@}"; do
case "$action" in
build|make)
make -f prepare-source.mak
(cd $dir && make -f prepare-source.mak)
;;
fetch)
if perl --version >/dev/null 2>/dev/null; then
files='c*'
else
files='[cp]*'
$dir/rsync-ssl -iip --no-motd rsync://download.samba.org/rsyncftp/generated-files/'[ca]*' $dir
if ! perl --version >/dev/null 2>/dev/null; then
$dir/rsync-ssl -iip --no-motd rsync://download.samba.org/rsyncftp/generated-files/'p*' .
fi
rsync -pvz rsync://rsync.samba.org/rsyncftp/generated-files/"$files" .
;;
fetchgen)
rsync -pvz rsync://rsync.samba.org/rsyncftp/generated-files/'*' .
$dir/rsync-ssl -iip --no-motd rsync://download.samba.org/rsyncftp/generated-files/'[ca]*' $dir
$dir/rsync-ssl -iip --no-motd rsync://download.samba.org/rsyncftp/generated-files/'[^ca]*' .
;;
fetchSRC)
rsync -pvrz --exclude=/.git/ rsync://rsync.samba.org/ftp/pub/unpacked/rsync/ .
./rsync-ssl -iipr --no-motd --exclude=/.git/ rsync://download.samba.org/ftp/pub/unpacked/rsync/ .
;;
*)
echo "Unknown action: $action"

View File

@@ -1,5 +1,8 @@
conf: configure.sh config.h.in
aclocal.m4: m4/*.m4
aclocal -I m4
configure.sh: configure.ac aclocal.m4
autoconf -o configure.sh

View File

@@ -4,7 +4,7 @@
* Copyright (C) 1996-2000 Andrew Tridgell
* Copyright (C) 1996 Paul Mackerras
* Copyright (C) 2001, 2002 Martin Pool <mbp@samba.org>
* Copyright (C) 2003-2014 Wayne Davison
* Copyright (C) 2003-2020 Wayne Davison
*
* 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
@@ -25,11 +25,15 @@
extern int am_server;
extern int flist_eof;
extern int quiet;
extern int need_unsorted_flist;
extern int output_needs_newline;
extern int stdout_format_has_i;
extern struct stats stats;
extern struct file_list *cur_flist;
BOOL want_progress_now = False;
#define PROGRESS_HISTORY_SECS 5
#ifdef GETPGRP_VOID
@@ -62,8 +66,7 @@ static unsigned long msdiff(struct timeval *t1, struct timeval *t2)
* printed for this file, so we should output a newline. (Not
* necessarily the same as all bytes being received.)
**/
static void rprint_progress(OFF_T ofs, OFF_T size, struct timeval *now,
int is_last)
static void rprint_progress(OFF_T ofs, OFF_T size, struct timeval *now, int is_last)
{
char rembuf[64], eol[128];
const char *units;
@@ -88,8 +91,7 @@ static void rprint_progress(OFF_T ofs, OFF_T size, struct timeval *now,
is_last = 0;
}
/* Compute stats based on the starting info. */
if (!ph_start.time.tv_sec
|| !(diff = msdiff(&ph_start.time, now)))
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. */
@@ -99,8 +101,7 @@ static void rprint_progress(OFF_T ofs, OFF_T size, struct timeval *now,
/* Compute stats based on recent progress. */
if (!(diff = msdiff(&ph_list[oldest_hpos].time, now)))
diff = 1;
rate = (double) (ofs - ph_list[oldest_hpos].ofs) * 1000.0
/ diff / 1024.0;
rate = (double) (ofs - ph_list[oldest_hpos].ofs) * 1000.0 / diff / 1024.0;
remain = rate ? (double) (size - ofs) / rate / 1000.0 : 0.0;
}
@@ -127,12 +128,22 @@ static void rprint_progress(OFF_T ofs, OFF_T size, struct timeval *now,
pct = ofs == size ? 100 : (int) (100.0 * ofs / size);
rprintf(FCLIENT, "\r%15s %3d%% %7.2f%s %s%s",
human_num(ofs), pct, rate, units, rembuf, eol);
if (!is_last) {
if (!is_last && !quiet) {
output_needs_newline = 1;
rflush(FCLIENT);
}
}
void progress_init(void)
{
if (!am_server && !INFO_GTE(PROGRESS, 1)) {
struct timeval now;
gettimeofday(&now, NULL);
ph_start.time.tv_sec = now.tv_sec;
ph_start.time.tv_usec = now.tv_usec;
}
}
void set_current_file_index(struct file_struct *file, int ndx)
{
if (!file)
@@ -144,12 +155,21 @@ void set_current_file_index(struct file_struct *file, int ndx)
current_file_index -= cur_flist->flist_num;
}
void instant_progress(const char *fname)
{
/* We only get here if want_progress_now is True */
if (!stdout_format_has_i && !INFO_GTE(NAME, 1))
rprintf(FINFO, "%s\n", fname);
end_progress(0);
want_progress_now = False;
}
void end_progress(OFF_T size)
{
if (!am_server) {
struct timeval now;
gettimeofday(&now, NULL);
if (INFO_GTE(PROGRESS, 2)) {
if (INFO_GTE(PROGRESS, 2) || want_progress_now) {
rprint_progress(stats.total_transferred_size,
stats.total_size, &now, True);
} else {

View File

@@ -3,7 +3,7 @@
*
* Copyright (C) 1996-2000 Andrew Tridgell
* Copyright (C) 1996 Paul Mackerras
* Copyright (C) 2003-2014 Wayne Davison
* Copyright (C) 2003-2020 Wayne Davison
*
* 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
@@ -30,6 +30,7 @@ extern int inc_recurse;
extern int log_before_transfer;
extern int stdout_format_has_i;
extern int logfile_format_has_i;
extern int want_xattr_optim;
extern int csum_length;
extern int read_batch;
extern int write_batch;
@@ -38,6 +39,7 @@ extern int protocol_version;
extern int relative_paths;
extern int preserve_hard_links;
extern int preserve_perms;
extern int write_devices;
extern int preserve_xattrs;
extern int basis_dir_cnt;
extern int make_backups;
@@ -47,11 +49,14 @@ extern int append_mode;
extern int sparse_files;
extern int preallocate_files;
extern int keep_partial;
extern int checksum_len;
extern int checksum_seed;
extern int whole_file;
extern int inplace;
extern int inplace_partial;
extern int allowed_lull;
extern int delay_updates;
extern int xfersum_type;
extern BOOL want_progress_now;
extern mode_t orig_umask;
extern struct stats stats;
extern char *tmpdir;
@@ -60,11 +65,12 @@ extern char *basis_dir[MAX_BASIS_DIRS+1];
extern char sender_file_sum[MAX_DIGEST_LEN];
extern struct file_list *cur_flist, *first_flist, *dir_flist;
extern filter_rule_list daemon_filter_list;
extern OFF_T preallocated_len;
static struct bitbag *delayed_bits = NULL;
static int phase = 0, redoing = 0;
static flist_ndx_list batch_redo_list;
/* We're either updating the basis file or an identical copy: */
/* This is non-0 when we are updating the basis file or an identical copy: */
static int updating_basis_or_equiv;
#define TMPNAME_SUFFIX ".XXXXXX"
@@ -228,33 +234,38 @@ int open_tmpfile(char *fnametmp, const char *fname, struct file_struct *file)
}
static int receive_data(int f_in, char *fname_r, int fd_r, OFF_T size_r,
const char *fname, int fd, OFF_T total_size)
const char *fname, int fd, struct file_struct *file, int inplace_sizing)
{
static char file_sum1[MAX_DIGEST_LEN];
struct map_struct *mapbuf;
struct sum_struct sum;
int sum_len;
int32 len;
OFF_T total_size = F_LENGTH(file);
OFF_T offset = 0;
OFF_T offset2;
char *data;
int32 i;
char *map = NULL;
#ifdef SUPPORT_PREALLOCATION
#ifdef PREALLOCATE_NEEDS_TRUNCATE
OFF_T preallocated_len = 0;
#endif
if (preallocate_files && fd != -1 && total_size > 0 && (!inplace || total_size > size_r)) {
#ifdef SUPPORT_PREALLOCATION
if (preallocate_files && fd != -1 && total_size > 0 && (!inplace_sizing || total_size > size_r)) {
/* Try to preallocate enough space for file's eventual length. Can
* reduce fragmentation on filesystems like ext4, xfs, and NTFS. */
if (do_fallocate(fd, 0, total_size) == 0) {
#ifdef PREALLOCATE_NEEDS_TRUNCATE
preallocated_len = total_size;
#endif
} else
if ((preallocated_len = do_fallocate(fd, 0, total_size)) < 0)
rsyserr(FWARNING, errno, "do_fallocate %s", full_fname(fname));
}
} else
#endif
if (inplace_sizing) {
#ifdef HAVE_FTRUNCATE
/* The most compatible way to create a sparse file is to start with no length. */
if (sparse_files > 0 && whole_file && fd >= 0 && do_ftruncate(fd, 0) == 0)
preallocated_len = 0;
else
#endif
preallocated_len = size_r;
} else
preallocated_len = 0;
read_sum_head(f_in, &sum);
@@ -268,7 +279,7 @@ static int receive_data(int f_in, char *fname_r, int fd_r, OFF_T size_r,
} else
mapbuf = NULL;
sum_init(checksum_seed);
sum_init(xfersum_type, checksum_seed);
if (append_mode > 0) {
OFF_T j;
@@ -316,7 +327,7 @@ static int receive_data(int f_in, char *fname_r, int fd_r, OFF_T size_r,
sum_update(data, i);
if (fd != -1 && write_file(fd,data,i) != i)
if (fd != -1 && write_file(fd, 0, offset, data, i) != i)
goto report_write_error;
offset += i;
continue;
@@ -346,70 +357,58 @@ static int receive_data(int f_in, char *fname_r, int fd_r, OFF_T size_r,
if (updating_basis_or_equiv) {
if (offset == offset2 && fd != -1) {
OFF_T pos;
if (flush_write_file(fd) < 0)
if (skip_matched(fd, offset, map, len) < 0)
goto report_write_error;
offset += len;
if ((pos = do_lseek(fd, len, SEEK_CUR)) != offset) {
rsyserr(FERROR_XFER, errno,
"lseek of %s returned %s, not %s",
full_fname(fname),
big_num(pos), big_num(offset));
exit_cleanup(RERR_FILEIO);
}
continue;
}
}
if (fd != -1 && map && write_file(fd, map, len) != (int)len)
if (fd != -1 && map && write_file(fd, 0, offset, map, len) != (int)len)
goto report_write_error;
offset += len;
}
if (flush_write_file(fd) < 0)
goto report_write_error;
if (fd != -1 && offset > 0) {
if (sparse_files > 0) {
if (sparse_end(fd, offset) != 0)
goto report_write_error;
} else if (flush_write_file(fd) < 0) {
report_write_error:
rsyserr(FERROR_XFER, errno, "write failed on %s", full_fname(fname));
exit_cleanup(RERR_FILEIO);
}
}
#ifdef HAVE_FTRUNCATE
/* inplace: New data could be shorter than old data.
* preallocate_files: total_size could have been an overestimate.
* Cut off any extra preallocated zeros from dest file. */
if ((inplace
#ifdef PREALLOCATE_NEEDS_TRUNCATE
|| preallocated_len > offset
#endif
) && fd != -1 && do_ftruncate(fd, offset) < 0) {
rsyserr(FERROR_XFER, errno, "ftruncate failed on %s",
full_fname(fname));
if ((inplace_sizing || preallocated_len > offset) && fd != -1 && !IS_DEVICE(file->mode)) {
if (do_ftruncate(fd, offset) < 0)
rsyserr(FERROR_XFER, errno, "ftruncate failed on %s", full_fname(fname));
}
#endif
if (INFO_GTE(PROGRESS, 1))
end_progress(total_size);
if (fd != -1 && offset > 0 && sparse_end(fd, offset) != 0) {
report_write_error:
rsyserr(FERROR_XFER, errno, "write failed on %s",
full_fname(fname));
exit_cleanup(RERR_FILEIO);
}
if (sum_end(file_sum1) != checksum_len)
overflow_exit("checksum_len"); /* Impossible... */
sum_len = sum_end(file_sum1);
if (mapbuf)
unmap_file(mapbuf);
read_buf(f_in, sender_file_sum, checksum_len);
read_buf(f_in, sender_file_sum, sum_len);
if (DEBUG_GTE(DELTASUM, 2))
rprintf(FINFO,"got file_sum\n");
if (fd != -1 && memcmp(file_sum1, sender_file_sum, checksum_len) != 0)
if (fd != -1 && memcmp(file_sum1, sender_file_sum, sum_len) != 0)
return 0;
return 1;
}
static void discard_receive_data(int f_in, OFF_T length)
static void discard_receive_data(int f_in, struct file_struct *file)
{
receive_data(f_in, NULL, -1, 0, NULL, -1, length);
receive_data(f_in, NULL, -1, 0, NULL, -1, file, 0);
}
static void handle_delayed_updates(char *local_name)
@@ -520,7 +519,7 @@ int recv_files(int f_in, int f_out, char *local_name)
int iflags, xlen;
char *fname, fbuf[MAXPATHLEN];
char xname[MAXPATHLEN];
char fnametmp[MAXPATHLEN];
char *fnametmp, fnametmpbuf[MAXPATHLEN];
char *fnamecmp, *partialptr;
char fnamecmpbuf[MAXPATHLEN];
uchar fnamecmp_type;
@@ -532,7 +531,7 @@ int recv_files(int f_in, int f_out, char *local_name)
#ifdef SUPPORT_ACLS
const char *parent_dirname = "";
#endif
int ndx, recv_ok;
int ndx, recv_ok, one_inplace;
if (DEBUG_GTE(RECV, 1))
rprintf(FINFO, "recv_files(%d) starting\n", cur_flist->used);
@@ -540,6 +539,8 @@ int recv_files(int f_in, int f_out, char *local_name)
if (delay_updates)
delayed_bits = bitbag_create(cur_flist->used + 1);
progress_init();
while (1) {
cleanup_disable();
@@ -547,9 +548,10 @@ int recv_files(int f_in, int f_out, char *local_name)
ndx = read_ndx_and_attrs(f_in, f_out, &iflags, &fnamecmp_type,
xname, &xlen);
if (ndx == NDX_DONE) {
if (!am_server && INFO_GTE(PROGRESS, 2) && cur_flist) {
if (!am_server && cur_flist) {
set_current_file_index(NULL, 0);
end_progress(0);
if (INFO_GTE(PROGRESS, 2))
end_progress(0);
}
if (inc_recurse && first_flist) {
if (read_batch) {
@@ -582,15 +584,23 @@ int recv_files(int f_in, int f_out, char *local_name)
if (DEBUG_GTE(RECV, 1))
rprintf(FINFO, "recv_files(%s)\n", fname);
if (daemon_filter_list.head && (*fname != '.' || fname[1] != '\0')
&& check_filter(&daemon_filter_list, FLOG, fname, 0) < 0) {
rprintf(FERROR, "attempt to hack rsync failed.\n");
exit_cleanup(RERR_PROTOCOL);
}
#ifdef SUPPORT_XATTRS
if (preserve_xattrs && iflags & ITEM_REPORT_XATTR && do_xfers)
if (preserve_xattrs && iflags & ITEM_REPORT_XATTR && do_xfers
&& !(want_xattr_optim && BITS_SET(iflags, ITEM_XNAME_FOLLOWS|ITEM_LOCAL_CHANGE)))
recv_xattr_request(file, f_in);
#endif
if (!(iflags & ITEM_TRANSFER)) {
maybe_log_item(file, iflags, itemizing, xname);
#ifdef SUPPORT_XATTRS
if (preserve_xattrs && iflags & ITEM_REPORT_XATTR && do_xfers)
if (preserve_xattrs && iflags & ITEM_REPORT_XATTR && do_xfers
&& !BITS_SET(iflags, ITEM_XNAME_FOLLOWS|ITEM_LOCAL_CHANGE))
set_file_attrs(fname, file, NULL, fname, 0);
#endif
if (iflags & ITEM_IS_NEW) {
@@ -641,19 +651,13 @@ int recv_files(int f_in, int f_out, char *local_name)
stats.created_files++;
}
if (!am_server && INFO_GTE(PROGRESS, 1))
if (!am_server)
set_current_file_index(file, ndx);
stats.xferred_files++;
stats.total_transferred_size += F_LENGTH(file);
cleanup_got_literal = 0;
if (daemon_filter_list.head
&& check_filter(&daemon_filter_list, FLOG, fname, 0) < 0) {
rprintf(FERROR, "attempt to hack rsync failed.\n");
exit_cleanup(RERR_PROTOCOL);
}
if (read_batch) {
int wanted = redoing
? we_want_redo(ndx)
@@ -663,25 +667,24 @@ int recv_files(int f_in, int f_out, char *local_name)
"(Skipping batched update for%s \"%s\")\n",
redoing ? " resend of" : "",
fname);
discard_receive_data(f_in, F_LENGTH(file));
discard_receive_data(f_in, file);
file->flags |= FLAG_FILE_SENT;
continue;
}
}
if (!log_before_transfer)
remember_initial_stats();
remember_initial_stats();
if (!do_xfers) { /* log the transfer */
log_item(FCLIENT, file, iflags, NULL);
if (read_batch)
discard_receive_data(f_in, F_LENGTH(file));
discard_receive_data(f_in, file);
continue;
}
if (write_batch < 0) {
log_item(FCLIENT, file, iflags, NULL);
if (!am_server)
discard_receive_data(f_in, F_LENGTH(file));
discard_receive_data(f_in, file);
if (inc_recurse)
send_msg_int(MSG_SUCCESS, ndx);
continue;
@@ -726,7 +729,7 @@ int recv_files(int f_in, int f_out, char *local_name)
break;
}
if (!fnamecmp || (daemon_filter_list.head
&& check_filter(&daemon_filter_list, FLOG, fname, 0) < 0)) {
&& check_filter(&daemon_filter_list, FLOG, fnamecmp, 0) < 0)) {
fnamecmp = fname;
fnamecmp_type = FNAMECMP_FNAME;
}
@@ -750,6 +753,7 @@ int recv_files(int f_in, int f_out, char *local_name)
if (fd1 == -1 && protocol_version < 29) {
if (fnamecmp != fname) {
fnamecmp = fname;
fnamecmp_type = FNAMECMP_FNAME;
fd1 = do_open(fnamecmp, O_RDONLY, 0);
}
@@ -758,12 +762,14 @@ int recv_files(int f_in, int f_out, char *local_name)
pathjoin(fnamecmpbuf, sizeof fnamecmpbuf,
basis_dir[0], fname);
fnamecmp = fnamecmpbuf;
fnamecmp_type = FNAMECMP_BASIS_DIR_LOW;
fd1 = do_open(fnamecmp, O_RDONLY, 0);
}
}
updating_basis_or_equiv = inplace
&& (fnamecmp == fname || fnamecmp_type == FNAMECMP_BACKUP);
one_inplace = inplace_partial && fnamecmp_type == FNAMECMP_PARTIAL_DIR;
updating_basis_or_equiv = one_inplace
|| (inplace && (fnamecmp == fname || fnamecmp_type == FNAMECMP_BACKUP));
if (fd1 == -1) {
st.st_mode = 0;
@@ -771,7 +777,7 @@ int recv_files(int f_in, int f_out, char *local_name)
} else if (do_fstat(fd1,&st) != 0) {
rsyserr(FERROR_XFER, errno, "fstat %s failed",
full_fname(fnamecmp));
discard_receive_data(f_in, F_LENGTH(file));
discard_receive_data(f_in, file);
close(fd1);
if (inc_recurse)
send_msg_int(MSG_NO_SEND, ndx);
@@ -786,18 +792,21 @@ int recv_files(int f_in, int f_out, char *local_name)
*/
rprintf(FERROR_XFER, "recv_files: %s is a directory\n",
full_fname(fnamecmp));
discard_receive_data(f_in, F_LENGTH(file));
discard_receive_data(f_in, file);
close(fd1);
if (inc_recurse)
send_msg_int(MSG_NO_SEND, ndx);
continue;
}
if (fd1 != -1 && !S_ISREG(st.st_mode)) {
if (fd1 != -1 && !(S_ISREG(st.st_mode) || (write_devices && IS_DEVICE(st.st_mode)))) {
close(fd1);
fd1 = -1;
}
if (fd1 != -1 && IS_DEVICE(st.st_mode) && st.st_size == 0)
st.st_size = get_device_size(fd1, fname);
/* If we're not preserving permissions, change the file-list's
* mode based on the local permissions and some heuristics. */
if (!preserve_perms) {
@@ -810,26 +819,27 @@ int recv_files(int f_in, int f_out, char *local_name)
parent_dirname = dn;
}
#endif
file->mode = dest_mode(file->mode, st.st_mode,
dflt_perms, exists);
file->mode = dest_mode(file->mode, st.st_mode, dflt_perms, exists);
}
/* We now check to see if we are writing the file "inplace" */
if (inplace) {
fd2 = do_open(fname, O_WRONLY|O_CREAT, 0600);
if (inplace || one_inplace) {
fnametmp = one_inplace ? partialptr : fname;
fd2 = do_open(fnametmp, O_WRONLY|O_CREAT, 0600);
if (fd2 == -1) {
rsyserr(FERROR_XFER, errno, "open %s failed",
full_fname(fname));
full_fname(fnametmp));
} else if (updating_basis_or_equiv)
cleanup_set(NULL, NULL, file, fd1, fd2);
} else {
fnametmp = fnametmpbuf;
fd2 = open_tmpfile(fnametmp, fname, file);
if (fd2 != -1)
cleanup_set(fnametmp, partialptr, file, fd1, fd2);
}
if (fd2 == -1) {
discard_receive_data(f_in, F_LENGTH(file));
discard_receive_data(f_in, file);
if (fd1 != -1)
close(fd1);
if (inc_recurse)
@@ -844,10 +854,11 @@ int recv_files(int f_in, int f_out, char *local_name)
rprintf(FINFO, "%s\n", fname);
/* recv file data */
recv_ok = receive_data(f_in, fnamecmp, fd1, st.st_size,
fname, fd2, F_LENGTH(file));
recv_ok = receive_data(f_in, fnamecmp, fd1, st.st_size, fname, fd2, file, inplace || one_inplace);
log_item(log_code, file, iflags, NULL);
if (want_progress_now)
instant_progress(fname);
if (fd1 != -1)
close(fd1);
@@ -860,19 +871,19 @@ int recv_files(int f_in, int f_out, char *local_name)
if ((recv_ok && (!delay_updates || !partialptr)) || inplace) {
if (partialptr == fname)
partialptr = NULL;
if (!finish_transfer(fname, fnametmp, fnamecmp,
partialptr, file, recv_ok, 1))
if (!finish_transfer(fname, fnametmp, fnamecmp, partialptr, file, recv_ok, 1))
recv_ok = -1;
else if (fnamecmp == partialptr) {
do_unlink(partialptr);
if (!one_inplace)
do_unlink(partialptr);
handle_partial_dir(partialptr, PDIR_DELETE);
}
} else if (keep_partial && partialptr) {
} else if (keep_partial && partialptr && !one_inplace) {
if (!handle_partial_dir(partialptr, PDIR_CREATE)) {
rprintf(FERROR,
"Unable to create partial-dir for %s -- discarding %s.\n",
local_name ? local_name : f_name(file, NULL),
recv_ok ? "completed file" : "partial file");
"Unable to create partial-dir for %s -- discarding %s.\n",
local_name ? local_name : f_name(file, NULL),
recv_ok ? "completed file" : "partial file");
do_unlink(fnametmp);
recv_ok = -1;
} else if (!finish_transfer(partialptr, fnametmp, fnamecmp, NULL,
@@ -883,7 +894,7 @@ int recv_files(int f_in, int f_out, char *local_name)
recv_ok = 2;
} else
partialptr = NULL;
} else
} else if (!one_inplace)
do_unlink(fnametmp);
cleanup_disable();
@@ -930,7 +941,7 @@ int recv_files(int f_in, int f_out, char *local_name)
} else if (inc_recurse)
send_msg_int(MSG_NO_SEND, ndx);
break;
}
}
case -1:
if (inc_recurse)
send_msg_int(MSG_NO_SEND, ndx);

View File

@@ -1,7 +1,7 @@
/*
* A pre-compilation helper program to aid in the creation of rounding.h.
*
* Copyright (C) 2007-2014 Wayne Davison
* Copyright (C) 2007-2020 Wayne Davison
*
* 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
@@ -23,8 +23,8 @@
#define SIZEOF(x) ((long int)sizeof (x))
struct test {
union file_extras extras[ARRAY_LEN];
struct file_struct file;
union file_extras extras[ARRAY_LEN];
struct file_struct file;
};
#define ACTUAL_SIZE SIZEOF(struct test)
@@ -32,7 +32,7 @@ struct test {
int main(UNUSED(int argc), UNUSED(char *argv[]))
{
static int test_array[1 - 2 * (ACTUAL_SIZE != EXPECTED_SIZE)];
test_array[0] = 0;
return 0;
static int test_array[1 - 2 * (ACTUAL_SIZE != EXPECTED_SIZE)];
test_array[0] = 0;
return 0;
}

190
rsync-ssl Executable file
View File

@@ -0,0 +1,190 @@
#!/bin/bash
# This script uses openssl, gnutls, or stunnel to secure an rsync daemon connection.
# By default this script takes rsync args and hands them off to the actual
# rsync command with an --rsh option that makes it open an SSL connection to an
# rsync daemon. See the rsync-ssl manpage for usage details and env variables.
# When the first arg is --HELPER, we are being used by rsync as an --rsh helper
# script, and the args are (note the trailing dot):
#
# rsync-ssl --HELPER HOSTNAME rsync --server --daemon .
#
# --HELPER is not a user-facing option, so it is not documented in the manpage.
# The first SSL setup was based on: http://dozzie.jarowit.net/trac/wiki/RsyncSSL
# Note that an stunnel connection requires at least version 4.x of stunnel.
function rsync_ssl_run {
case "$*" in
*rsync://*) ;;
*::*) ;;
*)
echo "You must use rsync-ssl with a daemon-style hostname." 1>&2
exit 1
;;
esac
exec rsync --rsh="$0 --HELPER" "${@}"
}
function rsync_ssl_helper {
if [[ -z "$RSYNC_SSL_TYPE" ]]; then
found=`path_search openssl stunnel4 stunnel` || exit 1
if [[ "$found" == */openssl ]]; then
RSYNC_SSL_TYPE=openssl
RSYNC_SSL_OPENSSL="$found"
elif [[ "$found" == */gnutls-cli ]]; then
RSYNC_SSL_TYPE=gnutls
RSYNC_SSL_GNUTLS="$found"
else
RSYNC_SSL_TYPE=stunnel
RSYNC_SSL_STUNNEL="$found"
fi
fi
case "$RSYNC_SSL_TYPE" in
openssl)
if [[ -z "$RSYNC_SSL_OPENSSL" ]]; then
RSYNC_SSL_OPENSSL=`path_search openssl` || exit 1
fi
optsep=' '
;;
gnutls)
if [[ -z "$RSYNC_SSL_GNUTLS" ]]; then
RSYNC_SSL_GNUTLS=`path_search gnutls-cli` || exit 1
fi
optsep=' '
;;
stunnel)
if [[ -z "$RSYNC_SSL_STUNNEL" ]]; then
RSYNC_SSL_STUNNEL=`path_search stunnel4 stunnel` || exit 1
fi
optsep=' = '
;;
*)
echo "The RSYNC_SSL_TYPE specifies an unknown type: $RSYNC_SSL_TYPE" 1>&2
exit 1
;;
esac
if [[ -z "$RSYNC_SSL_CERT" ]]; then
certopt=""
gnutls_cert_opt=""
else
certopt="cert$optsep$RSYNC_SSL_CERT"
gnutls_cert_opt="--x509keyfile=$RSYNC_SSL_CERT"
fi
if [[ -z ${RSYNC_SSL_CA_CERT+x} ]]; then
# RSYNC_SSL_CA_CERT unset - default CA set AND verify:
# openssl:
caopt="-verify_return_error -verify 4"
# gnutls:
gnutls_opts=""
# stunnel:
# Since there is no way of using the default CA certificate collection,
# we cannot do any verification. Thus, stunnel should really only be
# used if nothing else is available.
cafile=""
verify=""
elif [[ "$RSYNC_SSL_CA_CERT" == "" ]]; then
# RSYNC_SSL_CA_CERT set but empty -do NO verifications:
# openssl:
caopt="-verify 1"
# gnutls:
gnutls_opts="--insecure"
# stunnel:
cafile=""
verify="verifyChain = no"
else
# RSYNC_SSL_CA_CERT set - use CA AND verify:
# openssl:
caopt="-CAfile $RSYNC_SSL_CA_CERT -verify_return_error -verify 4"
# gnutls:
gnutls_opts="--x509cafile=$RSYNC_SSL_CA_CERT"
# stunnel:
cafile="CAfile = $RSYNC_SSL_CA_CERT"
verify="verifyChain = yes"
fi
port="${RSYNC_PORT:-0}"
if [[ "$port" == 0 ]]; then
port="${RSYNC_SSL_PORT:-874}"
fi
# If the user specified USER@HOSTNAME::module, then rsync passes us
# the -l USER option too, so we must be prepared to ignore it.
if [[ "$1" == "-l" ]]; then
shift 2
fi
hostname="$1"
shift
if [[ -z "$hostname" || "$1" != rsync || "$2" != --server || "$3" != --daemon ]]; then
echo "Usage: rsync-ssl --HELPER HOSTNAME rsync --server --daemon ." 1>&2
exit 1
fi
if [[ $RSYNC_SSL_TYPE == openssl ]]; then
exec $RSYNC_SSL_OPENSSL s_client $caopt $certopt -quiet -verify_quiet -servername $hostname -connect $hostname:$port
elif [[ $RSYNC_SSL_TYPE == gnutls ]]; then
exec $RSYNC_SSL_GNUTLS --logfile=/dev/null $gnutls_cert_opt $gnutls_opts $hostname:$port
else
# devzero@web.de came up with this no-tmpfile calling syntax:
exec $RSYNC_SSL_STUNNEL -fd 10 11<&0 <<EOF 10<&0 0<&11 11<&-
foreground = yes
debug = crit
connect = $hostname:$port
client = yes
TIMEOUTclose = 0
$verify
$certopt
$cafile
EOF
fi
}
function path_search {
IFS_SAVE="$IFS"
IFS=:
for prog in "${@}"; do
for dir in $PATH; do
[[ -z "$dir" ]] && dir=.
if [[ -f "$dir/$prog" && -x "$dir/$prog" ]]; then
echo "$dir/$prog"
IFS="$IFS_SAVE"
return 0
fi
done
done
IFS="$IFS_SAVE"
echo "Failed to find on your path: $*" 1>&2
echo "See the rsync-ssl manpage for configuration assistance." 1>&2
return 1
}
if [[ "$#" == 0 ]]; then
echo "Usage: rsync-ssl [--type=SSL_TYPE] RSYNC_ARG [...]" 1>&2
echo "The SSL_TYPE can be openssl or stunnel"
exit 1
fi
if [[ "$1" = --help || "$1" = -h ]]; then
exec rsync --help
fi
if [[ "$1" == --HELPER ]]; then
shift
rsync_ssl_helper "${@}"
fi
if [[ "$1" == --type=* ]]; then
export RSYNC_SSL_TYPE="${1/--type=/}"
shift
fi
rsync_ssl_run "${@}"

98
rsync-ssl.1.md Normal file
View File

@@ -0,0 +1,98 @@
# NAME
rsync-ssl - a helper script for connecting to an ssl rsync daemon
# SYNOPSIS
```
rsync-ssl [--type=SSL_TYPE] RSYNC_ARGS
```
# DESCRIPTION
The rsync-ssl script helps you to run an rsync copy to/from an rsync daemon
that requires ssl connections.
# OPTIONS
If the **first** arg is a `--type=SSL_TYPE` option, the script will only use
that particular program to open an ssl connection instead of trying to find an
openssl or stunnel executable via a simple heuristic (assuming that the
`RSYNC_SSL_TYPE` environment variable is not set as well -- see below). This
option must specify one of `openssl` or `stunnel`. The equal sign is
required for this particular option.
All the other options are passed through to the rsync command, so consult the
**rsync** manpage for more information on how it works.
# ENVIRONMENT VARIABLES
The ssl helper scripts are affected by the following environment variables:
0. `RSYNC_SSL_TYPE` Specifies the program type that should be used to open the
ssl connection. It must be one of `openssl` or `stunnel`. The
`--type=SSL_TYPE` option overrides this, when specified.
0. `RSYNC_SSL_PORT` If specified, the value is the port number that is used as
the default when the user does not specify a port in their rsync command.
When not specified, the default port number is 874. (Note that older rsync
versions (prior to 3.2.0) did not communicate an overriding port number
value to the helper script.)
0. `RSYNC_SSL_CERT` If specified, the value is a filename that contains a
certificate to use for the connection.
0. `RSYNC_SSL_CA_CERT` If specified, the value is a filename that contains a
certificate authority certificate that is used to validate the connection.
0. `RSYNC_SSL_OPENSSL` Specifies the openssl executable to run when the
connection type is set to openssl. If unspecified, the $PATH is searched
for "openssl".
0. `RSYNC_SSL_GNUTLS` Specifies the gnutls-cli executable to run when the
connection type is set to gnutls. If unspecified, the $PATH is searched
for "gnutls-cli".
0. `RSYNC_SSL_STUNNEL` Specifies the stunnel executable to run when the
connection type is set to stunnel. If unspecified, the $PATH is searched
first for "stunnel4" and then for "stunnel".
# EXAMPLES
> rsync-ssl -aiv example.com::src/ dest
> rsync-ssl --type=openssl -aiv example.com::src/ dest
# SEE ALSO
**rsync**(1), **rsyncd.conf**(5)
# CAVEATS
Note that using an stunnel connection requires at least version 4 of stunnel,
which should be the case on modern systems. Also, it does not verify a
connection against the CA certificate collection, so it only encrypts the
connection without any cert validation unless you have specified the
certificate environment options.
This script also supports a `--type=gnutls` option, but at the time of this
release the gnutls-cli command was dropping output, making it unusable. If
that bug has been fixed in your version, feel free to put gnutls into an
exported RSYNC_SSL_TYPE environment variable to make its use the default.
# BUGS
Please report bugs! See the web site at <http://rsync.samba.org/>.
# VERSION
This man page is current for version @VERSION@ of rsync.
# CREDITS
rsync is distributed under the GNU General Public License. See the file
COPYING for details.
A web site is available at <http://rsync.samba.org/>. The site includes an
FAQ-O-Matic which may cover questions unanswered by this manual page.
# AUTHOR
This manpage was written by Wayne Davison.
Mailing lists for support and development are available at
<http://lists.samba.org/>.

View File

@@ -1,12 +0,0 @@
#!/bin/bash
# This script supports using stunnel to secure an rsync daemon connection.
# Note that this requires at least version 4.x of stunnel.
case "$@" in
*rsync://*) ;;
*::*) ;;
*)
echo "You must use rsync-ssl with a daemon-style hostname." 0>&1
exit 1
;;
esac
exec @bindir@/rsync --rsh=@bindir@/stunnel-rsync "${@}"

3935
rsync.1.md Normal file
View File

File diff suppressed because it is too large Load Diff

98
rsync.c
View File

@@ -3,7 +3,7 @@
*
* Copyright (C) 1996 Andrew Tridgell
* Copyright (C) 1996 Paul Mackerras
* Copyright (C) 2003-2014 Wayne Davison
* Copyright (C) 2003-2020 Wayne Davison
*
* 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
@@ -43,12 +43,14 @@ extern int am_starting_up;
extern int allow_8bit_chars;
extern int protocol_version;
extern int got_kill_signal;
extern int called_from_signal_handler;
extern int inc_recurse;
extern int inplace;
extern int flist_eof;
extern int file_old_total;
extern int keep_dirlinks;
extern int make_backups;
extern int sanitize_paths;
extern struct file_list *cur_flist, *first_flist, *dir_flist;
extern struct chmod_mode_struct *daemon_chmod_modes;
#ifdef ICONV_OPTION
@@ -61,6 +63,15 @@ iconv_t ic_chck = (iconv_t)-1;
iconv_t ic_send = (iconv_t)-1, ic_recv = (iconv_t)-1;
# endif
#define UPDATED_OWNER (1<<0)
#define UPDATED_GROUP (1<<1)
#define UPDATED_MTIME (1<<2)
#define UPDATED_ATIME (1<<3)
#define UPDATED_ACLS (1<<4)
#define UPDATED_MODE (1<<5)
#define UPDATED_TIMES (UPDATED_MTIME|UPDATED_ATIME)
static const char *default_charset(void)
{
# if defined HAVE_LIBCHARSET_H && defined HAVE_LOCALE_CHARSET
@@ -307,8 +318,7 @@ void send_protected_args(int fd, char *args[])
#endif
}
int read_ndx_and_attrs(int f_in, int f_out, int *iflag_ptr, uchar *type_ptr,
char *buf, int *len_ptr)
int read_ndx_and_attrs(int f_in, int f_out, int *iflag_ptr, uchar *type_ptr, char *buf, int *len_ptr)
{
int len, iflags = 0;
struct file_list *flist;
@@ -364,7 +374,7 @@ int read_ndx_and_attrs(int f_in, int f_out, int *iflag_ptr, uchar *type_ptr,
}
/* Send all the data we read for this flist to the generator. */
start_flist_forward(ndx);
flist = recv_file_list(f_in);
flist = recv_file_list(f_in, ndx);
flist->parent_ndx = ndx;
stop_flist_forward();
}
@@ -396,6 +406,11 @@ int read_ndx_and_attrs(int f_in, int f_out, int *iflag_ptr, uchar *type_ptr,
if (iflags & ITEM_XNAME_FOLLOWS) {
if ((len = read_vstring(f_in, buf, MAXPATHLEN)) < 0)
exit_cleanup(RERR_PROTOCOL);
if (sanitize_paths) {
sanitize_path(buf, buf, "", 0, SP_DEFAULT);
len = strlen(buf);
}
} else {
*buf = '\0';
len = -1;
@@ -452,6 +467,21 @@ mode_t dest_mode(mode_t flist_mode, mode_t stat_mode, int dflt_perms,
return new_mode;
}
static int same_mtime(struct file_struct *file, STRUCT_STAT *st, int extra_accuracy)
{
#ifdef ST_MTIME_NSEC
uint32 f1_nsec = F_MOD_NSEC_or_0(file);
uint32 f2_nsec = (uint32)st->ST_MTIME_NSEC;
#else
uint32 f1_nsec = 0, f2_nsec = 0;
#endif
if (extra_accuracy) /* ignore modify_window when setting the time after a transfer or checksum check */
return file->modtime == st->st_mtime && f1_nsec == f2_nsec;
return same_time(file->modtime, f1_nsec, st->st_mtime , f2_nsec);
}
int set_file_attrs(const char *fname, struct file_struct *file, stat_x *sxp,
const char *fnamecmp, int flags)
{
@@ -517,8 +547,8 @@ int set_file_attrs(const char *fname, struct file_struct *file, stat_x *sxp,
/* We shouldn't have attempted to change uid
* or gid unless have the privilege. */
rsyserr(FERROR_XFER, errno, "%s %s failed",
change_uid ? "chown" : "chgrp",
full_fname(fname));
change_uid ? "chown" : "chgrp",
full_fname(fname));
goto cleanup;
}
if (uid == (uid_t)-1 && sxp->st.st_uid != (uid_t)-1)
@@ -533,7 +563,10 @@ int set_file_attrs(const char *fname, struct file_struct *file, stat_x *sxp,
keep_dirlinks && S_ISDIR(sxp->st.st_mode));
}
}
updated = 1;
if (change_uid)
updated |= UPDATED_OWNER;
if (change_gid)
updated |= UPDATED_GROUP;
}
#ifdef SUPPORT_XATTRS
@@ -546,19 +579,39 @@ int set_file_attrs(const char *fname, struct file_struct *file, stat_x *sxp,
if (!preserve_times
|| (!(preserve_times & PRESERVE_DIR_TIMES) && S_ISDIR(sxp->st.st_mode))
|| (!(preserve_times & PRESERVE_LINK_TIMES) && S_ISLNK(sxp->st.st_mode)))
flags |= ATTRS_SKIP_MTIME;
if (!(flags & ATTRS_SKIP_MTIME)
&& cmp_time(sxp->st.st_mtime, file->modtime) != 0) {
int ret = set_modtime(fname, file->modtime, F_MOD_NSEC(file), sxp->st.st_mode);
flags |= ATTRS_SKIP_MTIME | ATTRS_SKIP_ATIME;
else if (sxp != &sx2)
memcpy(&sx2.st, &sxp->st, sizeof (sx2.st));
if (!atimes_ndx || S_ISDIR(sxp->st.st_mode))
flags |= ATTRS_SKIP_ATIME;
if (!(flags & ATTRS_SKIP_MTIME) && !same_mtime(file, &sxp->st, flags & ATTRS_ACCURATE_TIME)) {
sx2.st.st_mtime = file->modtime;
#ifdef ST_MTIME_NSEC
sx2.st.ST_MTIME_NSEC = F_MOD_NSEC_or_0(file);
#endif
updated |= UPDATED_MTIME;
}
if (!(flags & ATTRS_SKIP_ATIME)) {
time_t file_atime = F_ATIME(file);
if (flags & ATTRS_ACCURATE_TIME || !same_time(sxp->st.st_atime, 0, file_atime, 0)) {
sx2.st.st_atime = file_atime;
#ifdef ST_ATIME_NSEC
sx2.st.ST_ATIME_NSEC = 0;
#endif
updated |= UPDATED_ATIME;
}
}
if (updated & UPDATED_TIMES) {
int ret = set_times(fname, &sx2.st);
if (ret < 0) {
rsyserr(FERROR_XFER, errno, "failed to set times on %s",
full_fname(fname));
goto cleanup;
}
if (ret == 0) /* ret == 1 if symlink could not be set */
updated = 1;
else
if (ret > 0) { /* ret == 1 if symlink could not be set */
updated &= ~UPDATED_TIMES;
file->flags |= FLAG_TIME_FAILED;
}
}
#ifdef SUPPORT_ACLS
@@ -570,7 +623,7 @@ int set_file_attrs(const char *fname, struct file_struct *file, stat_x *sxp,
* need to chmod(). */
if (preserve_acls && !S_ISLNK(new_mode)) {
if (set_acl(fname, file, sxp, new_mode) > 0)
updated = 1;
updated |= UPDATED_ACLS;
}
#endif
@@ -584,7 +637,7 @@ int set_file_attrs(const char *fname, struct file_struct *file, stat_x *sxp,
goto cleanup;
}
if (ret == 0) /* ret == 1 if symlink could not be set */
updated = 1;
updated |= UPDATED_MODE;
}
#endif
@@ -601,8 +654,10 @@ int set_file_attrs(const char *fname, struct file_struct *file, stat_x *sxp,
}
/* This is only called for SIGINT, SIGHUP, and SIGTERM. */
RETSIGTYPE sig_int(int sig_num)
void sig_int(int sig_num)
{
called_from_signal_handler = 1;
/* KLUGE: if the user hits Ctrl-C while ssh is prompting
* for a password, then our cleanup's sending of a SIGUSR1
* signal to all our children may kill ssh before it has a
@@ -626,6 +681,7 @@ RETSIGTYPE sig_int(int sig_num)
* we didn't already set the flag. */
if (!got_kill_signal && (am_server || am_receiver)) {
got_kill_signal = sig_num;
called_from_signal_handler = 0;
return;
}
@@ -636,7 +692,7 @@ RETSIGTYPE sig_int(int sig_num)
* attributes (e.g. permissions, ownership, etc.). If the robust_rename()
* call is forced to copy the temp file and partialptr is both non-NULL and
* not an absolute path, we stage the file into the partial-dir and then
* rename it into place. This returns 1 on succcess or 0 on failure. */
* rename it into place. This returns 1 on success or 0 on failure. */
int finish_transfer(const char *fname, const char *fnametmp,
const char *fnamecmp, const char *partialptr,
struct file_struct *file, int ok_to_set_time,
@@ -655,14 +711,14 @@ int finish_transfer(const char *fname, const char *fnametmp,
if (make_backups > 0 && overwriting_basis) {
int ok = make_backup(fname, False);
if (!ok)
return 1;
exit_cleanup(RERR_FILEIO);
if (ok == 1 && fnamecmp == fname)
fnamecmp = get_backup_name(fname);
}
/* Change permissions before putting the file into place. */
set_file_attrs(fnametmp, file, NULL, fnamecmp,
ok_to_set_time ? 0 : ATTRS_SKIP_MTIME);
ok_to_set_time ? ATTRS_ACCURATE_TIME : ATTRS_SKIP_MTIME | ATTRS_SKIP_ATIME);
/* move tmp file over real file */
if (DEBUG_GTE(RECV, 1))
@@ -687,7 +743,7 @@ int finish_transfer(const char *fname, const char *fnametmp,
do_set_file_attrs:
set_file_attrs(fnametmp, file, NULL, fnamecmp,
ok_to_set_time ? 0 : ATTRS_SKIP_MTIME);
ok_to_set_time ? ATTRS_ACCURATE_TIME : ATTRS_SKIP_MTIME | ATTRS_SKIP_ATIME);
if (temp_copy_name) {
if (do_rename(fnametmp, fname) < 0) {

119
rsync.h
View File

@@ -2,7 +2,7 @@
* Copyright (C) 1996, 2000 Andrew Tridgell
* Copyright (C) 1996 Paul Mackerras
* Copyright (C) 2001, 2002 Martin Pool <mbp@samba.org>
* Copyright (C) 2003-2014 Wayne Davison
* Copyright (C) 2003-2020 Wayne Davison
*
* 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
@@ -52,16 +52,24 @@
#define XMIT_SAME_NAME (1<<5)
#define XMIT_LONG_NAME (1<<6)
#define XMIT_SAME_TIME (1<<7)
#define XMIT_SAME_RDEV_MAJOR (1<<8) /* protocols 28 - now (devices only) */
#define XMIT_NO_CONTENT_DIR (1<<8) /* protocols 30 - now (dirs only) */
#define XMIT_HLINKED (1<<9) /* protocols 28 - now */
#define XMIT_HLINKED (1<<9) /* protocols 28 - now (non-dirs) */
#define XMIT_SAME_DEV_pre30 (1<<10) /* protocols 28 - 29 */
#define XMIT_USER_NAME_FOLLOWS (1<<10) /* protocols 30 - now */
#define XMIT_RDEV_MINOR_8_pre30 (1<<11) /* protocols 28 - 29 */
#define XMIT_RDEV_MINOR_8_pre30 (1<<11) /* protocols 28 - 29 */
#define XMIT_GROUP_NAME_FOLLOWS (1<<11) /* protocols 30 - now */
#define XMIT_HLINK_FIRST (1<<12) /* protocols 30 - now (HLINKED files only) */
#define XMIT_IO_ERROR_ENDLIST (1<<12) /* protocols 31*- now (w/XMIT_EXTENDED_FLAGS) (also protocol 30 w/'f' compat flag) */
#define XMIT_MOD_NSEC (1<<13) /* protocols 31 - now */
#define XMIT_SAME_ATIME (1<<14) /* any protocol - restricted by command-line option */
#define XMIT_UNUSED_15 (1<<15) /* unused flag bit */
/* The following XMIT flags require an rsync that uses a varint for the flag values */
#define XMIT_RESERVED_16 (1<<16) /* reserved for future fileflags use */
#define XMIT_RESERVED_17 (1<<17) /* reserved for future crtimes use */
/* These flags are used in the live flist data. */
@@ -87,9 +95,11 @@
/* These flags are passed to functions but not stored. */
#define FLAG_DIVERT_DIRS (1<<16) /* sender, but must be unique */
#define FLAG_PERHAPS_DIR (1<<17) /* generator */
/* These flags are for get_dirlist(). */
#define GDL_IGNORE_FILTER_RULES (1<<0)
#define GDL_PERHAPS_DIR (1<<1)
/* Some helper macros for matching bits. */
#define BITS_SET(val,bits) (((val) & (bits)) == (bits))
@@ -151,6 +161,10 @@
#define MAX_BASIS_DIRS 20
#define MAX_SERVER_ARGS (MAX_BASIS_DIRS*2 + 100)
#define COMPARE_DEST 1
#define COPY_DEST 2
#define LINK_DEST 3
#define MPLEX_BASE 7
#define NO_FILTERS 0
@@ -165,7 +179,10 @@
#define ATTRS_REPORT (1<<0)
#define ATTRS_SKIP_MTIME (1<<1)
#define ATTRS_ACCURATE_TIME (1<<2)
#define ATTRS_SKIP_ATIME (1<<3)
#define MSG_FLUSH 2
#define FULL_FLUSH 1
#define NORMAL_FLUSH 0
@@ -372,7 +389,7 @@ enum delret {
#include <utime.h>
#endif
#if defined HAVE_UTIMENSAT || defined HAVE_LUTIMES
#if defined HAVE_UTIMENSAT || defined HAVE_LUTIMES || defined HAVE_SETATTRLIST
#define CAN_SET_SYMLINK_TIMES 1
#endif
@@ -384,11 +401,20 @@ enum delret {
#define CAN_CHMOD_SYMLINK 1
#endif
#ifdef HAVE_UTIMENSAT
#if defined HAVE_UTIMENSAT || defined HAVE_SETATTRLIST
#define CAN_SET_NSEC 1
#endif
#ifdef CAN_SET_NSEC
#ifdef HAVE_STRUCT_STAT_ST_MTIM_TV_NSEC
#define ST_MTIME_NSEC st_mtim.tv_nsec
#define ST_ATIME_NSEC st_atim.tv_nsec
#elif defined(HAVE_STRUCT_STAT_ST_MTIMENSEC)
#define ST_MTIME_NSEC st_mtimensec
#define ST_ATIME_NSEC st_atimensec
#elif defined(HAVE_STRUCT_STAT_ST_MTIMESPEC_TV_NSEC)
#define ST_MTIME_NSEC st_mtimespec.tv_nsec
#define ST_ATIME_NSEC st_atimespec.tv_nsec
#endif
#endif
@@ -609,6 +635,9 @@ typedef unsigned int size_t;
# define SIZEOF_INT64 SIZEOF_OFF_T
#endif
#define HT_KEY32 0
#define HT_KEY64 1
struct hashtable {
void *nodes;
int32 size, entries;
@@ -691,9 +720,29 @@ struct ht_int64_node {
#endif
#endif
#if SIZEOF_CHARP == 4
# define PTRS_ARE_32 1
# define PTR_EXTRA_CNT 1
#elif SIZEOF_CHARP == 8
# define PTRS_ARE_64 1
# define PTR_EXTRA_CNT EXTRA64_CNT
#else
# error Character pointers are not 4 or 8 bytes.
#endif
union file_extras {
int32 num;
uint32 unum;
#ifdef PTRS_ARE_32
const char* ptr;
#endif
};
union file_extras64 {
int64 num;
#ifdef PTRS_ARE_64
const char* ptr;
#endif
};
struct file_struct {
@@ -707,6 +756,9 @@ struct file_struct {
extern int file_extra_cnt;
extern int inc_recurse;
extern int atimes_ndx;
extern int pathname_ndx;
extern int depth_ndx;
extern int uid_ndx;
extern int gid_ndx;
extern int acls_ndx;
@@ -714,14 +766,18 @@ extern int xattrs_ndx;
#define FILE_STRUCT_LEN (offsetof(struct file_struct, basename))
#define EXTRA_LEN (sizeof (union file_extras))
#define PTR_EXTRA_CNT ((sizeof (char *) + EXTRA_LEN - 1) / EXTRA_LEN)
#define DEV_EXTRA_CNT 2
#define DIRNODE_EXTRA_CNT 3
#define EXTRA64_CNT ((sizeof (union file_extras64) + EXTRA_LEN - 1) / EXTRA_LEN)
#define SUM_EXTRA_CNT ((MAX_DIGEST_LEN + EXTRA_LEN - 1) / EXTRA_LEN)
#define REQ_EXTRA(f,ndx) ((union file_extras*)(f) - (ndx))
#define OPT_EXTRA(f,bump) ((union file_extras*)(f) - file_extra_cnt - 1 - (bump))
/* These are guaranteed to be allocated first in the array so that they
* are aligned for direct int64-pointer access. */
#define REQ_EXTRA64(f,ndx) ((union file_extras64*)REQ_EXTRA(f,ndx))
#define NSEC_BUMP(f) ((f)->flags & FLAG_MOD_NSEC ? 1 : 0)
#define LEN64_BUMP(f) ((f)->flags & FLAG_LENGTH64 ? 1 : 0)
#define START_BUMP(f) (NSEC_BUMP(f) + LEN64_BUMP(f))
@@ -732,20 +788,25 @@ extern int xattrs_ndx;
#if SIZEOF_INT64 < 8
#define F_LENGTH(f) ((int64)(f)->len32)
#else
#define F_LENGTH(f) ((int64)(f)->len32 + ((f)->flags & FLAG_LENGTH64 \
? (int64)OPT_EXTRA(f, NSEC_BUMP(f))->unum << 32 : 0))
#define F_HIGH_LEN(f) (OPT_EXTRA(f, NSEC_BUMP(f))->unum)
#define F_LENGTH(f) ((int64)(f)->len32 + ((f)->flags & FLAG_LENGTH64 ? (int64)F_HIGH_LEN(f) << 32 : 0))
#endif
#define F_MOD_NSEC(f) ((f)->flags & FLAG_MOD_NSEC ? OPT_EXTRA(f, 0)->unum : 0)
#define F_MOD_NSEC(f) OPT_EXTRA(f, 0)->unum
#define F_MOD_NSEC_or_0(f) ((f)->flags & FLAG_MOD_NSEC ? F_MOD_NSEC(f) : 0)
/* If there is a symlink string, it is always right after the basename */
#define F_SYMLINK(f) ((f)->basename + strlen((f)->basename) + 1)
/* The sending side always has this available: */
#define F_PATHNAME(f) (*(const char**)REQ_EXTRA(f, PTR_EXTRA_CNT))
#ifdef PTRS_ARE_32
#define F_PATHNAME(f) REQ_EXTRA(f, pathname_ndx)->ptr
#else
#define F_PATHNAME(f) REQ_EXTRA64(f, pathname_ndx)->ptr
#endif
/* The receiving side always has this available: */
#define F_DEPTH(f) REQ_EXTRA(f, 1)->num
#define F_DEPTH(f) REQ_EXTRA(f, depth_ndx)->num
/* When the associated option is on, all entries will have these present: */
#define F_OWNER(f) REQ_EXTRA(f, uid_ndx)->unum
@@ -753,6 +814,7 @@ extern int xattrs_ndx;
#define F_ACL(f) REQ_EXTRA(f, acls_ndx)->num
#define F_XATTR(f) REQ_EXTRA(f, xattrs_ndx)->num
#define F_NDX(f) REQ_EXTRA(f, unsort_ndx)->num
#define F_ATIME(f) REQ_EXTRA64(f, atimes_ndx)->num
/* These items are per-entry optional: */
#define F_HL_GNUM(f) OPT_EXTRA(f, START_BUMP(f))->num /* non-dirs */
@@ -856,6 +918,10 @@ struct map_struct {
int status; /* first errno from read errors */
};
#define NAME_IS_FILE (0) /* filter name as a file */
#define NAME_IS_DIR (1<<0) /* filter name as a dir */
#define NAME_IS_XATTR (1<<2) /* filter name as an xattr */
#define FILTRULE_WILD (1<<0) /* pattern has '*', '[', and/or '?' */
#define FILTRULE_WILD2 (1<<1) /* pattern has '**' */
#define FILTRULE_WILD2_PREFIX (1<<2) /* pattern starts with "**" */
@@ -876,6 +942,7 @@ struct map_struct {
#define FILTRULE_RECEIVER_SIDE (1<<17)/* rule applies to the receiving side */
#define FILTRULE_CLEAR_LIST (1<<18)/* this item is the "!" token */
#define FILTRULE_PERISHABLE (1<<19)/* perishable if parent dir goes away */
#define FILTRULE_XATTR (1<<20)/* rule only applies to xattr names */
#define FILTRULES_SIDES (FILTRULE_SENDER_SIDE | FILTRULE_RECEIVER_SIDE)
@@ -892,7 +959,6 @@ typedef struct filter_struct {
typedef struct filter_list_struct {
filter_rule *head;
filter_rule *tail;
filter_rule *parent_dirscan_head;
char *debug_type;
} filter_rule_list;
@@ -1003,7 +1069,32 @@ typedef struct {
#define ACL_READY(sx) ((sx).acc_acl != NULL)
#define XATTR_READY(sx) ((sx).xattr != NULL)
#define CLVL_NOT_SPECIFIED INT_MIN
#define CPRES_AUTO (-1)
#define CPRES_NONE 0
#define CPRES_ZLIB 1
#define CPRES_ZLIBX 2
#define CPRES_LZ4 3
#define CPRES_ZSTD 4
struct name_num_item {
int num;
const char *name, *main_name;
};
struct name_num_obj {
const char *type;
const char *negotiated_name;
uchar *saw;
int saw_len;
int negotiated_num;
struct name_num_item list[];
};
#ifndef __cplusplus
#include "proto.h"
#endif
#ifndef SUPPORT_XATTRS
#define x_stat(fn,fst,xst) do_stat(fn,fst)
@@ -1030,7 +1121,6 @@ int vsnprintf(char *str, size_t count, const char *fmt, va_list args);
int snprintf(char *str, size_t count, const char *fmt,...);
#endif
#ifndef HAVE_STRERROR
extern char *sys_errlist[];
#define strerror(i) sys_errlist[i]
@@ -1269,7 +1359,8 @@ extern short info_levels[], debug_levels[];
#define DEBUG_HLINK (DEBUG_HASH+1)
#define DEBUG_ICONV (DEBUG_HLINK+1)
#define DEBUG_IO (DEBUG_ICONV+1)
#define DEBUG_OWN (DEBUG_IO+1)
#define DEBUG_NSTR (DEBUG_IO+1)
#define DEBUG_OWN (DEBUG_NSTR+1)
#define DEBUG_PROTO (DEBUG_OWN+1)
#define DEBUG_RECV (DEBUG_PROTO+1)
#define DEBUG_SEND (DEBUG_RECV+1)

3450
rsync.yo
View File

File diff suppressed because it is too large Load Diff

1208
rsyncd.conf.5.md Normal file
View File

File diff suppressed because it is too large Load Diff

View File

@@ -1,934 +0,0 @@
mailto(rsync-bugs@samba.org)
manpage(rsyncd.conf)(5)(26 May 2014)()()
manpagename(rsyncd.conf)(configuration file for rsync in daemon mode)
manpagesynopsis()
rsyncd.conf
manpagedescription()
The rsyncd.conf file is the runtime configuration file for rsync when
run as an rsync daemon.
The rsyncd.conf file controls authentication, access, logging and
available modules.
manpagesection(FILE FORMAT)
The file consists of modules and parameters. A module begins with the
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
either a comment, a module name or a parameter.
Only the first equals sign in a parameter is significant. Whitespace before
or after the first equals sign is discarded. Leading, trailing and internal
whitespace in module and parameter names is irrelevant. Leading and
trailing whitespace in a parameter value is discarded. Internal whitespace
within a parameter value is retained verbatim.
Any line bf(beginning) with a hash (#) is ignored, as are lines containing
only whitespace. (If a hash occurs after anything other than leading
whitespace, it is considered a part of the line's content.)
Any line ending in a \ is "continued" on the next line in the
customary UNIX fashion.
The values following the equals sign in parameters are all either a string
(no quotes needed) or a boolean, which may be given as yes/no, 0/1 or
true/false. Case is not significant in boolean values, but is preserved
in string values.
manpagesection(LAUNCHING THE RSYNC DAEMON)
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
bind to a port numbered under 1024 (as is the default 873), or to set
file ownership. Otherwise, it must just have permission to read and
write the appropriate data, log, and lock files.
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 "bf(rsync --daemon)" from a suitable startup script.
When run via inetd you should add a line like this to /etc/services:
verb( rsync 873/tcp)
and a single line something like this to /etc/inetd.conf:
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
reread its config file.
Note that you should bf(not) send the rsync daemon a HUP signal to force
it to reread the tt(rsyncd.conf) file. The file is re-read on each client
connection.
manpagesection(GLOBAL PARAMETERS)
The first parameters in the file (before a [module] header) are the
global parameters.
You may also include any module parameters in the global part of the
config file in which case the supplied value will override the
default for that parameter.
You may use references to environment variables in the values of parameters.
String parameters will have %VAR% references expanded as late as possible (when
the string is used in the program), allowing for the use of variables that
rsync sets at connection time, such as RSYNC_USER_NAME. Non-string parameters
(such as true/false settings) are expanded when read from the config file. If
a variable does not exist in the environment, or if a sequence of characters is
not a valid reference (such as an un-paired percent sign), the raw characters
are passed through unchanged. This helps with backward compatibility and
safety (e.g. expanding a non-existent %VAR% to an empty string in a path could
result in a very unsafe path). The safest way to insert a literal % into a
value is to use %%.
startdit()
dit(bf(motd file)) This parameter allows you to specify a
"message of the day" to display to clients on each connect. This
usually contains site information and any legal notices. The default
is no motd file.
This can be overridden by the bf(--dparam=motdfile=FILE)
command-line option when starting the daemon.
dit(bf(pid file)) This parameter tells the rsync daemon to write
its process ID to that file. If the file already exists, the rsync
daemon will abort rather than overwrite the file.
This can be overridden by the bf(--dparam=pidfile=FILE)
command-line option when starting the daemon.
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(socket options)) This parameter can provide endless fun for people
who like to tune their systems to the utmost degree. You can set all
sorts of socket options which may make transfers faster (or
slower!). Read the man page for the code(setsockopt()) system call for
details on some of the options you may be able to set. By default no
special socket options are set. These settings can also be specified
via the bf(--sockopts) command-line option.
dit(bf(listen backlog)) You can override the default backlog value when the
daemon listens for connections. It defaults to 5.
enddit()
manpagesection(MODULE PARAMETERS)
After the global parameters you should define a number of modules, each
module exports a directory tree as a symbolic name. Modules are
exported by specifying a module name in square brackets [module]
followed by the parameters for that module.
The module name cannot contain a slash or a closing square bracket. If the
name contains whitespace, each internal sequence of whitespace will be
changed into a single space, while leading or trailing whitespace will be
discarded.
As with GLOBAL PARAMETERS, you may use references to environment variables in
the values of parameters. See the GLOBAL PARAMETERS section for more details.
startdit()
dit(bf(comment)) This parameter specifies a description string
that is displayed next to the module name when clients obtain a list
of available modules. The default is no comment.
dit(bf(path)) This parameter specifies the directory in the daemon's
filesystem to make available in this module. You must specify this parameter
for each module in tt(rsyncd.conf).
You may base the path's value off of an environment variable by surrounding
the variable name with percent signs. You can even reference a variable
that is set by rsync when the user connects.
For example, this would use the authorizing user's name in the path:
verb( path = /home/%RSYNC_USER_NAME% )
It is fine if the path includes internal spaces -- they will be retained
verbatim (which means that you shouldn't try to escape them). If your final
directory has a trailing space (and this is somehow not something you wish to
fix), append a trailing slash to the path to avoid losing the trailing
whitespace.
dit(bf(use chroot)) If "use chroot" is true, the rsync daemon will chroot
to the "path" before starting the file transfer with the client. This has
the advantage of extra protection against possible implementation security
holes, but it has the disadvantages of requiring super-user privileges,
of not being able to follow symbolic links that are either absolute or outside
of the new root path, and of complicating the preservation of users and groups
by name (see below).
As an additional safety feature, you can specify a dot-dir in the module's
"path" to indicate the point where the chroot should occur. This allows rsync
to run in a chroot with a non-"/" path for the top of the transfer hierarchy.
Doing this guards against unintended library loading (since those absolute
paths will not be inside the transfer hierarchy unless you have used an unwise
pathname), and lets you setup libraries for the chroot that are outside of the
transfer. For example, specifying "/var/rsync/./module1" will chroot to the
"/var/rsync" directory and set the inside-chroot path to "/module1". If you
had omitted the dot-dir, the chroot would have used the whole path, and the
inside-chroot path would have been "/".
When "use chroot" is false or the inside-chroot path is not "/", rsync will:
(1) munge symlinks by
default for security reasons (see "munge symlinks" for a way to turn this
off, but only if you trust your users), (2) substitute leading slashes in
absolute paths with the module's path (so that options such as
bf(--backup-dir), bf(--compare-dest), etc. interpret an absolute path as
rooted in the module's "path" dir), and (3) trim ".." path elements from
args if rsync believes they would escape the module hierarchy.
The default for "use chroot" is true, and is the safer choice (especially
if the module is not read-only).
When this parameter is enabled, rsync will not attempt to map users and groups
by name (by default), but instead copy IDs as though bf(--numeric-ids) had
been specified. In order to enable name-mapping, rsync needs to be able to
use the standard library functions for looking up names and IDs (i.e.
code(getpwuid()), code(getgrgid()), code(getpwname()), and code(getgrnam())).
This means the rsync
process in the chroot hierarchy will need to have access to the resources
used by these library functions (traditionally /etc/passwd and
/etc/group, but perhaps additional dynamic libraries as well).
If you copy the necessary resources into the module's chroot area, you
should protect them through your OS's normal user/group or ACL settings (to
prevent the rsync module's user from being able to change them), and then
hide them from the user's view via "exclude" (see how in the discussion of
that parameter). At that point it will be safe to enable the mapping of users
and groups by name using the "numeric ids" daemon parameter (see below).
Note also that you are free to setup custom user/group information in the
chroot area that is different from your normal system. For example, you
could abbreviate the list of users and groups.
dit(bf(numeric ids)) Enabling this parameter disables the mapping
of users and groups by name for the current daemon module. This prevents
the daemon from trying to load any user/group-related files or libraries.
This enabling makes the transfer behave as if the client had passed
the bf(--numeric-ids) command-line option. By default, this parameter is
enabled for chroot modules and disabled for non-chroot modules.
A chroot-enabled module should not have this parameter enabled unless you've
taken steps to ensure that the module has the necessary resources it needs
to translate names, and that it is not possible for a user to change those
resources.
dit(bf(munge symlinks)) This parameter tells rsync to modify
all symlinks in the same way as the (non-daemon-affecting)
bf(--munge-links) command-line option (using a method described below).
This should help protect your files from user trickery when
your daemon module is writable. The default is disabled when "use chroot"
is on and the inside-chroot path is "/", otherwise it is enabled.
If you disable this parameter on a daemon that is not read-only, there
are tricks that a user can play with uploaded symlinks to access
daemon-excluded items (if your module has any), and, if "use chroot"
is off, rsync can even be tricked into showing or changing data that
is outside the module's path (as access-permissions allow).
The way rsync disables the use of symlinks is to prefix each one with
the string "/rsyncd-munged/". This prevents the links from being used
as long as that directory does not exist. When this parameter is enabled,
rsync will refuse to run if that path is a directory or a symlink to
a directory. When using the "munge symlinks" parameter in a chroot area
that has an inside-chroot path of "/", you should add "/rsyncd-munged/"
to the exclude setting for the module so that
a user can't try to create it.
Note: rsync makes no attempt to verify that any pre-existing symlinks in
the module's hierarchy are as safe as you want them to be (unless, of
course, it just copied in the whole hierarchy). If you setup an rsync
daemon on a new area or locally add symlinks, you can manually protect your
symlinks from being abused by prefixing "/rsyncd-munged/" to the start of
every symlink's value. There is a perl script in the support directory
of the source code named "munge-symlinks" that can be used to add or remove
this prefix from your symlinks.
When this parameter is disabled on a writable module and "use chroot" is off
(or the inside-chroot path is not "/"),
incoming symlinks will be modified to drop a leading slash and to remove ".."
path elements that rsync believes will allow a symlink to escape the module's
hierarchy. There are tricky ways to work around this, though, so you had
better trust your users if you choose this combination of parameters.
dit(bf(charset)) This specifies the name of the character set in which the
module's filenames are stored. If the client uses an bf(--iconv) option,
the daemon will use the value of the "charset" parameter regardless of the
character set the client actually passed. This allows the daemon to
support charset conversion in a chroot module without extra files in the
chroot area, and also ensures that name-translation is done in a consistent
manner. If the "charset" parameter is not set, the bf(--iconv) option is
refused, just as if "iconv" had been specified via "refuse options".
If you wish to force users to always use bf(--iconv) for a particular
module, add "no-iconv" to the "refuse options" parameter. Keep in mind
that this will restrict access to your module to very new rsync clients.
dit(bf(max connections)) This parameter allows you to
specify the maximum number of simultaneous connections you will allow.
Any clients connecting when the maximum has been reached will receive a
message telling them to try later. The default is 0, which means no limit.
A negative value disables the module.
See also the "lock file" parameter.
dit(bf(log file)) When the "log file" parameter is set to a non-empty
string, the rsync daemon will log messages to the indicated file rather
than using syslog. This is particularly useful on systems (such as AIX)
where code(syslog()) doesn't work for chrooted programs. The file is
opened before code(chroot()) is called, allowing it to be placed outside
the transfer. If this value is set on a per-module basis instead of
globally, the global log will still contain any authorization failures
or config-file error messages.
If the daemon fails to open the specified file, it will fall back to
using syslog and output an error about the failure. (Note that the
failure to open the specified log file used to be a fatal error.)
This setting can be overridden by using the bf(--log-file=FILE) or
bf(--dparam=logfile=FILE) command-line options. The former overrides
all the log-file parameters of the daemon and all module settings.
The latter sets the daemon's log file and the default for all the
modules, which still allows modules to override the default setting.
dit(bf(syslog facility)) This parameter allows you to
specify the syslog facility name to use when logging messages from the
rsync daemon. You may use any standard syslog facility name which is
defined on your system. Common names are auth, authpriv, cron, daemon,
ftp, kern, lpr, mail, news, security, syslog, user, uucp, local0,
local1, local2, local3, local4, local5, local6 and local7. The default
is daemon. This setting has no effect if the "log file" setting is a
non-empty string (either set in the per-modules settings, or inherited
from the global settings).
dit(bf(max verbosity)) This parameter 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.
This also affects the user's ability to request higher levels of bf(--info) and
bf(--debug) logging. If the max value is 2, then no info and/or debug value
that is higher than what would be set by bf(-vv) will be honored by the daemon
in its logging. To see how high of a verbosity level you need to accept for a
particular info/debug level, refer to "rsync --info=help" and "rsync --debug=help".
For instance, it takes max-verbosity 4 to be able to output debug TIME2 and FLIST3.
dit(bf(lock file)) This parameter specifies the file to use to
support the "max connections" parameter. The rsync daemon uses record
locking on this file to ensure that the max connections limit is not
exceeded for the modules sharing the lock file.
The default is tt(/var/run/rsyncd.lock).
dit(bf(read only)) This parameter determines whether clients
will be able to upload files or not. If "read only" is true then any
attempted uploads will fail. If "read only" is false then uploads will
be possible if file permissions on the daemon side allow them. The default
is for all modules to be read only.
Note that "auth users" can override this setting on a per-user basis.
dit(bf(write only)) This parameter determines whether clients
will be able to download files or not. If "write only" is true then any
attempted downloads will fail. If "write only" is false then downloads
will be possible if file permissions on the daemon side allow them. The
default is for this parameter to be disabled.
dit(bf(list)) This parameter determines whether this module is
listed when the client asks for a listing of available modules. In addition,
if this is false, the daemon will pretend the module does not exist
when a client denied by "hosts allow" or "hosts deny" attempts to access it.
Realize that if "reverse lookup" is disabled globally but enabled for the
module, the resulting reverse lookup to a potentially client-controlled DNS
server may still reveal to the client that it hit an existing module.
The default is for modules to be listable.
dit(bf(uid)) This parameter specifies the user name or user ID that
file transfers to and from that module should take place as when the daemon
was run as root. In combination with the "gid" parameter this determines what
file permissions are available. The default when run by a super-user is to
switch to the system's "nobody" user. The default for a non-super-user is to
not try to change the user. See also the "gid" parameter.
The RSYNC_USER_NAME environment variable may be used to request that rsync run
as the authorizing user. For example, if you want a rsync to run as the same
user that was received for the rsync authentication, this setup is useful:
verb( uid = %RSYNC_USER_NAME%
gid = * )
dit(bf(gid)) This parameter specifies one or more group names/IDs that will be
used when accessing the module. The first one will be the default group, and
any extra ones be set as supplemental groups. You may also specify a "*" as
the first gid in the list, which will be replaced by all the normal groups for
the transfer's user (see "uid"). The default when run by a super-user is to
switch to your OS's "nobody" (or perhaps "nogroup") group with no other
supplementary groups. The default for a non-super-user is to not change any
group attributes (and indeed, your OS may not allow a non-super-user to try to
change their group settings).
dit(bf(fake super)) Setting "fake super = yes" for a module causes the
daemon side to behave as if the bf(--fake-super) command-line option had
been specified. This allows the full attributes of a file to be stored
without having to have the daemon actually running as root.
dit(bf(filter)) The daemon has its own filter chain that determines what files
it will let the client access. This chain is not sent to the client and is
independent of any filters the client may have specified. Files excluded by
the daemon filter chain (bf(daemon-excluded) files) are treated as non-existent
if the client tries to pull them, are skipped with an error message if the
client tries to push them (triggering exit code 23), and are never deleted from
the module. You can use daemon filters to prevent clients from downloading or
tampering with private administrative files, such as files you may add to
support uid/gid name translations.
The daemon filter chain is built from the "filter", "include from", "include",
"exclude from", and "exclude" parameters, in that order of priority. Anchored
patterns are anchored at the root of the module. To prevent access to an
entire subtree, for example, "/secret", you em(must) exclude everything in the
subtree; the easiest way to do this is with a triple-star pattern like
"/secret/***".
The "filter" parameter takes a space-separated list of daemon filter rules,
though it is smart enough to know not to split a token at an internal space in
a rule (e.g. "- /foo - /bar" is parsed as two rules). You may specify one or
more merge-file rules using the normal syntax. Only one "filter" parameter can
apply to a given module in the config file, so put all the rules you want in a
single parameter. 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 during a client download operation if the per-dir merge files are
included in the transfer and the client requests that they be used.
dit(bf(exclude)) This parameter takes a space-separated list of daemon
exclude patterns. As with the client bf(--exclude) option, patterns can be
qualified with "- " or "+ " to explicitly indicate exclude/include. Only one
"exclude" parameter can apply to a given module. See the "filter" parameter
for a description of how excluded files affect the daemon.
dit(bf(include)) Use an "include" to override the effects of the "exclude"
parameter. Only one "include" parameter can apply to a given module. See the
"filter" parameter for a description of how excluded files affect the daemon.
dit(bf(exclude from)) This parameter specifies the name of a file
on the daemon that contains daemon exclude patterns, one per line. Only one
"exclude from" parameter can apply to a given module; if you have multiple
exclude-from files, you can specify them as a merge file in the "filter"
parameter. See the "filter" parameter for a description of how excluded files
affect the daemon.
dit(bf(include from)) Analogue of "exclude from" for a file of daemon include
patterns. Only one "include from" parameter can apply to a given module. See
the "filter" parameter for a description of how excluded files affect the
daemon.
dit(bf(incoming chmod)) This parameter allows you to specify a set of
comma-separated chmod strings that will affect the permissions of all
incoming files (files that are being received by the daemon). These
changes happen after all other permission calculations, and this will
even override destination-default and/or existing permissions when the
client does not specify bf(--perms).
See the description of the bf(--chmod) rsync option and the bf(chmod)(1)
manpage for information on the format of this string.
dit(bf(outgoing chmod)) This parameter allows you to specify a set of
comma-separated chmod strings that will affect the permissions of all
outgoing files (files that are being sent out from the daemon). These
changes happen first, making the sent permissions appear to be different
than those stored in the filesystem itself. For instance, you could
disable group write permissions on the server while having it appear to
be on to the clients.
See the description of the bf(--chmod) rsync option and the bf(chmod)(1)
manpage for information on the format of this string.
dit(bf(auth users)) This parameter specifies a comma and/or space-separated
list of authorization rules. In its simplest form, you list the usernames
that will be allowed to connect to
this module. The usernames do not need to exist on the local
system. The rules may contain shell wildcard characters that will be matched
against the username provided by the client for authentication. If
"auth users" is set then the client will be challenged to supply a
username and password to connect to the module. A challenge response
authentication protocol is used for this exchange. The plain text
usernames and passwords are stored in the file specified by the
"secrets file" parameter. The default is for all users to be able to
connect without a password (this is called "anonymous rsync").
In addition to username matching, you can specify groupname matching via a '@'
prefix. When using groupname matching, the authenticating username must be a
real user on the system, or it will be assumed to be a member of no groups.
For example, specifying "@rsync" will match the authenticating user if the
named user is a member of the rsync group.
Finally, options may be specified after a colon (:). The options allow you to
"deny" a user or a group, set the access to "ro" (read-only), or set the access
to "rw" (read/write). Setting an auth-rule-specific ro/rw setting overrides
the module's "read only" setting.
Be sure to put the rules in the order you want them to be matched, because the
checking stops at the first matching user or group, and that is the only auth
that is checked. For example:
verb( auth users = joe:deny @guest:deny admin:rw @rsync:ro susan joe sam )
In the above rule, user joe will be denied access no matter what. Any user
that is in the group "guest" is also denied access. The user "admin" gets
access in read/write mode, but only if the admin user is not in group "guest"
(because the admin user-matching rule would never be reached if the user is in
group "guest"). Any other user who is in group "rsync" will get read-only
access. Finally, users susan, joe, and sam get the ro/rw setting of the
module, but only if the user didn't match an earlier group-matching rule.
See the description of the secrets file for how you can have per-user passwords
as well as per-group passwords. It also explains how a user can authenticate
using their user password or (when applicable) a group password, depending on
what rule is being authenticated.
See also the section entitled "USING RSYNC-DAEMON FEATURES VIA A REMOTE
SHELL CONNECTION" in bf(rsync)(1) for information on how handle an
rsyncd.conf-level username that differs from the remote-shell-level
username when using a remote shell to connect to an rsync daemon.
dit(bf(secrets file)) This parameter specifies the name of a file that contains
the username:password and/or @groupname:password pairs used for authenticating
this module. This file is only consulted if the "auth users" parameter is
specified. The file is line-based and contains one name:password pair per
line. Any line has a hash (#) as the very first character on the line is
considered a comment and is skipped. The passwords can contain any characters
but be warned that many operating systems limit the length of passwords that
can be typed at the client end, so you may find that passwords longer than 8
characters don't work.
The use of group-specific lines are only relevant when the module is being
authorized using a matching "@groupname" rule. When that happens, the user
can be authorized via either their "username:password" line or the
"@groupname:password" line for the group that triggered the authentication.
It is up to you what kind of password entries you want to include, either
users, groups, or both. The use of group rules in "auth users" does not
require that you specify a group password if you do not want to use shared
passwords.
There is no default for the "secrets file" parameter, you must choose a name
(such as tt(/etc/rsyncd.secrets)). The file must normally not be readable
by "other"; see "strict modes". If the file is not found or is rejected, no
logins for a "user auth" module will be possible.
dit(bf(strict modes)) This parameter determines whether or not
the permissions on the secrets file will be checked. If "strict modes" is
true, then the secrets file must not be readable by any user ID other
than the one that the rsync daemon is running under. If "strict modes" is
false, the check is not performed. The default is true. This parameter
was added to accommodate rsync running on the Windows operating system.
dit(bf(hosts allow)) This parameter allows you to specify a
list of patterns that are matched against a connecting clients
hostname and IP address. If none of the patterns match then the
connection is rejected.
Each pattern can be in one of five forms:
quote(itemization(
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 pattern using wildcards. If the hostname of the connecting IP
(as determined by a reverse lookup) matches the wildcarded name (using the
same rules as normal unix filename matching), the client is allowed in. This
only works if "reverse lookup" is enabled (the default).
it() a hostname. A plain hostname is matched against the reverse DNS of the
connecting IP (if "reverse lookup" is enabled), and/or the IP of the given
hostname is matched against the connecting IP (if "forward lookup" is
enabled, as it is by default). Any match will be allowed in.
))
Note IPv6 link-local addresses can have a scope in the address specification:
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"
parameter. If both parameters are specified then the "hosts allow" parameter is
checked first and a match results in the client being able to
connect. The "hosts deny" parameter is then checked and a match means
that the host is rejected. If the host does not match either the
"hosts allow" or the "hosts deny" patterns then it is allowed to
connect.
The default is no "hosts allow" parameter, which means all hosts can connect.
dit(bf(hosts deny)) This parameter allows you to specify a
list of patterns that are matched against a connecting clients
hostname and IP address. If the pattern matches then the connection is
rejected. See the "hosts allow" parameter for more information.
The default is no "hosts deny" parameter, which means all hosts can connect.
dit(bf(reverse lookup)) Controls whether the daemon performs a reverse lookup
on the client's IP address to determine its hostname, which is used for
"hosts allow"/"hosts deny" checks and the "%h" log escape. This is enabled by
default, but you may wish to disable it to save time if you know the lookup will
not return a useful result, in which case the daemon will use the name
"UNDETERMINED" instead.
If this parameter is enabled globally (even by default), rsync performs the
lookup as soon as a client connects, so disabling it for a module will not
avoid the lookup. Thus, you probably want to disable it globally and then
enable it for modules that need the information.
dit(bf(forward lookup)) Controls whether the daemon performs a forward lookup
on any hostname specified in an hosts allow/deny setting. By default this is
enabled, allowing the use of an explicit hostname that would not be returned
by reverse DNS of the connecting IP.
dit(bf(ignore errors)) This parameter tells rsyncd to
ignore I/O errors on the daemon when deciding whether to run the delete
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 parameter to turn off this
behavior.
dit(bf(ignore nonreadable)) This tells the rsync daemon to completely
ignore files that are not readable by the user. This is useful for
public archives that may have some non-readable files among the
directories, and the sysadmin doesn't want those files to be seen at all.
dit(bf(transfer logging)) This parameter enables per-file
logging of downloads and uploads in a format somewhat similar to that
used by ftp daemons. The daemon 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" parameter.
dit(bf(log format)) This parameter 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. An optional numeric
field width may also be specified between the percent and the escape
letter (e.g. "bf(%-50n %8l %07p)").
In addition, one or more apostrophes may be specified prior to a numerical
escape to indicate that the numerical value should be made more human-readable.
The 3 supported levels are the same as for the bf(--human-readable)
command-line option, though the default is for human-readability to be off.
Each added apostrophe increases the level (e.g. "bf(%''l %'b %f)").
The default log format is "%o %h [%a] %m (%u) %f %l", and a "%t [%p] "
is always prefixed when using the "log file" parameter.
(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:
quote(itemization(
it() %a the remote IP address (only available for a daemon)
it() %b the number of bytes actually transferred
it() %B the permission bits of the file (e.g. rwxrwxrwt)
it() %c the total size of the block checksums received for the basis file (only when sending)
it() %C the full-file MD5 checksum if bf(--checksum) is enabled or a file was transferred (only for protocol 30 or above).
it() %f the filename (long form on sender; no trailing "/")
it() %G the gid of the file (decimal) or "DEFAULT"
it() %h the remote host name (only available for a daemon)
it() %i an itemized list of what is being updated
it() %l the length of the file in bytes
it() %L the string " -> SYMLINK", " => HARDLINK", or "" (where bf(SYMLINK) or bf(HARDLINK) is a filename)
it() %m the module name
it() %M the last-modified time of the file
it() %n the filename (short form; trailing "/" on dir)
it() %o the operation, which is "send", "recv", or "del." (the latter includes the trailing period)
it() %p the process ID of this rsync session
it() %P the module path
it() %t the current date time
it() %u the authenticated username or an empty string
it() %U the uid of the file (decimal)
))
For a list of what the characters mean that are output by "%i", see the
bf(--itemize-changes) option in the rsync manpage.
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)) This parameter allows you to override the
clients choice for I/O timeout for this module. Using this parameter you
can ensure that rsync won't wait on a dead client forever. The timeout
is specified in seconds. A value of zero means no timeout and is the
default. A good choice for anonymous rsync daemons may be 600 (giving
a 10 minute timeout).
dit(bf(refuse options)) This parameter allows you to
specify a space-separated list of rsync command line options that will
be refused by your rsync daemon.
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 bf(--checksum) (bf(-c)) and all the various
delete options:
quote(tt( 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-source-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-source-files).
When an option is refused, the daemon prints an error message and exits.
To prevent all compression when serving files,
you can use "dont compress = *" (see below)
instead of "refuse options = compress" to avoid returning an error to a
client that requests compression.
dit(bf(dont compress)) This parameter allows you to select
filenames based on wildcard patterns that should not be compressed
when pulling files from the daemon (no analogous parameter exists to
govern the pushing of files to a daemon).
Compression is expensive in terms of CPU usage, so it
is usually good to not try to compress files that won't compress well,
such as already compressed files.
The "dont compress" parameter takes a space-separated list of
case-insensitive wildcard patterns. Any source filename matching one
of the patterns will not be compressed during transfer.
See the bf(--skip-compress) parameter in the bf(rsync)(1) manpage for the list
of file suffixes that are not compressed by default. Specifying a value
for the "dont compress" parameter changes the default when the daemon is
the sender.
dit(bf(pre-xfer exec), bf(post-xfer exec)) You may specify a command to be run
before and/or after the transfer. If the bf(pre-xfer exec) command fails, the
transfer is aborted before it begins. Any output from the script on stdout (up
to several KB) will be displayed to the user when aborting, but is NOT
displayed if the script returns success. Any output from the script on stderr
goes to the daemon's stderr, which is typically discarded (though see
--no-detatch option for a way to see the stderr output, which can assist with
debugging).
The following environment variables will be set, though some are
specific to the pre-xfer or the post-xfer environment:
quote(itemization(
it() bf(RSYNC_MODULE_NAME): The name of the module being accessed.
it() bf(RSYNC_MODULE_PATH): The path configured for the module.
it() bf(RSYNC_HOST_ADDR): The accessing host's IP address.
it() bf(RSYNC_HOST_NAME): The accessing host's name.
it() bf(RSYNC_USER_NAME): The accessing user's name (empty if no user).
it() bf(RSYNC_PID): A unique number for this transfer.
it() bf(RSYNC_REQUEST): (pre-xfer only) The module/path info specified
by the user. Note that the user can specify multiple source files,
so the request can be something like "mod/path1 mod/path2", etc.
it() bf(RSYNC_ARG#): (pre-xfer only) The pre-request arguments are set
in these numbered values. RSYNC_ARG0 is always "rsyncd", followed by
the options that were used in RSYNC_ARG1, and so on. There will be a
value of "." indicating that the options are done and the path args
are beginning -- these contain similar information to RSYNC_REQUEST,
but with values separated and the module name stripped off.
it() bf(RSYNC_EXIT_STATUS): (post-xfer only) the server side's exit value.
This will be 0 for a successful run, a positive value for an error that the
server generated, or a -1 if rsync failed to exit properly. Note that an
error that occurs on the client side does not currently get sent to the
server side, so this is not the final exit status for the whole transfer.
it() bf(RSYNC_RAW_STATUS): (post-xfer only) the raw exit value from code(waitpid()).
))
Even though the commands can be associated with a particular module, they
are run using the permissions of the user that started the daemon (not the
module's uid/gid setting) without any chroot restrictions.
enddit()
manpagesection(CONFIG DIRECTIVES)
There are currently two config directives available that allow a config file to
incorporate the contents of other files: bf(&include) and bf(&merge). Both
allow a reference to either a file or a directory. They differ in how
segregated the file's contents are considered to be.
The bf(&include) directive treats each file as more distinct, with each one
inheriting the defaults of the parent file, starting the parameter parsing
as globals/defaults, and leaving the defaults unchanged for the parsing of
the rest of the parent file.
The bf(&merge) directive, on the other hand, treats the file's contents as
if it were simply inserted in place of the directive, and thus it can set
parameters in a module started in another file, can affect the defaults for
other files, etc.
When an bf(&include) or bf(&merge) directive refers to a directory, it will read
in all the bf(*.conf) or bf(*.inc) files (respectively) that are contained inside
that directory (without any
recursive scanning), with the files sorted into alpha order. So, if you have a
directory named "rsyncd.d" with the files "foo.conf", "bar.conf", and
"baz.conf" inside it, this directive:
verb( &include /path/rsyncd.d )
would be the same as this set of directives:
verb( &include /path/rsyncd.d/bar.conf
&include /path/rsyncd.d/baz.conf
&include /path/rsyncd.d/foo.conf )
except that it adjusts as files are added and removed from the directory.
The advantage of the bf(&include) directive is that you can define one or more
modules in a separate file without worrying about unintended side-effects
between the self-contained module files.
The advantage of the bf(&merge) directive is that you can load config snippets
that can be included into multiple module definitions, and you can also set
global values that will affect connections (such as bf(motd file)), or globals
that will affect other include files.
For example, this is a useful /etc/rsyncd.conf file:
verb( port = 873
log file = /var/log/rsync.log
pid file = /var/lock/rsync.lock
&merge /etc/rsyncd.d
&include /etc/rsyncd.d )
This would merge any /etc/rsyncd.d/*.inc files (for global values that should
stay in effect), and then include any /etc/rsyncd.d/*.conf files (defining
modules without any global-value cross-talk).
manpagesection(AUTHENTICATION STRENGTH)
The authentication protocol used in rsync is a 128 bit MD4 based
challenge response system. This is fairly weak protection, though (with
at least one brute-force hash-finding algorithm publicly available), so
if you want really top-quality security, then I recommend that you run
rsync over ssh. (Yes, a future version of rsync will switch over to a
stronger hashing method.)
Also note that the rsync daemon protocol does not currently provide any
encryption of the data that is transferred over the connection. Only
authentication is provided. Use ssh as the transport if you want
encryption.
Future versions of rsync may support SSL for better authentication and
encryption, but that is still being investigated.
manpagesection(EXAMPLES)
A simple rsyncd.conf file that allow anonymous rsync to a ftp area at
tt(/home/ftp) would be:
verb(
[ftp]
path = /home/ftp
comment = ftp export area
)
A more sophisticated example would be:
verb(
uid = nobody
gid = nobody
use chroot = yes
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)
[sambaftp]
path = /var/ftp/./pub/samba
comment = Samba ftp area (approx 300 MB)
[rsyncftp]
path = /var/ftp/./pub/rsync
comment = rsync ftp area (approx 6 MB)
[sambawww]
path = /public_html/samba
comment = Samba WWW pages (approx 240 MB)
[cvs]
path = /data/cvs
comment = CVS repository (requires authentication)
auth users = tridge, susan
secrets file = /etc/rsyncd.secrets
)
The /etc/rsyncd.secrets file would look something like this:
quote(
tt(tridge:mypass)nl()
tt(susan:herpass)nl()
)
manpagefiles()
/etc/rsyncd.conf or rsyncd.conf
manpageseealso()
bf(rsync)(1)
manpagediagnostics()
manpagebugs()
Please report bugs! The rsync bug tracking system is online at
url(http://rsync.samba.org/)(http://rsync.samba.org/)
manpagesection(VERSION)
This man page is current for version 3.1.1pre2 of rsync.
manpagesection(CREDITS)
rsync is distributed under the GNU General Public License. See the file
COPYING for details.
The primary ftp site for rsync is
url(ftp://rsync.samba.org/pub/rsync)(ftp://rsync.samba.org/pub/rsync).
A WEB site is available at
url(http://rsync.samba.org/)(http://rsync.samba.org/)
We would be delighted to hear from you if you like this program.
This program uses the zlib compression library written by Jean-loup
Gailly and Mark Adler.
manpagesection(THANKS)
Thanks to Warren Stanley for his original idea and patch for the rsync
daemon. Thanks to Karsten Thygesen for his many suggestions and
documentation!
manpageauthor()
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)

Some files were not shown because too many files have changed in this diff Show More