Compare commits

..

262 Commits

Author SHA1 Message Date
Wayne Davison
93bdc6478e Preparing for release of 3.0.9pre1 2011-06-22 08:00:35 -07:00
Wayne Davison
2d07fa6350 Mention latest fix. 2011-06-22 07:58:23 -07:00
Wayne Davison
33e37a49ba Make daemon-exclude errors more error-like.
Fixes bug 7765.
2011-06-18 12:44:47 -07:00
Wayne Davison
5782ac04d7 Prepare for 3.0.9pre1 release. 2011-06-18 10:31:30 -07:00
Wayne Davison
fc41c32159 Mention coming Solaris support. 2011-06-18 10:22:24 -07:00
Wayne Davison
365124a214 Don't force \(em in the manpages. Fixes bug 7941. 2011-06-04 12:53:22 -07:00
Wayne Davison
dbf68ca4c1 Linux needs symlink xattrs. Fixes bug 8201. 2011-06-04 09:46:06 -07:00
Wayne Davison
ba35ba06c9 Fix unwritable directory issue due to misordered chmod call. 2011-05-30 08:41:02 -07:00
Wayne Davison
0b519262c6 Expand NO_ENTRY items from fake-super ACLs in get_rsync_acl(). 2011-05-30 08:39:07 -07:00
Wayne Davison
3ef38b0d1b Avoid adding a slash to path '/'. 2011-04-22 15:51:55 -07:00
Wayne Davison
5a1d092ae1 Fix a potential crash when trying to find a better block match. 2011-04-22 11:27:16 -07:00
Wayne Davison
1ddcdaf3f6 Preparing for release of 3.0.8 2011-03-26 14:34:18 -07:00
Wayne Davison
93562b1941 Mention CVE-2011-1097. 2011-03-26 14:31:45 -07:00
Wayne Davison
959bd70820 Tweak dir xattrs after the writability fudging. 2011-03-26 10:17:14 -07:00
Wayne Davison
a7271fb30f Avoid re-setting xattrs on a hard-linked file w/the same xattrs.
Improved the xattrs testing to include hard-linking.
2011-03-26 10:01:37 -07:00
Wayne Davison
277036153a Mention the latest changes. 2011-03-20 19:46:27 -07:00
Wayne Davison
bc6363f9ab Enhance the -liconv check for OS X. Fixes bug 8018. 2011-03-20 19:31:58 -07:00
Wayne Davison
e71130fd77 Don't send user/group names for ACLs with --numeric-ids.
Fixes bug 8020.
2011-03-18 14:42:28 -07:00
Wayne Davison
38c9f1becf Get rid of an unused extern. 2011-03-17 11:25:12 -07:00
Wayne Davison
779663fc6c Fix xattrs test on OS X. 2011-03-13 20:48:55 -07:00
Wayne Davison
9562cc8925 A few minor NEWS improvements. 2011-02-26 08:10:27 -08:00
Wayne Davison
a945aa19d9 Clarify what extraneous hard link are. 2011-02-23 07:19:23 -08:00
Wayne Davison
2a1d251750 Get rid of obsolete tempfs warning. 2011-02-22 15:37:13 -08:00
Wayne Davison
8750f64ec7 Preparing for release of 3.0.8pre1 2011-02-22 11:03:42 -08:00
Wayne Davison
922895d9a3 Mention even more fixes. 2011-02-22 10:58:33 -08:00
Wayne Davison
72193c82a6 Some uid/gid fixes for (id_t)-1.
The code now avoids any special internal meaning for gid -1.  If chown()
is called with a uid or gid of -1, complain that the ID is not settable
and signal a transfer error.
2011-02-22 10:48:13 -08:00
Wayne Davison
b178eb04d3 Allow a failure of EINVAL to mean no ACLs are available.
(If our POSIX types aren't valid, we can't handle the ACLs.)
2011-02-22 08:51:14 -08:00
Wayne Davison
3158b8df6c Fix --force with --one-file-system w/o --delete. 2011-02-22 08:21:08 -08:00
Wayne Davison
aa3640c09b Fix issue with devices-fake test. 2011-02-22 07:59:08 -08:00
Wayne Davison
07b5c770db Fix test 5's failure message. 2011-02-22 07:41:02 -08:00
Wayne Davison
8b7f20b6d3 Mention latest changes. 2011-02-21 11:32:51 -08:00
Wayne Davison
1dabd5dc9a A few more xattr-support fixes from the master branch. 2011-02-21 11:32:51 -08:00
Wayne Davison
58d657c98f Be clear on which part(s) of testsuite's checkit() failed. 2011-02-21 11:32:51 -08:00
Wayne Davison
e46262f36d Fix issues with unchanged_attrs() for symlinks. 2011-02-21 11:32:51 -08:00
Wayne Davison
4d92246a54 Use ftruncate() at the end of a --sparse file.
Fixes bug 7337.
2011-02-21 11:32:51 -08:00
Wayne Davison
8f48ba03b5 Integrate time-setting fixes/improvements from the master branch. 2011-02-21 11:32:48 -08:00
Wayne Davison
eb8058577d Make case_N.h more generic. 2011-02-21 10:20:58 -08:00
Wayne Davison
3c624bba85 Better mask handling, including some changes to help solaris. 2011-02-21 10:20:58 -08:00
Wayne Davison
24e76f840e Pass "new_mode" to set_acl() and change its return values. 2011-02-21 10:20:58 -08:00
Wayne Davison
b62ea517f6 Put file descriptor arg at the start of the arg list for consistency. 2011-02-21 10:20:58 -08:00
Wayne Davison
a6b3c2b512 Added more missing NEWS items. 2011-02-20 23:51:25 -08:00
Wayne Davison
4e95f91f27 Some manpage enhancements. 2011-02-20 23:48:19 -08:00
Wayne Davison
fad4ab9d0b Suggest a better solution for a make without wildcard support. 2011-02-20 23:48:19 -08:00
Wayne Davison
f91b15fbd6 Add .hg dir exclude to default_cvsignore list.
Fixes bug 7957.
2011-02-20 23:48:19 -08:00
Wayne Davison
83b94efa6b Switch over to Matt's idea of using FLAG_OWNED_BY_US. 2011-01-29 22:19:14 -08:00
Wayne Davison
2064c28d6d Move FLAG_DEL_NEEDS_UID into the "not stored" section. 2011-01-29 20:52:38 -08:00
Wayne Davison
c499002e51 Fix a random flist data bug w/delete, inc-recurse, and no -o.
Fixes bug 7936.
2011-01-29 19:25:53 -08:00
Wayne Davison
c8255147b0 Optimize finding the sum that matches our --inplace position. 2011-01-16 17:23:55 -08:00
Wayne Davison
eee85e3c36 Make sure an alternate --inplace sum has the right length
and add missing break in --inplace same-offset loop.
2011-01-14 15:45:12 -08:00
Wayne Davison
0c0219fe84 Some fixes and improvements from the master branch. 2011-01-13 23:03:59 -08:00
Wayne Davison
a92edcbf5c Avoid splitting a multi-byte character when trimming a name.
Fixes bug 7816.  Also makes the get_tmpname() code and comments
more like the master.
2011-01-03 20:07:28 -08:00
Wayne Davison
17549c95de Mention that sorting the --files-from input is helpful. 2011-01-03 19:49:29 -08:00
Wayne Davison
9d6fe1a6f0 Avoid reading ACL/xattr info on filetypes not being copied.
Make Linux avoid xattr access on symlinks.
Make OS X avoid xattr access on device/special files.
Fixes bug 5458.
2011-01-03 11:23:19 -08:00
Wayne Davison
c43624c575 Mention the latest changes. 2011-01-01 21:24:36 -08:00
Wayne Davison
4baef8d663 Make xattrs.test more like the master version. 2011-01-01 21:24:27 -08:00
Wayne Davison
c3ee6ac369 Avoid directory permission issues with --fake-super.
Fixes bug 7070.
2011-01-01 16:57:08 -08:00
Wayne Davison
63c5ac38a2 Report all socket connection errors if we fail.
Fixes bug 6588.
2011-01-01 13:55:03 -08:00
Wayne Davison
ce41e68995 Itemize xattrs of a missing dir from an alt-dest dir.
Fixes bug 6576.
2011-01-01 13:03:23 -08:00
Wayne Davison
8538db7829 Use full_fname() for system error messages. 2011-01-01 12:33:53 -08:00
Wayne Davison
559bd2ff31 Tweak the year. 2011-01-01 11:51:29 -08:00
Wayne Davison
485a40318c Protect a remote filename that starts with a dash. 2010-12-23 22:08:34 -08:00
Wayne Davison
ede8cae34b Tweak some apostrophes to make editor highlighting less problematic. 2010-12-19 09:11:46 -08:00
Wayne Davison
58ab32037d Optimize --inplace chunck search to avoid a non-aligned search. 2010-12-18 08:27:03 -08:00
Wayne Davison
00cde6582c Mention seek effect of an unmoved --inplace chunk. 2010-12-18 08:17:03 -08:00
Wayne Davison
e6ba6e1107 Improve description of --chmod example. 2010-12-18 08:13:52 -08:00
Wayne Davison
efad2e85ea Fix crash when --backup-dir is excessively long. 2010-12-16 22:20:10 -08:00
Wayne Davison
c463617443 Some quoting fixes/improvements. 2010-09-06 08:42:02 -07:00
Wayne Davison
6abb59adf6 If we create an off_t type, define SIZEOF_OFF_T. 2010-09-06 08:26:50 -07:00
Wayne Davison
d79bc5c791 Fix rsync_xal_set reference in an error. 2010-09-06 08:09:20 -07:00
Wayne Davison
10cd07c225 Avoid infinite loop if the file's length is negative.
Fixes bug 4664.
2010-09-06 08:05:26 -07:00
Wayne Davison
62e9eb7bc2 Mention need of wildcard support in make.
See bug 7625.
2010-08-28 18:05:20 -07:00
Wayne Davison
de20d72541 Remove duplication for -x option. 2010-08-28 18:04:09 -07:00
Wayne Davison
f8cd1c4730 A couple more NEWS items. 2010-07-03 09:30:44 -07:00
Wayne Davison
5de3fe19b6 Always use lchmod() if it is available. 2010-07-03 09:22:50 -07:00
Wayne Davison
0ac2d243bf Mention what -XX (repeated --xattrs) does. 2010-07-03 09:22:13 -07:00
Matt McCutchen
14556a30b3 Document the "copy-some-dirlinks" trick in the man page.
Originally explained at:

http://lists.samba.org/archive/rsync/2006-February/014838.html
2010-07-03 09:21:10 -07:00
Matt McCutchen
8c1f2d53ec Fix erroneous "--fake-user" in the rsyncd.conf(5) man page. 2010-07-03 09:20:07 -07:00
Matt McCutchen
f532cede11 In "ignoring unsafe symlink" messages, show only the file-list path.
Rsync was showing the full destination path, which was confusing because
nothing is created at that path and was especially bogus in combination
with the source name of a solo file.

http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=506830
2010-07-03 09:19:01 -07:00
Wayne Davison
05022e00a2 More NEWS. 2010-07-03 08:56:09 -07:00
Wayne Davison
24a743b565 If a module has no path setting, return an error. 2010-07-03 08:54:40 -07:00
Wayne Davison
e36f5c9f6c Mention latest changes. 2010-07-03 08:49:46 -07:00
Wayne Davison
c9c3215698 Refer to the right lsetxattr() caller in a error message. 2010-07-03 08:47:02 -07:00
Wayne Davison
dbfde9e50a Fix compression-ignoring of upper-case suffixes.
Fixes bug 7512.
2010-07-03 08:47:02 -07:00
Wayne Davison
1cdb5e1c86 Fix a couple socketpair_tcp() issues (see bug 7514). 2010-07-03 08:47:02 -07:00
Wayne Davison
24afdc500a Fix a typo that Andrea Gelmini pointed out. 2010-07-03 08:40:23 -07:00
Wayne Davison
303759b803 Get rid of trailing whitespace. 2010-07-03 08:40:23 -07:00
Matt McCutchen
a699f7c6af Man page description of --xattrs should not assume a push. 2010-07-03 08:37:25 -07:00
Wayne Davison
a250fa251b More manpage improvements. 2010-07-03 08:35:44 -07:00
Matt McCutchen
e44aa644c2 Amplify the man page description of --hard-links (see bug 3693), and
improve that of --inplace while I'm at it.
2010-07-03 08:33:24 -07:00
Wayne Davison
ef67c238b5 Reject passing an arg to an option that doesn't take one (bug 6915).
Based on a patch by Matt, but further tweaked to deal with -q=foo.
2010-07-03 08:27:38 -07:00
Wayne Davison
111599be2b Mention 2010 in the main copyright. 2010-07-03 08:24:58 -07:00
Wayne Davison
8e918e1861 Make an empty-string dest-dir the same as "." again. 2010-07-03 08:23:31 -07:00
Wayne Davison
0874fc4872 Setup for 3.0.8dev. 2010-06-30 09:19:01 -07:00
Wayne Davison
55dbbdeafe Fixed inconsistencies reported by packaging/var-checker. 2010-06-30 09:17:26 -07:00
Wayne Davison
cbd27d5e18 Update support/rrsync and some packaging/* scripts. 2010-06-30 09:17:13 -07:00
Matt McCutchen
178ccdde7d Rename configure.in to configure.ac, the current autoconf standard. 2010-06-30 08:29:48 -07:00
Wayne Davison
e51bb8f330 Write out the right compat_flags value into the batch file. 2010-06-26 16:14:15 -07:00
Wayne Davison
6d9207bd38 Turn some asserts into descriptive errors. 2010-06-26 16:13:58 -07:00
Wayne Davison
6b87566744 Make sure our use of idev_find() hashtable is right
while also supporting older rsyncs that send dev == 0.
2010-06-26 16:13:20 -07:00
Wayne Davison
b384d71e53 Make sure that the code doesn't try to use an illegal key. 2010-06-26 11:32:14 -07:00
Wayne Davison
11f4f34ed9 Fix daemon-filter crash issue (bug 7489). 2010-06-04 23:10:47 -07:00
Wayne Davison
fe2c582af8 Removing now-redundant path-size check from send_if_directory(). 2010-03-31 15:00:53 -07:00
Wayne Davison
2ecd8b7cd2 Fix directory-length overflow bug (7057). 2010-03-26 16:56:40 -07:00
Wayne Davison
54f00c3f89 Preparing for release of 3.0.7 2009-12-31 13:08:07 -08:00
Wayne Davison
1fc8c51705 Allow any gcc to make use of __builtin_alloca for alloca. 2009-12-30 20:03:49 -08:00
Wayne Davison
b04604945d Configure check for -Wno-unused-parameter now tries to link too. 2009-12-30 19:57:47 -08:00
Wayne Davison
808b1d61c0 Fixed the passing of a '/' modifier for an absolute-path filter rule. 2009-12-30 12:25:33 -08:00
Wayne Davison
2f01fb1152 Preparing for release of 3.0.7pre2 2009-12-24 08:31:37 -08:00
Wayne Davison
ae358c1960 Revert to having the receiver handle timeouts on the receiving side.
This will give 3.0.7 the standard timeout handling with just a few
improvements: a fix for the detection of recent sender I/O, the use
of MSG_DATA for really old rsync versions, and better setting of
select_timeout for shorter timeout settings.
2009-12-23 11:36:27 -08:00
Wayne Davison
212dfdb960 Preparing for release of 3.0.7pre1 2009-12-21 18:25:00 -08:00
Wayne Davison
c11a77894b Ensure that the generator gets notified about an I/O error for the dir
that generated the error.  This ensures that a --delete-during avoids
deleting in a newly transferred inc-recurse directory.  Requires 3.0.7
or greater on both sides of the transfer.
2009-12-21 14:40:41 -08:00
Wayne Davison
96cce18ce6 Defer forwarding messages during the forwarding of flist data. 2009-12-21 13:48:44 -08:00
Wayne Davison
a21264a8b9 Mention the compress fix. 2009-12-21 10:52:54 -08:00
Wayne Davison
96486cc534 Mention latest --timeout fixes. 2009-12-21 10:25:15 -08:00
Wayne Davison
e0b1b82d84 Don't die if inflate() returns Z_BUF_ERROR in see_deflate_token(). 2009-12-21 10:15:39 -08:00
Wayne Davison
d94b958400 Improve --timeout method to take into account all socket I/O that is
going on.  The receiving side also switches timeout handling from the
receiver to the generator.  Given this setup, all keep-alive messages
are now sent as empty MSG_DATA messages, with MSG_NOOP messages only
being understood and (when necessary) acted upon to forward a keep-alive
event to an older receiver.  This is both safer and more compatible with
older versions.
2009-12-19 13:39:49 -08:00
Wayne Davison
79731940bb Added an am_receiver variable. 2009-12-19 12:04:25 -08:00
Wayne Davison
bdc038fce0 Use 0-length MSG_DATA when MSG_NOOP is not available
(is both safer and supports older rsyncs).
2009-12-16 13:32:03 -08:00
Wayne Davison
2eacba9c41 Avoid -u option to id since solaris doesn't support it. 2009-12-13 19:35:01 -08:00
Wayne Davison
0c5853c32e Get rid of some unused externs. 2009-12-12 22:43:51 -08:00
Wayne Davison
3baa4d2b31 Include info on who is exiting. 2009-12-12 22:42:35 -08:00
Wayne Davison
018dc6f998 Mention the newly cherry-picked changes. 2009-12-12 17:26:11 -08:00
Wayne Davison
523dad4bb3 Use seteuid() (if available) when using setuid(). 2009-12-12 17:26:05 -08:00
Wayne Davison
e0c17aa3b7 Beginning work on a 3.0.7 release. 2009-12-12 17:25:48 -08:00
Wayne Davison
79870bd269 Don't (wrongly) retouch dir permissions with --fake-super.
(Patch from Matt.)
2009-12-12 17:25:19 -08:00
Wayne Davison
e4368e37fe Add IPv6 detection on cygwin. 2009-12-12 17:25:12 -08:00
Wayne Davison
eee529f571 Save first filename and linenum in case exit_cleanup() recurses. 2009-12-12 17:25:06 -08:00
Wayne Davison
ff4715a7c2 Moved some --iconv text that was supposed to be in --files-from. 2009-12-12 17:24:45 -08:00
Wayne Davison
855983b434 Make sure daemon's io_timeout is used as a maximum value. 2009-12-12 17:24:39 -08:00
Wayne Davison
2455140b04 Fix some man page problems Scott Kostyshak pointed out. 2009-12-12 17:24:33 -08:00
Wayne Davison
ae4d4205e3 Avoid type-punned compiler warnings for the byteorder.h macros
by using inline functions for the 4-char <-> uint32 conversions.
2009-12-12 17:24:29 -08:00
Wayne Davison
9523670032 Improve the "--delete does not work without -r or -d" message. 2009-12-12 17:23:55 -08:00
Wayne Davison
01e57e926c Improve error handling and get rid of a lingering fprintf(). 2009-12-12 17:23:45 -08:00
Wayne Davison
ebbab3788f Fix daemon's conveyance of io_error value from sender. 2009-12-12 17:23:03 -08:00
Wayne Davison
d041c17c40 Avoid an dry-run error trying to stat a prior hard-link
file that hasn't really been created.
2009-12-12 17:22:55 -08:00
Wayne Davison
b2b1af40c2 Rebuild proto.h if config.h changes. 2009-12-12 17:22:43 -08:00
Wayne Davison
c5759a2817 Fix the chmod-temp-dir test if /var/tmp doesn't exist.
Fixes bug 6569.
2009-12-12 17:22:12 -08:00
Wayne Davison
5ef08b8c39 Get section reference right. Fixes bug #6573. 2009-12-12 17:22:05 -08:00
Wayne Davison
03f907e386 Added solaris IPv6 checking to configure. Fixes #6438.
Patch from Tim Spriggs.
2009-12-12 17:21:25 -08:00
Wayne Davison
573e24346c Mention that --whole-file is not the default for a local transfer when
writing a batch file.
2009-12-12 17:21:08 -08:00
Wayne Davison
a415379037 Support an older AIX system that doesn't have ENOTSUP. 2009-12-12 17:20:42 -08:00
Wayne Davison
cc4edc2d78 Switch from inet_aton() to inet_pton() (since we supply a compatibility
function for the latter, it will always exist).
2009-12-12 17:20:35 -08:00
Wayne Davison
07bd6618b9 Allow $RSYNC_TEST_TMP to indicate a good tmp dir for our tests. 2009-12-12 17:19:59 -08:00
Wayne Davison
2daed024b1 Fix a bogus free in uncache_tmp_xattrs(). 2009-08-14 07:04:24 -07:00
Wayne Davison
6622816eff Preparing for release of 3.0.6 2009-05-08 10:07:14 -07:00
Wayne Davison
3f137ce0e2 Fix typo pointed out by Chris Pepper. 2009-05-07 08:04:24 -07:00
Matt McCutchen
d616bff57f Move the description of include/exclude modifiers to a better place
in the man page.
2009-05-05 08:18:36 -07:00
Wayne Davison
40b3a59fc8 Clarify which options are transfer rules, and what that means. 2009-04-27 07:26:04 -07:00
Wayne Davison
4640ae85fe Change sending/receiving/storing of the rdev value for special files.
Since the value is not needed, the (superfluous) sending of the value
is optimized so that a valid rdev value is sent as efficiently as
possible.  The receiver no longer caches an rdev value for special
files, and the generator will always pass a 0 rdev value to do_mknod()
for special files. Fixes bug #6280.
2009-04-26 07:51:50 -07:00
Wayne Davison
24f739c118 Clarify the read-batch fix. 2009-04-13 07:42:20 -07:00
Wayne Davison
996824825f Preparing for release of 3.0.6pre1 2009-04-12 15:28:34 -07:00
Wayne Davison
bbef6566cd Changed the commands used to "make gen" without any stoppage. 2009-04-12 15:19:30 -07:00
Wayne Davison
9be5093726 Don't allow --remove-s*-files with --read-batch. 2009-04-12 13:01:14 -07:00
Wayne Davison
feb8dacc14 Fixed the use of --xattrs with --only-write-batch. 2009-04-12 12:48:59 -07:00
Wayne Davison
ff908116ef Allow a "make reconfigure" to continue, even if the Makefile changes. 2009-04-10 16:24:49 -07:00
Wayne Davison
ea53d161be Fixed an ACL/xattr corruption issue where the --backup option could cause
rsync to associate the wrong ACL/xattr information with received files.
2009-04-10 16:09:39 -07:00
Wayne Davison
7875e6fe63 Don't try to simplify an ACL that has a mask w/o any named values. 2009-04-09 22:52:26 -07:00
Wayne Davison
8e2771aa6e Some improvements to the rsync.yo manpage:
- Mention the switch from MD4 to MD5.
- Mention the default for the --log-file-format option.
2009-04-07 07:40:30 -07:00
Wayne Davison
386f22cec6 Make sure that config.h.in is up-to-date before allowing the
Makefile-updating rule to run ./config.status.
2009-04-04 07:53:14 -07:00
Wayne Davison
272adea36b Fixed --dry-run with --read-batch:
- Avoid sending MSG_NO_SEND to the generator.
- Check if the file is wanted before discarding the batched data.
2009-04-04 07:38:37 -07:00
Wayne Davison
a69b165524 Fixed improper deletion of mount-point hierarchies.
Fixes bug #6240.
2009-03-31 20:26:10 -07:00
Wayne Davison
bf350d7b31 Fixed a word ending that Jesse Weinstein and revamp some of the text
to make it clearer.
2009-03-31 14:35:53 -07:00
Wayne Davison
70a9cd5752 Make symlink iconv work for a local copy.
Fixes issue mention in bug #5615.
2009-03-29 13:25:43 -07:00
Matt McCutchen
42560e2e53 Give a meaningful error message when we fail to write to a batch file. 2009-03-13 09:46:39 -07:00
Wayne Davison
d058d0aecd Simplify an "if" in ssh-basic.test. Fixes bug #6169; 2009-03-06 07:08:49 -08:00
Wayne Davison
af00666a40 Mention the fix to --safe-links/--copy-unsafe-links. 2009-03-03 09:00:29 -08:00
Wayne Davison
2517f5440d Improved the unsafe_symlink() code to not get fooled by extra '/' chars
in the symlink's path.  Added test cases.  This fixes bug #6151.
2009-03-03 08:57:43 -08:00
Wayne Davison
f2522e3f53 Make the backup code call unsafe_symlink() correctly. 2009-03-03 08:57:39 -08:00
Wayne Davison
8fba76d5c3 Mention vanishing-directory fix. 2009-02-14 08:38:24 -08:00
Wayne Davison
782b96d3e2 Handle a link_stat() failure with errno ENOENT as a vanished file. 2009-02-14 08:37:10 -08:00
Wayne Davison
1f6b697f28 Mention the latest configure fixes. 2009-02-14 08:05:07 -08:00
Wayne Davison
919491948e Added --disable-iconv-open option for configure to turn off all use
of the iconv_open() function.  Implies --disable-iconv (which turns
off the --iconv option).  Fixes bug #6107.
2009-02-14 07:57:50 -08:00
Wayne Davison
0ea6f486d9 Moved the --disable-debug check sooner in configure.in so that it
happens prior to checking for the compiler.  Switched no-debug code
to setting ac_cv_prog_cc_g=no.  Fixes bug #6106.
2009-02-14 07:57:36 -08:00
Wayne Davison
9493048c10 Ensure that the sender turns off any msg_fd_in use earlier.
This avoids a problem where an extra message from the sender
could give the generator time to start sending data that will
not be understood by the sender's use of read_msg_fd().
2009-02-04 18:27:07 -08:00
Wayne Davison
4dea1a9492 Do not try to send a symlink with a 0-length value.
This avoids a transfer error in the receiver.
2009-02-04 18:16:16 -08:00
Wayne Davison
650bca3770 A few more improvements to the hostspec-parsing code. 2009-01-28 23:18:45 -08:00
Wayne Davison
794f38099a Fixed the parsing of IPv6 literal addresses with a username
prefixed.  Fixes bug #6067.
2009-01-28 15:58:48 -08:00
Wayne Davison
8250d8a1c6 Fixed a hang in the inc_recurse batch-reading code. 2009-01-17 13:54:52 -08:00
Matt McCutchen
1fb6163c51 Handle simultaneous arrival of multiple connections. 2009-01-17 13:46:11 -08:00
Wayne Davison
7f51d0e849 Avoid a server-side problem with -e is at the start of the short options.
(Bug #6020)
2009-01-17 13:44:06 -08:00
Wayne Davison
ece2d0e415 Fixed bug #6011: use of target in configure. 2009-01-17 13:43:48 -08:00
Wayne Davison
445640e803 Update the copyright year. 2009-01-17 13:41:35 -08:00
Wayne Davison
5ea7c8aae3 Beginning work on a 3.0.6 release. 2009-01-17 13:37:20 -08:00
Wayne Davison
7221063019 Preparing for release of 3.0.5 2008-12-28 18:02:17 -08:00
Wayne Davison
b64ae8b3b4 Avoid a hang when using at least 3 --verbose options on a transfer with
a client sender (which includes local copying).
2008-12-28 17:51:36 -08:00
Wayne Davison
9938bad34a Allow opendir() in send_directory() to fail with ENOENT. 2008-12-27 11:22:02 -08:00
Wayne Davison
1ff3e90507 Make it clearer which configure files changed. 2008-11-15 15:32:02 -08:00
Wayne Davison
b292021e45 Mention a few NEWS items that hadn't been mentioned yet. 2008-11-15 15:25:30 -08:00
Wayne Davison
13e40ca0c6 Preparing for release of 3.0.5pre2 2008-11-15 14:55:30 -08:00
Wayne Davison
8e85627fb3 An ftruncate() failure should result in FERROR_XFER. 2008-11-15 14:49:28 -08:00
Wayne Davison
d552250fbb Tweaked the month guess in OLDNEWS. 2008-11-15 14:38:14 -08:00
Wayne Davison
5436b64557 Change clean_fname() to keep "//" at the start for cygwin. 2008-11-15 14:17:49 -08:00
Wayne Davison
b325dd0326 Change some size_t vars to ints. 2008-11-15 13:29:03 -08:00
Wayne Davison
49818a8378 Make sparse_seek an OFF_T (pointed out by Pedro Valasco). 2008-11-11 18:06:50 -08:00
Wayne Davison
af03a7049c A "make reconfigure" doesn't stop if configure changes. 2008-11-11 15:55:53 -08:00
Wayne Davison
e401b30403 Mention Matt's -K --delete fix. 2008-11-10 07:48:00 -08:00
Matt McCutchen
e512826786 Add flist_find_ignore_dirness() and change delete_in_dir() to use it.
This fixes an issue with -K noticed by eric casteleijn, avoids some
inconsistent itemizing when a file/dir is replaced by a dir/file,
and removes a now-obsolete chunk of code from make_file().
2008-11-10 07:46:41 -08:00
Wayne Davison
ccdc2efd67 Mention the fix for --files-from dot/./paths. 2008-11-09 21:48:21 -08:00
Wayne Davison
b8a1fd6404 Fixed the use of a dot-dir path (foo/./bar) inside of a files-from file. 2008-11-09 21:39:08 -08:00
Wayne Davison
3082dffbe2 Fixed a bunch of "warn_unused_result" compiler warnings. 2008-11-09 18:55:14 -08:00
Wayne Davison
42130f9cb0 Mention hang fix in the NEWS. 2008-11-09 18:07:30 -08:00
Wayne Davison
c6c339cd18 Avoid a potential hang when --remove-*-files is active. 2008-11-09 18:02:11 -08:00
Matt McCutchen
6767ca617b The protect filter automatically added with --backup is not perishable
(see f41152d393), so remove the inaccurate
"p" from the man page.  Noticed by Jacob Balazer:

http://lists.samba.org/archive/rsync/2008-November/022022.html
2008-11-02 20:53:01 -08:00
Wayne Davison
7d9e30d383 Mention the getnameinfo() fix in the NEWS. 2008-10-25 09:47:08 -07:00
Wayne Davison
3f81ad6060 Mention rsync's definition of client and server. 2008-10-25 09:44:21 -07:00
Wayne Davison
723e9f856d Fixed our supplied getnameinfo()'s ability to do a reverse lookup,
as reported in bug 5851.
2008-10-25 08:39:41 -07:00
Wayne Davison
9189e41f6e Added another file-list filter to handle odd-ball systems that don't
seem to size their sprintf() fields correctly.
2008-10-14 07:27:56 -07:00
Wayne Davison
6f6f9d1020 Preparing for release of 3.0.5pre1 2008-10-11 11:41:05 -07:00
Wayne Davison
a76ba8b425 Mention the latest NEWS. 2008-10-11 11:40:40 -07:00
Wayne Davison
b8fd528794 Fixed a glitch when using -s with a remote-shell daemon. 2008-10-11 11:14:43 -07:00
Wayne Davison
0ea5d30479 Don't lookup address "0.0.0.0" when we're a remote-shell daemon.
Gets rid of a DNS delay waiting for a lookup failure.
2008-10-11 11:13:43 -07:00
Wayne Davison
cf1b292201 Fixed send_protected_args() to send "." in place of an empty arg. 2008-10-11 10:16:47 -07:00
Wayne Davison
f3721ed133 Added a fully atomic update if the user has setup a symlink
to a *-1 or *-2 directory.  A few other minor improvements.
2008-10-11 09:29:23 -07:00
Wayne Davison
b1220d62f4 Fix the error message on one of the rename operations. 2008-10-10 06:55:21 -07:00
Wayne Davison
5df89a1a44 Remove bogus "non-empty" qualifier in '*' discussion. 2008-09-26 21:47:53 -07:00
Wayne Davison
d47ac91209 Properly ignore source args on a --read-batch command. 2008-09-26 21:34:40 -07:00
Wayne Davison
7c573428a9 Fixed skipping of unneeded updates in a batch file when incremental
recursion is active.  Added a test for this.  Made batch-mode handle
redos properly (and without hanging).
2008-09-26 21:32:43 -07:00
Wayne Davison
f7e65c7b61 Moved the flist_ndx_{push,pop}() routines from io.c into util.c. 2008-09-26 21:21:52 -07:00
Wayne Davison
fe62d30de8 Fix the %P logfile escape inside a chroot. 2008-09-26 21:19:51 -07:00
Wayne Davison
494895fb4b Initialize xattr data in a couple spots in the hlink code, which avoids
a crash when the xattr pointer's memory happens to start out non-zero.
Also fixed the itemizing of an alt-dest file's xattrs when hard-linking.
2008-09-26 21:10:58 -07:00
Wayne Davison
ac68345a34 Don't send a bogus "-" option to an older server if there were
no short options specified.
2008-09-26 21:09:41 -07:00
Wayne Davison
6a9ade2ded Beginning work on a 3.0.5 release. 2008-09-26 21:07:56 -07:00
Wayne Davison
d596d389fe Preparing for release of 3.0.4 2008-09-06 09:32:26 -07:00
Wayne Davison
bc2337717e A few more improvements and a mention of the latest fix. 2008-09-06 08:03:52 -07:00
Wayne Davison
3df40f044a Changed some "rsync" commands into proper "$RSYNC" commands. 2008-09-03 12:14:13 -07:00
Wayne Davison
d11a5b80c1 Made human_num() and human_dnum() able to output negative numbers. 2008-09-01 13:25:41 -07:00
Wayne Davison
deea1f70bd Got rid of the check_for_io_err code, as it could cause a hang.
The io_error issue will be fixed in a better way in 3.1.0.
2008-08-31 09:51:29 -07:00
Wayne Davison
a91e678324 Some minor improvements to the flushing code to try to make it
even more solid.
2008-08-24 13:39:44 -07:00
Wayne Davison
25a22d8501 Make the !flist_eof assumption explicit before the check_for_io_err
code calls wait_for_receiver().
2008-08-24 12:33:22 -07:00
Wayne Davison
fac9e234ae Added /support/savetransfer to .gitignore. 2008-08-17 09:28:06 -07:00
Wayne Davison
f3d87ee972 An improved RERR_PARTIAL message. 2008-08-17 09:25:34 -07:00
Wayne Davison
9bed85542c Changed flist_for_ndx() to optionally die with an error
if the index isn't found.
2008-08-14 07:32:18 -07:00
Wayne Davison
5b979530a7 Made an error of readlink_stat() use the right function name. 2008-08-10 07:31:45 -07:00
Wayne Davison
7ec8baaa7e Make sure that the hlink node->data allocation doesn't fail. 2008-08-08 07:47:31 -07:00
Wayne Davison
8c2c008984 Improved a couple NEWS items. 2008-08-05 18:43:51 -07:00
Wayne Davison
719a29e1cf Preparing for release of 3.0.4pre2 2008-08-02 14:06:31 -07:00
Wayne Davison
4a95d61251 Tweaked the symlink iconv buffer size and fixed a comment. 2008-08-02 13:45:15 -07:00
Wayne Davison
fc088e30c8 When using --iconv, if a server-side receiver can't convert a filename,
it now outputs the name back to the client without mangling the charset.
2008-08-02 10:25:17 -07:00
Wayne Davison
aef51b4c68 Refer to the symlink's contents as "symlink data", not "symlink name". 2008-08-02 10:18:10 -07:00
Wayne Davison
7790ee3684 Added logic to the receiving side to ensure that the --delete-during
code will not delete in a directory prior to receiving an I/O error
for that directory (or not receiving it, as the case may be).
2008-08-02 09:03:49 -07:00
Wayne Davison
ed12c8eb21 Skip new symlink conversion step if the remote rsync is not
new enough to do symlink content conversions.
2008-08-02 07:04:54 -07:00
Wayne Davison
91dd3d0d48 The --iconv option now converts the content of a symlink too. 2008-08-01 19:20:41 -07:00
Wayne Davison
95d1d2a9a4 Fixed a problem with checking for the '.' dir in the first file
list that is transferred.  This fixes a glitch where a failed
--iconv conversion on the receiving side could prevent deletions
from happening in the root-dir of the transfer.
2008-08-01 19:00:21 -07:00
Wayne Davison
a808346dbe Fixed a couple minor problems in util.c:
- Make sure that handle_partial_dir() never returns a truncated fname.
- Make robust_rename() return that it failed to do a cross-device
  copy if the partial-dir could not be created.
2008-08-01 18:00:18 -07:00
Wayne Davison
fa181223d8 Properly handle a failure to create a partial directory, which is
especially important for --delay-updates, particularly when
--remove-source-files was also specified.
2008-08-01 18:00:09 -07:00
Wayne Davison
9ed569486f Output an FERROR* for a general io_error, and an FWARNING for other
io_error flags.
2008-07-31 07:57:55 -07:00
Wayne Davison
2fa069d85f Mention a missing sender-side hash improvment that went out in 3.0.0. 2008-07-30 08:33:35 -07:00
Wayne Davison
a25aed50e6 Make hard-linking work when a device has an st_dev of 0. 2008-07-29 18:08:51 -07:00
Wayne Davison
302e4346c2 Mention some mount options that can interfere with --link-dest. 2008-07-28 18:24:25 -07:00
Wayne Davison
8e5eafccdf Back-porting some manpage improvements. 2008-07-28 17:07:38 -07:00
Wayne Davison
e88b92bade Preparing for release of 3.0.4pre1 2008-07-24 17:03:26 -07:00
Wayne Davison
f8722dba56 Fixed the --fake-super test in the xattrs testsuite when there are
root-level xattrs on the files (e.g. selinux values).
2008-07-24 07:57:57 -07:00
Wayne Davison
ee03cb99d9 Fixed the timeout/flush loop-check logic to work properly with
incremental recursion.
2008-07-23 23:37:11 -07:00
Wayne Davison
92d706a274 Don't interrupt the make if a generated build file didn't really change. 2008-07-23 23:28:57 -07:00
Wayne Davison
581c830c56 A couple xattr fixes for --fake-super. 2008-07-23 23:12:39 -07:00
Wayne Davison
9e58ef45f3 If the user specifies --protocol=29, rsync will avoid sending an -e
option to the server (which is only useful for protocols 30 and above
anyway).  This gives the user an easy way to talk to a restricted
server that has overly restrictive option-checking.
2008-07-23 23:09:15 -07:00
Wayne Davison
05bd05a7a1 Pass --branch option to patch-update script. 2008-07-23 17:13:29 -07:00
Wayne Davison
89b6b4ce4b We only need to deal with local patch branches now. 2008-07-23 14:32:58 -07:00
Wayne Davison
68cdc3b791 Fixed a potential alignment issue in the IRIX ACL code when allocating
the initial struct acl object.  Also, cast mallocs to avoid warnings.
2008-07-22 21:35:21 -07:00
Wayne Davison
209371b891 Fixed a bug in match_hard_links() where an empty directory would try
to allocate 0 bytes of memory (which can fail on some OSes).
2008-07-22 21:34:20 -07:00
Wayne Davison
6fd2662982 Allow a release from a non-master branch. 2008-07-22 09:11:34 -07:00
Wayne Davison
1fdf0302c0 Start the 3.0.4 branch. 2008-07-22 09:11:22 -07:00
419 changed files with 25239 additions and 64486 deletions

8
.gitattributes vendored
View File

@@ -1,8 +0,0 @@
* text=auto eol=lf
# The rsync-web/ subdirectory holds the project website source content
# (mirrors what gets pushed to https://rsync.samba.org). Exclude it from
# `git archive` output so the release source tarball produced by
# packaging/release.py step_7_tarball does not bloat with HTML the
# tarball doesn't need.
/rsync-web/ export-ignore

View File

@@ -1,82 +0,0 @@
name: Test rsync on AlmaLinux 8
# Older-LTS coverage on the Fedora/RHEL family to help with backporting
# security fixes. AlmaLinux 8 is the RHEL 8 rebuild and is the oldest
# active LTS in this family (RHEL 8 full support runs to 2029).
# GitHub Actions has no native runner for this family, so the job runs
# inside an almalinux:8 container hosted on ubuntu-latest.
on:
push:
branches: [ master ]
paths-ignore:
- '.github/workflows/*.yml'
- '!.github/workflows/almalinux-8-build.yml'
pull_request:
branches: [ master ]
paths-ignore:
- '.github/workflows/*.yml'
- '!.github/workflows/almalinux-8-build.yml'
schedule:
- cron: '42 8 * * *'
jobs:
test:
runs-on: ubuntu-latest
container:
image: almalinux:8
name: Test rsync on AlmaLinux 8
steps:
- name: install git
# actions/checkout needs git in the container before the checkout step.
run: dnf -y install git
- uses: actions/checkout@v4
with:
fetch-depth: 0
- name: prep
# PowerTools is needed for libzstd-devel etc; xxhash and lz4 dev
# headers live in EPEL on RHEL 8. The default python3 on RHEL 8
# is 3.6, which is too old for runtests.py (uses capture_output=
# / text= introduced in 3.7), so install python39 and point
# /usr/bin/python3 at it.
run: |
dnf -y install epel-release
dnf config-manager --set-enabled powertools
dnf -y install gcc gcc-c++ make autoconf automake m4 \
python39 python39-pip diffutils \
openssl openssl-devel \
attr libattr-devel acl libacl-devel \
zstd libzstd-devel \
lz4 lz4-devel \
xxhash xxhash-devel
alternatives --set python3 /usr/bin/python3.9
pip3 install commonmark
- name: configure
run: ./configure --with-rrsync
- name: make
run: make
- name: info
run: ./rsync --version
- name: check
# In the container we already run as root, so no sudo. The
# crtimes-not-supported skip matches the other Linux jobs;
# daemon-chroot-acl and proxy-response-line-too-long skip because
# the default (secure) transport opens no listening socket.
run: RSYNC_EXPECT_SKIPPED=crtimes,daemon-access-ip,daemon-chroot-acl,proxy-response-line-too-long make check
- name: check (TCP daemon transport)
# Second run exercising the real loopback-TCP daemon path.
run: ./runtests.py --rsync-bin=`pwd`/rsync --use-tcp -j 8
- name: ssl file list
run: ./rsync-ssl --no-motd download.samba.org::rsyncftp/ || true
- name: save artifact
uses: actions/upload-artifact@v4
with:
name: almalinux-8-bin
path: |
rsync
rsync-ssl
rsync.1
rsync-ssl.1
rsyncd.conf.5
rrsync.1
rrsync

View File

@@ -1,120 +0,0 @@
name: Build static rsync for Android
# Cross-compiles statically-linked rsync binaries with the Android NDK,
# suitable for dropping onto a phone (adb push / Termux) with no shared
# libraries. arm64-v8a covers all modern phones; armeabi-v7a covers older
# 32-bit devices. The binaries are uploaded as workflow artifacts.
#
# These are cross-compiled, so the test suite can't run here; we sanity
# check that each binary is the right architecture, is static, and that
# it executes (`--version`) under qemu-user.
on:
push:
branches: [ master ]
paths-ignore:
- '.github/workflows/*.yml'
- '!.github/workflows/android-static-build.yml'
pull_request:
branches: [ master ]
paths-ignore:
- '.github/workflows/*.yml'
- '!.github/workflows/android-static-build.yml'
schedule:
- cron: '42 8 * * *'
workflow_dispatch:
env:
# Minimum supported API level. 24 (Android 7.0) runs on every modern
# phone while keeping broad reach; bump if you need newer Bionic APIs.
ANDROID_API: 24
jobs:
build:
runs-on: ubuntu-latest
name: ${{ matrix.abi }}
strategy:
fail-fast: false
matrix:
include:
- abi: arm64-v8a # modern phones
triple: aarch64-linux-android
qemu: qemu-aarch64-static
- abi: armeabi-v7a # older 32-bit phones
triple: armv7a-linux-androideabi
qemu: qemu-arm-static
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Install build prerequisites
run: sudo apt-get update && sudo apt-get install -y autoconf automake gawk qemu-user-static
- name: Configure and build (${{ matrix.abi }})
shell: bash
run: |
set -euo pipefail
NDK="${ANDROID_NDK_LATEST_HOME:-$ANDROID_NDK_ROOT}"
TC="$NDK/toolchains/llvm/prebuilt/linux-x86_64/bin"
export CC="$TC/${{ matrix.triple }}${ANDROID_API}-clang"
export AR="$TC/llvm-ar" RANLIB="$TC/llvm-ranlib" STRIP="$TC/llvm-strip"
export CFLAGS="-O2" LDFLAGS="-static"
# Bionic doesn't declare lchmod()/lutimes() until API 36, but the
# symbols link, so configure mis-detects them -- force them off so
# rsync uses its fallbacks. The other cache vars restore values
# that configure can't probe when cross-compiling (Android runs a
# normal Linux kernel, so these match the native Linux result).
export ac_cv_func_lchmod=no ac_cv_func_lutimes=no \
rsync_cv_HAVE_SOCKETPAIR=yes \
rsync_cv_MKNOD_CREATES_FIFOS=yes \
rsync_cv_MKNOD_CREATES_SOCKETS=yes
# Self-contained build: drop optional external libraries so the
# static binary needs nothing at runtime. rsync keeps md5/md4
# checksums and its bundled zlib.
./configure --host=${{ matrix.triple }} --build=x86_64-pc-linux-gnu \
--enable-ipv6 \
--disable-zstd --disable-lz4 --disable-xxhash --disable-openssl \
--disable-iconv --disable-iconv-open \
--disable-acl-support --disable-xattr-support \
--disable-md2man --disable-roll-simd \
--with-included-popt --with-included-zlib
# Generate the awk-built headers serially first so the parallel
# build can't race on proto.h <- daemon-parm.h.
make proto.h
make -j"$(nproc)" rsync
"$STRIP" rsync
- name: Verify binary
shell: bash
run: |
set -euo pipefail
file rsync
# Gate: must be a statically-linked executable (no interpreter).
file rsync | grep -q "statically linked"
if file rsync | grep -q "dynamically linked"; then
echo "ERROR: binary is not static" >&2; exit 1
fi
# Best-effort: confirm it actually runs under qemu-user.
${{ matrix.qemu }} ./rsync --version | head -3 || \
echo "WARNING: qemu smoke test did not run cleanly (check on a real device)"
- name: Package
shell: bash
run: |
set -euo pipefail
VER=$(sed -n 's/.*RSYNC_VERSION "\([^"]*\)".*/\1/p' version.h)
out="rsync-${VER}-android-${{ matrix.abi }}"
mkdir -p dist
cp rsync "dist/$out"
( cd dist && sha256sum "$out" > "$out.sha256" )
echo "ARTIFACT_NAME=rsync-android-${{ matrix.abi }}" >>"$GITHUB_ENV"
- name: Upload artifact
uses: actions/upload-artifact@v4
with:
name: ${{ env.ARTIFACT_NAME }}
path: dist/

View File

@@ -1,71 +0,0 @@
name: Coverage (Ubuntu)
on:
push:
branches: [ master ]
paths-ignore:
- '.github/workflows/*.yml'
- '!.github/workflows/coverage.yml'
pull_request:
branches: [ master ]
paths-ignore:
- '.github/workflows/*.yml'
- '!.github/workflows/coverage.yml'
schedule:
- cron: '42 9 * * *'
workflow_dispatch:
jobs:
coverage:
runs-on: ubuntu-latest
name: gcov coverage
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0
- name: prep
run: |
sudo apt-get update
sudo apt-get install -y acl libacl1-dev attr libattr1-dev liblz4-dev libzstd-dev libxxhash-dev python3-cmarkgfm openssl gcovr
echo "/usr/local/bin" >>$GITHUB_PATH
- name: configure
run: ./configure --enable-coverage --with-rrsync
- name: make
run: make
- name: info
run: rsync --version
# Two coverage runs: the default pipe transport, then a second pass over a
# real loopback rsyncd (--use-tcp) which also exercises the require_tcp-only
# tests. gcovr's --print-summary line/branch/decision totals go to the step
# log (and the job summary below), so the numbers are visible in CI.
# `make coverage` exits with the suite's status, so a regression fails CI.
- name: coverage (pipe transport)
run: |
set -o pipefail
sudo make coverage 2>&1 | tee cov-pipe.log
- name: coverage (TCP transport)
run: |
set -o pipefail
sudo make coverage-tcp 2>&1 | tee cov-tcp.log
- name: coverage summary
if: always()
run: |
{
echo "## gcov coverage"
echo "### Pipe transport (\`make coverage\`)"
echo '```'
grep -E '^(lines|functions|branches|decisions):' cov-pipe.log || echo '(no summary -- see step log)'
echo '```'
echo "### TCP transport (\`make coverage-tcp\`)"
echo '```'
grep -E '^(lines|functions|branches|decisions):' cov-tcp.log || echo '(no summary -- see step log)'
echo '```'
} >> "$GITHUB_STEP_SUMMARY"
- name: upload HTML reports
if: always()
uses: actions/upload-artifact@v4
with:
name: coverage-html
path: |
coverage
coverage-tcp

View File

@@ -1,65 +0,0 @@
name: Test rsync on Cygwin
on:
push:
branches: [ master ]
paths-ignore:
- '.github/workflows/*.yml'
- '!.github/workflows/cygwin-build.yml'
pull_request:
branches: [ master ]
paths-ignore:
- '.github/workflows/*.yml'
- '!.github/workflows/cygwin-build.yml'
schedule:
- cron: '42 8 * * *'
jobs:
test:
runs-on: windows-2022
name: Test rsync on Cygwin
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0
- name: cygwin
run: choco install -y --no-progress cygwin cyg-get
- name: prep
run: |
cyg-get make autoconf automake gcc-core attr libattr-devel python39 python39-pip libzstd-devel liblz4-devel libssl-devel libxxhash0 libxxhash-devel
echo "C:/tools/cygwin/bin" >>$Env:GITHUB_PATH
- name: commonmark
run: bash -c 'python3 -mpip install --user commonmark'
- name: configure
run: bash -c './configure --with-rrsync'
- name: make
run: bash -c 'make'
- name: install
run: bash -c 'make install'
- name: info
run: bash -c '/usr/local/bin/rsync --version'
- name: check
# chown-fake / devices-fake / xattrs / xattrs-hlink now RUN on Cygwin
# (rsyncfns.py drives xattrs via getfattr/setfattr from the `attr`
# package installed above), verified on a real Cygwin host. The real
# chown/devices tests still skip (need root/mknod), as do the
# RESOLVE_BENEATH symlink-race tests.
run: bash -c 'RSYNC_EXPECT_SKIPPED=acls-default,acls-depth,acls,bare-do-open-symlink-race,chdir-symlink-race,chown,daemon-access-ip,daemon-chroot-acl,devices,dir-sgid,open-noatime,protected-regular,proxy-response-line-too-long,sender-flist-symlink-leak,simd-checksum,symlink-dirlink-basis make check'
- name: check (TCP daemon transport)
# Second run with daemon tests over a real loopback rsyncd; the default
# 'make check' above uses the secure stdio-pipe transport.
run: bash -c './runtests.py --rsync-bin=`pwd`/rsync.exe --use-tcp -j 8'
- name: ssl file list
run: bash -c 'PATH="/usr/local/bin:$PATH" rsync-ssl --no-motd download.samba.org::rsyncftp/ || true'
- name: save artifact
uses: actions/upload-artifact@v4
with:
name: cygwin-bin
path: |
rsync.exe
rsync-ssl
rsync.1
rsync-ssl.1
rsyncd.conf.5
rrsync.1
rrsync

View File

@@ -1,51 +0,0 @@
name: Test rsync on FreeBSD
on:
push:
branches: [ master ]
paths-ignore:
- '.github/workflows/*.yml'
- '!.github/workflows/freebsd-build.yml'
pull_request:
branches: [ master ]
paths-ignore:
- '.github/workflows/*.yml'
- '!.github/workflows/freebsd-build.yml'
schedule:
- cron: '42 8 * * *'
jobs:
test:
runs-on: ubuntu-latest
name: Test rsync on FreeBSD
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Test in FreeBSD VM
id: test
uses: vmactions/freebsd-vm@v1
with:
usesh: true
prepare: |
pkg install -y bash autotools m4 devel/xxhash zstd liblz4 python3 archivers/liblz4 git
run: |
freebsd-version
./configure --with-rrsync -disable-zstd --disable-md2man --disable-xxhash --disable-lz4
make
./rsync --version
make check
./runtests.py --rsync-bin=`pwd`/rsync --use-tcp -j 8
./rsync-ssl --no-motd download.samba.org::rsyncftp/ || true
- name: save artifact
uses: actions/upload-artifact@v4
with:
name: freebsd-bin
path: |
rsync
rsync-ssl
rsync.1
rsync-ssl.1
rsyncd.conf.5
rrsync.1
rrsync

View File

@@ -1,65 +0,0 @@
name: Test rsync on macOS
on:
push:
branches: [ master ]
paths-ignore:
- '.github/workflows/*.yml'
- '!.github/workflows/macos-build.yml'
pull_request:
branches: [ master ]
paths-ignore:
- '.github/workflows/*.yml'
- '!.github/workflows/macos-build.yml'
schedule:
- cron: '42 8 * * *'
jobs:
test:
runs-on: macos-latest
name: Test rsync on macOS
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0
- name: prep
run: |
brew install automake openssl xxhash zstd lz4
pip3 install --user --break-system-packages commonmark
echo "$(brew --prefix)/bin" >>$GITHUB_PATH
- name: configure
run: |
BREW_PREFIX=$(brew --prefix)
OPENSSL_PREFIX=$(brew --prefix openssl)
CPPFLAGS="-I${BREW_PREFIX}/include -I${OPENSSL_PREFIX}/include" \
LDFLAGS="-L${BREW_PREFIX}/lib -L${OPENSSL_PREFIX}/lib" \
./configure --with-rrsync
- name: make
run: make
- name: install
run: sudo make install
- name: info
run: rsync --version
- name: check
# chown-fake / devices-fake / xattrs / xattrs-hlink now RUN on macOS
# (rsyncfns.py drives xattrs via the `xattr` command), verified on a
# real macOS host, so they're no longer in the skip set.
run: sudo RSYNC_EXPECT_SKIPPED=acls-default,acls-depth,chmod-temp-dir,daemon-access-ip,daemon-chroot-acl,dir-sgid,open-noatime,preallocate,protected-regular,proxy-response-line-too-long,simd-checksum,sparse make check
- name: check (TCP daemon transport)
# Second run with daemon tests over a real loopback rsyncd; the default
# 'make check' above uses the secure stdio-pipe transport.
run: sudo ./runtests.py --rsync-bin=`pwd`/rsync --use-tcp -j 8
- name: ssl file list
run: rsync-ssl --no-motd download.samba.org::rsyncftp/ || true
- name: save artifact
uses: actions/upload-artifact@v4
with:
name: macos-bin
path: |
rsync
rsync-ssl
rsync.1
rsync-ssl.1
rsyncd.conf.5
rrsync.1
rrsync

View File

@@ -1,52 +0,0 @@
name: Test rsync on NetBSD
on:
push:
branches: [ master ]
paths-ignore:
- '.github/workflows/*.yml'
- '!.github/workflows/netbsd-build.yml'
pull_request:
branches: [ master ]
paths-ignore:
- '.github/workflows/*.yml'
- '!.github/workflows/netbsd-build.yml'
schedule:
- cron: '42 8 * * *'
jobs:
test:
runs-on: ubuntu-latest
name: Test rsync on NetBSD
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Test in NetBSD VM
id: test
uses: vmactions/netbsd-vm@v1
with:
usesh: true
prepare: |
PATH=/usr/sbin:$PATH pkg_add autoconf automake python312
ln -sf /usr/pkg/bin/python3.12 /usr/pkg/bin/python3
run: |
uname -a
./configure --with-rrsync --disable-zstd --disable-md2man --disable-xxhash --disable-lz4
make
./rsync --version
make check
./runtests.py --rsync-bin=`pwd`/rsync --use-tcp -j 8
./rsync-ssl --no-motd download.samba.org::rsyncftp/ || true
- name: save artifact
uses: actions/upload-artifact@v4
with:
name: netbsd-bin
path: |
rsync
rsync-ssl
rsync.1
rsync-ssl.1
rsyncd.conf.5
rrsync.1
rrsync

View File

@@ -1,61 +0,0 @@
name: Test rsync on OpenBSD
on:
push:
branches: [ master ]
paths-ignore:
- '.github/workflows/*.yml'
- '!.github/workflows/openbsd-build.yml'
pull_request:
branches: [ master ]
paths-ignore:
- '.github/workflows/*.yml'
- '!.github/workflows/openbsd-build.yml'
schedule:
- cron: '42 8 * * *'
jobs:
test:
runs-on: ubuntu-latest
name: Test rsync on OpenBSD
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Test in OpenBSD VM
id: test
uses: vmactions/openbsd-vm@v1
with:
usesh: true
prepare: |
pkg_add -I bash autoconf%2.71 automake%1.16
run: |
uname -a
export AUTOCONF_VERSION=2.71
export AUTOMAKE_VERSION=1.16
./configure --with-rrsync --disable-zstd --disable-md2man --disable-xxhash --disable-lz4
make
./rsync --version
make check
# The --use-tcp daemon tests run at -j2 here (vs -j8 elsewhere): this
# job runs inside a nested VM, and at -j8 the many concurrent loopback
# daemons occasionally lose a connection-handshake timing race under
# that resource pressure, hanging one test to the 300s timeout. It is
# an environment artifact, not an rsync bug (the handshake is
# deadlock-free and unreproducible elsewhere, even pinned to 1 CPU at
# -j8); -j2 keeps the VM from over-subscribing. The pipe `make check`
# above stays at the default parallelism.
./runtests.py --rsync-bin=`pwd`/rsync --use-tcp -j 2
./rsync-ssl --no-motd download.samba.org::rsyncftp/ || true
- name: save artifact
uses: actions/upload-artifact@v4
with:
name: openbsd-bin
path: |
rsync
rsync-ssl
rsync.1
rsync-ssl.1
rsyncd.conf.5
rrsync.1
rrsync

View File

@@ -1,51 +0,0 @@
name: Test rsync on Solaris
on:
push:
branches: [ master ]
paths-ignore:
- '.github/workflows/*.yml'
- '!.github/workflows/solaris-build.yml'
pull_request:
branches: [ master ]
paths-ignore:
- '.github/workflows/*.yml'
- '!.github/workflows/solaris-build.yml'
schedule:
- cron: '42 8 * * *'
jobs:
test:
runs-on: ubuntu-latest
name: Test rsync on Solaris
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Test in Solaris VM
id: test
uses: vmactions/solaris-vm@v1
with:
usesh: true
prepare: |
pkg install bash automake gnu-m4 pkg://solaris/runtime/python-35 autoconf gcc git
run: |
uname -a
./configure --with-rrsync -disable-zstd --disable-md2man --disable-xxhash --disable-lz4
make
./rsync --version
make check
./runtests.py --rsync-bin=`pwd`/rsync --use-tcp -j 8
./rsync-ssl --no-motd download.samba.org::rsyncftp/ || true
- name: save artifact
uses: actions/upload-artifact@v4
with:
name: solaris-bin
path: |
rsync
rsync-ssl
rsync.1
rsync-ssl.1
rsyncd.conf.5
rrsync.1
rrsync

View File

@@ -1,64 +0,0 @@
name: Test rsync on Ubuntu 22.04
# Older-LTS coverage to help with backporting security fixes. ubuntu-22.04
# is currently the oldest GitHub Actions runner image (20.04 was retired
# in April 2025).
on:
push:
branches: [ master ]
paths-ignore:
- '.github/workflows/*.yml'
- '!.github/workflows/ubuntu-22.04-build.yml'
pull_request:
branches: [ master ]
paths-ignore:
- '.github/workflows/*.yml'
- '!.github/workflows/ubuntu-22.04-build.yml'
schedule:
- cron: '42 8 * * *'
jobs:
test:
runs-on: ubuntu-22.04
name: Test rsync on Ubuntu 22.04
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0
- name: prep
run: |
sudo apt-get install acl libacl1-dev attr libattr1-dev liblz4-dev libzstd-dev libxxhash-dev python3-cmarkgfm openssl
echo "/usr/local/bin" >>$GITHUB_PATH
- name: configure
run: ./configure --with-rrsync
- name: make
run: make
- name: install
run: sudo make install
- name: info
run: rsync --version
- name: check
run: sudo RSYNC_EXPECT_SKIPPED=crtimes,daemon-access-ip,daemon-chroot-acl,proxy-response-line-too-long make check
- name: check30
run: sudo RSYNC_EXPECT_SKIPPED=crtimes,daemon-access-ip,daemon-chroot-acl,proxy-response-line-too-long make check30
- name: check29
run: sudo RSYNC_EXPECT_SKIPPED=crtimes,daemon-access-ip,daemon-chroot-acl,proxy-response-line-too-long make check29
- name: check (TCP daemon transport)
# Second run with daemon tests over a real loopback rsyncd; the default
# 'make check' above uses the secure stdio-pipe transport.
run: sudo ./runtests.py --rsync-bin=`pwd`/rsync --use-tcp -j 8
- name: ssl file list
run: rsync-ssl --no-motd download.samba.org::rsyncftp/ || true
- name: save artifact
uses: actions/upload-artifact@v4
with:
name: ubuntu-22.04-bin
path: |
rsync
rsync-ssl
rsync.1
rsync-ssl.1
rsyncd.conf.5
rrsync.1
rrsync

View File

@@ -1,62 +0,0 @@
name: Test rsync on Ubuntu
on:
push:
branches: [ master ]
paths-ignore:
- '.github/workflows/*.yml'
- '!.github/workflows/ubuntu-build.yml'
pull_request:
branches: [ master ]
paths-ignore:
- '.github/workflows/*.yml'
- '!.github/workflows/ubuntu-build.yml'
schedule:
- cron: '42 8 * * *'
jobs:
test:
runs-on: ubuntu-latest
name: Test rsync on Ubuntu
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0
- name: prep
run: |
sudo apt-get install acl libacl1-dev attr libattr1-dev liblz4-dev libzstd-dev libxxhash-dev python3-cmarkgfm openssl
echo "/usr/local/bin" >>$GITHUB_PATH
- name: configure
run: ./configure --with-rrsync
- name: make
run: make
- name: install
run: sudo make install
- name: info
run: rsync --version
- name: check
run: sudo RSYNC_EXPECT_SKIPPED=crtimes,daemon-access-ip,daemon-chroot-acl,proxy-response-line-too-long make check
- name: check30
run: sudo RSYNC_EXPECT_SKIPPED=crtimes,daemon-access-ip,daemon-chroot-acl,proxy-response-line-too-long make check30
- name: check29
run: sudo RSYNC_EXPECT_SKIPPED=crtimes,daemon-access-ip,daemon-chroot-acl,proxy-response-line-too-long make check29
- name: check (TCP daemon transport)
# Second run with daemon tests over a real loopback rsyncd. The default
# 'make check' above uses the secure stdio-pipe transport (no listening
# sockets); this run exercises the real TCP accept/auth path. Skip-set
# is env-dependent here (chroot-acl), so leave RSYNC_EXPECT_SKIPPED unset.
run: sudo ./runtests.py --rsync-bin=`pwd`/rsync --use-tcp -j 8
- name: ssl file list
run: rsync-ssl --no-motd download.samba.org::rsyncftp/ || true
- name: save artifact
uses: actions/upload-artifact@v4
with:
name: ubuntu-bin
path: |
rsync
rsync-ssl
rsync.1
rsync-ssl.1
rsyncd.conf.5
rrsync.1
rrsync

23
.gitignore vendored
View File

@@ -12,35 +12,22 @@ config.h.in
config.h.in.old
config.log
config.status
aclocal.m4
/proto.h
/proto.h-tstamp
/rsync*.[15]
/rrsync
/rrsync*.1
/rsync*.html
/rrsync*.html
/help-rsync*.h
/default-cvsignore.h
/default-dont-compress.h
/daemon-parm.h
/.md2man-works
/rsync.1
/rsyncd.conf.5
/autom4te*.cache
/confdefs.h
/conftest*
/dox
/getgroups
/gists
/gmon.out
/rsync
/stunnel-rsyncd.conf
/shconfig
/git-version.h
/testdir
/tests-dont-exist
/testtmp
/tls
/testrun
/trimslash
/t_unsafe
/wildtest
@@ -53,9 +40,3 @@ aclocal.m4
/testsuite/devices-fake.test
/testsuite/xattrs-hlink.test
/patches
/patches.gen
/build
/auto-build-save
.deps
/*.exe
*.dSYM/

17
COPYING
View File

@@ -1,16 +1,7 @@
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.
GNU GENERAL PUBLIC LICENSE
Version 3, 29 June 2007
Copyright (C) 2007 Free Software Foundation, Inc. <https://fsf.org/>
Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
@@ -654,7 +645,7 @@ the "copyright" line and a pointer to where the full notice is found.
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>.
along with this program. If not, see <http://www.gnu.org/licenses/>.
Also add information on how to contact you by electronic and paper mail.
@@ -673,11 +664,11 @@ might be different; for a GUI interface, you would use an "about box".
You should also get your employer (if you work as a programmer) or school,
if any, to sign a "copyright disclaimer" for the program, if necessary.
For more information on this, and how to apply and follow the GNU GPL, see
<https://www.gnu.org/licenses/>.
<http://www.gnu.org/licenses/>.
The GNU General Public License does not permit incorporating your program
into proprietary programs. If your program is a subroutine library, you
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
<https://www.gnu.org/licenses/why-not-lgpl.html>.
<http://www.gnu.org/philosophy/why-not-lgpl.html>.

74
INSTALL Normal file
View File

@@ -0,0 +1,74 @@
To build and install rsync:
$ ./configure
$ make
# make install
You may set the installation directory and other parameters by options
to ./configure. To see them, use:
$ ./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
default group of an rsync daemon, which attempts to run with "nobody"
user and group permissions.) You can change the default user and group
for the daemon by editing the NOBODY_USER and NOBODY_GROUP defines in
config.h, or just override them in your /etc/rsyncd.conf file.
As of 2.4.7, rsync uses Eric Troan's popt option-parsing library. A
cut-down copy of a recent release is included in the rsync distribution,
and will be used if there is no popt library on your build host, or if
the --with-included-popt option is passed to ./configure.
If you configure using --enable-maintainer-mode, then rsync will try
to pop up an xterm on DISPLAY=:0 if it crashes. You might find this
useful, but it should be turned off for production builds.
MAKE COMPATIBILITY
------------------
Note that Makefile.in has a rule that uses a wildcard in a prerequisite. If
your make has a problem with this rule, you will see an error like this:
Don't know how to make ./*.c
You can change the "proto.h-tstamp" target in Makefile.in to list all the *.c
filenames explicitly in order to avoid this issue.
RPM NOTES
---------
Under packaging you will find .spec files for several distributions.
The .spec file in packaging/lsb can be used for Linux systems that
adhere to the Linux Standards Base (e.g., RedHat and others).
HP-UX NOTES
-----------
The HP-UX 10.10 "bundled" C compiler seems not to be able to cope with
ANSI C. You may see this error message in config.log if ./configure
fails:
(Bundled) cc: "configure", line 2162: error 1705: Function prototypes are an ANSI feature.
Install gcc or HP's "ANSI/C Compiler".
MAC OSX NOTES
-------------
Some versions of Mac OS X (Darwin) seem to have an IPv6 stack, but do
not completely implement the "New Sockets" API.
<http://www.ipv6.org/impl/mac.html> says that Apple started to support
IPv6 in 10.2 (Jaguar). If your build fails, try again after running
configure with --disable-ipv6.
IBM AIX NOTES
-------------
IBM AIX has a largefile problem with mkstemp. See IBM PR-51921.
The workaround is to append the below to config.h
#ifdef _LARGE_FILES
#undef HAVE_SECURE_MKSTEMP
#endif

View File

@@ -1,263 +0,0 @@
# How to build and install rsync
When building rsync, you'll want to install various libraries in order to get
all the features enabled. The configure script will alert you when the
newest libraries are missing and tell you the appropriate `--disable-LIB`
option to use if you want to just skip that feature. What follows are various
support libraries that you may want to install to build rsync with the maximum
features (the impatient can skip down to the package summary):
## Ubuntu users: skip the build, use the PPA
If you are on a currently supported Ubuntu series (jammy 22.04 LTS, noble
24.04 LTS, questing 25.10, resolute 26.04 LTS) and just want the latest
upstream rsync, the rsync project maintains a Launchpad PPA that tracks
stable releases:
> sudo add-apt-repository ppa:rsyncproject/rsync
> sudo apt update && sudo apt install rsync
See [the PPA page][ppa] for current build status across architectures.
[ppa]: https://launchpad.net/~rsyncproject/+archive/ubuntu/rsync
The rest of this document covers building from source.
## The basic setup
You need to have a C compiler installed and optionally a C++ compiler in order
to try to build some hardware-accelerated checksum routines. Rsync also needs
a modern awk, which might be provided via gawk or nawk on some OSes.
## Autoconf & manpages
If you're installing from the git repo (instead of a release tar file) you'll
also need the GNU autotools (autoconf & automake) and your choice of 2 python3
markdown libraries: cmarkgfm or commonmark (needed to generate the manpages).
If your OS doesn't provide a python3-cmarkgfm or python3-commonmark package,
you can run the following to install the commonmark python library for your
build user (after installing python3's pip package):
> python3 -mpip install --user commonmark
You can test if you've got it fixed by running (from the rsync checkout):
> ./md-convert --test rsync-ssl.1.md
Alternately, you can avoid generating the manpages by fetching the very latest
versions (that match the latest git source) from the [generated-files][6] dir.
One way to do that is to run:
> ./prepare-source fetchgen
[6]: https://download.samba.org/pub/rsync/generated-files/
## ACL support
To support copying ACL file information, make sure you have an acl
development library installed. It also helps to have the helper programs
installed to manipulate ACLs and to run the rsync testsuite.
## Xattr support
To support copying xattr file information, make sure you have an attr
development library installed. It also helps to have the helper programs
installed to manipulate xattrs and to run the rsync testsuite.
## xxhash
The [xxHash library][1] provides extremely fast checksum functions that can
make the "rsync algorithm" run much more quickly, especially when matching
blocks in large files. Installing this development library adds xxhash
checksums as the default checksum algorithm. You'll need at least v0.8.0
if you want rsync to include the full range of its checksum algorithms.
[1]: https://cyan4973.github.io/xxHash/
## zstd
The [zstd library][2] compression algorithm that uses less CPU than
the default zlib algorithm at the same compression level. Note that you
need at least version 1.4, so you might need to skip the zstd compression if
you can only install a 1.3 release. Installing this development library
adds zstd compression as the default compression algorithm.
[2]: http://facebook.github.io/zstd/
## lz4
The [lz4 library][3] compression algorithm that uses very little CPU, though
it also has the smallest compression ratio of other algorithms. Installing
this development library adds lz4 compression as an available compression
algorithm.
[3]: https://lz4.github.io/lz4/
## openssl crypto
The [openssl crypto library][4] provides some hardware accelerated checksum
algorithms for MD4 and MD5. Installing this development library makes rsync
use the (potentially) faster checksum routines when computing MD4 & MD5
checksums.
[4]: https://www.openssl.org/docs/man1.0.2/man3/crypto.html
## Package summary
To help you get the libraries installed, here are some package install commands
for various OSes. The commands are split up to correspond with the above
items, but feel free to combine the package names into a single install, if you
like.
- For Debian and Ubuntu (Debian Buster users may want to briefly(?) enable
buster-backports to update zstd from 1.3 to 1.4):
> sudo apt install -y gcc g++ gawk autoconf automake python3-cmarkgfm
> sudo apt install -y acl libacl1-dev
> sudo apt install -y attr libattr1-dev
> sudo apt install -y libxxhash-dev
> sudo apt install -y libzstd-dev
> sudo apt install -y liblz4-dev
> sudo apt install -y libssl-dev
Or run support/install_deps_ubuntu.sh
- For CentOS (use EPEL for python3-pip):
> sudo yum -y install epel-release
> sudo yum -y install gcc g++ gawk autoconf automake python3-pip
> sudo yum -y install acl libacl-devel
> sudo yum -y install attr libattr-devel
> sudo yum -y install xxhash-devel
> sudo yum -y install libzstd-devel
> sudo yum -y install lz4-devel
> sudo yum -y install openssl-devel
> python3 -mpip install --user commonmark
- For Fedora 33:
> sudo dnf -y install acl libacl-devel
> sudo dnf -y install attr libattr-devel
> sudo dnf -y install xxhash-devel
> sudo dnf -y install libzstd-devel
> sudo dnf -y install lz4-devel
> sudo dnf -y install openssl-devel
- For FreeBSD (this assumes that the python3 version is 3.7):
> sudo pkg install -y autotools python3 py37-CommonMark
> sudo pkg install -y xxhash
> sudo pkg install -y zstd
> sudo pkg install -y liblz4
- For macOS:
> brew install automake
> brew install xxhash
> brew install zstd
> brew install lz4
> brew install openssl
- For Cygwin (with all cygwin programs stopped, run the appropriate setup program from a cmd shell):
> setup-x86_64 --quiet-mode -P make,gawk,autoconf,automake,gcc-core,python38,python38-pip
> setup-x86_64 --quiet-mode -P attr,libattr-devel
> setup-x86_64 --quiet-mode -P libzstd-devel
> setup-x86_64 --quiet-mode -P liblz4-devel
> setup-x86_64 --quiet-mode -P libssl-devel
Sometimes cygwin has commonmark packaged and sometimes it doesn't. Now that
its python38 has stabilized, you could install python38-commonmark. Or just
avoid the issue by running this from a bash shell as your build user:
> python3 -mpip install --user commonmark
## Build and install
After installing the various libraries, you need to configure, build, and
install the source:
> ./configure
> make
> sudo make install
The default install path is /usr/local/bin, but you can set the installation
directory and other parameters using options to ./configure. To see them, use:
> ./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
default group of an rsync daemon, which attempts to run with "nobody"
user and group permissions.) You can change the default user and group
for the daemon by editing the NOBODY_USER and NOBODY_GROUP defines in
config.h, or just override them in your /etc/rsyncd.conf file.
As of 2.4.7, rsync uses Eric Troan's popt option-parsing library. A
cut-down copy of a recent release is included in the rsync distribution,
and will be used if there is no popt library on your build host, or if
the `--with-included-popt` option is passed to ./configure.
If you configure using `--enable-maintainer-mode`, then rsync will try
to pop up an xterm on DISPLAY=:0 if it crashes. You might find this
useful, but it should be turned off for production builds.
If you want to automatically use a separate "build" directory based on
the current git branch name, start with a pristine git checkout and run
"mkdir auto-build-save" before you run the first ./configure command.
That will cause a fresh build dir to spring into existence along with a
special Makefile symlink that allows you to run "make" and "./configure"
from the source dir (the "build" dir gets auto switched based on branch).
This is helpful when using the branch-from-patch and patch-update scripts
to maintain the official rsync patches. If you ever need to build from
a "detached head" git position then you'll need to manually chdir into
the build dir to run make. I also like to create 2 more symlinks in the
source dir: `ln -s build/rsync . ; ln -s build/testtmp .`
## Make compatibility
Note that Makefile.in has a rule that uses a wildcard in a prerequisite. If
your make has a problem with this rule, you will see an error like this:
Don't know how to make ./*.c
You can change the "proto.h-tstamp" target in Makefile.in to list all the \*.c
filenames explicitly in order to avoid this issue.
## RPM notes
Under packaging you will find .spec files for several distributions.
The .spec file in packaging/lsb can be used for Linux systems that
adhere to the Linux Standards Base (e.g., RedHat and others).
## HP-UX notes
The HP-UX 10.10 "bundled" C compiler seems not to be able to cope with
ANSI C. You may see this error message in config.log if ./configure
fails:
(Bundled) cc: "configure", line 2162: error 1705: Function prototypes are an ANSI feature.
Install gcc or HP's "ANSI/C Compiler".
## Mac OS X notes
Some versions of Mac OS X (Darwin) seem to have an IPv6 stack, but do
not completely implement the "New Sockets" API.
[This site][5] says that Apple started to support IPv6 in 10.2 (Jaguar). If
your build fails, try again after running configure with `--disable-ipv6`.
Apple Silicon macs may install packages in a slightly different location and require flags.
CFLAGS="-I /opt/homebrew/include" LDFLAGS="-L /opt/homebrew/lib"
[5]: http://www.ipv6.org/impl/mac.html
## IBM AIX notes
IBM AIX has a largefile problem with mkstemp. See IBM PR-51921.
The workaround is to append the following to config.h:
> #ifdef _LARGE_FILES
> #undef HAVE_SECURE_MKSTEMP
> #endif

View File

@@ -1,70 +1,57 @@
# The Makefile for rsync (configure creates it from Makefile.in).
# Makefile for rsync. This is processed by configure to produce the final
# Makefile
prefix=@prefix@
datarootdir=@datarootdir@
exec_prefix=@exec_prefix@
bindir=@bindir@
libdir=@libdir@/rsync
mandir=@mandir@
with_rrsync=@with_rrsync@
LIBS=@LIBS@
CC=@CC@
AWK=@AWK@
CFLAGS=@CFLAGS@
CPPFLAGS=@CPPFLAGS@
CXX=@CXX@
CXXFLAGS=@CXXFLAGS@
EXEEXT=@EXEEXT@
LDFLAGS=@LDFLAGS@
LIBOBJDIR=lib/
INSTALLCMD=@INSTALL@
INSTALLMAN=@INSTALL@
srcdir=@srcdir@
MKDIR_P=@MKDIR_P@
VPATH=$(srcdir)
SHELL=/bin/sh
VERSION=@VERSION@
.SUFFIXES:
.SUFFIXES: .c .o
ROLL_SIMD_x86_64=simd-checksum-x86_64.o
ROLL_ASM_x86_64=simd-checksum-avx2.o
MD5_ASM_x86_64=lib/md5-asm-x86_64.o
GENFILES=configure.sh aclocal.m4 config.h.in rsync.1 rsync.1.html \
rsync-ssl.1 rsync-ssl.1.html rsyncd.conf.5 rsyncd.conf.5.html \
@GEN_RRSYNC@
HEADERS=byteorder.h config.h errcode.h proto.h rsync.h ifuncs.h itypes.h inums.h \
lib/pool_alloc.h lib/mdigest.h lib/md-defines.h
GENFILES=configure.sh config.h.in proto.h proto.h-tstamp rsync.1 rsyncd.conf.5
HEADERS=byteorder.h config.h errcode.h proto.h rsync.h ifuncs.h lib/pool_alloc.h
LIBOBJ=lib/wildmatch.o lib/compat.o lib/snprintf.o lib/mdfour.o lib/md5.o \
lib/permstring.o lib/pool_alloc.o lib/sysacls.o lib/sysxattrs.o @LIBOBJS@
zlib_OBJS=zlib/deflate.o zlib/inffast.o zlib/inflate.o zlib/inftrees.o \
ZLIBOBJ=zlib/deflate.o zlib/inffast.o zlib/inflate.o zlib/inftrees.o \
zlib/trees.o zlib/zutil.o zlib/adler32.o zlib/compress.o zlib/crc32.o
OBJS1=flist.o rsync.o generator.o receiver.o cleanup.o sender.o exclude.o \
util1.o util2.o main.o checksum.o match.o syscall.o log.o backup.o delete.o
util.o main.o checksum.o match.o syscall.o log.o backup.o
OBJS2=options.o io.o compat.o hlink.o token.o uidlist.o socket.o hashtable.o \
usage.o fileio.o batch.o clientname.o chmod.o acls.o xattrs.o
OBJS3=progress.o pipe.o @MD5_ASM@ @ROLL_SIMD@ @ROLL_ASM@
fileio.o batch.o clientname.o chmod.o acls.o xattrs.o
OBJS3=progress.o pipe.o
DAEMON_OBJ = params.o loadparm.o clientserver.o access.o connection.o authenticate.o
popt_OBJS= popt/popt.o popt/poptconfig.o \
popt/popthelp.o popt/poptparse.o popt/poptint.o
OBJS=$(OBJS1) $(OBJS2) $(OBJS3) $(DAEMON_OBJ) $(LIBOBJ) @BUILD_ZLIB@ @BUILD_POPT@
popt_OBJS=popt/findme.o popt/popt.o popt/poptconfig.o \
popt/popthelp.o popt/poptparse.o
OBJS=$(OBJS1) $(OBJS2) $(OBJS3) $(DAEMON_OBJ) $(LIBOBJ) $(ZLIBOBJ) @BUILD_POPT@
TLS_OBJ = tls.o syscall.o util2.o t_stub.o lib/compat.o lib/snprintf.o lib/permstring.o lib/sysxattrs.o @BUILD_POPT@
TLS_OBJ = tls.o syscall.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) \
testrun$(EXEEXT) trimslash$(EXEEXT) t_unsafe$(EXEEXT) t_chmod_secure$(EXEEXT) \
t_secure_relpath$(EXEEXT) wildtest$(EXEEXT) simdtest$(EXEEXT)
trimslash$(EXEEXT) t_unsafe$(EXEEXT) wildtest$(EXEEXT)
CHECK_SYMLINKS = testsuite/chown-fake_test.py testsuite/devices-fake_test.py \
testsuite/xattrs-hlink_test.py testsuite/exclude-lsh_test.py
CHECK_SYMLINKS = testsuite/chown-fake.test testsuite/devices-fake.test testsuite/xattrs-hlink.test
# Objects for CHECK_PROGS to clean
CHECK_OBJS=tls.o testrun.o getgroups.o getfsdev.o t_stub.o t_unsafe.o t_chmod_secure.o t_secure_relpath.o trimslash.o wildtest.o
CHECK_OBJS=tls.o getgroups.o getfsdev.o t_stub.o t_unsafe.o trimslash.o wildtest.o
# note that the -I. is needed to handle config.h when using VPATH
.c.o:
@@ -72,34 +59,15 @@ CHECK_OBJS=tls.o testrun.o getgroups.o getfsdev.o t_stub.o t_unsafe.o t_chmod_se
$(CC) -I. -I$(srcdir) $(CFLAGS) $(CPPFLAGS) -c $< @CC_SHOBJ_FLAG@
@OBJ_RESTORE@
# NOTE: consider running "packaging/smart-make" instead of "make" to auto-handle
# any changes to configure.sh and the main Makefile prior to a "make all".
all: Makefile rsync$(EXEEXT) stunnel-rsyncd.conf @MAKE_RRSYNC@ @MAKE_MAN@
.PHONY: all
all: Makefile rsync$(EXEEXT) @MAKE_MAN@
.PHONY: install
install: all
-$(MKDIR_P) $(DESTDIR)$(bindir)
$(INSTALLCMD) $(INSTALL_STRIP) -m 755 rsync$(EXEEXT) $(DESTDIR)$(bindir)
$(INSTALLCMD) -m 755 $(srcdir)/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
if test "$(with_rrsync)" = yes; then \
$(INSTALLCMD) -m 755 rrsync $(DESTDIR)$(bindir); \
if test -f rrsync.1; then $(INSTALLMAN) -m 644 rrsync.1 $(DESTDIR)$(mandir)/man1; fi; \
fi
install-ssl-daemon: stunnel-rsyncd.conf
-$(MKDIR_P) $(DESTDIR)/etc/stunnel
$(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
install-all: install install-ssl-daemon
-mkdir -p ${DESTDIR}${bindir}
${INSTALLCMD} ${INSTALL_STRIP} -m 755 rsync$(EXEEXT) ${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 rsyncd.conf.5; then ${INSTALLMAN} -m 644 rsyncd.conf.5 ${DESTDIR}${mandir}/man5; fi
install-strip:
$(MAKE) INSTALL_STRIP='-s' install
@@ -107,27 +75,12 @@ install-strip:
rsync$(EXEEXT): $(OBJS)
$(CC) $(CFLAGS) $(LDFLAGS) -o $@ $(OBJS) $(LIBS)
rrsync: support/rrsync
cp -p $(srcdir)/support/rrsync rrsync
$(OBJS): $(HEADERS)
$(CHECK_OBJS): $(HEADERS)
tls.o xattrs.o: lib/sysxattrs.h
usage.o: version.h latest-year.h help-rsync.h help-rsyncd.h git-version.h default-cvsignore.h
loadparm.o: default-dont-compress.h daemon-parm.h
flist.o: rounding.h
default-cvsignore.h default-dont-compress.h: rsync.1.md define-from-md.awk
$(AWK) -f $(srcdir)/define-from-md.awk -v hfile=$@ $(srcdir)/rsync.1.md
help-rsync.h help-rsyncd.h: rsync.1.md help-from-md.awk
$(AWK) -f $(srcdir)/help-from-md.awk -v hfile=$@ $(srcdir)/rsync.1.md
daemon-parm.h: daemon-parm.txt daemon-parm.awk
$(AWK) -f $(srcdir)/daemon-parm.awk $(srcdir)/daemon-parm.txt
rounding.h: rounding.c rsync.h proto.h
rounding.h: rounding.c rsync.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; \
@@ -145,57 +98,30 @@ rounding.h: rounding.c rsync.h proto.h
fi
@rm -f rounding.out
git-version.h: ALWAYS_RUN
$(srcdir)/mkgitver
.PHONY: ALWAYS_RUN
ALWAYS_RUN:
simd-checksum-x86_64.o: simd-checksum-x86_64.cpp
@$(srcdir)/cmd-or-msg disable-roll-simd $(CXX) -I. $(CXXFLAGS) $(CPPFLAGS) -c -o $@ $(srcdir)/simd-checksum-x86_64.cpp
simd-checksum-avx2.o: simd-checksum-avx2.S
@$(srcdir)/cmd-or-msg disable-roll-asm $(CC) $(CFLAGS) -I. @NOEXECSTACK@ -c -o $@ $(srcdir)/simd-checksum-avx2.S
lib/md5-asm-x86_64.o: lib/md5-asm-x86_64.S lib/md-defines.h
@$(srcdir)/cmd-or-msg disable-md5-asm $(CC) -I. @NOEXECSTACK@ -c -o $@ $(srcdir)/lib/md5-asm-x86_64.S
tls$(EXEEXT): $(TLS_OBJ)
$(CC) $(CFLAGS) $(LDFLAGS) -o $@ $(TLS_OBJ) $(LIBS)
testrun$(EXEEXT): testrun.o
$(CC) $(CFLAGS) $(LDFLAGS) -o $@ testrun.o
getgroups$(EXEEXT): getgroups.o
$(CC) $(CFLAGS) $(LDFLAGS) -o $@ getgroups.o $(LIBS)
getfsdev$(EXEEXT): getfsdev.o
$(CC) $(CFLAGS) $(LDFLAGS) -o $@ getfsdev.o $(LIBS)
TRIMSLASH_OBJ = trimslash.o syscall.o util2.o t_stub.o lib/compat.o lib/snprintf.o
TRIMSLASH_OBJ = trimslash.o syscall.o lib/compat.o lib/snprintf.o
trimslash$(EXEEXT): $(TRIMSLASH_OBJ)
$(CC) $(CFLAGS) $(LDFLAGS) -o $@ $(TRIMSLASH_OBJ) $(LIBS)
T_UNSAFE_OBJ = t_unsafe.o syscall.o util1.o util2.o t_stub.o lib/compat.o lib/snprintf.o lib/wildmatch.o
T_UNSAFE_OBJ = t_unsafe.o syscall.o util.o t_stub.o lib/compat.o lib/snprintf.o lib/wildmatch.o
t_unsafe$(EXEEXT): $(T_UNSAFE_OBJ)
$(CC) $(CFLAGS) $(LDFLAGS) -o $@ $(T_UNSAFE_OBJ) $(LIBS)
T_CHMOD_SECURE_OBJ = t_chmod_secure.o syscall.o util1.o util2.o t_stub.o lib/compat.o lib/snprintf.o lib/wildmatch.o lib/permstring.o
t_chmod_secure$(EXEEXT): $(T_CHMOD_SECURE_OBJ)
$(CC) $(CFLAGS) $(LDFLAGS) -o $@ $(T_CHMOD_SECURE_OBJ) $(LIBS)
gen: conf proto.h man
T_SECURE_RELPATH_OBJ = t_secure_relpath.o syscall.o util1.o util2.o t_stub.o lib/compat.o lib/snprintf.o lib/wildmatch.o lib/permstring.o
t_secure_relpath$(EXEEXT): $(T_SECURE_RELPATH_OBJ)
$(CC) $(CFLAGS) $(LDFLAGS) -o $@ $(T_SECURE_RELPATH_OBJ) $(LIBS)
gensend: gen
rsync -aivzc $(GENFILES) samba.org:/home/ftp/pub/rsync/generated-files/
.PHONY: conf
conf: configure.sh config.h.in
.PHONY: gen
gen: conf proto.h man git-version.h
aclocal.m4: $(srcdir)/m4/*.m4
aclocal -I $(srcdir)/m4
conf:
cd $(srcdir) && $(MAKE) -f prepare-source.mak conf
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
@@ -214,7 +140,7 @@ configure.sh config.h.in: configure.ac aclocal.m4
else \
echo "config.h.in has CHANGED."; \
fi
@if test -f configure.sh.old || test -f config.h.in.old; then \
@if test -f configure.sh.old -o -f config.h.in.old; then \
if test "$(MAKECMDGOALS)" = reconfigure; then \
echo 'Continuing with "make reconfigure".'; \
else \
@@ -224,15 +150,10 @@ configure.sh config.h.in: configure.ac aclocal.m4
fi \
fi
.PHONY: reconfigure
reconfigure: configure.sh
./config.status --recheck
./config.status
.PHONY: restatus
restatus:
./config.status
Makefile: Makefile.in config.status configure.sh config.h.in
@if test -f Makefile; then cp -p Makefile Makefile.old; else touch Makefile.old; fi
@./config.status
@@ -248,68 +169,58 @@ Makefile: Makefile.in config.status configure.sh config.h.in
fi \
fi
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 daemon-parm.h
$(AWK) -f $(srcdir)/mkproto.awk $(srcdir)/*.c $(srcdir)/lib/compat.c daemon-parm.h
proto.h-tstamp: $(srcdir)/*.c $(srcdir)/lib/compat.c config.h
perl $(srcdir)/mkproto.pl $(srcdir)/*.c $(srcdir)/lib/compat.c
.PHONY: man
man: rsync.1 rsync-ssl.1 rsyncd.conf.5 @MAKE_RRSYNC_1@
man: rsync.1 rsyncd.conf.5
@if test -f rsync.1; then :; else cp -p $(srcdir)/rsync.1 .; fi
@if test -f rsyncd.conf.5; then :; else cp -p $(srcdir)/rsyncd.conf.5 .; fi
rsync.1: rsync.1.md md-convert version.h Makefile
@$(srcdir)/maybe-make-man 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 md-convert version.h Makefile
@$(srcdir)/maybe-make-man 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 md-convert version.h Makefile
@$(srcdir)/maybe-make-man rsyncd.conf.5.md
rrsync.1: support/rrsync.1.md md-convert Makefile
@$(srcdir)/maybe-make-man support/rrsync.1.md
.PHONY: clean
clean: cleantests
rm -f *~ $(OBJS) $(CHECK_PROGS) $(CHECK_OBJS) $(CHECK_SYMLINKS) @MAKE_RRSYNC@ \
git-version.h rounding rounding.h *.old rsync*.1 rsync*.5 @MAKE_RRSYNC_1@ \
*.html daemon-parm.h help-*.h default-*.h proto.h proto.h-tstamp
rm -f *.gcno *.gcda lib/*.gcno lib/*.gcda zlib/*.gcno zlib/*.gcda popt/*.gcno popt/*.gcda
rm -rf coverage coverage-tcp coverage-all coverage-fallback
rm -f *~ $(OBJS) $(CHECK_PROGS) $(CHECK_OBJS) $(CHECK_SYMLINKS) \
rounding rounding.h *.old
.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
for dir in $(srcdir) . ; do \
(cd "$$dir" && rm -rf Makefile config.h config.status stunnel-rsyncd.conf \
lib/dummy popt/dummy zlib/dummy config.cache config.log shconfig \
$(GENFILES) autom4te.cache) ; \
done
rm -f Makefile config.h config.status
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
rm -f config.cache config.log
rm -f $(srcdir)/config.cache $(srcdir)/config.log
rm -f shconfig $(srcdir)/shconfig
rm -f $(GENFILES)
rm -rf autom4te.cache
# 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
@rm nmused.txt nmfns.txt
# 'check' is the GNU name, 'test' is the name for everybody else :-)
.PHONY: test
.PHONY: check test
test: check
# There seems to be no standard way to specify some variables as
@@ -322,141 +233,31 @@ 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.
# `make check` runs tests in parallel by default. Override with
# `make check CHECK_J=1` (serial) or any other value.
CHECK_J = 8
# Parallelism for `make coverage`. Defaults to the same as CHECK_J: the
# coverage build sets -fprofile-update=atomic (atomic in-memory counters) and
# gcc's libgcov serializes the per-source .gcda read-modify-write merge with a
# file lock, so concurrent rsync processes (incl. the forked sender/generator/
# receiver) accumulate exactly -- verified by a count-linearity check (a hot
# line accumulates identically at -j1 and -P16). Override with
# `make coverage COVERAGE_J=1` if your libgcov does not lock .gcda merges.
COVERAGE_J = $(CHECK_J)
# Output directory and extra runtests.py flags for `make coverage`. The
# `coverage-tcp` target reuses the coverage recipe with --use-tcp (real
# loopback rsyncd, which exercises the TCP accept/auth path and the
# require_tcp-only tests) and a separate output directory.
COVERAGE_DIR = coverage
COVERAGE_RUNFLAGS =
# Bundled third-party code that rsync ships but does not own; excluded from the
# coverage report so the percentages reflect rsync's own source. zlib/ and popt/
# are wholly vendored; the named lib/ files are PostgreSQL (getaddrinfo) and ISC
# (inet_ntop/inet_pton) / standalone (getpass) imports. The other lib/*.c
# (md5, mdfour, wildmatch, permstring, pool_alloc, snprintf, sysacls, sysxattrs,
# compat) are rsync's own and stay in the report.
COVERAGE_EXCLUDE = -e '(^|/)zlib/' -e '(^|/)popt/' \
-e '(^|/)lib/(getaddrinfo|getpass|inet_ntop|inet_pton)\.'
.PHONY: check
check: all $(CHECK_PROGS) $(CHECK_SYMLINKS)
$(srcdir)/runtests.py --rsync-bin=`pwd`/rsync$(EXEEXT) -j $(CHECK_J)
rsync_bin=`pwd`/rsync$(EXEEXT) $(srcdir)/runtests.sh
.PHONY: check29
check29: all $(CHECK_PROGS) $(CHECK_SYMLINKS)
$(srcdir)/runtests.py --rsync-bin=`pwd`/rsync$(EXEEXT) -j $(CHECK_J) --protocol=29
rsync_bin=`pwd`/rsync$(EXEEXT) $(srcdir)/runtests.sh --protocol=29
.PHONY: check30
check30: all $(CHECK_PROGS) $(CHECK_SYMLINKS)
$(srcdir)/runtests.py --rsync-bin=`pwd`/rsync$(EXEEXT) -j $(CHECK_J) --protocol=30
# Whole-suite gcov coverage report (HTML, with branch + decision coverage).
# Requires a build configured with --enable-coverage and the `gcovr` tool
# (pip install gcovr). Runs the suite in parallel (COVERAGE_J, default CHECK_J):
# this is safe because the coverage build uses -fprofile-update=atomic and
# libgcov locks the per-source .gcda during its merge, so concurrent rsync
# processes accumulate exactly (see COVERAGE_J above). Use COVERAGE_J=1 if your
# toolchain's libgcov does not lock .gcda merges.
.PHONY: coverage
coverage: all $(CHECK_PROGS) $(CHECK_SYMLINKS)
@case '$(CFLAGS)' in *--coverage*) ;; \
*) echo "*** not a coverage build; reconfigure with --enable-coverage"; exit 1 ;; esac
@command -v gcovr >/dev/null 2>&1 || { echo "*** gcovr not found (pip install gcovr)"; exit 1; }
find . -name '*.gcda' -delete
@rc=0; $(srcdir)/runtests.py --rsync-bin=`pwd`/rsync$(EXEEXT) -j $(COVERAGE_J) $(COVERAGE_RUNFLAGS) || rc=$$?; \
rm -rf $(COVERAGE_DIR) && mkdir -p $(COVERAGE_DIR); \
gcovr --root $(srcdir) $(COVERAGE_EXCLUDE) --decisions --print-summary \
--html-details -o $(COVERAGE_DIR)/index.html . || exit $$?; \
echo "Coverage report written to $(COVERAGE_DIR)/index.html"; \
if test $$rc != 0; then \
echo "*** test suite FAILED (status $$rc) -- coverage report still written above"; \
fi; \
exit $$rc
# Same as `make coverage` but with the daemon tests run over a real loopback
# rsyncd (--use-tcp), into a separate report directory.
.PHONY: coverage-tcp
coverage-tcp:
$(MAKE) coverage COVERAGE_RUNFLAGS=--use-tcp COVERAGE_DIR=coverage-tcp
# Comprehensive single report: run the suite under several configurations,
# accumulating into the shared .gcda counters (NOT cleared between runs), then
# emit one merged, rsync-scoped report. Covers the default (pipe) transport, the
# protocol-29/30 compat branches, and the real-TCP daemon path (which also runs
# the require_tcp-only tests). Run under sudo to additionally cover root-only
# paths (devices, chown, use-chroot, protected-regular). Local target -- CI uses
# the plain `coverage`/`coverage-tcp` targets.
.PHONY: coverage-all
coverage-all: all $(CHECK_PROGS) $(CHECK_SYMLINKS)
@case '$(CFLAGS)' in *--coverage*) ;; \
*) echo "*** not a coverage build; reconfigure with --enable-coverage"; exit 1 ;; esac
@command -v gcovr >/dev/null 2>&1 || { echo "*** gcovr not found (pip install gcovr)"; exit 1; }
find . -name '*.gcda' -delete
@rc=0; \
for cfg in '' '--protocol=30' '--protocol=29' '--use-tcp'; do \
echo "===== coverage-all: runtests.py $$cfg ====="; \
$(srcdir)/runtests.py --rsync-bin=`pwd`/rsync$(EXEEXT) -j $(COVERAGE_J) $$cfg || rc=$$?; \
done; \
rm -rf coverage-all && mkdir -p coverage-all; \
gcovr --root $(srcdir) $(COVERAGE_EXCLUDE) --decisions --print-summary \
--html-details -o coverage-all/index.html . || exit $$?; \
echo "Merged coverage report written to coverage-all/index.html"; \
if test $$rc != 0; then \
echo "*** some suite runs FAILED (status $$rc) -- report still written above"; \
fi; \
exit $$rc
# Coverage for the portable (non-openat2) resolver tier. Requires a SEPARATE
# build configured with --enable-coverage --disable-openat2: its .gcno differ
# from the openat2 build, so this report cannot be merged with the others.
.PHONY: coverage-fallback
coverage-fallback:
$(MAKE) coverage COVERAGE_DIR=coverage-fallback
wildtest.o: wildtest.c t_stub.o lib/wildmatch.c rsync.h config.h
wildtest.o: wildtest.c 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)
simdtest$(EXEEXT): simd-checksum-x86_64.cpp $(HEADERS)
@if test x"@ROLL_SIMD@" != x; then \
$(CXX) -I. $(CXXFLAGS) $(CPPFLAGS) $(LDFLAGS) -DTEST_SIMD_CHECKSUM1 \
-o $@ $(srcdir)/simd-checksum-x86_64.cpp @ROLL_ASM@ $(LIBS); \
else \
touch $@; \
fi
testsuite/chown-fake.test:
ln -s chown.test $(srcdir)/testsuite/chown-fake.test
testsuite/chown-fake_test.py:
ln -s chown_test.py $(srcdir)/testsuite/chown-fake_test.py
testsuite/devices-fake.test:
ln -s devices.test $(srcdir)/testsuite/devices-fake.test
testsuite/devices-fake_test.py:
ln -s devices_test.py $(srcdir)/testsuite/devices-fake_test.py
testsuite/xattrs-hlink_test.py:
ln -s xattrs_test.py $(srcdir)/testsuite/xattrs-hlink_test.py
testsuite/exclude-lsh_test.py:
ln -s exclude_test.py $(srcdir)/testsuite/exclude-lsh_test.py
testsuite/xattrs-hlink.test:
ln -s xattrs.test $(srcdir)/testsuite/xattrs-hlink.test
# This does *not* depend on building or installing: you can use it to
# check a version installed from a binary or some other source tree,
# if you want.
.PHONY: installcheck
installcheck: $(CHECK_PROGS) $(CHECK_SYMLINKS)
$(srcdir)/runtests.py --rsync-bin="$(bindir)/rsync$(EXEEXT)" --srcdir="$(srcdir)" --tooldir=`pwd` -j $(CHECK_J)
POSIXLY_CORRECT=1 TOOLDIR=`pwd` rsync_bin="$(bindir)/rsync$(EXEEXT)" srcdir="$(srcdir)" $(srcdir)/runtests.sh
# TODO: Add 'dist' target; need to know which files will be included
@@ -465,12 +266,21 @@ installcheck: $(CHECK_PROGS) $(CHECK_SYMLINKS)
splint:
splint +unixlib +gnuextensions -weak rsync.c
.PHONY: doxygen
rsync.dvi: doc/rsync.texinfo
texi2dvi -o $@ $<
rsync.ps: rsync.dvi
dvips -ta4 -o $@ $<
rsync.pdf: doc/rsync.texinfo
texi2dvi -o $@ --pdf $<
doxygen:
cd $(srcdir) && rm dox/html/* && doxygen
# for maintainers only
.PHONY: doxygen-upload
doxygen-upload:
rsync -avzv $(srcdir)/dox/html/ --delete \
$${RSYNC_SAMBA_HOST-samba.org}:/home/httpd/html/rsync/doxygen/head/
samba.org:/home/httpd/html/rsync/doxygen/head/

19
NEWS Normal file
View File

@@ -0,0 +1,19 @@
NEWS for rsync 3.0.9 (UNRELEASED)
Protocol: 30 (unchanged)
Changes since 3.0.8:
BUG FIXES:
- Fix a crash bug in checksum scanning when --inplace is used.
- Fix preservation of a symlink's system xattrs (e.g. selinux) on Linux.
- Fix a bug with the modifying of unwritable directories.
- Fix --fake-super's interaction with --link-dest same-file comparisons.
- Fix the updating of the curr_dir buffer to avoid a duplicate slash.
- Make daemon-excluded file errors more error-like.
- Fix some issues with the post-processing of the man pages.

5252
NEWS.md
View File

File diff suppressed because it is too large Load Diff

3298
OLDNEWS Normal file
View File

File diff suppressed because it is too large Load Diff

View File

@@ -23,18 +23,8 @@ options. To get a complete list of supported options type:
rsync --help
See the [manpage][0] for more detailed information.
See the manpage for more detailed information.
[0]: https://download.samba.org/pub/rsync/rsync.1
BUILDING AND INSTALLING
-----------------------
If you need to build rsync yourself, check out the [INSTALL][1] page for
information on what libraries and packages you can use to get the maximum
features in your build.
[1]: https://github.com/RsyncProject/rsync/blob/master/INSTALL.md
SETUP
-----
@@ -65,17 +55,17 @@ RSYNC DAEMONS
-------------
Rsync can also talk to "rsync daemons" which can provide anonymous or
authenticated rsync. See the rsyncd.conf(5) manpage for details on how
to setup an rsync daemon. See the rsync(1) manpage for info on how to
authenticated rsync. See the rsyncd.conf(5) man page for details on how
to setup an rsync daemon. See the rsync(1) man page for info on how to
connect to an rsync daemon.
WEB SITE
--------
For more information, visit the [main rsync web site][2].
The main rsync web site is here:
[2]: https://rsync.samba.org/
http://rsync.samba.org/
You'll find a FAQ list, downloads, resources, HTML versions of the
manpages, etc.
@@ -87,67 +77,64 @@ MAILING LISTS
There is a mailing list for the discussion of rsync and its applications
that is open to anyone to join. New releases are announced on this
list, and there is also an announcement-only mailing list for those that
want official announcements. See the [mailing-list page][3] for full
details.
want official announcements. See the mailing-list page for full
details:
[3]: https://rsync.samba.org/lists.html
DISCORD
-------
There is also an rsync [Discord server][d] for real-time chat about rsync
and its development.
[d]: https://discord.gg/Avfvy9zhdp
http://rsync.samba.org/lists.html
BUG REPORTS
-----------
The [bug-tracking web page][4] has full details on bug reporting.
To visit this web page for full the details on bug reporting:
[4]: https://rsync.samba.org/bug-tracking.html
http://rsync.samba.org/bugzilla.html
That page contains links to the current bug list, and information on how to
do a good job when reporting a bug. You might also like to try searching
the Internet for the error message you've received, or looking in the
[mailing list archives][5].
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:
[5]: https://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 .
For security issues please email details of the issue to <rsync.project@gmail.com>.
GIT REPOSITORY
--------------
If you want to get the very latest version of rsync direct from the
source code repository, then you will need to use git. The git repo
is hosted [on GitHub][6] and [on Samba's site][7].
source code repository then you can use git:
[6]: https://github.com/RsyncProject/rsync
[7]: https://git.samba.org/?p=rsync.git;a=summary
git clone git://git.samba.org/rsync.git
See [the download page][8] for full details on all the ways to grab the
source.
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.:
[8]: https://rsync.samba.org/download.html
http://rsync.samba.org/download.html
COPYRIGHT
---------
Rsync was originally written by Andrew Tridgell and Paul Mackerras. Many
people from around the world have helped to maintain and improve it.
Rsync was originally written by Andrew Tridgell and is currently
maintained by Wayne Davison. It has been improved by many developers
from around the world.
Rsync may be used, modified and redistributed only under the terms of
the GNU General Public License, found in the file [COPYING][9] in this
distribution, or at [the Free Software Foundation][10].
the GNU General Public License, found in the file COPYING in this
distribution, or at:
[9]: https://github.com/RsyncProject/rsync/blob/master/COPYING
[10]: https://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/

View File

@@ -1,13 +0,0 @@
# Security Policy
## Supported Versions
Only the current release of the software is actively supported. If you need
help backporting fixes into an older release, feel free to ask.
## Reporting a Vulnerability
Email your vulnerability information to rsync's maintainer:
Rsync Project <rsync.project@gmail.com>

16
TODO
View File

@@ -49,7 +49,7 @@ Create test makefile target for some tests
RELATED PROJECTS -----------------------------------------------------
rsyncsh
https://rsync.samba.org/rsync-and-debian/
http://rsync.samba.org/rsync-and-debian/
rsyncable gzip patch
rsyncsplit as alternative to real integration with gzip?
reverse rsync over HTTP Range
@@ -66,8 +66,8 @@ Use chroot only if supported
If running as non-root, then don't fail, just give a warning.
(There was a thread about this a while ago?)
https://lists.samba.org/pipermail/rsync/2001-August/thread.html
https://lists.samba.org/pipermail/rsync/2001-September/thread.html
http://lists.samba.org/pipermail/rsync/2001-August/thread.html
http://lists.samba.org/pipermail/rsync/2001-September/thread.html
-- --
@@ -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 important.
are moderately improtant.
Perhaps the simplest solution would be to have two different files
implementing the same interface, and choose either the new or the
@@ -204,7 +204,7 @@ Create more granular verbosity 2003/05/15
fine grained selection of statistical reporting and what
actions are logged.
https://lists.samba.org/archive/rsync/2003-May/006059.html
http://lists.samba.org/archive/rsync/2003-May/006059.html
-- --
@@ -236,7 +236,7 @@ Memory accounting
At exit, show how much memory was used for the file list, etc.
We also do a weird exponential-growth allocation in flist.c. I'm
Also we do a wierd 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.
@@ -287,7 +287,7 @@ Perhaps flush stdout like syslog
Perhaps flush stdout after each filename, so that people trying to
monitor progress in a log file can do so more easily. See
https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=48108
http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=48108
-- --
@@ -495,7 +495,7 @@ rsyncsh
-- --
https://rsync.samba.org/rsync-and-debian/
http://rsync.samba.org/rsync-and-debian/
-- --

101
access.c
View File

@@ -2,7 +2,7 @@
* Routines to authenticate access to a daemon (hosts allow/deny).
*
* Copyright (C) 1998 Andrew Tridgell
* Copyright (C) 2004-2022 Wayne Davison
* Copyright (C) 2004-2009 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,58 +19,15 @@
*/
#include "rsync.h"
#include "ifuncs.h"
#ifdef HAVE_NETGROUP_H
#include <netgroup.h>
#endif
static int allow_forward_dns;
extern const char undetermined_hostname[];
static int match_hostname(const char **host_ptr, const char *addr, const char *tok)
static int match_hostname(char *host, char *tok)
{
struct hostent *hp;
unsigned int i;
const char *host = *host_ptr;
if (!host || !*host)
return 0;
#ifdef HAVE_INNETGR
if (*tok == '@' && tok[1])
return innetgr(tok + 1, host, NULL, NULL);
#endif
/* First check if the reverse-DNS-determined hostname matches. */
if (iwildmatch(tok, host))
return 1;
if (!allow_forward_dns)
return 0;
/* Fail quietly if tok is an address or wildcarded entry, not a simple hostname. */
if (!tok[strspn(tok, ".0123456789")] || tok[strcspn(tok, ":/*?[")])
return 0;
/* Now try forward-DNS on the token (config-specified hostname) and see if the IP matches. */
if (!(hp = gethostbyname(tok)))
return 0;
for (i = 0; hp->h_addr_list[i] != NULL; i++) {
if (strcmp(addr, inet_ntoa(*(struct in_addr*)(hp->h_addr_list[i]))) == 0) {
/* If reverse lookups are off, we'll use the conf-specified
* hostname in preference to UNDETERMINED. */
if (host == undetermined_hostname)
*host_ptr = strdup(tok);
return 1;
}
}
return 0;
return wildmatch(tok, host);
}
static int match_binary(const char *b1, const char *b2, const char *mask, int addrlen)
static int match_binary(char *b1, char *b2, char *mask, int addrlen)
{
int i;
@@ -99,7 +56,7 @@ static void make_mask(char *mask, int plen, int addrlen)
return;
}
static int match_address(const char *addr, char *tok)
static int match_address(char *addr, char *tok)
{
char *p;
struct addrinfo hints, *resa, *rest;
@@ -113,16 +70,24 @@ static int match_address(const char *addr, char *tok)
#endif
char mask[16];
char *a = NULL, *t = NULL;
unsigned int len;
if (!addr || !*addr)
return 0;
p = strchr(tok,'/');
if (p)
if (p) {
*p = '\0';
len = p - tok;
} else
len = strlen(tok);
/* Fail quietly if tok is a hostname, not an address. */
if (tok[strspn(tok, ".0123456789")] && strchr(tok, ':') == NULL) {
/* Fail quietly if tok is a hostname (not an address) */
if (strspn(tok, ".0123456789") != len
#ifdef INET6
&& strchr(tok, ':') == NULL
#endif
) {
if (p)
*p = '/';
return 0;
@@ -165,7 +130,8 @@ static int match_address(const char *addr, char *tok)
break;
#ifdef INET6
case PF_INET6: {
case PF_INET6:
{
struct sockaddr_in6 *sin6a, *sin6t;
sin6a = (struct sockaddr_in6 *)resa->ai_addr;
@@ -177,19 +143,20 @@ static int match_address(const char *addr, 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;
@@ -243,15 +210,20 @@ static int match_address(const char *addr, char *tok)
return ret;
}
static int access_match(const char *list, const char *addr, const char **host_ptr)
static int access_match(char *list, char *addr, char *host)
{
char *tok;
char *list2 = strdup(list);
if (!list2)
out_of_memory("access_match");
strlower(list2);
if (host)
strlower(host);
for (tok = strtok(list2, " ,\t"); tok; tok = strtok(NULL, " ,\t")) {
if (match_hostname(host_ptr, addr, tok) || match_address(addr, tok)) {
if (match_hostname(host, tok) || match_address(addr, tok)) {
free(list2);
return 1;
}
@@ -261,21 +233,16 @@ static int access_match(const char *list, const char *addr, const char **host_pt
return 0;
}
int allow_access(const char *addr, const char **host_ptr, int i)
int allow_access(char *addr, char *host, char *allow_list, char *deny_list)
{
const char *allow_list = lp_hosts_allow(i);
const char *deny_list = lp_hosts_deny(i);
if (allow_list && !*allow_list)
allow_list = NULL;
if (deny_list && !*deny_list)
deny_list = NULL;
allow_forward_dns = lp_forward_lookup(i);
/* If we match an allow-list item, we always allow access. */
if (allow_list) {
if (access_match(allow_list, addr, host_ptr))
if (access_match(allow_list, addr, host))
return 1;
/* For an allow-list w/o a deny-list, disallow non-matches. */
if (!deny_list)
@@ -284,7 +251,7 @@ int allow_access(const char *addr, const char **host_ptr, int i)
/* If we match a deny-list item (and got past any allow-list
* items), we always disallow access. */
if (deny_list && access_match(deny_list, addr, host_ptr))
if (deny_list && access_match(deny_list, addr, host))
return 0;
/* Allow all other access. */

92
aclocal.m4 vendored Normal file
View File

@@ -0,0 +1,92 @@
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
])

59
acls.c
View File

@@ -3,7 +3,7 @@
*
* Copyright (C) 1996 Andrew Tridgell
* Copyright (C) 1996 Paul Mackerras
* Copyright (C) 2006-2022 Wayne Davison
* Copyright (C) 2006-2009 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
@@ -28,7 +28,7 @@ extern int dry_run;
extern int am_root;
extern int read_only;
extern int list_only;
extern mode_t orig_umask;
extern int orig_umask;
extern int numeric_ids;
extern int inc_recurse;
extern int preserve_devices;
@@ -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 highest bits set. */
* be likely to have its hightest bits set. */
#define XFLAG_NAME_FOLLOWS 0x0001u
#define XFLAG_NAME_IS_USER 0x0002u
@@ -168,6 +168,8 @@ static rsync_acl *create_racl(void)
{
rsync_acl *racl = new(rsync_acl);
if (!racl)
out_of_memory("create_racl");
*racl = empty_rsync_acl;
return racl;
@@ -330,11 +332,14 @@ 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
racl->names.idas = new_array(id_access, temp_ida_list.count);
memcpy(racl->names.idas, temp_ida_list.items, temp_ida_list.count * sizeof (id_access));
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));
} else
racl->names.idas = NULL;
@@ -418,7 +423,7 @@ static BOOL pack_smb_acl(SMB_ACL_T *smb_acl, const rsync_acl *racl)
#ifdef ACLS_NEED_MASK
mask_bits = racl->mask_obj == NO_ENTRY ? racl->group_obj & ~NO_ENTRY : racl->mask_obj;
COE( sys_acl_create_entry,(smb_acl, &entry) );
COE( sys_acl_set_info,(entry, SMB_ACL_MASK, mask_bits, 0) );
COE( sys_acl_set_info,(entry, SMB_ACL_MASK, mask_bits, NULL) );
#else
if (racl->mask_obj != NO_ENTRY) {
COE( sys_acl_create_entry,(smb_acl, &entry) );
@@ -502,7 +507,9 @@ static int get_rsync_acl(const char *fname, rsync_acl *racl,
if (cnt) {
char *bp = buf + 4*4;
id_access *ida = racl->names.idas = new_array(id_access, cnt);
id_access *ida;
if (!(ida = racl->names.idas = new_array(id_access, cnt)))
out_of_memory("get_rsync_acl");
racl->names.count = cnt;
for ( ; cnt--; ida++, bp += 4+4) {
ida->id = IVAL(bp, 0);
@@ -519,7 +526,6 @@ static int get_rsync_acl(const char *fname, rsync_acl *racl,
sys_acl_free_acl(sacl);
if (!ok) {
rsyserr(FERROR_XFER, errno, "get_acl: unpack_smb_acl(%s)", fname);
return -1;
}
} else if (no_acl_syscall_error(errno)) {
@@ -554,8 +560,7 @@ int get_acl(const char *fname, stat_x *sxp)
if (!preserve_devices)
#endif
return 0;
} else if (IS_MISSING_FILE(sxp->st))
return 0;
}
if (get_rsync_acl(fname, sxp->acc_acl, SMB_ACL_TYPE_ACCESS,
sxp->st.st_mode) < 0) {
@@ -697,9 +702,14 @@ static uint32 recv_acl_access(int f, uchar *name_follows_ptr)
static uchar recv_ida_entries(int f, ida_entries *ent)
{
uchar computed_mask_bits = 0;
int i, count = read_varint_bounded(f, 0, MAX_WIRE_ACL_COUNT, "ACL count");
int i, count = read_varint(f);
if (count) {
if (!(ent->idas = new_array(id_access, count)))
out_of_memory("recv_ida_entries");
} else
ent->idas = NULL;
ent->idas = count ? new_array(id_access, count) : NULL;
ent->count = count;
for (i = 0; i < count; i++) {
@@ -713,7 +723,7 @@ static uchar recv_ida_entries(int f, ida_entries *ent)
else
id = recv_group_name(f, id, NULL);
} else if (access & NAME_IS_USER) {
if (inc_recurse && !numeric_ids)
if (inc_recurse && am_root && !numeric_ids)
id = match_uid(id);
} else {
if (inc_recurse && (!am_root || !numeric_ids))
@@ -764,8 +774,6 @@ static int recv_rsync_acl(int f, item_list *racl_list, SMB_ACL_TYPE_T type, mode
#ifdef HAVE_OSX_ACLS
/* If we received a superfluous mask, throw it away. */
duo_item->racl.mask_obj = NO_ENTRY;
(void)mode;
(void)computed_mask_bits;
#else
if (duo_item->racl.names.count && duo_item->racl.mask_obj == NO_ENTRY) {
/* Mask must be non-empty with lists. */
@@ -816,12 +824,14 @@ 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);
}
}
@@ -982,10 +992,11 @@ static int set_rsync_acl(const char *fname, acl_duo *duo_item,
&& !pack_smb_acl(&duo_item->sacl, &duo_item->racl))
return -1;
#ifdef HAVE_OSX_ACLS
(void)mode; /* eliminate compiler warning */
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;
}
@@ -1105,12 +1116,14 @@ int default_perms_for_dir(const char *dir)
case ENOSYS:
/* No ACLs are available. */
break;
default:
if (dry_run && errno == ENOENT) {
case ENOENT:
if (dry_run) {
/* 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));
@@ -1130,7 +1143,7 @@ int default_perms_for_dir(const char *dir)
/* Apply the permission-bit entries of the default ACL, if any. */
if (racl.user_obj != NO_ENTRY) {
perms = rsync_acl_get_perms(&racl);
if (DEBUG_GTE(ACL, 1))
if (verbose > 2)
rprintf(FINFO, "got ACL-based default perms %o for directory %s\n", perms, dir);
}

View File

@@ -2,7 +2,7 @@
* Support rsync daemon authentication.
*
* Copyright (C) 1998-2000 Andrew Tridgell
* Copyright (C) 2002-2022 Wayne Davison
* Copyright (C) 2002-2009 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,12 +19,8 @@
*/
#include "rsync.h"
#include "itypes.h"
#include "ifuncs.h"
extern int read_only;
extern char *password_file;
extern struct name_num_obj valid_auth_checksums;
/***************************************************************************
encode a buffer using base64 - simple and slow algorithm. null terminates
@@ -73,13 +69,136 @@ static void gen_challenge(const char *addr, char *challenge)
SIVAL(input, 20, tv.tv_usec);
SIVAL(input, 24, getpid());
len = sum_init(valid_auth_checksums.negotiated_nni, 0);
sum_init(0);
sum_update(input, sizeof input);
sum_end(digest);
len = sum_end(digest);
base64_encode(digest, len, challenge, 0);
}
/* Return the secret for a user from the secret file, null terminated.
* Maximum length is len (not counting the null). */
static int get_secret(int module, const char *user, char *secret, int len)
{
const char *fname = lp_secrets_file(module);
STRUCT_STAT st;
int fd, ok = 1;
const char *p;
char ch, *s;
if (!fname || !*fname)
return 0;
if ((fd = open(fname, O_RDONLY)) < 0)
return 0;
if (do_stat(fname, &st) == -1) {
rsyserr(FLOG, errno, "stat(%s)", fname);
ok = 0;
} else if (lp_strict_modes(module)) {
if ((st.st_mode & 06) != 0) {
rprintf(FLOG, "secrets file must not be other-accessible (see strict modes option)\n");
ok = 0;
} else if (MY_UID() == 0 && st.st_uid != 0) {
rprintf(FLOG, "secrets file must be owned by root when running as root (see strict modes)\n");
ok = 0;
}
}
if (!ok) {
rprintf(FLOG, "continuing without secrets file\n");
close(fd);
return 0;
}
if (*user == '#') {
/* Reject attempt to match a comment. */
close(fd);
return 0;
}
/* Try to find a line that starts with the user name and a ':'. */
p = user;
while (1) {
if (read(fd, &ch, 1) != 1) {
close(fd);
return 0;
}
if (ch == '\n')
p = user;
else if (p) {
if (*p == ch)
p++;
else if (!*p && ch == ':')
break;
else
p = NULL;
}
}
/* Slurp the secret into the "secret" buffer. */
s = secret;
while (len > 0) {
if (read(fd, s, 1) != 1 || *s == '\n')
break;
if (*s == '\r')
continue;
s++;
len--;
}
*s = '\0';
close(fd);
return 1;
}
static const char *getpassf(const char *filename)
{
STRUCT_STAT st;
char buffer[512], *p;
int fd, n, ok = 1;
const char *envpw = getenv("RSYNC_PASSWORD");
if (!filename)
return NULL;
if ((fd = open(filename,O_RDONLY)) < 0) {
rsyserr(FWARNING, errno, "could not open password file \"%s\"",
filename);
if (envpw)
rprintf(FINFO, "falling back to RSYNC_PASSWORD environment variable.\n");
return NULL;
}
if (do_stat(filename, &st) == -1) {
rsyserr(FWARNING, errno, "stat(%s)", filename);
ok = 0;
} else if ((st.st_mode & 06) != 0) {
rprintf(FWARNING, "password file must not be other-accessible\n");
ok = 0;
} else if (MY_UID() == 0 && st.st_uid != 0) {
rprintf(FWARNING, "password file must be owned by root when running as root\n");
ok = 0;
}
if (!ok) {
close(fd);
rprintf(FWARNING, "continuing without password file\n");
if (envpw)
rprintf(FINFO, "falling back to RSYNC_PASSWORD environment variable.\n");
return NULL;
}
n = read(fd, buffer, sizeof buffer - 1);
close(fd);
if (n > 0) {
buffer[n] = '\0';
if ((p = strtok(buffer, "\n\r")) != NULL)
return strdup(p);
}
return NULL;
}
/* Generate an MD4 hash created from the combination of the password
* and the challenge string and return it base64-encoded. */
static void generate_hash(const char *in, const char *challenge, char *out)
@@ -87,135 +206,14 @@ static void generate_hash(const char *in, const char *challenge, char *out)
char buf[MAX_DIGEST_LEN];
int len;
len = sum_init(valid_auth_checksums.negotiated_nni, 0);
sum_init(0);
sum_update(in, strlen(in));
sum_update(challenge, strlen(challenge));
sum_end(buf);
len = sum_end(buf);
base64_encode(buf, len, out, 0);
}
/* Return the secret for a user from the secret file, null terminated.
* Maximum length is len (not counting the null). */
static const char *check_secret(int module, const char *user, const char *group,
const char *challenge, const char *pass)
{
char line[1024];
char pass2[MAX_DIGEST_LEN*2];
const char *fname = lp_secrets_file(module);
STRUCT_STAT st;
int ok = 1;
int user_len = strlen(user);
int group_len = group ? strlen(group) : 0;
char *err;
FILE *fh;
if (!fname || !*fname || (fh = fopen(fname, "r")) == NULL)
return "no secrets file";
if (do_fstat(fileno(fh), &st) == -1) {
rsyserr(FLOG, errno, "fstat(%s)", fname);
ok = 0;
} else if (lp_strict_modes(module)) {
if ((st.st_mode & 06) != 0) {
rprintf(FLOG, "secrets file must not be other-accessible (see strict modes option)\n");
ok = 0;
} else if (MY_UID() == ROOT_UID && st.st_uid != ROOT_UID) {
rprintf(FLOG, "secrets file must be owned by root when running as root (see strict modes)\n");
ok = 0;
}
}
if (!ok) {
fclose(fh);
return "ignoring secrets file";
}
if (*user == '#') {
/* Reject attempt to match a comment. */
fclose(fh);
return "invalid username";
}
/* Try to find a line that starts with the user (or @group) name and a ':'. */
err = "secret not found";
while ((user || group) && fgets(line, sizeof line, fh) != NULL) {
const char **ptr, *s = strtok(line, "\n\r");
int len;
if (!s)
continue;
if (*s == '@') {
ptr = &group;
len = group_len;
s++;
} else {
ptr = &user;
len = user_len;
}
if (!*ptr || strncmp(s, *ptr, len) != 0 || s[len] != ':')
continue;
generate_hash(s+len+1, challenge, pass2);
if (strcmp(pass, pass2) == 0) {
err = NULL;
break;
}
err = "password mismatch";
*ptr = NULL; /* Don't look for name again. */
}
fclose(fh);
force_memzero(line, sizeof line);
force_memzero(pass2, sizeof pass2);
return err;
}
static const char *getpassf(const char *filename)
{
STRUCT_STAT st;
char buffer[512], *p;
int n;
if (!filename)
return NULL;
if (strcmp(filename, "-") == 0) {
n = fgets(buffer, sizeof buffer, stdin) == NULL ? -1 : (int)strlen(buffer);
} else {
int fd;
if ((fd = open(filename,O_RDONLY)) < 0) {
rsyserr(FERROR, errno, "could not open password file %s", filename);
exit_cleanup(RERR_SYNTAX);
}
if (do_stat(filename, &st) == -1) {
rsyserr(FERROR, errno, "stat(%s)", filename);
exit_cleanup(RERR_SYNTAX);
}
if ((st.st_mode & 06) != 0) {
rprintf(FERROR, "ERROR: password file must not be other-accessible\n");
exit_cleanup(RERR_SYNTAX);
}
if (MY_UID() == ROOT_UID && st.st_uid != ROOT_UID) {
rprintf(FERROR, "ERROR: password file must be owned by root when running as root\n");
exit_cleanup(RERR_SYNTAX);
}
n = read(fd, buffer, sizeof buffer - 1);
close(fd);
}
if (n > 0) {
buffer[n] = '\0';
if ((p = strtok(buffer, "\n\r")) != NULL)
return strdup(p);
}
rprintf(FERROR, "ERROR: failed to read a password from %s\n", filename);
exit_cleanup(RERR_SYNTAX);
}
/* Possibly negotiate authentication with the client. Use "leader" to
* start off the auth if necessary.
*
@@ -228,23 +226,19 @@ char *auth_server(int f_in, int f_out, int module, const char *host,
char *users = lp_auth_users(module);
char challenge[MAX_DIGEST_LEN*2];
char line[BIGPATHBUFLEN];
const char **auth_uid_groups = NULL;
int auth_uid_groups_cnt = -1;
const char *err = NULL;
int group_match = -1;
char secret[512];
char pass2[MAX_DIGEST_LEN*2];
char *tok, *pass;
char opt_ch = '\0';
/* if no auth list then allow anyone in! */
if (!users || !*users)
return "";
negotiate_daemon_auth(f_out, 0);
gen_challenge(addr, challenge);
io_printf(f_out, "%s%s\n", leader, challenge);
if (!read_line_old(f_in, line, sizeof line, 0)
if (!read_line_old(f_in, line, sizeof line)
|| (pass = strchr(line, ' ')) == NULL) {
rprintf(FLOG, "auth failed on module %s from %s (%s): "
"invalid challenge response\n",
@@ -253,94 +247,40 @@ char *auth_server(int f_in, int f_out, int module, const char *host,
}
*pass++ = '\0';
users = strdup(users);
if (!(users = strdup(users)))
out_of_memory("auth_server");
for (tok = strtok(users, " ,\t"); tok; tok = strtok(NULL, " ,\t")) {
char *opts;
/* See if the user appended :deny, :ro, or :rw. */
if ((opts = strchr(tok, ':')) != NULL) {
*opts++ = '\0';
opt_ch = isUpper(opts) ? toLower(opts) : *opts;
if (opt_ch == 'r') { /* handle ro and rw */
opt_ch = isUpper(opts+1) ? toLower(opts+1) : opts[1];
if (opt_ch == 'o')
opt_ch = 'r';
else if (opt_ch != 'w')
opt_ch = '\0';
} else if (opt_ch != 'd') /* if it's not deny, ignore it */
opt_ch = '\0';
} else
opt_ch = '\0';
if (*tok != '@') {
/* Match the username */
if (wildmatch(tok, line))
break;
} else {
#ifdef HAVE_GETGROUPLIST
int j;
/* 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) {
item_list gid_list = EMPTY_ITEM_LIST;
uid_t auth_uid;
if (!user_to_uid(line, &auth_uid, False)
|| 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;
auth_uid_groups = new_array(const char *, auth_uid_groups_cnt);
for (j = 0; j < auth_uid_groups_cnt; j++)
auth_uid_groups[j] = gid_to_group(gid_array[j]);
}
}
for (j = 0; j < auth_uid_groups_cnt; j++) {
if (auth_uid_groups[j] && wildmatch(tok+1, auth_uid_groups[j])) {
group_match = j;
break;
}
}
if (group_match >= 0)
break;
#else
rprintf(FLOG, "your computer doesn't support getgrouplist(), so no @group authorization is possible.\n");
#endif
}
if (wildmatch(tok, line))
break;
}
free(users);
if (!tok)
err = "no matching rule";
else if (opt_ch == 'd')
err = "denied by rule";
else {
const char *group = group_match >= 0 ? auth_uid_groups[group_match] : NULL;
err = check_secret(module, line, group, challenge, pass);
}
force_memzero(challenge, sizeof challenge);
force_memzero(pass, strlen(pass));
if (auth_uid_groups) {
int j;
for (j = 0; j < auth_uid_groups_cnt; j++) {
if (auth_uid_groups[j])
free((char*)auth_uid_groups[j]);
}
free(auth_uid_groups);
}
if (err) {
rprintf(FLOG, "auth failed on module %s from %s (%s) for %s: %s\n",
lp_name(module), host, addr, line, err);
if (!tok) {
rprintf(FLOG, "auth failed on module %s from %s (%s): "
"unauthorized user\n",
lp_name(module), host, addr);
return NULL;
}
if (opt_ch == 'r')
read_only = 1;
else if (opt_ch == 'w')
read_only = 0;
memset(secret, 0, sizeof secret);
if (!get_secret(module, line, secret, sizeof secret - 1)) {
memset(secret, 0, sizeof secret);
rprintf(FLOG, "auth failed on module %s from %s (%s): "
"missing secret for user \"%s\"\n",
lp_name(module), host, addr, line);
return NULL;
}
generate_hash(secret, challenge, pass2);
memset(secret, 0, sizeof secret);
if (strcmp(pass, pass2) != 0) {
rprintf(FLOG, "auth failed on module %s from %s (%s): "
"password mismatch\n",
lp_name(module), host, addr);
return NULL;
}
return strdup(line);
}
@@ -352,19 +292,18 @@ void auth_client(int fd, const char *user, const char *challenge)
if (!user || !*user)
user = "nobody";
negotiate_daemon_auth(-1, 1);
if (!(pass = getpassf(password_file))
&& !(pass = getenv("RSYNC_PASSWORD"))) {
/* 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: ");
}

507
backup.c
View File

@@ -2,7 +2,7 @@
* Backup handling code.
*
* Copyright (C) 1999 Andrew Tridgell
* Copyright (C) 2003-2022 Wayne Davison
* Copyright (C) 2003-2009 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,8 +19,8 @@
*/
#include "rsync.h"
#include "ifuncs.h"
extern int verbose;
extern int am_root;
extern int preserve_acls;
extern int preserve_xattrs;
@@ -34,231 +34,210 @@ extern char backup_dir_buf[MAXPATHLEN];
extern char *backup_suffix;
extern char *backup_dir;
/* Returns -1 on error, 0 on missing dir, and 1 on present dir. */
static int validate_backup_dir(void)
{
STRUCT_STAT st;
if (do_lstat_at(backup_dir_buf, &st) < 0) {
if (errno == ENOENT)
return 0;
rsyserr(FERROR, errno, "backup lstat %s failed", backup_dir_buf);
return -1;
}
if (!S_ISDIR(st.st_mode)) {
int flags = get_del_for_flag(st.st_mode) | DEL_FOR_BACKUP | DEL_RECURSE;
if (delete_item(backup_dir_buf, st.st_mode, flags) == 0)
return 0;
return -1;
}
return 1;
}
/* Create a backup path from the given fname, putting the result into
* backup_dir_buf. Any new directories (compared to the prior backup
* path) are ensured to exist as directories, replacing anything else
* that may be in the way (e.g. a symlink). */
static BOOL copy_valid_path(const char *fname)
{
const char *f;
int val;
BOOL ret = True;
stat_x sx;
char *b, *rel = backup_dir_buf + backup_dir_len, *name = rel;
for (f = fname, b = rel; *f && *f == *b; f++, b++) {
if (*b == '/')
name = b + 1;
}
if (stringjoin(rel, backup_dir_remainder, fname, backup_suffix, NULL) >= backup_dir_remainder) {
rprintf(FERROR, "backup filename too long\n");
*name = '\0';
return False;
}
for ( ; ; name = b + 1) {
if ((b = strchr(name, '/')) == NULL)
return True;
*b = '\0';
val = validate_backup_dir();
if (val == 0)
break;
if (val < 0) {
*name = '\0';
return False;
}
*b = '/';
}
init_stat_x(&sx);
for ( ; b; name = b + 1, b = strchr(name, '/')) {
*b = '\0';
while (do_mkdir_at(backup_dir_buf, ACCESSPERMS) < 0) {
if (errno == EEXIST) {
val = validate_backup_dir();
if (val > 0)
break;
if (val == 0)
continue;
} else
rsyserr(FERROR, errno, "backup mkdir %s failed", backup_dir_buf);
*name = '\0';
ret = False;
goto cleanup;
}
/* Try to transfer the directory settings of the actual dir
* that the files are coming from. */
if (x_stat(rel, &sx.st, NULL) < 0)
rsyserr(FERROR, errno, "backup stat %s failed", full_fname(rel));
else {
struct file_struct *file;
if (!(file = make_file(rel, NULL, NULL, 0, NO_FILTERS)))
continue;
#ifdef SUPPORT_ACLS
if (preserve_acls && !S_ISLNK(file->mode)) {
get_acl(rel, &sx);
cache_tmp_acl(file, &sx);
free_acl(&sx);
}
#endif
#ifdef SUPPORT_XATTRS
if (preserve_xattrs) {
get_xattr(rel, &sx);
cache_tmp_xattr(file, &sx);
free_xattr(&sx);
}
#endif
set_file_attrs(backup_dir_buf, file, NULL, NULL, 0);
unmake_file(file);
}
*b = '/';
}
cleanup:
#ifdef SUPPORT_ACLS
uncache_tmp_acls();
#endif
#ifdef SUPPORT_XATTRS
uncache_tmp_xattrs();
#endif
return ret;
}
/* Make a complete pathname for backup file and verify any new path elements. */
/* make a complete pathname for backup file */
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))
if (stringjoin(backup_dir_buf + backup_dir_len, backup_dir_remainder,
fname, backup_suffix, NULL) < backup_dir_remainder)
return backup_dir_buf;
} else {
if (stringjoin(backup_dir_buf, MAXPATHLEN,
fname, backup_suffix, NULL) < MAXPATHLEN)
return backup_dir_buf;
/* copy_valid_path() has printed an error message. */
return NULL;
}
if (stringjoin(backup_dir_buf, MAXPATHLEN, fname, backup_suffix, NULL) < MAXPATHLEN)
return backup_dir_buf;
rprintf(FERROR, "backup filename too long\n");
return NULL;
}
/* Has same return codes as make_backup(). */
static inline int link_or_rename(const char *from, const char *to,
BOOL prefer_rename, STRUCT_STAT *stp)
/* simple backup creates a backup with a suffix in the same directory */
static int make_simple_backup(const char *fname)
{
#ifdef SUPPORT_HARD_LINKS
if (!prefer_rename) {
#ifndef CAN_HARDLINK_SYMLINK
if (S_ISLNK(stp->st_mode))
return 0; /* Use copy code. */
#endif
#ifndef CAN_HARDLINK_SPECIAL
if (IS_SPECIAL(stp->st_mode) || IS_DEVICE(stp->st_mode))
return 0; /* Use copy code. */
#endif
if (do_link_at(from, to) == 0) {
if (DEBUG_GTE(BACKUP, 1))
rprintf(FINFO, "make_backup: HLINK %s successful.\n", from);
return 2;
int rename_errno;
const char *fnamebak = get_backup_name(fname);
if (!fnamebak)
return 0;
while (1) {
if (do_rename(fname, fnamebak) == 0) {
if (verbose > 1) {
rprintf(FINFO, "backed up %s to %s\n",
fname, fnamebak);
}
break;
}
/* We prefer to rename a regular file rather than copy it. */
if (!S_ISREG(stp->st_mode) || errno == EEXIST || errno == EISDIR)
return 0;
/* cygwin (at least version b19) reports EINVAL */
if (errno == ENOENT || errno == EINVAL)
break;
rename_errno = errno;
if (errno == EISDIR && do_rmdir(fnamebak) == 0)
continue;
if (errno == ENOTDIR && do_unlink(fnamebak) == 0)
continue;
rsyserr(FERROR, rename_errno, "rename %s to backup %s",
fname, fnamebak);
errno = rename_errno;
return 0;
}
#endif
if (do_rename_at(from, to) == 0) {
if (stp->st_nlink > 1 && !S_ISDIR(stp->st_mode)) {
/* If someone has hard-linked the file into the backup
* dir, rename() might return success but do nothing! */
robust_unlink(from); /* Just in case... */
return 1;
}
/****************************************************************************
Create a directory given an absolute path, perms based upon another directory
path
****************************************************************************/
int make_bak_dir(const char *fullpath)
{
char fbuf[MAXPATHLEN], *rel, *end, *p;
struct file_struct *file;
int len = backup_dir_len;
stat_x sx;
while (*fullpath == '.' && fullpath[1] == '/') {
fullpath += 2;
len -= 2;
}
if (strlcpy(fbuf, fullpath, sizeof fbuf) >= sizeof fbuf)
return -1;
rel = fbuf + len;
end = p = rel + strlen(rel);
/* Try to find an existing dir, starting from the deepest dir. */
while (1) {
if (--p == fbuf)
return -1;
if (*p == '/') {
*p = '\0';
if (mkdir_defmode(fbuf) == 0)
break;
if (errno != ENOENT) {
rsyserr(FERROR, errno,
"make_bak_dir mkdir %s failed",
full_fname(fbuf));
return -1;
}
}
}
/* Make all the dirs that we didn't find on the way here. */
while (1) {
if (p >= rel) {
/* Try to transfer the directory settings of the
* actual dir that the files are coming from. */
if (x_stat(rel, &sx.st, NULL) < 0) {
rsyserr(FERROR, errno,
"make_bak_dir stat %s failed",
full_fname(rel));
} else {
#ifdef SUPPORT_ACLS
sx.acc_acl = sx.def_acl = NULL;
#endif
#ifdef SUPPORT_XATTRS
sx.xattr = NULL;
#endif
if (!(file = make_file(rel, NULL, NULL, 0, NO_FILTERS)))
continue;
#ifdef SUPPORT_ACLS
if (preserve_acls && !S_ISLNK(file->mode)) {
get_acl(rel, &sx);
cache_tmp_acl(file, &sx);
free_acl(&sx);
}
#endif
#ifdef SUPPORT_XATTRS
if (preserve_xattrs) {
get_xattr(rel, &sx);
cache_tmp_xattr(file, &sx);
free_xattr(&sx);
}
#endif
set_file_attrs(fbuf, file, NULL, NULL, 0);
unmake_file(file);
#ifdef SUPPORT_ACLS
uncache_tmp_acls();
#endif
#ifdef SUPPORT_XATTRS
uncache_tmp_xattrs();
#endif
}
}
*p = '/';
p += strlen(p);
if (p == end)
break;
if (mkdir_defmode(fbuf) < 0) {
rsyserr(FERROR, errno, "make_bak_dir mkdir %s failed",
full_fname(fbuf));
return -1;
}
}
return 0;
}
/* robustly move a file, creating new directory structures if necessary */
static int robust_move(const char *src, char *dst)
{
if (robust_rename(src, dst, NULL, 0755) < 0) {
int save_errno = errno ? errno : EINVAL; /* 0 paranoia */
if (errno == ENOENT && make_bak_dir(dst) == 0) {
if (robust_rename(src, dst, NULL, 0755) < 0)
save_errno = errno ? errno : save_errno;
else
save_errno = 0;
}
if (save_errno) {
errno = save_errno;
return -1;
}
if (DEBUG_GTE(BACKUP, 1))
rprintf(FINFO, "make_backup: RENAME %s successful.\n", from);
return 1;
}
return 0;
}
/* 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)
/* If we have a --backup-dir, then we get here from make_backup().
* We will move the file to be deleted into a parallel directory tree. */
static int keep_backup(const char *fname)
{
stat_x sx;
struct file_struct *file;
int save_preserve_xattrs;
char *buf;
int ret = 0;
int save_preserve_xattrs = preserve_xattrs;
int kept = 0;
int ret_code;
init_stat_x(&sx);
/* Return success if no file to keep. */
/* return if no file to keep */
if (x_lstat(fname, &sx.st, NULL) < 0)
return 3;
return 1;
#ifdef SUPPORT_ACLS
sx.acc_acl = sx.def_acl = NULL;
#endif
#ifdef SUPPORT_XATTRS
sx.xattr = NULL;
#endif
if (!(buf = get_backup_name(fname)))
if (!(file = make_file(fname, NULL, NULL, 0, NO_FILTERS)))
return 1; /* the file could have disappeared */
if (!(buf = get_backup_name(fname))) {
unmake_file(file);
#ifdef SUPPORT_ACLS
uncache_tmp_acls();
#endif
#ifdef SUPPORT_XATTRS
uncache_tmp_xattrs();
#endif
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-
* linking is possible. */
if ((ret = link_or_rename(fname, buf, prefer_rename, &sx.st)) != 0)
goto success;
if (errno == EEXIST || errno == EISDIR) {
STRUCT_STAT bakst;
if (do_lstat_at(buf, &bakst) == 0) {
int flags = get_del_for_flag(bakst.st_mode) | DEL_FOR_BACKUP | DEL_RECURSE;
if (delete_item(buf, bakst.st_mode, flags) != 0)
return 0;
}
if ((ret = link_or_rename(fname, buf, prefer_rename, &sx.st)) != 0)
goto success;
}
/* Fall back to making a copy. */
if (!(file = make_file(fname, NULL, &sx.st, 0, NO_FILTERS)))
return 3; /* the file could have disappeared */
#ifdef SUPPORT_ACLS
if (preserve_acls && !S_ISLNK(file->mode)) {
get_acl(fname, &sx);
@@ -277,35 +256,87 @@ int make_backup(const char *fname, BOOL prefer_rename)
/* Check to see if this is a device file, or link */
if ((am_root && preserve_devices && IS_DEVICE(file->mode))
|| (preserve_specials && IS_SPECIAL(file->mode))) {
if (do_mknod_at(buf, file->mode, sx.st.st_rdev) < 0)
rsyserr(FERROR, errno, "mknod %s failed", full_fname(buf));
else if (DEBUG_GTE(BACKUP, 1))
rprintf(FINFO, "make_backup: DEVICE %s successful.\n", fname);
ret = 2;
int save_errno;
do_unlink(buf);
if (do_mknod(buf, file->mode, sx.st.st_rdev) < 0) {
save_errno = errno ? errno : EINVAL; /* 0 paranoia */
if (errno == ENOENT && make_bak_dir(buf) == 0) {
if (do_mknod(buf, file->mode, sx.st.st_rdev) < 0)
save_errno = errno ? errno : save_errno;
else
save_errno = 0;
}
if (save_errno) {
rsyserr(FERROR, save_errno, "mknod %s failed",
full_fname(buf));
}
} else
save_errno = 0;
if (verbose > 2 && save_errno == 0) {
rprintf(FINFO, "make_backup: DEVICE %s successful.\n",
fname);
}
kept = 1;
do_unlink(fname);
}
if (!kept && S_ISDIR(file->mode)) {
/* make an empty directory */
if (do_mkdir(buf, file->mode) < 0) {
int save_errno = errno ? errno : EINVAL; /* 0 paranoia */
if (errno == ENOENT && make_bak_dir(buf) == 0) {
if (do_mkdir(buf, file->mode) < 0)
save_errno = errno ? errno : save_errno;
else
save_errno = 0;
}
if (save_errno) {
rsyserr(FINFO, save_errno, "mkdir %s failed",
full_fname(buf));
}
}
ret_code = do_rmdir(fname);
if (verbose > 2) {
rprintf(FINFO, "make_backup: RMDIR %s returns %i\n",
full_fname(fname), ret_code);
}
kept = 1;
}
#ifdef SUPPORT_LINKS
if (!ret && preserve_links && S_ISLNK(file->mode)) {
if (!kept && preserve_links && S_ISLNK(file->mode)) {
const char *sl = F_SYMLINK(file);
if (safe_symlinks && unsafe_symlink(sl, fname)) {
if (INFO_GTE(SYMSAFE, 1)) {
if (verbose) {
rprintf(FINFO, "not backing up unsafe symlink \"%s\" -> \"%s\"\n",
fname, sl);
}
ret = 2;
kept = 1;
} else {
if (do_symlink_at(sl, buf) < 0)
rsyserr(FERROR, errno, "link %s -> \"%s\"", full_fname(buf), sl);
else if (DEBUG_GTE(BACKUP, 1))
rprintf(FINFO, "make_backup: SYMLINK %s successful.\n", fname);
ret = 2;
do_unlink(buf);
if (do_symlink(sl, buf) < 0) {
int save_errno = errno ? errno : EINVAL; /* 0 paranoia */
if (errno == ENOENT && make_bak_dir(buf) == 0) {
if (do_symlink(sl, buf) < 0)
save_errno = errno ? errno : save_errno;
else
save_errno = 0;
}
if (save_errno) {
rsyserr(FERROR, save_errno, "link %s -> \"%s\"",
full_fname(buf), sl);
}
}
do_unlink(fname);
kept = 1;
}
}
#endif
if (!ret && !S_ISREG(file->mode)) {
if (INFO_GTE(NONREG, 1))
rprintf(FINFO, "make_bak: skipping non-regular file %s\n", fname);
if (!kept && !S_ISREG(file->mode)) {
rprintf(FINFO, "make_bak: skipping non-regular file %s\n",
fname);
unmake_file(file);
#ifdef SUPPORT_ACLS
uncache_tmp_acls();
@@ -313,33 +344,23 @@ int make_backup(const char *fname, BOOL prefer_rename)
#ifdef SUPPORT_XATTRS
uncache_tmp_xattrs();
#endif
return 3;
return 1;
}
/* Copy to backup tree if a file. */
if (!ret) {
if (copy_file(fname, buf, -1, file->mode) < 0) {
/* move to keep tree if a file */
if (!kept) {
if (robust_move(fname, buf) != 0) {
rsyserr(FERROR, errno, "keep_backup failed: %s -> \"%s\"",
full_fname(fname), buf);
unmake_file(file);
#ifdef SUPPORT_ACLS
uncache_tmp_acls();
#endif
#ifdef SUPPORT_XATTRS
uncache_tmp_xattrs();
#endif
return 0;
} else if (sx.st.st_nlink > 1) {
/* If someone has hard-linked the file into the backup
* dir, rename() might return success but do nothing! */
robust_unlink(fname); /* Just in case... */
}
if (DEBUG_GTE(BACKUP, 1))
rprintf(FINFO, "make_backup: COPY %s successful.\n", fname);
ret = 2;
}
save_preserve_xattrs = preserve_xattrs;
preserve_xattrs = 0;
set_file_attrs(buf, file, NULL, fname, ATTRS_ACCURATE_TIME);
set_file_attrs(buf, file, NULL, fname, 0);
preserve_xattrs = save_preserve_xattrs;
unmake_file(file);
#ifdef SUPPORT_ACLS
uncache_tmp_acls();
@@ -348,8 +369,18 @@ int make_backup(const char *fname, BOOL prefer_rename)
uncache_tmp_xattrs();
#endif
success:
if (INFO_GTE(BACKUP, 1))
rprintf(FINFO, "backed up %s to %s\n", fname, buf);
return ret;
if (verbose > 1) {
rprintf(FINFO, "backed up %s to %s\n",
fname, buf);
}
return 1;
}
/* main backup switch routine */
int make_backup(const char *fname)
{
if (backup_dir)
return keep_backup(fname);
return make_simple_backup(fname);
}

169
batch.c
View File

@@ -3,7 +3,7 @@
*
* Copyright (C) 1999 Weiss
* Copyright (C) 2004 Chris Shoemaker
* Copyright (C) 2004-2022 Wayne Davison
* Copyright (C) 2004-2009 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
@@ -20,7 +20,7 @@
*/
#include "rsync.h"
#include <zlib.h>
#include "zlib/zlib.h"
#include <time.h>
extern int eol_nulls;
@@ -37,19 +37,14 @@ extern int always_checksum;
extern int do_compression;
extern int inplace;
extern int append_mode;
extern int write_batch;
extern int protocol_version;
extern int raw_argc, cooked_argc;
extern char **raw_argv, **cooked_argv;
extern char *batch_name;
#ifdef ICONV_OPTION
extern char *iconv_opt;
#endif
extern filter_rule_list filter_list;
extern struct filter_list_struct filter_list;
int batch_fd = -1;
int batch_sh_fd = -1;
int batch_stream_flags;
static int tweaked_append;
@@ -75,7 +70,7 @@ static int *flag_ptr[] = {
NULL
};
static const char *const flag_name[] = {
static char *flag_name[] = {
"--recurse (-r)",
"--owner (-o)",
"--group (-g)",
@@ -140,7 +135,7 @@ void check_batch_flags(void)
set ? "Please" : "Do not");
exit_cleanup(RERR_SYNTAX);
}
if (INFO_GTE(MISC, 1)) {
if (verbose) {
rprintf(FINFO,
"%sing the %s option to match the batchfile.\n",
set ? "Sett" : "Clear", flag_name[i]);
@@ -161,58 +156,50 @@ void check_batch_flags(void)
append_mode = 2;
}
static int write_arg(const char *arg)
static int write_arg(int fd, char *arg)
{
const char *x, *s;
int len, err = 0;
char *x, *s;
int len, ret = 0;
if (*arg == '-' && (x = strchr(arg, '=')) != NULL) {
err |= write(batch_sh_fd, arg, x - arg + 1) != x - arg + 1;
if (write(fd, arg, x - arg + 1) != x - arg + 1)
ret = -1;
arg += x - arg + 1;
}
if (strpbrk(arg, " \"'&;|[]()$#!*?^\\") != NULL) {
err |= write(batch_sh_fd, "'", 1) != 1;
if (write(fd, "'", 1) != 1)
ret = -1;
for (s = arg; (x = strchr(s, '\'')) != NULL; s = x + 1) {
err |= write(batch_sh_fd, s, x - s + 1) != x - s + 1;
err |= write(batch_sh_fd, "'", 1) != 1;
if (write(fd, s, x - s + 1) != x - s + 1
|| write(fd, "'", 1) != 1)
ret = -1;
}
len = strlen(s);
err |= write(batch_sh_fd, s, len) != len;
err |= write(batch_sh_fd, "'", 1) != 1;
return err;
if (write(fd, s, len) != len
|| write(fd, "'", 1) != 1)
ret = -1;
return ret;
}
len = strlen(arg);
err |= write(batch_sh_fd, arg, len) != len;
if (write(fd, arg, len) != len)
ret = -1;
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;
return ret;
}
static void write_filter_rules(int fd)
{
filter_rule *ent;
struct filter_struct *ent;
write_sbuf(fd, " <<'#E#'\n");
for (ent = filter_list.head; ent; ent = ent->next) {
unsigned int plen;
char *p = get_rule_prefix(ent, "- ", 0, &plen);
char *p = get_rule_prefix(ent->match_flags, "- ", 0, &plen);
write_buf(fd, p, plen);
write_sbuf(fd, ent->pattern);
if (ent->rflags & FILTRULE_DIRECTORY)
if (ent->match_flags & MATCHFLG_DIRECTORY)
write_byte(fd, '/');
write_byte(fd, eol_nulls ? 0 : '\n');
}
@@ -221,66 +208,41 @@ 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(void)
void write_batch_shell_file(int argc, char *argv[], int file_arg_cnt)
{
int i, j, len, err = 0;
char *p, *p2;
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_IEXEC);
if (fd < 0) {
rsyserr(FERROR, errno, "Batch file %s open error",
filename);
exit_cleanup(RERR_FILESELECT);
}
/* Write argvs info to BATCH.sh file */
err |= write_arg(raw_argv[0]);
if (write_arg(fd, argv[0]) < 0)
err = 1;
if (filter_list.head) {
if (protocol_version >= 29)
err |= write_opt("--filter", "._-");
write_sbuf(fd, " --filter=._-");
else
err |= write_opt("--exclude-from", "-");
write_sbuf(fd, " --exclude-from=-");
}
/* 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;
for (i = 1; i < argc - file_arg_cnt; i++) {
p = argv[i];
if (strncmp(p, "--files-from", 12) == 0
|| strncmp(p, "--filter", 8) == 0
|| strncmp(p, "--include", 9) == 0
|| strncmp(p, "--exclude", 9) == 0) {
|| strncmp(p, "--filter", 8) == 0
|| strncmp(p, "--include", 9) == 0
|| strncmp(p, "--exclude", 9) == 0) {
if (strchr(p, '=') == NULL)
i++;
continue;
@@ -289,24 +251,33 @@ void write_batch_shell_file(void)
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)
err |= write_opt("--read-batch", p[len] == '=' ? p + len + 1 : NULL);
else {
err |= write(batch_sh_fd, " ", 1) != 1;
err |= write_arg(p);
|| 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;
}
}
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 (!(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 (filter_list.head)
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);
write_filter_rules(fd);
if (write(fd, "\n", 1) != 1 || close(fd) < 0 || err) {
rsyserr(FERROR, errno, "Batch file %s write error",
filename);
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-2022 Wayne Davison
* Copyright (C) 2007-2008 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,10 +19,11 @@
*/
#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. */
#if defined __i386__ || defined __i486__ || defined __i586__ || defined __i686__ || __amd64
#ifdef __i386__
#define CAREFUL_ALIGNMENT 0
#endif
@@ -35,36 +36,14 @@
#if CAREFUL_ALIGNMENT
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 PVAL(buf,pos) (UVAL(buf,pos)|UVAL(buf,(pos)+1)<<8)
#define IVAL(buf,pos) (PVAL(buf,pos)|PVAL(buf,(pos)+2)<<16)
#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)))
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);
}
#define IVALu(buf,pos) IVAL(buf,pos)
#define SIVALu(buf,pos,val) SIVAL(buf,pos,val)
#else /* !CAREFUL_ALIGNMENT */
@@ -72,6 +51,16 @@ SIVAL64(char *buf, int pos, int64 val)
* 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)
{
@@ -94,30 +83,6 @@ SIVALu(uchar *buf, int pos, uint32 val)
*u.num = val;
}
static inline int64
IVAL64(const char *buf, int pos)
{
union {
const char *b;
const int64 *num;
} u;
u.b = buf + pos;
return *u.num;
}
static inline void
SIVAL64(char *buf, int pos, int64 val)
{
union {
char *b;
int64 *num;
} u;
u.b = buf + pos;
*u.num = val;
}
#endif /* !CAREFUL_ALIGNMENT */
static inline uint32
IVAL(const char *buf, int pos)
{
@@ -129,3 +94,7 @@ SIVAL(char *buf, int pos, uint32 val)
{
SIVALu((uchar*)buf, pos, val);
}
# endif /* !AVOID_BYTEORDER_INLINE */
#endif /* !CAREFUL_ALIGNMENT */

View File

@@ -1,7 +1,7 @@
/*
* Allow an arbitrary sequence of case labels.
*
* Copyright (C) 2006-2020 Wayne Davison
* Copyright (C) 2006-2010 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 segment in a switch statement.
/* This is included multiple times, once for every segement in a switch statement.
* This produces the next "case N:" statement in sequence. */
#if !defined CASE_N_STATE_0
@@ -25,67 +25,51 @@
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,20 +3,13 @@
*
* Copyright (C) 1996 Andrew Tridgell
* Copyright (C) 1996 Paul Mackerras
* Copyright (C) 2004-2023 Wayne Davison
* Copyright (C) 2004-2009 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
@@ -28,348 +21,59 @@
#include "rsync.h"
#ifdef SUPPORT_XXHASH
#include <xxhash.h>
# if XXH_VERSION_NUMBER >= 800
# define SUPPORT_XXH3 1
# endif
#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;
#define NNI_BUILTIN (1<<0)
#define NNI_EVP (1<<1)
#define NNI_EVP_OK (1<<2)
struct name_num_item valid_checksums_items[] = {
#ifdef SUPPORT_XXH3
{ CSUM_XXH3_128, 0, "xxh128", NULL },
{ CSUM_XXH3_64, 0, "xxh3", NULL },
#endif
#ifdef SUPPORT_XXHASH
{ CSUM_XXH64, 0, "xxh64", NULL },
{ CSUM_XXH64, 0, "xxhash", NULL },
#endif
{ CSUM_MD5, NNI_BUILTIN|NNI_EVP, "md5", NULL },
{ CSUM_MD4, NNI_BUILTIN|NNI_EVP, "md4", NULL },
#ifdef SHA_DIGEST_LENGTH
{ CSUM_SHA1, NNI_EVP, "sha1", NULL },
#endif
{ CSUM_NONE, 0, "none", NULL },
{ 0, 0, NULL, NULL }
};
struct name_num_obj valid_checksums = {
"checksum", NULL, 0, 0, valid_checksums_items
};
struct name_num_item valid_auth_checksums_items[] = {
#ifdef SHA512_DIGEST_LENGTH
{ CSUM_SHA512, NNI_EVP, "sha512", NULL },
#endif
#ifdef SHA256_DIGEST_LENGTH
{ CSUM_SHA256, NNI_EVP, "sha256", NULL },
#endif
#ifdef SHA_DIGEST_LENGTH
{ CSUM_SHA1, NNI_EVP, "sha1", NULL },
#endif
{ CSUM_MD5, NNI_BUILTIN|NNI_EVP, "md5", NULL },
{ CSUM_MD4, NNI_BUILTIN|NNI_EVP, "md4", NULL },
{ 0, 0, NULL, NULL }
};
struct name_num_obj valid_auth_checksums = {
"daemon auth checksum", NULL, 0, 0, valid_auth_checksums_items
};
/* These cannot make use of openssl, so they're marked just as built-in */
struct name_num_item implied_checksum_md4 =
{ CSUM_MD4, NNI_BUILTIN, "md4", NULL };
struct name_num_item implied_checksum_md5 =
{ CSUM_MD5, NNI_BUILTIN, "md5", NULL };
struct name_num_item *xfer_sum_nni; /* used for the transfer checksum2 computations */
int xfer_sum_len;
struct name_num_item *file_sum_nni; /* used for the pre-transfer --checksum computations */
int file_sum_len, file_sum_extra_cnt;
#ifdef USE_OPENSSL
const EVP_MD *xfer_sum_evp_md;
const EVP_MD *file_sum_evp_md;
EVP_MD_CTX *ctx_evp = NULL;
#endif
static int initialized_choices = 0;
struct name_num_item *parse_csum_name(const char *name, int len)
{
struct name_num_item *nni;
if (len < 0 && name)
len = strlen(name);
init_checksum_choices();
if (!name || (len == 4 && strncasecmp(name, "auto", 4) == 0)) {
if (protocol_version >= 30) {
if (!proper_seed_order)
return &implied_checksum_md5;
name = "md5";
len = 3;
} else {
if (protocol_version >= 27)
implied_checksum_md4.num = CSUM_MD4_OLD;
else if (protocol_version >= 21)
implied_checksum_md4.num = CSUM_MD4_BUSTED;
else
implied_checksum_md4.num = CSUM_MD4_ARCHAIC;
return &implied_checksum_md4;
}
}
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;
}
#ifdef USE_OPENSSL
static const EVP_MD *csum_evp_md(struct name_num_item *nni)
{
const EVP_MD *emd;
if (!(nni->flags & NNI_EVP))
return NULL;
#ifdef USE_MD5_ASM
if (nni->num == CSUM_MD5)
emd = NULL;
else
#endif
emd = EVP_get_digestbyname(nni->name);
if (emd && !(nni->flags & NNI_EVP_OK)) { /* Make sure it works before we advertise it */
if (!ctx_evp && !(ctx_evp = EVP_MD_CTX_create()))
out_of_memory("csum_evp_md");
/* Some routines are marked as legacy and are not enabled in the openssl.cnf file.
* If we can't init the emd, we'll fall back to our built-in code. */
if (EVP_DigestInit_ex(ctx_evp, emd, NULL) == 0)
emd = NULL;
else
nni->flags = (nni->flags & ~NNI_BUILTIN) | NNI_EVP_OK;
}
if (!emd)
nni->flags &= ~NNI_EVP;
return emd;
}
#endif
void parse_checksum_choice(int final_call)
{
if (valid_checksums.negotiated_nni)
xfer_sum_nni = file_sum_nni = valid_checksums.negotiated_nni;
else {
const char *cp = checksum_choice ? strchr(checksum_choice, ',') : NULL;
if (cp) {
xfer_sum_nni = parse_csum_name(checksum_choice, cp - checksum_choice);
file_sum_nni = parse_csum_name(cp+1, -1);
} else
xfer_sum_nni = file_sum_nni = parse_csum_name(checksum_choice, -1);
if (am_server && checksum_choice)
validate_choice_vs_env(NSTR_CHECKSUM, xfer_sum_nni->num, file_sum_nni->num);
}
xfer_sum_len = csum_len_for_type(xfer_sum_nni->num, 0);
file_sum_len = csum_len_for_type(file_sum_nni->num, 0);
#ifdef USE_OPENSSL
xfer_sum_evp_md = csum_evp_md(xfer_sum_nni);
file_sum_evp_md = csum_evp_md(file_sum_nni);
#endif
file_sum_extra_cnt = (file_sum_len + EXTRA_LEN - 1) / EXTRA_LEN;
if (xfer_sum_nni->num == CSUM_NONE)
whole_file = 1;
/* Snag the checksum name for both write_batch's option output & the following debug output. */
if (valid_checksums.negotiated_nni)
checksum_choice = valid_checksums.negotiated_nni->name;
else if (checksum_choice == NULL)
checksum_choice = xfer_sum_nni->name;
if (final_call && DEBUG_GTE(NSTR, am_server ? 3 : 1)) {
rprintf(FINFO, "%s%s checksum: %s\n",
am_server ? "Server" : "Client",
valid_checksums.negotiated_nni ? " 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 SHA_DIGEST_LENGTH
case CSUM_SHA1:
return SHA_DIGEST_LENGTH;
#endif
#ifdef SHA256_DIGEST_LENGTH
case CSUM_SHA256:
return SHA256_DIGEST_LENGTH;
#endif
#ifdef SHA512_DIGEST_LENGTH
case CSUM_SHA512:
return SHA512_DIGEST_LENGTH;
#endif
case CSUM_XXH64:
case CSUM_XXH3_64:
return 64/8;
case CSUM_XXH3_128:
return 128/8;
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:
case CSUM_SHA1:
case CSUM_SHA256:
case CSUM_SHA512:
return -1;
case CSUM_XXH64:
case CSUM_XXH3_64:
case CSUM_XXH3_128:
return 1;
default: /* paranoia to prevent missing case values */
exit_cleanup(RERR_UNSUPPORTED);
}
return 0;
}
#ifndef USE_ROLL_SIMD /* See simd-checksum-*.cpp. */
/*
a simple 32 bit checksum that can be updated from either end
a simple 32 bit checksum that can be upadted from either end
(inspired by Mark Adler's Adler-32 checksum)
*/
uint32 get_checksum1(char *buf1, 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
/* The "sum" buffer must be at least MAX_DIGEST_LEN bytes! */
void get_checksum2(char *buf, int32 len, char *sum)
{
#ifdef USE_OPENSSL
if (xfer_sum_evp_md) {
static EVP_MD_CTX *evp = NULL;
md_context m;
if (protocol_version >= 30) {
uchar seedbuf[4];
if (!evp && !(evp = EVP_MD_CTX_create()))
out_of_memory("get_checksum2");
EVP_DigestInit_ex(evp, xfer_sum_evp_md, NULL);
md5_begin(&m);
md5_update(&m, (uchar *)buf, len);
if (checksum_seed) {
SIVALu(seedbuf, 0, checksum_seed);
EVP_DigestUpdate(evp, seedbuf, 4);
md5_update(&m, seedbuf, 4);
}
EVP_DigestUpdate(evp, (uchar *)buf, len);
EVP_DigestFinal_ex(evp, (uchar *)sum, NULL);
} else
#endif
switch (xfer_sum_nni->num) {
#ifdef SUPPORT_XXHASH
case CSUM_XXH64:
SIVAL64(sum, 0, XXH64(buf, len, checksum_seed));
break;
#endif
#ifdef SUPPORT_XXH3
case CSUM_XXH3_64:
SIVAL64(sum, 0, XXH3_64bits_withSeed(buf, len, checksum_seed));
break;
case CSUM_XXH3_128: {
XXH128_hash_t digest = XXH3_128bits_withSeed(buf, len, checksum_seed);
SIVAL64(sum, 0, digest.low64);
SIVAL64(sum, 8, digest.high64);
break;
}
#endif
case CSUM_MD5: {
md_context m5;
uchar seedbuf[4];
md5_begin(&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(&m5, (uchar *)sum);
break;
}
case CSUM_MD4:
case CSUM_MD4_OLD:
case CSUM_MD4_BUSTED:
case CSUM_MD4_ARCHAIC: {
md_context m;
md5_result(&m, (uchar *)sum);
} else {
int32 i;
static char *buf1;
static int32 len1;
mdfour_begin(&m);
if (len > len1 || !buf1) {
free(buf1);
if (len > len1) {
if (buf1)
free(buf1);
buf1 = new_array(char, len+4);
len1 = len;
if (!buf1)
out_of_memory("get_checksum2");
}
memcpy(buf1, buf, len);
@@ -387,150 +91,59 @@ 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 || xfer_sum_nni->num > CSUM_MD4_BUSTED)
if (len - i > 0 || protocol_version >= 27)
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);
}
}
void file_checksum(const char *fname, const STRUCT_STAT *st_p, char *sum)
void file_checksum(char *fname, char *sum, OFF_T size)
{
struct map_struct *buf;
OFF_T i, len = st_p->st_size;
OFF_T i, len = size;
md_context m;
int32 remainder;
int fd;
fd = do_open_checklinks(fname);
if (fd == -1) {
memset(sum, 0, file_sum_len);
memset(sum, 0, MAX_DIGEST_LEN);
fd = do_open(fname, O_RDONLY, 0);
if (fd == -1)
return;
}
buf = map_file(fd, len, MAX_MAP_SIZE, CHUNK_SIZE);
buf = map_file(fd, size, MAX_MAP_SIZE, CSUM_CHUNK);
#ifdef USE_OPENSSL
if (file_sum_evp_md) {
static EVP_MD_CTX *evp = NULL;
if (!evp && !(evp = EVP_MD_CTX_create()))
out_of_memory("file_checksum");
if (protocol_version >= 30) {
md5_begin(&m);
EVP_DigestInit_ex(evp, file_sum_evp_md, NULL);
for (i = 0; i + CHUNK_SIZE <= len; i += CHUNK_SIZE)
EVP_DigestUpdate(evp, (uchar *)map_ptr(buf, i, CHUNK_SIZE), CHUNK_SIZE);
for (i = 0; i + CSUM_CHUNK <= len; i += CSUM_CHUNK) {
md5_update(&m, (uchar *)map_ptr(buf, i, CSUM_CHUNK),
CSUM_CHUNK);
}
remainder = (int32)(len - i);
if (remainder > 0)
EVP_DigestUpdate(evp, (uchar *)map_ptr(buf, i, remainder), remainder);
EVP_DigestFinal_ex(evp, (uchar *)sum, NULL);
} else
#endif
switch (file_sum_nni->num) {
#ifdef SUPPORT_XXHASH
case CSUM_XXH64: {
static XXH64_state_t* state = NULL;
if (!state && !(state = XXH64_createState()))
out_of_memory("file_checksum");
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)
XXH64_update(state, (uchar *)map_ptr(buf, i, remainder), remainder);
SIVAL64(sum, 0, XXH64_digest(state));
break;
}
#endif
#ifdef SUPPORT_XXH3
case CSUM_XXH3_64: {
static XXH3_state_t* state = NULL;
if (!state && !(state = XXH3_createState()))
out_of_memory("file_checksum");
XXH3_64bits_reset(state);
for (i = 0; i + CHUNK_SIZE <= len; i += CHUNK_SIZE)
XXH3_64bits_update(state, (uchar *)map_ptr(buf, i, CHUNK_SIZE), CHUNK_SIZE);
remainder = (int32)(len - i);
if (remainder > 0)
XXH3_64bits_update(state, (uchar *)map_ptr(buf, i, remainder), remainder);
SIVAL64(sum, 0, XXH3_64bits_digest(state));
break;
}
case CSUM_XXH3_128: {
XXH128_hash_t digest;
static XXH3_state_t* state = NULL;
if (!state && !(state = XXH3_createState()))
out_of_memory("file_checksum");
XXH3_128bits_reset(state);
for (i = 0; i + CHUNK_SIZE <= len; i += CHUNK_SIZE)
XXH3_128bits_update(state, (uchar *)map_ptr(buf, i, CHUNK_SIZE), CHUNK_SIZE);
remainder = (int32)(len - i);
if (remainder > 0)
XXH3_128bits_update(state, (uchar *)map_ptr(buf, i, remainder), remainder);
digest = XXH3_128bits_digest(state);
SIVAL64(sum, 0, digest.low64);
SIVAL64(sum, 8, digest.high64);
break;
}
#endif
case CSUM_MD5: {
md_context m5;
md5_begin(&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_result(&m5, (uchar *)sum);
break;
}
case CSUM_MD4:
case CSUM_MD4_OLD:
case CSUM_MD4_BUSTED:
case CSUM_MD4_ARCHAIC: {
md_context m;
md5_update(&m, (uchar *)map_ptr(buf, i, remainder), remainder);
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 + CSUM_CHUNK <= len; i += CSUM_CHUNK) {
mdfour_update(&m, (uchar *)map_ptr(buf, i, CSUM_CHUNK),
CSUM_CHUNK);
}
/* 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 || file_sum_nni->num > CSUM_MD4_BUSTED)
if (remainder > 0 || protocol_version >= 27)
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",
file_sum_nni->name, file_sum_nni->num);
exit_cleanup(RERR_UNSUPPORTED);
}
close(fd);
@@ -538,266 +151,73 @@ void file_checksum(const char *fname, const STRUCT_STAT *st_p, char *sum)
}
static int32 sumresidue;
static md_context ctx_md;
#ifdef SUPPORT_XXHASH
static XXH64_state_t* xxh64_state;
#endif
#ifdef SUPPORT_XXH3
static XXH3_state_t* xxh3_state;
#endif
static struct name_num_item *cur_sum_nni;
int cur_sum_len;
static md_context md;
#ifdef USE_OPENSSL
static const EVP_MD *cur_sum_evp_md;
#endif
/* Initialize a hash digest accumulator. Data is supplied via
* sum_update() and the resulting binary digest is retrieved via
* sum_end(). This only supports one active sum at a time. */
int sum_init(struct name_num_item *nni, int seed)
void sum_init(int seed)
{
char s[4];
if (!nni)
nni = parse_csum_name(NULL, 0);
cur_sum_nni = nni;
cur_sum_len = csum_len_for_type(nni->num, 0);
#ifdef USE_OPENSSL
cur_sum_evp_md = csum_evp_md(nni);
#endif
#ifdef USE_OPENSSL
if (cur_sum_evp_md) {
if (!ctx_evp && !(ctx_evp = EVP_MD_CTX_create()))
out_of_memory("file_checksum");
EVP_DigestInit_ex(ctx_evp, cur_sum_evp_md, NULL);
} else
#endif
switch (cur_sum_nni->num) {
#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
#ifdef SUPPORT_XXH3
case CSUM_XXH3_64:
if (!xxh3_state && !(xxh3_state = XXH3_createState()))
out_of_memory("sum_init");
XXH3_64bits_reset(xxh3_state);
break;
case CSUM_XXH3_128:
if (!xxh3_state && !(xxh3_state = XXH3_createState()))
out_of_memory("sum_init");
XXH3_128bits_reset(xxh3_state);
break;
#endif
case CSUM_MD5:
md5_begin(&ctx_md);
break;
case CSUM_MD4:
mdfour_begin(&ctx_md);
sumresidue = 0;
break;
case CSUM_MD4_OLD:
case CSUM_MD4_BUSTED:
case CSUM_MD4_ARCHAIC:
mdfour_begin(&ctx_md);
if (protocol_version >= 30)
md5_begin(&md);
else {
mdfour_begin(&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);
}
return cur_sum_len;
}
/* Feed data into a hash digest accumulator. */
/**
* Feed data into an MD4 accumulator, md. The results may be
* retrieved using sum_end(). md is used for different purposes at
* different points during execution.
*
* @todo Perhaps get rid of md and just pass in the address each time.
* Very slightly clearer and slower.
**/
void sum_update(const char *p, int32 len)
{
#ifdef USE_OPENSSL
if (cur_sum_evp_md) {
EVP_DigestUpdate(ctx_evp, (uchar *)p, len);
} else
#endif
switch (cur_sum_nni->num) {
#ifdef SUPPORT_XXHASH
case CSUM_XXH64:
XXH64_update(xxh64_state, p, len);
break;
#endif
#ifdef SUPPORT_XXH3
case CSUM_XXH3_64:
XXH3_64bits_update(xxh3_state, p, len);
break;
case CSUM_XXH3_128:
XXH3_128bits_update(xxh3_state, p, len);
break;
#endif
case CSUM_MD5:
md5_update(&ctx_md, (uchar *)p, len);
break;
case CSUM_MD4:
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 (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;
}
while (len >= CSUM_CHUNK) {
mdfour_update(&ctx_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);
}
}
/* The sum buffer only needs to be as long as the current checksum's digest
* len, not MAX_DIGEST_LEN. Note that for CSUM_MD4_ARCHAIC that is the full
* MD4_DIGEST_LEN even if the file-list code is going to ignore all but the
* first 2 bytes of it. */
void sum_end(char *sum)
{
#ifdef USE_OPENSSL
if (cur_sum_evp_md) {
EVP_DigestFinal_ex(ctx_evp, (uchar *)sum, NULL);
} else
#endif
switch (cur_sum_nni->num) {
#ifdef SUPPORT_XXHASH
case CSUM_XXH64:
SIVAL64(sum, 0, XXH64_digest(xxh64_state));
break;
#endif
#ifdef SUPPORT_XXH3
case CSUM_XXH3_64:
SIVAL64(sum, 0, XXH3_64bits_digest(xxh3_state));
break;
case CSUM_XXH3_128: {
XXH128_hash_t digest = XXH3_128bits_digest(xxh3_state);
SIVAL64(sum, 0, digest.low64);
SIVAL64(sum, 8, digest.high64);
break;
}
#endif
case CSUM_MD5:
md5_result(&ctx_md, (uchar *)sum);
break;
case CSUM_MD4:
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 defined SUPPORT_XXH3 || defined USE_OPENSSL
static void verify_digest(struct name_num_item *nni, BOOL check_auth_list)
{
#ifdef SUPPORT_XXH3
static int xxh3_result = 0;
#endif
#ifdef USE_OPENSSL
static int prior_num = 0, prior_flags = 0, prior_result = 0;
#endif
#ifdef SUPPORT_XXH3
if (nni->num == CSUM_XXH3_64 || nni->num == CSUM_XXH3_128) {
if (!xxh3_result) {
char buf[32816];
int j;
for (j = 0; j < (int)sizeof buf; j++)
buf[j] = ' ' + (j % 96);
sum_init(nni, 0);
sum_update(buf, 32816);
sum_update(buf, 31152);
sum_update(buf, 32474);
sum_update(buf, 9322);
xxh3_result = XXH3_64bits_digest(xxh3_state) != 0xadbcf16d4678d1de ? -1 : 1;
}
if (xxh3_result < 0)
nni->num = CSUM_gone;
if (protocol_version >= 30) {
md5_update(&md, (uchar *)p, len);
return;
}
#endif
#ifdef USE_OPENSSL
if (BITS_SETnUNSET(nni->flags, NNI_EVP, NNI_BUILTIN|NNI_EVP_OK)) {
if (nni->num == prior_num && nni->flags == prior_flags) {
nni->flags = prior_result;
if (!(nni->flags & NNI_EVP))
nni->num = CSUM_gone;
} else {
prior_num = nni->num;
prior_flags = nni->flags;
if (!csum_evp_md(nni))
nni->num = CSUM_gone;
prior_result = nni->flags;
if (check_auth_list && (nni = get_nni_by_num(&valid_auth_checksums, prior_num)) != NULL)
verify_digest(nni, False);
}
}
#endif
}
#endif
void init_checksum_choices()
{
#if defined SUPPORT_XXH3 || defined USE_OPENSSL
struct name_num_item *nni;
#endif
if (initialized_choices)
if (len + sumresidue < CSUM_CHUNK) {
memcpy(md.buffer + sumresidue, p, len);
sumresidue += len;
return;
}
#if defined USE_OPENSSL && OPENSSL_VERSION_NUMBER < 0x10100000L
OpenSSL_add_all_algorithms();
#endif
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;
}
#if defined SUPPORT_XXH3 || defined USE_OPENSSL
for (nni = valid_checksums.list; nni->name; nni++)
verify_digest(nni, True);
while (len >= CSUM_CHUNK) {
mdfour_update(&md, (uchar *)p, CSUM_CHUNK);
len -= CSUM_CHUNK;
p += CSUM_CHUNK;
}
for (nni = valid_auth_checksums.list; nni->name; nni++)
verify_digest(nni, False);
#endif
initialized_choices = 1;
sumresidue = len;
if (sumresidue)
memcpy(md.buffer, p, sumresidue);
}
int sum_end(char *sum)
{
if (protocol_version >= 30) {
md5_result(&md, (uchar *)sum);
return MD5_DIGEST_LEN;
}
if (sumresidue || protocol_version >= 27)
mdfour_update(&md, (uchar *)md.buffer, sumresidue);
mdfour_result(&md, (uchar *)sum);
return MD4_DIGEST_LEN;
}

34
chmod.c
View File

@@ -2,7 +2,7 @@
* Implement the core of the --chmod option.
*
* Copyright (C) 2002 Scott Howard
* Copyright (C) 2005-2020 Wayne Davison
* Copyright (C) 2005-2009 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 @@
*/
#include "rsync.h"
#include "itypes.h"
extern mode_t orig_umask;
@@ -36,15 +35,13 @@ struct chmod_mode_struct {
#define CHMOD_ADD 1
#define CHMOD_SUB 2
#define CHMOD_EQ 3
#define CHMOD_SET 4
#define STATE_ERROR 0
#define STATE_1ST_HALF 1
#define STATE_2ND_HALF 2
#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 success
* pairs in a linked list. We return a pointer to new items on succcess
* (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)
@@ -90,10 +87,6 @@ struct chmod_mode_struct *parse_chmod(const char *modestr,
curr_mode->ModeAND = CHMOD_BITS - (where * 7) - (topoct ? topbits : 0);
curr_mode->ModeOR = bits + topoct;
break;
case CHMOD_SET:
curr_mode->ModeAND = 0;
curr_mode->ModeOR = bits;
break;
}
curr_mode->flags = flags;
@@ -106,8 +99,7 @@ struct chmod_mode_struct *parse_chmod(const char *modestr,
where = what = op = topoct = topbits = flags = 0;
}
switch (state) {
case STATE_1ST_HALF:
if (state != STATE_2ND_HALF) {
switch (*modestr) {
case 'D':
if (flags & FLAG_FILES_ONLY)
@@ -146,17 +138,10 @@ struct chmod_mode_struct *parse_chmod(const char *modestr,
state = STATE_2ND_HALF;
break;
default:
if (isDigit(modestr) && *modestr < '8' && !where) {
op = CHMOD_SET;
state = STATE_OCTAL_NUM;
where = 1;
what = *modestr - '0';
} else
state = STATE_ERROR;
state = STATE_ERROR;
break;
}
break;
case STATE_2ND_HALF:
} else {
switch (*modestr) {
case 'r':
what |= 4;
@@ -183,15 +168,6 @@ struct chmod_mode_struct *parse_chmod(const char *modestr,
state = STATE_ERROR;
break;
}
break;
case STATE_OCTAL_NUM:
if (isDigit(modestr) && *modestr < '8') {
what = what*8 + *modestr - '0';
if (what > CHMOD_BITS)
state = STATE_ERROR;
} else
state = STATE_ERROR;
break;
}
modestr++;
}

144
cleanup.c
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-2020 Wayne Davison
* Copyright (C) 2003-2009 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,23 +22,15 @@
#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;
extern int protocol_version;
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;
#ifdef HAVE_SIGACTION
static struct sigaction sigact;
#endif
@@ -90,7 +82,7 @@ int cleanup_got_literal = 0;
static const char *cleanup_fname;
static const char *cleanup_new_fname;
static struct file_struct *cleanup_file;
static int cleanup_fd_r = -1, cleanup_fd_w = -1;
static int cleanup_fd_r, cleanup_fd_w;
static pid_t cleanup_pid = 0;
pid_t cleanup_child_pid = -1;
@@ -105,15 +97,15 @@ NORETURN void _exit_cleanup(int code, const char *file, int line)
static int switch_step = 0;
static int exit_code = 0, exit_line = 0;
static const char *exit_file = NULL;
static int first_code = 0;
static int unmodified_code = 0;
SIGACTION(SIGUSR1, SIG_IGN);
SIGACTION(SIGUSR2, SIG_IGN);
if (!exit_code) { /* Preserve first error exit info when recursing. */
exit_code = code;
exit_file = file;
exit_line = line < 0 ? -line : line;
if (exit_code) { /* Preserve first exit info when recursing. */
code = exit_code;
file = exit_file;
line = exit_line;
}
/* If this is the exit at the end of the run, the server side
@@ -127,19 +119,17 @@ NORETURN void _exit_cleanup(int code, const char *file, int line)
#include "case_N.h" /* case 0: */
switch_step++;
first_code = code;
exit_code = unmodified_code = code;
exit_file = file;
exit_line = line;
if (output_needs_newline) {
fputc('\n', stdout);
output_needs_newline = 0;
}
if (DEBUG_GTE(EXIT, 2)) {
if (verbose > 3) {
rprintf(FINFO,
"[%s] _exit_cleanup(code=%d, file=%s, line=%d): entered\n",
who_am_i(), code, src_file(file), line);
who_am_i(), code, file, line);
}
/* FALLTHROUGH */
#include "case_N.h"
switch_step++;
@@ -148,58 +138,43 @@ NORETURN void _exit_cleanup(int code, const char *file, int line)
int pid = wait_process(cleanup_child_pid, &status, WNOHANG);
if (pid == cleanup_child_pid) {
status = WEXITSTATUS(status);
if (status > exit_code)
exit_code = status;
if (status > code)
code = exit_code = status;
}
}
/* FALLTHROUGH */
#include "case_N.h"
switch_step++;
if (cleanup_got_literal && (cleanup_fname || cleanup_fd_w != -1)) {
if (cleanup_fd_r != -1) {
if (cleanup_got_literal && cleanup_fname && cleanup_new_fname
&& keep_partial && handle_partial_dir(cleanup_new_fname, PDIR_CREATE)) {
const char *fname = cleanup_fname;
cleanup_fname = NULL;
if (cleanup_fd_r != -1)
close(cleanup_fd_r);
cleanup_fd_r = -1;
}
if (cleanup_fd_w != -1) {
flush_write_file(cleanup_fd_w);
close(cleanup_fd_w);
cleanup_fd_w = -1;
}
if (cleanup_fname && cleanup_new_fname && keep_partial
&& handle_partial_dir(cleanup_new_fname, PDIR_CREATE)) {
int tweak_modtime = 0;
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;
}
finish_transfer(cleanup_new_fname, fname, NULL, NULL,
cleanup_file, tweak_modtime, !partial_dir);
}
finish_transfer(cleanup_new_fname, fname, NULL, NULL,
cleanup_file, 0, !partial_dir);
}
/* FALLTHROUGH */
#include "case_N.h"
switch_step++;
if (flush_ok_after_signal) {
flush_ok_after_signal = False;
if (code == RERR_SIGNAL)
io_flush(FULL_FLUSH);
}
if (!exit_code && !code)
if (!code || am_server || am_receiver)
io_flush(FULL_FLUSH);
/* FALLTHROUGH */
#include "case_N.h"
switch_step++;
if (cleanup_fname)
do_unlink_at(cleanup_fname);
if (exit_code)
do_unlink(cleanup_fname);
if (code)
kill_all(SIGUSR1);
if (cleanup_pid && cleanup_pid == getpid()) {
char *pidf = lp_pid_file();
@@ -207,60 +182,34 @@ NORETURN void _exit_cleanup(int code, const char *file, int line)
unlink(lp_pid_file());
}
if (exit_code == 0) {
if (code)
exit_code = code;
if (code == 0) {
if (io_error & IOERR_DEL_LIMIT)
exit_code = RERR_DEL_LIMIT;
code = exit_code = RERR_DEL_LIMIT;
if (io_error & IOERR_VANISHED)
exit_code = RERR_VANISHED;
code = exit_code = RERR_VANISHED;
if (io_error & IOERR_GENERAL || got_xfer_error)
exit_code = RERR_PARTIAL;
code = exit_code = RERR_PARTIAL;
}
/* If line < 0, this exit is after a MSG_ERROR_EXIT event, so
* we don't want to output a duplicate error. */
if ((exit_code && line > 0)
|| am_daemon || (logfile_name && (am_server || !INFO_GTE(STATS, 1)))) {
log_exit(exit_code, exit_file, exit_line);
}
if (code || am_daemon || (logfile_name && (am_server || !verbose)))
log_exit(code, file, line);
/* FALLTHROUGH */
#include "case_N.h"
switch_step++;
if (DEBUG_GTE(EXIT, 1)) {
if (verbose > 2) {
rprintf(FINFO,
"[%s] _exit_cleanup(code=%d, file=%s, line=%d): "
"about to call exit(%d)%s\n",
who_am_i(), first_code, exit_file, exit_line, exit_code,
dry_run ? " (DRY RUN)" : "");
"about to call exit(%d)\n",
who_am_i(), unmodified_code, file, line, code);
}
/* 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) {
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);
}
if (!am_sender)
io_flush(MSG_FLUSH); /* Be sure to send all messages */
noop_io_until_death();
}
else if (!am_sender)
io_flush(MSG_FLUSH); /* Be sure to send all messages */
}
#include "case_N.h"
switch_step++;
if (am_server && exit_code)
if (am_server && code)
msleep(100);
close_all();
@@ -269,23 +218,12 @@ NORETURN void _exit_cleanup(int code, const char *file, int line)
break;
}
if (called_from_signal_handler) {
#ifdef GCOV_COVERAGE
/* _exit() bypasses the gcov atexit flush; rsync's generator (and
* other processes) normally finish via the signal handler, so
* without this they would write no .gcda. Harmless otherwise. */
extern void __gcov_dump(void);
__gcov_dump();
#endif
_exit(exit_code);
}
exit(exit_code);
exit(code);
}
void cleanup_disable(void)
{
cleanup_fname = cleanup_new_fname = NULL;
cleanup_fd_r = cleanup_fd_w = -1;
cleanup_got_literal = 0;
}

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-2022 Wayne Davison
* Copyright (C) 2002-2009 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,60 +27,50 @@
*/
#include "rsync.h"
#include "itypes.h"
extern int am_daemon;
static const char default_name[] = "UNKNOWN";
static const char proxyv2sig[] = "\r\n\r\n\0\r\nQUIT\n";
extern int am_server;
static char ipaddr_buf[100];
#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, int allow_scope);
/* Return the IP addr of the client as a string. */
/**
* 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;
char *ssh_info, *p;
if (*ipaddr_buf)
return ipaddr_buf;
if (initialised)
return addr_buf;
if (am_daemon < 0) { /* daemon over --rsh mode */
char *env_str;
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(ipaddr_buf, env_str, sizeof ipaddr_buf);
initialised = 1;
if (am_server) { /* daemon over --rsh mode */
strlcpy(addr_buf, "0.0.0.0", sizeof addr_buf);
if ((ssh_info = getenv("SSH_CONNECTION")) != NULL
|| (ssh_info = getenv("SSH_CLIENT")) != NULL
|| (ssh_info = getenv("SSH2_CLIENT")) != NULL) {
strlcpy(addr_buf, ssh_info, sizeof addr_buf);
/* Truncate the value to just the IP address. */
if ((p = strchr(ipaddr_buf, ' ')) != NULL)
if ((p = strchr(addr_buf, ' ')) != NULL)
*p = '\0';
}
if (valid_ipaddr(ipaddr_buf, True))
return ipaddr_buf;
} else {
client_sockaddr(fd, &ss, &length);
getnameinfo((struct sockaddr *)&ss, length,
addr_buf, sizeof addr_buf, NULL, 0, NI_NUMERICHOST);
}
client_sockaddr(fd, &ss, &length);
getnameinfo((struct sockaddr *)&ss, length, ipaddr_buf, sizeof ipaddr_buf, NULL, 0, NI_NUMERICHOST);
return addr_buf;
}
return ipaddr_buf;
static int get_sockaddr_family(const struct sockaddr_storage *ss)
{
return ((struct sockaddr *) ss)->sa_family;
}
@@ -97,218 +87,71 @@ char *client_addr(int fd)
* After translation from sockaddr to name we do a forward lookup to
* make sure nobody is spoofing PTR records.
**/
char *client_name(const char *ipaddr)
char *client_name(int fd)
{
static char name_buf[100];
char port_buf[100];
static char port_buf[100];
static int initialised;
struct sockaddr_storage ss;
socklen_t ss_len;
struct addrinfo hint, *answer;
int err;
if (*name_buf)
if (initialised)
return name_buf;
strlcpy(name_buf, default_name, sizeof name_buf);
if (strcmp(ipaddr, "0.0.0.0") == 0)
return name_buf;
initialised = 1;
memset(&ss, 0, sizeof ss);
memset(&hint, 0, sizeof hint);
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);
#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(ipaddr, NULL, &hint, &answer)) != 0) {
rprintf(FLOG, "malformed address %s: %s\n", ipaddr, gai_strerror(err));
return name_buf;
}
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;
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;
case AF_INET6:
ss_len = sizeof (struct sockaddr_in6);
memcpy(&ss, answer->ai_addr, ss_len);
break;
#endif
default:
NOISY_DEATH("Unknown ai_family value");
default:
exit_cleanup(RERR_SOCKETIO);
}
freeaddrinfo(answer);
} else {
ss_len = sizeof ss;
client_sockaddr(fd, &ss, &ss_len);
}
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);
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);
return name_buf;
}
/* Try to read a 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;
unsigned 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, False);
#ifdef INET6
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, False);
#endif
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, False))
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, False))
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.
@@ -316,7 +159,9 @@ int read_proxy_protocol_header(int fd)
* If it comes in as an ipv4 address mapped into IPv6 format then we
* convert it back to a regular IPv4.
**/
static void client_sockaddr(int fd, struct sockaddr_storage *ss, socklen_t *ss_len)
void client_sockaddr(int fd,
struct sockaddr_storage *ss,
socklen_t *ss_len)
{
memset(ss, 0, sizeof *ss);
@@ -327,8 +172,8 @@ static void client_sockaddr(int fd, struct sockaddr_storage *ss, socklen_t *ss_l
}
#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
@@ -351,20 +196,51 @@ static void client_sockaddr(int fd, struct sockaddr_storage *ss, socklen_t *ss_l
/* 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.
**/
static int compare_addrinfo_sockaddr(const struct addrinfo *ai, const struct sockaddr_storage *ss)
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) {
@@ -380,7 +256,8 @@ static int compare_addrinfo_sockaddr(const struct addrinfo *ai, const struct soc
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
@@ -390,13 +267,14 @@ static int compare_addrinfo_sockaddr(const struct addrinfo *ai, const struct soc
sin1 = (const struct sockaddr_in6 *) ss;
sin2 = (const struct sockaddr_in6 *) ai->ai_addr;
if (ai->ai_addrlen < (int)sizeof (struct sockaddr_in6)) {
if (ai->ai_addrlen < sizeof (struct sockaddr_in6)) {
rprintf(FLOG, "%s: too short sockaddr_in6; length=%d\n",
fn, (int)ai->ai_addrlen);
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
@@ -422,11 +300,13 @@ static int compare_addrinfo_sockaddr(const struct addrinfo *ai, const struct soc
* 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.
**/
static int check_name(const char *ipaddr, const struct sockaddr_storage *ss, char *name_buf, size_t name_buf_size)
int check_name(int fd,
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;
@@ -457,82 +337,10 @@ static int check_name(const char *ipaddr, const struct sockaddr_storage *ss, cha
/* 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", ipaddr, name_buf);
"spoofed address?\n", client_addr(fd), 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 allow_scope)
{
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;
if (allow_scope && *s == '%') {
if (saw_double_colon)
break;
return 0;
}
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) {
if (allow_scope && *s == '%')
for (s++; isAlNum(s); s++) { }
return !*s && s[-1] != '%';
}
}
/* 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

File diff suppressed because it is too large Load Diff

View File

@@ -1,11 +0,0 @@
#!/bin/sh
srcdir=`dirname $0`
opt="$1"
shift
echo "$*"
if ! "${@}"; then
echo "If you can't fix the issue, re-run $srcdir/configure with --$opt."
exit 1
fi

679
compat.c
View File

@@ -3,7 +3,7 @@
*
* Copyright (C) Andrew Tridgell 1996
* Copyright (C) Paul Mackerras 1996
* Copyright (C) 2004-2022 Wayne Davison
* Copyright (C) 2004-2009 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
@@ -20,9 +20,14 @@
*/
#include "rsync.h"
#include "itypes.h"
#include "ifuncs.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 verbose;
extern int am_server;
extern int am_sender;
extern int local_server;
@@ -30,11 +35,9 @@ extern int inplace;
extern int recurse;
extern int use_qsort;
extern int allow_inc_recurse;
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;
@@ -43,51 +46,24 @@ extern int protocol_version;
extern int protect_args;
extern int preserve_uid;
extern int preserve_gid;
extern int preserve_atimes;
extern int preserve_crtimes;
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 int do_compression_threads;
extern int saw_stderr_opt;
extern int msgs2stderr;
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 char *daemon_auth_choices;
extern filter_rule_list filter_list;
extern struct filter_list_struct 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, valid_auth_checksums;
extern struct name_num_item *xfer_sum_nni;
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;
int xmit_id0_names = 0;
struct name_num_item *xattr_sum_nni;
int xattr_sum_len = 0;
/* These index values are for the file-list's extra-attribute array. */
int pathname_ndx, depth_ndx, atimes_ndx, crtimes_ndx, uid_ndx, gid_ndx, acls_ndx, xattrs_ndx, unsort_ndx;
int 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 */
@@ -96,34 +72,10 @@ int sender_symlink_iconv = 0; /* sender should convert symlink content */
int filesfrom_convert = 0;
#endif
#define MAX_NSTR_STRLEN 256
struct name_num_item valid_compressions_items[] = {
#ifdef SUPPORT_ZSTD
{ CPRES_ZSTD, 0, "zstd", NULL },
#endif
#ifdef SUPPORT_LZ4
{ CPRES_LZ4, 0, "lz4", NULL },
#endif
{ CPRES_ZLIBX, 0, "zlibx", NULL },
{ CPRES_ZLIB, 0, "zlib", NULL },
{ CPRES_NONE, 0, "none", NULL },
{ 0, 0, NULL, NULL }
};
struct name_num_obj valid_compressions = {
"compress", NULL, 0, 0, valid_compressions_items
};
#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)
#define CF_ID0_NAMES (1<<8)
static const char *client_info;
@@ -132,9 +84,13 @@ static const char *client_info;
* of that protocol for it to be advertised as available. */
static void check_sub_protocol(void)
{
const char *dot;
char *dot;
int their_protocol, their_sub;
int our_sub = get_subprotocol_version();
#if SUBPROTOCOL_VERSION != 0
int our_sub = protocol_version < PROTOCOL_VERSION ? 0 : SUBPROTOCOL_VERSION;
#else
int our_sub = 0;
#endif
/* client_info starts with VER.SUB string if client is a pre-release. */
if (!(their_protocol = atoi(client_info))
@@ -161,13 +117,7 @@ static void check_sub_protocol(void)
void set_allow_inc_recurse(void)
{
if (!local_server)
client_info = shell_cmd ? shell_cmd : "";
else if (am_server) {
char buf[64];
maybe_add_e_option(buf, sizeof buf);
client_info = *buf ? strdup(buf+1) : ""; /* The +1 skips the leading "e". */
}
client_info = shell_cmd ? shell_cmd : "";
if (!recurse || use_qsort)
allow_inc_recurse = 0;
@@ -175,416 +125,17 @@ void set_allow_inc_recurse(void)
&& (delete_before || delete_after
|| delay_updates || prune_empty_dirs))
allow_inc_recurse = 0;
else if (am_server && strchr(client_info, 'i') == NULL)
else if (am_server && !local_server
&& (strchr(client_info, 'i') == NULL))
allow_inc_recurse = 0;
}
void parse_compress_choice(int final_call)
{
if (valid_compressions.negotiated_nni)
do_compression = valid_compressions.negotiated_nni->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;
if (am_server)
validate_choice_vs_env(NSTR_COMPRESS, do_compression, -1);
} 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_nni)
compress_choice = valid_compressions.negotiated_nni->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_nni ? " 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 (nni->num == CSUM_gone)
continue;
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) {
nno->saw = new_array0(uchar, nno->saw_len);
/* We'll take this opportunity to set the main_nni values for duplicates. */
for (cnt = 1, nni = nno->list; nni->name; nni++, cnt++) {
if (nni->num == CSUM_gone)
continue;
if (nno->saw[nni->num])
nni->main_nni = &nno->list[nno->saw[nni->num]-1];
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 saw_tok = 0, cnt = 0;
while (1) {
int at_space = isSpace(from);
char ch = *from++;
if (ch == '&')
ch = '\0';
if (!ch || at_space) {
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_nni) {
to = tok + strlcpy(tok, nni->main_nni->name, tobuf_len - (tok - tobuf));
if (to - tobuf >= tobuf_len) {
to = tok - 1;
break;
}
}
} else
to = tok - (tok != tobuf);
saw_tok = 1;
tok = NULL;
}
if (!ch)
break;
continue;
}
if (!tok) {
if (to != tobuf)
*to++ = ' ';
tok = to;
}
if (to - tobuf >= tobuf_len - 1) {
to = tok - (tok != tobuf);
break;
}
*to++ = ch;
}
*to = '\0';
if (saw_tok && to == tobuf)
return strlcpy(tobuf, "INVALID", MAX_NSTR_STRLEN);
return to - tobuf;
}
static int parse_negotiate_str(struct name_num_obj *nno, char *tmpbuf)
{
struct name_num_item *nni, *ret = NULL;
int best = nno->saw_len; /* We want best == 1 from the client list, so start with a big number. */
char *space, *tok = tmpbuf;
while (tok) {
while (*tok == ' ') tok++; /* Should be unneeded... */
if (!*tok)
break;
if ((space = strchr(tok, ' ')) != NULL)
*space = '\0';
nni = get_nni_by_name(nno, tok, -1);
if (space) {
*space = ' ';
tok = space + 1;
} else
tok = NULL;
if (!nni || !nno->saw[nni->num] || best <= nno->saw[nni->num])
continue;
ret = nni;
best = nno->saw[nni->num];
if (best == 1 || am_server) /* The server side stops at the first acceptable client choice */
break;
}
if (ret) {
free(nno->saw);
nno->saw = NULL;
nno->negotiated_nni = ret->main_nni ? ret->main_nni : ret;
return 1;
}
return 0;
}
/* This routine is always called with a tmpbuf of MAX_NSTR_STRLEN length, but the
* buffer may be pre-populated with a "len" length string to use OR a len of -1
* to tell us to read a string from the fd. */
static void recv_negotiate_str(int f_in, struct name_num_obj *nno, char *tmpbuf, int len)
{
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 && parse_negotiate_str(nno, tmpbuf))
return;
if (!am_server || !do_negotiated_strings) {
char *cp = tmpbuf;
int j;
rprintf(FERROR, "Failed to negotiate a %s choice.\n", nno->type);
rprintf(FERROR, "%s list: %s\n", am_server ? "Client" : "Server", tmpbuf);
/* Recreate our original list from the saw values. This can't overflow our huge
* buffer because we don't have enough valid entries to get anywhere close. */
for (j = 1, *cp = '\0'; j <= nno->saw_len; j++) {
struct name_num_item *nni;
for (nni = nno->list; nni->name; nni++) {
if (nno->saw[nni->num] == j) {
*cp++ = ' ';
cp += strlcpy(cp, nni->name, MAX_NSTR_STRLEN - (cp - tmpbuf));
break;
}
}
}
if (!*tmpbuf)
strlcpy(cp, " INVALID", MAX_NSTR_STRLEN);
rprintf(FERROR, "%s list:%s\n", am_server ? "Server" : "Client", tmpbuf);
}
exit_cleanup(RERR_UNSUPPORTED);
}
static const char *getenv_nstr(int ntype)
{
const char *env_str = getenv(ntype == NSTR_COMPRESS ? "RSYNC_COMPRESS_LIST" : "RSYNC_CHECKSUM_LIST");
/* When writing a batch file, we always negotiate an old-style choice. */
if (write_batch)
env_str = ntype == NSTR_COMPRESS ? "zlib" : protocol_version >= 30 ? "md5" : "md4";
if (am_server && env_str) {
const char *cp = strchr(env_str, '&');
if (cp)
env_str = cp + 1;
}
return env_str;
}
void validate_choice_vs_env(int ntype, int num1, int num2)
{
struct name_num_obj *nno = ntype == NSTR_COMPRESS ? &valid_compressions : &valid_checksums;
const char *list_str = getenv_nstr(ntype);
char tmpbuf[MAX_NSTR_STRLEN];
if (!list_str)
return;
while (isSpace(list_str)) list_str++;
if (!*list_str)
return;
init_nno_saw(nno, 0);
parse_nni_str(nno, list_str, tmpbuf, MAX_NSTR_STRLEN);
if (ntype == NSTR_CHECKSUM) /* If "md4" is in the env list, all the old MD4 choices are OK too. */
nno->saw[CSUM_MD4_ARCHAIC] = nno->saw[CSUM_MD4_BUSTED] = nno->saw[CSUM_MD4_OLD] = nno->saw[CSUM_MD4];
if (!nno->saw[num1] || (num2 >= 0 && !nno->saw[num2])) {
rprintf(FERROR, "Your --%s-choice value (%s) was refused by the server.\n",
ntype == NSTR_COMPRESS ? "compress" : "checksum",
ntype == NSTR_COMPRESS ? compress_choice : checksum_choice);
exit_cleanup(RERR_UNSUPPORTED);
}
free(nno->saw);
nno->saw = NULL;
}
/* 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.
* "none" is removed on the client side unless dup_markup != '\0'. */
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->num == CSUM_gone)
continue;
if (nni->main_nni) {
if (!dup_markup || nni->main_nni->num == CSUM_gone)
continue;
delim = dup_markup;
}
if (nni->num == 0 && !am_server && !dup_markup)
continue;
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, int ntype)
{
char tmpbuf[MAX_NSTR_STRLEN];
const char *list_str = getenv_nstr(ntype);
int len;
if (list_str && *list_str) {
init_nno_saw(nno, 0);
len = parse_nni_str(nno, list_str, tmpbuf, 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);
}
/* 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. */
if (do_negotiated_strings)
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. */
init_checksum_choices();
if (!checksum_choice)
send_negotiate_str(f_out, &valid_checksums, NSTR_CHECKSUM);
if (do_compression && !compress_choice)
send_negotiate_str(f_out, &valid_compressions, NSTR_COMPRESS);
if (valid_checksums.saw) {
char tmpbuf[MAX_NSTR_STRLEN];
int len;
if (do_negotiated_strings)
len = -1;
else
len = strlcpy(tmpbuf, protocol_version >= 30 ? "md5" : "md4", MAX_NSTR_STRLEN);
recv_negotiate_str(f_in, &valid_checksums, tmpbuf, len);
}
if (valid_compressions.saw) {
char tmpbuf[MAX_NSTR_STRLEN];
int len;
if (do_negotiated_strings)
len = -1;
else
len = strlcpy(tmpbuf, "zlib", MAX_NSTR_STRLEN);
recv_negotiate_str(f_in, &valid_compressions, tmpbuf, len);
}
/* If the other side is too old to negotiate, the above steps just made sure that
* the env didn't disallow the old algorithm. Mark things as non-negotiated. */
if (!do_negotiated_strings)
valid_checksums.negotiated_nni = valid_compressions.negotiated_nni = NULL;
}
void setup_protocol(int f_out,int f_in)
{
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 (preserve_crtimes)
crtimes_ndx = (file_extra_cnt += EXTRA64_CNT);
if (am_sender) /* This is most likely in the file_extras64 union as well. */
pathname_ndx = (file_extra_cnt += PTR_EXTRA_CNT);
if (am_sender)
file_extra_cnt += PTR_EXTRA_CNT;
else
depth_ndx = ++file_extra_cnt;
file_extra_cnt++;
if (preserve_uid)
uid_ndx = ++file_extra_cnt;
if (preserve_gid)
@@ -612,14 +163,14 @@ void setup_protocol(int f_out,int f_in)
exit_cleanup(RERR_PROTOCOL);
}
if (DEBUG_GTE(PROTO, 1)) {
if (verbose > 3) {
rprintf(FINFO, "(%s) Protocol versions: remote=%d, negotiated=%d\n",
am_server? "Server" : "Client", remote_protocol, protocol_version);
}
if (remote_protocol < MIN_PROTOCOL_VERSION
|| remote_protocol > MAX_PROTOCOL_VERSION) {
rprintf(FERROR,"protocol version mismatch -- is your shell clean?\n");
rprintf(FERROR,"(see the rsync manpage for an explanation)\n");
rprintf(FERROR,"(see the rsync man page for an explanation)\n");
exit_cleanup(RERR_PROTOCOL);
}
if (remote_protocol < OLD_PROTOCOL_VERSION) {
@@ -639,32 +190,21 @@ void setup_protocol(int f_out,int f_in)
if (read_batch)
check_batch_flags();
if (!saw_stderr_opt && protocol_version <= 28 && am_server)
msgs2stderr = 0; /* The client side may not have stderr setup for us. */
#ifndef SUPPORT_PREALLOCATION
if (preallocate_files && !am_sender) {
rprintf(FERROR, "preallocation is not supported on this %s\n",
am_server ? "Server" : "Client");
exit_cleanup(RERR_SYNTAX);
}
#endif
if (protocol_version < 30) {
if (append_mode == 1)
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);
}
}
@@ -679,33 +219,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",
alt_dest_opt(0), protocol_version);
"%s with --inplace requires protocol 29 or higher"
" (negotiated %d).\n",
dest_option, 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",
alt_dest_opt(0), protocol_version);
"Using more than one %s option requires protocol"
" 29 or higher (negotiated %d).\n",
dest_option, 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) {
@@ -717,41 +257,13 @@ void setup_protocol(int f_out,int f_in)
#ifdef ICONV_OPTION
compat_flags |= CF_SYMLINK_ICONV;
#endif
if (strchr(client_info, 'f') != NULL)
if (local_server || strchr(client_info, 'f') != NULL)
compat_flags |= CF_SAFE_FLIST;
if (strchr(client_info, 'x') != NULL)
compat_flags |= CF_AVOID_XATTR_OPTIM;
if (strchr(client_info, 'C') != NULL)
compat_flags |= CF_CHKSUM_SEED_FIX;
if (strchr(client_info, 'I') != NULL)
compat_flags |= CF_INPLACE_PARTIAL_DIR;
if (strchr(client_info, 'u') != NULL)
compat_flags |= CF_ID0_NAMES;
if (strchr(client_info, 'v') != NULL) {
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;
}
write_byte(f_out, compat_flags);
} else
compat_flags = read_byte(f_in);
/* 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;
xmit_id0_names = compat_flags & CF_ID0_NAMES ? 1 : 0;
if (!xfer_flags_as_varint && preserve_crtimes) {
fprintf(stderr, "Both rsync versions must be at least 3.2.0 for --crtimes.\n");
exit_cleanup(RERR_PROTOCOL);
}
if (am_sender) {
receiver_symlink_times = am_server
? strchr(client_info, 'L') != NULL
@@ -763,37 +275,32 @@ void setup_protocol(int f_out,int f_in)
#endif
#ifdef ICONV_OPTION
sender_symlink_iconv = iconv_opt && (am_server
? strchr(client_info, 's') != NULL
? local_server || strchr(client_info, 's') != NULL
: !!(compat_flags & CF_SYMLINK_ICONV));
#endif
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;
use_safe_inc_flist = !!(compat_flags & CF_SAFE_FLIST);
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;
#endif
}
if (read_batch)
do_negotiated_strings = 0;
if (need_unsorted_flist && (!am_sender || inc_recurse))
unsort_ndx = ++file_extra_cnt;
if (partial_dir && *partial_dir != '/' && (!am_server || local_server)) {
int rflags = FILTRULE_NO_PREFIXES | FILTRULE_DIRECTORY;
int flags = MATCHFLG_NO_PREFIXES | MATCHFLG_DIRECTORY;
if (!am_sender || protocol_version >= 30)
rflags |= FILTRULE_PERISHABLE;
parse_filter_str(&filter_list, partial_dir, rule_template(rflags), 0);
flags |= MATCHFLG_PERISHABLE;
parse_rule(&filter_list, partial_dir, flags, 0);
}
@@ -806,87 +313,11 @@ 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) ^ (getpid() << 6);
checksum_seed = time(NULL);
write_int(f_out, checksum_seed);
} else {
checksum_seed = read_int(f_in);
}
parse_checksum_choice(1); /* Sets file_sum_nni & xfer_sum_nni */
parse_compress_choice(1); /* Sets do_compression */
/* TODO in the future allow this algorithm to be chosen somehow, but it can't get too
* long or the size starts to cause a problem in the xattr abbrev/non-abbrev code. */
xattr_sum_nni = parse_csum_name(NULL, 0);
xattr_sum_len = csum_len_for_type(xattr_sum_nni->num, 0);
if (write_batch && !am_server)
write_batch_shell_file();
init_flist();
}
void output_daemon_greeting(int f_out, int am_client)
{
char tmpbuf[MAX_NSTR_STRLEN];
int our_sub = get_subprotocol_version();
init_checksum_choices();
get_default_nno_list(&valid_auth_checksums, tmpbuf, MAX_NSTR_STRLEN, '\0');
io_printf(f_out, "@RSYNCD: %d.%d %s\n", protocol_version, our_sub, tmpbuf);
if (am_client && DEBUG_GTE(NSTR, 2))
rprintf(FINFO, "Client %s list (on client): %s\n", valid_auth_checksums.type, tmpbuf);
}
void negotiate_daemon_auth(int f_out, int am_client)
{
char tmpbuf[MAX_NSTR_STRLEN];
int save_am_server = am_server;
int md4_is_old = 0;
if (!am_client)
am_server = 1;
if (daemon_auth_choices)
strlcpy(tmpbuf, daemon_auth_choices, MAX_NSTR_STRLEN);
else {
strlcpy(tmpbuf, protocol_version >= 30 ? "md5" : "md4", MAX_NSTR_STRLEN);
md4_is_old = 1;
}
if (am_client) {
recv_negotiate_str(-1, &valid_auth_checksums, tmpbuf, strlen(tmpbuf));
if (DEBUG_GTE(NSTR, 1)) {
rprintf(FINFO, "Client negotiated %s: %s\n", valid_auth_checksums.type,
valid_auth_checksums.negotiated_nni->name);
}
} else {
if (!parse_negotiate_str(&valid_auth_checksums, tmpbuf)) {
get_default_nno_list(&valid_auth_checksums, tmpbuf, MAX_NSTR_STRLEN, '\0');
io_printf(f_out, "@ERROR: your client does not support one of our daemon-auth checksums: %s\n",
tmpbuf);
exit_cleanup(RERR_UNSUPPORTED);
}
}
am_server = save_am_server;
if (md4_is_old && valid_auth_checksums.negotiated_nni->num == CSUM_MD4) {
valid_auth_checksums.negotiated_nni->num = CSUM_MD4_OLD;
valid_auth_checksums.negotiated_nni->flags = 0;
}
}
int get_subprotocol_version()
{
#if SUBPROTOCOL_VERSION != 0
return protocol_version < PROTOCOL_VERSION ? 0 : SUBPROTOCOL_VERSION;
#else
return 0;
#endif
}

1950
config.guess vendored Normal file → Executable file
View File

File diff suppressed because it is too large Load Diff

2825
config.sub vendored Normal file → Executable file
View File

File diff suppressed because it is too large Load Diff

26
configure vendored
View File

@@ -4,24 +4,22 @@
# then transfer control to the configure.sh script to do the real work.
dir=`dirname $0`
if test x"$dir" = x; then
dir=.
fi
realconfigure="$dir/configure.sh"
if test "$dir" = '.'; then
branch=`packaging/prep-auto-dir` || exit 1
if test x"$branch" != x; then
cd build || exit 1
dir=..
if test ! -f "$realconfigure"; then
if test -f "$HOME/build_farm/build_test.fns"; then
# Allow the build farm to grab latest files via rsync.
actions='build fetch'
else
actions='build'
fi
fi
if test ! -f configure.sh; then
if ! "$dir/prepare-source" build; then
if "$dir/prepare-source" $actions; then
:
else
echo 'Failed to build configure.sh and/or config.h.in -- giving up.' >&2
rm -f configure.sh
rm -f "$realconfigure"
exit 1
fi
fi
exec ./configure.sh --srcdir="$dir" "${@}"
exec "$realconfigure" "${@}"

View File

File diff suppressed because it is too large Load Diff

View File

@@ -2,7 +2,6 @@
* 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

@@ -7,54 +7,39 @@ basically a summary of clientserver.c and authenticate.c.
This is the protocol used for rsync --daemon; i.e. connections to port
873 rather than invocations over a remote shell.
When the server accepts a connection, it prints a newline-terminated
greeting line:
When the server accepts a connection, it prints a greeting
@RSYNCD: <version>.<subprotocol> <digest1> <digestN>
@RSYNCD: <version>.<subprotocol>
The <version> is the numeric version (see PROTOCOL_VERSION in rsync.h)
The <subprotocol> is the numeric subprotocol version (which is 0 for a
final protocol version, as the SUBPROTOCOL_VERSION define discusses).
The <digestN> names are the authentication digest algorithms that the
daemon supports, listed in order of preference.
An rsync prior to 3.2.7 omits the digest names. An rsync prior to 3.0.0
also omits the period and the <subprotocol> value. Since a final
protocol has a subprotocol value of 0, a missing subprotocol value is
assumed to be 0 for any protocol prior to 30. It is considered a fatal
error for protocol 30 and above to omit it. It is considered a fatal
error for protocol 32 and above to omit the digest name list (currently
31 is the newest protocol).
The daemon expects to see a similar greeting line back from the client.
Once received, the daemon follows the opening line with a free-format
text message-of-the-day (if any is defined).
where <version> is the numeric version (see PROTOCOL_VERSION in rsync.h)
'.' is a literal period, and <subprotocol> is the numeric subprotocol
version (see SUBPROTOCOL_VERSION -- it will be 0 for final releases).
Protocols prior to 30 only output <version> alone. The daemon expects
to see a similar greeting back from the client. For protocols prior to
30, an absent ".<subprotocol>" value is assumed to be 0. For protocol
30, an absent value is a fatal error. The daemon then follows this line
with a free-format text message-of-the-day (if any is defined).
The server is now in the connected state. The client can either send
the command:
the command
#list
(to get a listing of modules) or the name of a module. After this, the
to get a listing of modules, or the name of a module. After this, the
connection is now bound to a particular module. Access per host for
this module is now checked, as is per-module connection limits.
If authentication is required to use this module, the server will say:
If authentication is required to use this module, the server will say
@RSYNCD: AUTHREQD <challenge>
where <challenge> is a random string of base64 characters. The client
must respond with:
must respond with
<user> <response>
The <user> is the username they claim to be. The <response> is the
base64 form of the digest hash of the challenge+password string. The
chosen digest method is the most preferred client method that is also in
the server's list. If no digest list was explicitly provided, the side
expecting a list assumes the other side provided either the single name
"md5" (for a negotiated protocol 30 or 31), or the single name "md4"
(for an older protocol).
where <user> is the username they claim to be, and <response> is the
base64 form of the MD4 hash of challenge+password.
At this point the server applies all remaining constraints before
handing control to the client, including switching uid/gid, setting up
@@ -91,13 +76,6 @@ stay tuned (or write it yourself!).
------------
Protocol version changes
31 (2013-09-28, 3.1.0)
Initial release of protocol 31 had no changes. Rsync 3.2.7
introduced the suffixed list of digest names on the greeting
line. The presence of the list is allowed even if the greeting
indicates an older protocol version number.
30 (2007-10-04, 3.0.0pre1)
The use of a ".<subprotocol>" number was added to

View File

@@ -1,114 +0,0 @@
#!/usr/bin/awk -f
# The caller must pass arg: daemon-parm.txt
# The resulting code is output into daemon-parm.h
BEGIN {
heading = "/* DO NOT EDIT THIS FILE! It is auto-generated from a list of values in " ARGV[1] "! */\n\n"
sect = psect = defines = accessors = prior_ptype = ""
parms = "\nstatic const struct parm_struct parm_table[] = {"
comment_fmt = "\n/********** %s **********/\n"
tdstruct = "typedef struct {"
}
/^\s*$/ { next }
/^#/ { next }
/^Globals:/ {
if (defines != "") {
print "The Globals section must come first!"
defines = ""
exit
}
defines = tdstruct
values = "\nstatic const all_vars Defaults = {\n { /* Globals: */\n"
exps = exp_values = sprintf(comment_fmt, "EXP")
sect = "GLOBAL"
psect = ", P_GLOBAL, &Vars.g."
next
}
/^Locals:/ {
if (sect == "") {
print "The Locals section must come after the Globals!"
exit
}
defines = defines exps "} global_vars;\n\n" tdstruct
values = values exp_values "\n }, { /* Locals: */\n"
exps = exp_values = sprintf(comment_fmt, "EXP")
sect = "LOCAL"
psect = ", P_LOCAL, &Vars.l."
next
}
/^(STRING|CHAR|PATH|INTEGER|ENUM|OCTAL|BOOL|BOOLREV|BOOL3)[ \t]/ {
ptype = $1
name = $2
$1 = $2 = ""
sub(/^[ \t]+/, "")
if (ptype != prior_ptype) {
comment = sprintf(comment_fmt, ptype)
defines = defines comment
values = values comment
parms = parms "\n"
accessors = accessors "\n"
prior_ptype = ptype
}
if (ptype == "STRING" || ptype == "PATH") {
atype = "STRING"
vtype = "char*"
} else if (ptype ~ /BOOL/) {
atype = vtype = "BOOL"
} else if (ptype == "CHAR") {
atype = "CHAR"
vtype = "char"
} else {
atype = "INTEGER"
vtype = "int"
}
# The name might be var_name|public_name
pubname = name
sub(/\|.*/, "", name)
sub(/.*\|/, "", pubname)
gsub(/_/, " ", pubname)
gsub(/-/, "", name)
if (ptype == "ENUM")
enum = "enum_" name
else
enum = "NULL"
defines = defines "\t" vtype " " name ";\n"
values = values "\t" $0 ", /* " name " */\n"
parms = parms " {\"" pubname "\", P_" ptype psect name ", " enum ", 0},\n"
accessors = accessors "FN_" sect "_" atype "(lp_" name ", " name ")\n"
if (vtype == "char*") {
exps = exps "\tBOOL " name "_EXP;\n"
exp_values = exp_values "\tFalse, /* " name "_EXP */\n"
}
next
}
/./ {
print "Extraneous line:" $0
defines = ""
exit
}
END {
if (sect != "" && defines != "") {
defines = defines exps "} local_vars;\n\n"
defines = defines tdstruct "\n\tglobal_vars g;\n\tlocal_vars l;\n} all_vars;\n"
values = values exp_values "\n }\n};\n\nstatic all_vars Vars;\n"
parms = parms "\n {NULL, P_BOOL, P_NONE, NULL, NULL, 0}\n};\n"
print heading defines values parms accessors > "daemon-parm.h"
} else {
print "Failed to parse the data in " ARGV[1]
exit 1
}
}

View File

@@ -1,68 +0,0 @@
Globals: ================================================================
STRING bind_address|address NULL
STRING daemon_chroot NULL
STRING daemon_gid NULL
STRING daemon_uid NULL
STRING motd_file NULL
STRING pid_file NULL
STRING socket_options NULL
INTEGER listen_backlog 5
INTEGER rsync_port|port 0
BOOL proxy_protocol False
Locals: =================================================================
STRING auth_users NULL
STRING charset NULL
STRING comment NULL
STRING dont_compress DEFAULT_DONT_COMPRESS
STRING early_exec NULL
STRING exclude NULL
STRING exclude_from NULL
STRING filter NULL
STRING gid NULL
STRING hosts_allow NULL
STRING hosts_deny NULL
STRING include NULL
STRING include_from NULL
STRING incoming_chmod NULL
STRING lock_file DEFAULT_LOCK_FILE
STRING log_file NULL
STRING log_format "%o %h [%a] %m (%u) %f %l"
STRING name NULL
STRING name_converter NULL
STRING outgoing_chmod NULL
STRING post-xfer_exec NULL
STRING pre-xfer_exec NULL
STRING refuse_options NULL
STRING secrets_file NULL
STRING syslog_tag "rsyncd"
STRING uid NULL
PATH path NULL
PATH temp_dir NULL
INTEGER max_connections 0
INTEGER max_verbosity 1
INTEGER timeout 0
ENUM syslog_facility LOG_DAEMON
BOOL fake_super False
BOOL forward_lookup True
BOOL ignore_errors False
BOOL ignore_nonreadable False
BOOL list True
BOOL read_only True
BOOL reverse_lookup True
BOOL strict_modes True
BOOL transfer_logging False
BOOL write_only False
BOOL3 munge_symlinks Unset
BOOL3 numeric_ids Unset
BOOL3 open_noatime Unset
BOOL3 use_chroot Unset

View File

@@ -1,41 +0,0 @@
#!/usr/bin/awk -f
# The caller must pass args: -v hfile=NAME rsync.1.md
BEGIN {
heading = "/* DO NOT EDIT THIS FILE! It is auto-generated from a list of values in " ARGV[1] "! */"
if (hfile ~ /compress/) {
define = "#define DEFAULT_DONT_COMPRESS"
prefix = "*."
} else {
define = "#define DEFAULT_CVSIGNORE"
prefix = ""
}
value_list = ""
}
/^ > [^ ]+$/ {
gsub(/`/, "")
if (value_list != "") value_list = value_list " "
value_list = value_list prefix $2
next
}
value_list ~ /\.gz / && hfile ~ /compress/ {
exit
}
value_list ~ /SCCS / && hfile ~ /cvsignore/ {
exit
}
value_list = ""
END {
if (value_list != "")
print heading "\n\n" define " \"" value_list "\"" > hfile
else {
print "Failed to find a value list in " ARGV[1] " for " hfile
exit 1
}
}

240
delete.c
View File

@@ -1,240 +0,0 @@
/*
* Deletion routines used in rsync.
*
* Copyright (C) 1996-2000 Andrew Tridgell
* Copyright (C) 1996 Paul Mackerras
* Copyright (C) 2002 Martin Pool <mbp@samba.org>
* Copyright (C) 2003-2024 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.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, visit the http://fsf.org website.
*/
#include "rsync.h"
extern int am_root;
extern int make_backups;
extern int max_delete;
extern char *backup_dir;
extern char *backup_suffix;
extern int backup_suffix_len;
extern struct stats stats;
int ignore_perishable = 0;
int non_perishable_cnt = 0;
int skipped_deletes = 0;
static inline int is_backup_file(char *fn)
{
int k = strlen(fn) - backup_suffix_len;
return k > 0 && strcmp(fn+k, backup_suffix) == 0;
}
/* The directory is about to be deleted: if DEL_RECURSE is given, delete all
* its contents, otherwise just checks for content. Returns DR_SUCCESS or
* DR_NOT_EMPTY. Note that fname must point to a MAXPATHLEN buffer! (The
* buffer is used for recursion, but returned unchanged.)
*/
static enum delret delete_dir_contents(char *fname, uint16 flags)
{
struct file_list *dirlist;
enum delret ret;
unsigned remainder;
void *save_filters;
int j, dlen;
char *p;
if (DEBUG_GTE(DEL, 3)) {
rprintf(FINFO, "delete_dir_contents(%s) flags=%d\n",
fname, flags);
}
dlen = strlen(fname);
save_filters = push_local_filters(fname, dlen);
non_perishable_cnt = 0;
dirlist = get_dirlist(fname, dlen, 0);
ret = non_perishable_cnt ? DR_NOT_EMPTY : DR_SUCCESS;
if (!dirlist->used)
goto done;
if (!(flags & DEL_RECURSE)) {
ret = DR_NOT_EMPTY;
goto done;
}
p = fname + dlen;
if (dlen != 1 || *fname != '/')
*p++ = '/';
remainder = MAXPATHLEN - (p - fname);
/* We do our own recursion, so make delete_item() non-recursive. */
flags = (flags & ~(DEL_RECURSE|DEL_MAKE_ROOM|DEL_NO_UID_WRITE))
| DEL_DIR_IS_EMPTY;
for (j = dirlist->used; j--; ) {
struct file_struct *fp = dirlist->files[j];
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));
}
ret = DR_NOT_EMPTY;
continue;
}
strlcpy(p, fp->basename, remainder);
if (!(fp->mode & S_IWUSR) && !am_root && fp->flags & FLAG_OWNED_BY_US)
do_chmod_at(fname, fp->mode | S_IWUSR);
/* Save stack by recursing to ourself directly. */
if (S_ISDIR(fp->mode)) {
if (delete_dir_contents(fname, flags | DEL_RECURSE) != DR_SUCCESS)
ret = DR_NOT_EMPTY;
}
if (delete_item(fname, fp->mode, flags) != DR_SUCCESS)
ret = DR_NOT_EMPTY;
}
fname[dlen] = '\0';
done:
flist_free(dirlist);
pop_local_filters(save_filters);
if (ret == DR_NOT_EMPTY) {
rprintf(FINFO, "cannot delete non-empty directory: %s\n",
fname);
}
return ret;
}
/* Delete a file or directory. If DEL_RECURSE is set in the flags, this will
* delete recursively.
*
* Note that fbuf must point to a MAXPATHLEN buffer if the mode indicates it's
* a directory! (The buffer is used for recursion, but returned unchanged.)
*/
enum delret delete_item(char *fbuf, uint16 mode, uint16 flags)
{
enum delret ret;
char *what;
int ok;
if (DEBUG_GTE(DEL, 2)) {
rprintf(FINFO, "delete_item(%s) mode=%o flags=%d\n",
fbuf, (int)mode, (int)flags);
}
if (flags & DEL_NO_UID_WRITE)
do_chmod_at(fbuf, mode | S_IWUSR);
if (S_ISDIR(mode) && !(flags & DEL_DIR_IS_EMPTY)) {
/* This only happens on the first call to delete_item() since
* delete_dir_contents() always calls us w/DEL_DIR_IS_EMPTY. */
ignore_perishable = 1;
/* If DEL_RECURSE is not set, this just reports emptiness. */
ret = delete_dir_contents(fbuf, flags);
ignore_perishable = 0;
if (ret == DR_NOT_EMPTY || ret == DR_AT_LIMIT)
goto check_ret;
/* OK: try to delete the directory. */
}
if (!(flags & DEL_MAKE_ROOM) && max_delete >= 0 && stats.deleted_files >= max_delete) {
skipped_deletes++;
return DR_AT_LIMIT;
}
if (S_ISDIR(mode)) {
what = "rmdir";
ok = do_rmdir_at(fbuf) == 0;
} else {
if (make_backups > 0 && !(flags & DEL_FOR_BACKUP) && (backup_dir || !is_backup_file(fbuf))) {
what = "make_backup";
ok = make_backup(fbuf, True);
if (ok == 2) {
what = "unlink";
ok = robust_unlink(fbuf) == 0;
}
} else {
what = "unlink";
ok = robust_unlink(fbuf) == 0;
}
}
if (ok) {
if (!(flags & DEL_MAKE_ROOM)) {
log_delete(fbuf, mode);
stats.deleted_files++;
if (S_ISREG(mode)) {
/* Nothing more to count */
} else if (S_ISDIR(mode))
stats.deleted_dirs++;
#ifdef SUPPORT_LINKS
else if (S_ISLNK(mode))
stats.deleted_symlinks++;
#endif
else if (IS_DEVICE(mode))
stats.deleted_devices++;
else
stats.deleted_specials++;
}
ret = DR_SUCCESS;
} else {
if (S_ISDIR(mode) && errno == ENOTEMPTY) {
rprintf(FINFO, "cannot delete non-empty directory: %s\n",
fbuf);
ret = DR_NOT_EMPTY;
} else if (errno != ENOENT) {
rsyserr(FERROR_XFER, errno, "delete_file: %s(%s) failed",
what, fbuf);
ret = DR_FAILURE;
} else
ret = DR_SUCCESS;
}
check_ret:
if (ret != DR_SUCCESS && flags & DEL_MAKE_ROOM) {
const char *desc;
switch (flags & DEL_MAKE_ROOM) {
case DEL_FOR_FILE: desc = "regular file"; break;
case DEL_FOR_DIR: desc = "directory"; break;
case DEL_FOR_SYMLINK: desc = "symlink"; break;
case DEL_FOR_DEVICE: desc = "device file"; break;
case DEL_FOR_SPECIAL: desc = "special file"; break;
default: exit_cleanup(RERR_UNSUPPORTED); /* IMPOSSIBLE */
}
rprintf(FERROR_XFER, "could not make way for %s %s: %s\n",
flags & DEL_FOR_BACKUP ? "backup" : "new",
desc, fbuf);
}
return ret;
}
uint16 get_del_for_flag(uint16 mode)
{
if (S_ISREG(mode))
return DEL_FOR_FILE;
if (S_ISDIR(mode))
return DEL_FOR_DIR;
if (S_ISLNK(mode))
return DEL_FOR_SYMLINK;
if (IS_DEVICE(mode))
return DEL_FOR_DEVICE;
if (IS_SPECIAL(mode))
return DEL_FOR_SPECIAL;
exit_cleanup(RERR_UNSUPPORTED); /* IMPOSSIBLE */
}

View File

@@ -126,7 +126,7 @@
<para><option>-P</option>
Display a progress indicator while files are transferred. This should
normally be omitted if rsync is not run on a terminal.
normally be ommitted 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-2019 Wayne Davison
* Copyright (C) 2003-2008 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

1154
exclude.c
View File

File diff suppressed because it is too large Load Diff

160
fileio.c
View File

@@ -3,7 +3,7 @@
*
* Copyright (C) 1998 Andrew Tridgell
* Copyright (C) 2002 Martin Pool
* Copyright (C) 2004-2023 Wayne Davison
* Copyright (C) 2004-2009 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
@@ -20,62 +20,43 @@
*/
#include "rsync.h"
#include "inums.h"
#ifndef ENODATA
#define ENODATA EAGAIN
#endif
/* 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_BOUNDARY-1))
/* Round up a length to the next boundary */
#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 updating_basis_or_equiv)
int sparse_end(int f, OFF_T size)
{
int ret = 0;
int ret;
if (!sparse_seek)
return 0;
if (updating_basis_or_equiv) {
if (sparse_seek && do_punch_hole(f, sparse_past_write, sparse_seek) < 0)
ret = -1;
#ifdef HAVE_FTRUNCATE /* A compilation formality -- in-place requires ftruncate() */
else /* Just in case the original file was longer */
ret = do_ftruncate(f, size);
#endif
} else if (sparse_seek) {
#ifdef HAVE_FTRUNCATE
ret = do_ftruncate(f, size);
ret = do_ftruncate(f, size);
#else
if (do_lseek(f, sparse_seek-1, SEEK_CUR) != size-1)
ret = -1;
else {
do {
ret = write(f, "", 1);
} while (ret < 0 && errno == EINTR);
if (do_lseek(f, sparse_seek-1, SEEK_CUR) != size-1)
ret = -1;
else {
do {
ret = write(f, "", 1);
} while (ret < 0 && errno == EINTR);
ret = ret <= 0 ? -1 : 0;
}
#endif
ret = ret <= 0 ? -1 : 0;
}
#endif
sparse_past_write = sparse_seek = 0;
sparse_seek = 0;
return ret;
}
/* 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)
static int write_sparse(int f, char *buf, int len)
{
int l1 = 0, l2 = 0;
int ret;
@@ -88,40 +69,23 @@ static int write_sparse(int f, int use_seek, OFF_T offset, const char *buf, int
if (l1 == len)
return len;
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;
}
}
if (sparse_seek)
do_lseek(f, sparse_seek, SEEK_CUR);
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)
continue;
sparse_seek = 0;
return ret;
}
if (ret != (int)(len - (l1+l2))) {
sparse_seek = 0;
if (ret != (int)(len - (l1+l2)))
return l1+ret;
}
return len;
}
static char *wf_writeBuf;
static size_t wf_writeBufSize;
static size_t wf_writeBufCnt;
@@ -143,10 +107,12 @@ 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. 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)
/*
* 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)
{
int ret = 0;
@@ -154,13 +120,14 @@ int write_file(int f, int use_seek, OFF_T offset, const char *buf, int len)
int r1;
if (sparse_files > 0) {
int len1 = MIN(len, SPARSE_WRITE_SIZE);
r1 = write_sparse(f, use_seek, offset, buf, len1);
offset += r1;
r1 = write_sparse(f, buf, len1);
} else {
if (!wf_writeBuf) {
wf_writeBufSize = WRITE_SIZE * 8;
wf_writeBufCnt = 0;
wf_writeBuf = new_array(char, wf_writeBufSize);
if (!wf_writeBuf)
out_of_memory("write_file");
}
r1 = (int)MIN((size_t)len, wf_writeBufSize - wf_writeBufCnt);
if (r1) {
@@ -186,47 +153,25 @@ int write_file(int f, int use_seek, OFF_T offset, const 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
* the possibility of another program (such as a mailer) truncating the
* file thus giving us a SIGBUS. */
struct map_struct *map_file(int fd, OFF_T len, int32 read_size, int32 blk_size)
struct map_struct *map_file(int fd, OFF_T len, int32 read_size,
int32 blk_size)
{
struct map_struct *map;
map = new0(struct map_struct);
if (!(map = new0(struct map_struct)))
out_of_memory("map_file");
if (blk_size && (read_size % blk_size))
read_size += blk_size - (read_size % blk_size);
map->fd = fd;
map->file_size = len;
map->def_window_size = ALIGNED_LENGTH(read_size);
map->def_window_size = read_size;
return map;
}
@@ -235,8 +180,9 @@ struct map_struct *map_file(int fd, OFF_T len, int32 read_size, int32 blk_size)
/* slide the read window in the file */
char *map_ptr(struct map_struct *map, OFF_T offset, int32 len)
{
int32 nread;
OFF_T window_start, read_start;
int32 window_size, read_size, read_offset, align_fudge;
int32 window_size, read_size, read_offset;
if (len == 0)
return NULL;
@@ -251,23 +197,26 @@ char *map_ptr(struct map_struct *map, OFF_T offset, int32 len)
return map->p + (offset - map->p_offset);
/* nope, we are going to have to do a read. Work out our desired window */
align_fudge = (int32)ALIGNED_OVERSHOOT(offset);
window_start = offset - align_fudge;
window_start = offset;
window_size = map->def_window_size;
if (window_start + window_size > map->file_size)
window_size = (int32)(map->file_size - window_start);
if (window_size < len + align_fudge)
window_size = ALIGNED_LENGTH(len + align_fudge);
if (len > window_size)
window_size = len;
/* make sure we have allocated enough memory for the window */
if (window_size > map->p_size) {
map->p = realloc_array(map->p, char, window_size);
if (!map->p)
out_of_memory("map_ptr");
map->p_size = window_size;
}
/* Now try to avoid re-reading any bytes by reusing any bytes from the previous buffer. */
if (window_start >= map->p_offset && window_start < map->p_offset + map->p_len
&& window_start + window_size >= map->p_offset + map->p_len) {
/* Now try to avoid re-reading any bytes by reusing any bytes
* from the previous buffer. */
if (window_start >= map->p_offset &&
window_start < map->p_offset + map->p_len &&
window_start + window_size >= map->p_offset + map->p_len) {
read_start = map->p_offset + map->p_len;
read_offset = (int32)(read_start - window_start);
read_size = window_size - read_offset;
@@ -287,8 +236,8 @@ char *map_ptr(struct map_struct *map, OFF_T offset, int32 len)
if (map->p_fd_offset != read_start) {
OFF_T ret = do_lseek(map->fd, read_start, SEEK_SET);
if (ret != read_start) {
rsyserr(FERROR, errno, "lseek returned %s, not %s",
big_num(ret), big_num(read_start));
rsyserr(FERROR, errno, "lseek returned %.0f, not %.0f",
(double)ret, (double)read_start);
exit_cleanup(RERR_FILEIO);
}
map->p_fd_offset = read_start;
@@ -297,7 +246,7 @@ char *map_ptr(struct map_struct *map, OFF_T offset, int32 len)
map->p_len = window_size;
while (read_size > 0) {
int32 nread = read(map->fd, map->p + read_offset, read_size);
nread = read(map->fd, map->p + read_offset, read_size);
if (nread <= 0) {
if (!map->status)
map->status = nread ? errno : ENODATA;
@@ -311,9 +260,10 @@ char *map_ptr(struct map_struct *map, OFF_T offset, int32 len)
read_size -= nread;
}
return map->p + align_fudge;
return map->p;
}
int unmap_file(struct map_struct *map)
{
int ret;
@@ -323,9 +273,7 @@ int unmap_file(struct map_struct *map)
map->p = NULL;
}
ret = map->status;
#if 0 /* I don't think we really need this. */
force_memzero(map, sizeof map[0]);
#endif
memset(map, 0, sizeof map[0]);
free(map);
return ret;

849
flist.c
View File

File diff suppressed because it is too large Load Diff

View File

File diff suppressed because it is too large Load Diff

View File

@@ -15,7 +15,8 @@
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-2020 Wayne Davison
* Copyright (C) 2003-2008 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
@@ -20,7 +20,8 @@
#include "rsync.h"
int main(UNUSED(int argc), UNUSED(char *argv[]))
int
main(UNUSED(int argc), UNUSED(char *argv[]))
{
int n, i;
gid_t *list;

View File

@@ -1,7 +1,7 @@
/*
* Routines to provide a memory-efficient hashtable.
*
* Copyright (C) 2007-2022 Wayne Davison
* Copyright (C) 2007-2009 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,61 +23,38 @@
struct hashtable *hashtable_create(int size, int key64)
{
int req = size;
struct hashtable *tbl;
int node_size = key64 ? sizeof (struct ht_int64_node)
: sizeof (struct ht_int32_node);
/* Pick a power of 2 that can hold the requested size. */
if (size & (size-1) || size < 16) {
int req = size;
size = 16;
while (size < req)
size *= 2;
}
tbl = new(struct hashtable);
tbl->nodes = new_array0(char, size * node_size);
if (!(tbl = new(struct hashtable))
|| !(tbl->nodes = new_array0(char, size * node_size)))
out_of_memory("hashtable_create");
tbl->size = size;
tbl->entries = 0;
tbl->node_size = node_size;
tbl->key64 = key64 ? 1 : 0;
if (DEBUG_GTE(HASH, 1)) {
char buf[32];
if (req != size)
snprintf(buf, sizeof buf, "req: %d, ", req);
else
*buf = '\0';
rprintf(FINFO, "[%s] created hashtable %lx (%ssize: %d, keys: %d-bit)\n",
who_am_i(), (long)tbl, buf, size, key64 ? 64 : 32);
}
return tbl;
}
void hashtable_destroy(struct hashtable *tbl)
{
if (DEBUG_GTE(HASH, 1)) {
rprintf(FINFO, "[%s] destroyed hashtable %lx (size: %d, keys: %d-bit)\n",
who_am_i(), (long)tbl, tbl->size, tbl->key64 ? 64 : 32);
}
free(tbl->nodes);
free(tbl);
}
/* 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)
/* 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)
{
int key64 = tbl->key64;
struct ht_int32_node *node;
@@ -88,31 +65,23 @@ void *hashtable_find(struct hashtable *tbl, int64 key, void *data_when_new)
exit_cleanup(RERR_MESSAGEIO);
}
if (data_when_new && tbl->entries > HASH_LOAD_LIMIT(tbl->size)) {
if (allocate_if_missing && tbl->entries > HASH_LOAD_LIMIT(tbl->size)) {
void *old_nodes = tbl->nodes;
int size = tbl->size * 2;
int i;
tbl->nodes = new_array0(char, size * tbl->node_size);
if (!(tbl->nodes = new_array0(char, size * tbl->node_size)))
out_of_memory("hashtable_node");
tbl->size = size;
tbl->entries = 0;
if (DEBUG_GTE(HASH, 1)) {
rprintf(FINFO, "[%s] growing hashtable %lx (size: %d, keys: %d-bit)\n",
who_am_i(), (long)tbl, size, key64 ? 64 : 32);
}
for (i = size / 2; i-- > 0; ) {
struct ht_int32_node *move_node = HT_NODE(tbl, old_nodes, i);
int64 move_key = HT_KEY(move_node, key64);
if (move_key == 0)
continue;
if (move_node->data)
hashtable_find(tbl, move_key, move_node->data);
else {
node = hashtable_find(tbl, move_key, "");
node->data = 0;
}
node = hashtable_find(tbl, move_key, 1);
node->data = move_node->data;
}
free(old_nodes);
@@ -167,7 +136,7 @@ void *hashtable_find(struct hashtable *tbl, int64 key, void *data_when_new)
if (nkey == key)
return node;
if (nkey == 0) {
if (!data_when_new)
if (!allocate_if_missing)
return NULL;
break;
}
@@ -179,484 +148,6 @@ void *hashtable_find(struct hashtable *tbl, int64 key, void *data_when_new)
((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.
-------------------------------------------------------------------------------
*/
#define NON_ZERO_32(x) ((x) ? (x) : (uint32_t)1)
#define NON_ZERO_64(x, y) ((x) || (y) ? (y) | (int64)(x) << 32 | (y) : (int64)1)
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 NON_ZERO_32(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 NON_ZERO_32(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 NON_ZERO_32(c);
}
}
final(a,b,c);
return NON_ZERO_32(c);
}
#if SIZEOF_INT64 >= 8
/*
* hashlittle2: return 2 32-bit hash values joined into an int64.
*
* This is identical to hashlittle(), except it returns two 32-bit hash
* values instead of just one. This is good enough for hash table
* lookup with 2^^64 buckets, or if you want a second hash if you're not
* happy with the first, or if you want a probably-unique 64-bit ID for
* the key. *pc is better mixed than *pb, so use *pc first. If you want
* a 64-bit value do something like "*pc + (((uint64_t)*pb)<<32)".
*/
int64 hashlittle2(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 NON_ZERO_64(b, 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 NON_ZERO_64(b, c); /* zero length strings require 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 NON_ZERO_64(b, c);
}
}
final(a,b,c);
return NON_ZERO_64(b, c);
}
#else
#define hashlittle2(key, len) hashlittle(key, len)
#endif

View File

@@ -1,40 +0,0 @@
#!/usr/bin/awk -f
# The caller must pass args: -v hfile=help-NAME.h NAME.NUM.md
BEGIN {
heading = "/* DO NOT EDIT THIS FILE! It is auto-generated from the option list in " ARGV[1] "! */"
findcomment = hfile
sub("\\.", "\\.", findcomment)
findcomment = "\\[comment\\].*" findcomment
backtick_cnt = 0
prints = ""
}
/^```/ {
backtick_cnt++
next
}
foundcomment {
if (backtick_cnt > 1) exit
if (backtick_cnt == 1) {
gsub(/"/, "\\\"")
prints = prints "\n rprintf(F,\"" $0 "\\n\");"
}
next
}
$0 ~ findcomment {
foundcomment = 1
backtick_cnt = 0
}
END {
if (foundcomment && backtick_cnt > 1)
print heading "\n" prints > hfile
else {
print "Failed to find " hfile " section in " ARGV[1]
exit 1
}
}

146
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-2022 Wayne Davison
* Copyright (C) 2004-2009 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,17 +21,17 @@
*/
#include "rsync.h"
#include "inums.h"
#include "ifuncs.h"
extern int verbose;
extern int dry_run;
extern int list_only;
extern int am_sender;
extern int inc_recurse;
extern int do_xfers;
extern int alt_dest_type;
extern int link_dest;
extern int preserve_acls;
extern int preserve_xattrs;
extern int make_backups;
extern int protocol_version;
extern int remove_source_files;
extern int stdout_format_has_i;
@@ -48,8 +48,6 @@ 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;
@@ -59,29 +57,26 @@ static struct file_list *hlink_flist;
void init_hard_links(void)
{
if (am_sender || protocol_version < 30)
dev_tbl = hashtable_create(16, HT_KEY64);
dev_tbl = hashtable_create(16, 1);
else if (inc_recurse)
prior_hlinks = hashtable_create(1024, HT_KEY32);
prior_hlinks = hashtable_create(1024, 0);
}
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, 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));
}
}
}
dev_node = hashtable_find(dev_tbl, dev+1, 1);
if (!(tbl = dev_node->data))
tbl = dev_node->data = hashtable_create(512, 1);
} else
tbl = dev_node->data;
return hashtable_find(dev_node->data, ino, (void*)-1L);
return hashtable_find(tbl, ino, 1);
}
void idev_destroy(void)
@@ -117,15 +112,17 @@ 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 (*)(const void*, const void*))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, data_when_new);
if (node->data == data_when_new) {
node->data = new_array0(char, 5);
node = hashtable_find(prior_hlinks, gnum, 1);
if (!node->data) {
if (!(node->data = new_array0(char, 5)))
out_of_memory("match_gnums");
assert(gnum >= hlink_flist->ndx_start);
file->flags |= FLAG_HLINK_FIRST;
prev = -1;
@@ -189,7 +186,8 @@ void match_hard_links(struct file_list *flist)
int i, ndx_count = 0;
int32 *ndx_list;
ndx_list = new_array(int32, flist->used);
if (!(ndx_list = new_array(int32, flist->used)))
out_of_memory("match_hard_links");
for (i = 0; i < flist->used; i++) {
if (F_IS_HLINKED(flist->sorted[i]))
@@ -208,7 +206,7 @@ void match_hard_links(struct file_list *flist)
}
static int maybe_hard_link(struct file_struct *file, int ndx,
char *fname, int statret, stat_x *sxp,
const char *fname, int statret, stat_x *sxp,
const char *oldname, STRUCT_STAT *old_stp,
const char *realname, int itemizing, enum logcode code)
{
@@ -220,24 +218,31 @@ static int maybe_hard_link(struct file_struct *file, int ndx,
ITEM_LOCAL_CHANGE | ITEM_XNAME_FOLLOWS,
0, "");
}
if (INFO_GTE(NAME, 2) && maybe_ATTRS_REPORT)
if (verbose > 1 && maybe_ATTRS_REPORT)
rprintf(FCLIENT, "%s is uptodate\n", fname);
file->flags |= FLAG_HLINK_DONE;
return 0;
}
if (make_backups > 0) {
if (!make_backup(fname))
return -1;
} else if (robust_unlink(fname)) {
rsyserr(FERROR_XFER, errno, "unlink %s failed",
full_fname(fname));
return -1;
}
}
if (atomic_create(file, fname, NULL, oldname, MAKEDEV(0, 0), sxp, statret == 0 ? DEL_FOR_FILE : 0)) {
if (hard_link_one(file, fname, oldname, 0)) {
if (itemizing) {
itemize(fname, file, ndx, statret, sxp,
ITEM_LOCAL_CHANGE | ITEM_XNAME_FOLLOWS, 0,
realname);
}
if (code != FNONE && INFO_GTE(NAME, 1))
if (code != FNONE && verbose)
rprintf(code, "%s => %s\n", fname, realname);
return 0;
}
return -1;
}
@@ -265,7 +270,7 @@ static char *check_prior(struct file_struct *file, int gnum,
}
if (inc_recurse
&& (node = hashtable_find(prior_hlinks, gnum, NULL)) != NULL) {
&& (node = hashtable_find(prior_hlinks, gnum, 0)) != NULL) {
assert(node->data != NULL);
if (CVAL(node->data, 0) != 0) {
*prev_ndx_p = -1;
@@ -283,7 +288,7 @@ static char *check_prior(struct file_struct *file, int gnum,
/* Only called if FLAG_HLINKED is set and FLAG_HLINK_FIRST is not. Returns:
* 0 = process the file, 1 = skip the file, -1 = error occurred. */
int hard_link_check(struct file_struct *file, int ndx, char *fname,
int hard_link_check(struct file_struct *file, int ndx, const char *fname,
int statret, stat_x *sxp, int itemizing,
enum logcode code)
{
@@ -302,10 +307,6 @@ int hard_link_check(struct file_struct *file, int ndx, char *fname,
if (!flist) {
/* The previous file was skipped, so this one is
* treated as if it were the first in its group. */
if (DEBUG_GTE(HLINK, 2)) {
rprintf(FINFO, "hlink for %d (%s,%d): virtual first\n",
ndx, f_name(file, NULL), gnum);
}
return 0;
}
@@ -322,16 +323,8 @@ int hard_link_check(struct file_struct *file, int ndx, char *fname,
F_HL_PREV(prev_file) = ndx;
file->flags |= FLAG_FILE_SENT;
cur_flist->in_progress++;
if (DEBUG_GTE(HLINK, 2)) {
rprintf(FINFO, "hlink for %d (%s,%d): waiting for %d\n",
ndx, f_name(file, NULL), gnum, F_HL_PREV(file));
}
return 1;
}
if (DEBUG_GTE(HLINK, 2)) {
rprintf(FINFO, "hlink for %d (%s,%d): looking for a leader\n",
ndx, f_name(file, NULL), gnum);
}
return 0;
}
@@ -339,6 +332,7 @@ int hard_link_check(struct file_struct *file, int ndx, char *fname,
if (!(prev_file->flags & FLAG_HLINK_FIRST)) {
/* The previous previous is FIRST when prev is not. */
prev_name = realname = check_prior(prev_file, gnum, &prev_ndx, &flist);
assert(prev_name != NULL || flist != NULL);
/* Update our previous pointer to point to the FIRST. */
F_HL_PREV(file) = prev_ndx;
}
@@ -346,14 +340,9 @@ int hard_link_check(struct file_struct *file, int ndx, char *fname,
if (!prev_name) {
int alt_dest;
assert(flist != NULL);
prev_file = flist->files[prev_ndx - flist->ndx_start];
/* F_HL_PREV() is alt_dest value when DONE && FIRST. */
alt_dest = F_HL_PREV(prev_file);
if (DEBUG_GTE(HLINK, 2)) {
rprintf(FINFO, "hlink for %d (%s,%d): found flist match (alt %d)\n",
ndx, f_name(file, NULL), gnum, alt_dest);
}
if (alt_dest >= 0 && dry_run) {
pathjoin(namebuf, MAXPATHLEN, basis_dir[alt_dest],
@@ -367,11 +356,6 @@ int hard_link_check(struct file_struct *file, int ndx, char *fname,
}
}
if (DEBUG_GTE(HLINK, 2)) {
rprintf(FINFO, "hlink for %d (%s,%d): leader is %d (%s)\n",
ndx, f_name(file, NULL), gnum, prev_ndx, prev_name);
}
if (link_stat(prev_name, &prev_st, 0) < 0) {
if (!dry_run || errno != ENOENT) {
rsyserr(FERROR_XFER, errno, "stat %s failed", full_fname(prev_name));
@@ -387,26 +371,31 @@ int hard_link_check(struct file_struct *file, int ndx, char *fname,
char cmpbuf[MAXPATHLEN];
stat_x alt_sx;
int j = 0;
init_stat_x(&alt_sx);
#ifdef SUPPORT_ACLS
alt_sx.acc_acl = alt_sx.def_acl = NULL;
#endif
#ifdef SUPPORT_XATTRS
alt_sx.xattr = NULL;
#endif
do {
pathjoin(cmpbuf, MAXPATHLEN, basis_dir[j], fname);
if (link_stat(cmpbuf, &alt_sx.st, 0) < 0)
continue;
if (alt_dest_type == LINK_DEST) {
if (link_dest) {
if (prev_st.st_dev != alt_sx.st.st_dev
|| prev_st.st_ino != alt_sx.st.st_ino)
continue;
statret = 1;
if (stdout_format_has_i == 0
|| (!INFO_GTE(NAME, 2) && stdout_format_has_i < 2)) {
|| (verbose < 2 && stdout_format_has_i < 2)) {
itemizing = 0;
code = FNONE;
if (INFO_GTE(NAME, 2) && maybe_ATTRS_REPORT)
if (verbose > 1 && maybe_ATTRS_REPORT)
rprintf(FCLIENT, "%s is uptodate\n", fname);
}
break;
}
if (!quick_check_ok(FT_REG, cmpbuf, file, &alt_sx.st))
if (!unchanged_file(cmpbuf, file, &alt_sx.st))
continue;
statret = 1;
if (unchanged_attrs(cmpbuf, file, &alt_sx))
@@ -437,8 +426,16 @@ int hard_link_check(struct file_struct *file, int ndx, char *fname,
}
}
#endif
} else
free_stat_x(&alt_sx);
} else {
#ifdef SUPPORT_ACLS
if (preserve_acls)
free_acl(&alt_sx);
#endif
#ifdef SUPPORT_XATTRS
if (preserve_xattrs)
free_xattr(&alt_sx);
#endif
}
}
if (maybe_hard_link(file, ndx, fname, statret, sxp, prev_name, &prev_st,
@@ -446,7 +443,7 @@ int hard_link_check(struct file_struct *file, int ndx, char *fname,
return -1;
if (remove_source_files == 1 && do_xfers)
send_msg_success(fname, ndx);
send_msg_int(MSG_SUCCESS, ndx);
return 1;
}
@@ -454,10 +451,10 @@ int hard_link_check(struct file_struct *file, int ndx, char *fname,
int hard_link_one(struct file_struct *file, const char *fname,
const char *oldname, int terse)
{
if (do_link_at(oldname, fname) < 0) {
if (do_link(oldname, fname) < 0) {
enum logcode code;
if (terse) {
if (!INFO_GTE(NAME, 1))
if (!verbose)
return 0;
code = FINFO;
} else
@@ -484,7 +481,7 @@ void finish_hard_link(struct file_struct *file, const char *fname, int fin_ndx,
int prev_statret, ndx, prev_ndx = F_HL_PREV(file);
if (stp == NULL && prev_ndx >= 0) {
if (link_stat(fname, &st, 0) < 0 && !dry_run) {
if (link_stat(fname, &st, 0) < 0) {
rsyserr(FERROR_XFER, errno, "stat %s failed",
full_fname(fname));
return;
@@ -502,7 +499,12 @@ void finish_hard_link(struct file_struct *file, const char *fname, int fin_ndx,
} else
our_name = fname;
init_stat_x(&prev_sx);
#ifdef SUPPORT_ACLS
prev_sx.acc_acl = prev_sx.def_acl = NULL;
#endif
#ifdef SUPPORT_XATTRS
prev_sx.xattr = NULL;
#endif
while ((ndx = prev_ndx) >= 0) {
int val;
@@ -515,16 +517,23 @@ void finish_hard_link(struct file_struct *file, const char *fname, int fin_ndx,
val = maybe_hard_link(file, ndx, prev_name, prev_statret, &prev_sx,
our_name, stp, fname, itemizing, code);
flist->in_progress--;
free_stat_x(&prev_sx);
#ifdef SUPPORT_ACLS
if (preserve_acls)
free_acl(&prev_sx);
#endif
#ifdef SUPPORT_XATTRS
if (preserve_xattrs)
free_xattr(&prev_sx);
#endif
if (val < 0)
continue;
if (remove_source_files == 1 && do_xfers)
send_msg_success(fname, ndx);
send_msg_int(MSG_SUCCESS, ndx);
}
if (inc_recurse) {
int gnum = F_HL_GNUM(file);
struct ht_int32_node *node = hashtable_find(prior_hlinks, gnum, NULL);
struct ht_int32_node *node = hashtable_find(prior_hlinks, gnum, 0);
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);
@@ -539,7 +548,8 @@ void finish_hard_link(struct file_struct *file, const char *fname, int fin_ndx,
exit_cleanup(RERR_MESSAGEIO);
}
free(node->data);
node->data = strdup(our_name);
if (!(node->data = strdup(our_name)))
out_of_memory("finish_hard_link");
}
}

View File

@@ -1,6 +1,6 @@
/* Inline functions for rsync.
*
* Copyright (C) 2007-2022 Wayne Davison
* Copyright (C) 2007-2008 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,8 @@
static inline void
alloc_xbuf(xbuf *xb, size_t sz)
{
xb->buf = new_array(char, sz);
if (!(xb->buf = new_array(char, sz)))
out_of_memory("alloc_xbuf");
xb->size = sz;
xb->len = xb->pos = 0;
}
@@ -28,18 +29,12 @@ static inline void
realloc_xbuf(xbuf *xb, size_t sz)
{
char *bf = realloc_array(xb->buf, char, sz);
if (!bf)
out_of_memory("realloc_xbuf");
xb->buf = bf;
xb->size = sz;
}
static inline void
free_xbuf(xbuf *xb)
{
if (xb->buf)
free(xb->buf);
memset(xb, 0, sizeof (xbuf));
}
static inline int
to_wire_mode(mode_t mode)
{
@@ -72,41 +67,44 @@ d_name(struct dirent *di)
#endif
}
static inline void
init_stat_x(stat_x *sx_p)
static inline int
isDigit(const char *ptr)
{
sx_p->crtime = 0;
#ifdef SUPPORT_ACLS
sx_p->acc_acl = sx_p->def_acl = NULL;
#endif
#ifdef SUPPORT_XATTRS
sx_p->xattr = NULL;
#endif
return isdigit(*(unsigned char *)ptr);
}
static inline void
free_stat_x(stat_x *sx_p)
static inline int
isPrint(const char *ptr)
{
#ifdef SUPPORT_ACLS
{
extern int preserve_acls;
if (preserve_acls)
free_acl(sx_p);
}
#endif
#ifdef SUPPORT_XATTRS
{
extern int preserve_xattrs;
if (preserve_xattrs)
free_xattr(sx_p);
}
#endif
return isprint(*(unsigned char *)ptr);
}
static inline char *my_strdup(const char *str, const char *file, int line)
static inline int
isSpace(const char *ptr)
{
int len = strlen(str)+1;
char *buf = my_alloc(NULL, len, 1, file, line);
memcpy(buf, str, len);
return buf;
return isspace(*(unsigned char *)ptr);
}
static inline int
isLower(const char *ptr)
{
return islower(*(unsigned char *)ptr);
}
static inline int
isUpper(const char *ptr)
{
return isupper(*(unsigned char *)ptr);
}
static inline int
toLower(const char *ptr)
{
return tolower(*(unsigned char *)ptr);
}
static inline int
toUpper(const char *ptr)
{
return toupper(*(unsigned char *)ptr);
}

View File

@@ -115,7 +115,7 @@ else
# might cause directories to be created, which would be especially bad
# if $src (and thus $dsttmp) contains '*'.
if [ -f $src ] || [ -d $src ]
if [ -f $src -o -d $src ]
then
true
else

57
inums.h
View File

@@ -1,57 +0,0 @@
/* Inline functions for rsync.
*
* 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
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, visit the http://fsf.org website.
*/
static inline char *
big_num(int64 num)
{
return do_big_num(num, 0, NULL);
}
static inline char *
comma_num(int64 num)
{
extern int human_readable;
return do_big_num(num, human_readable != 0, NULL);
}
static inline char *
human_num(int64 num)
{
extern int human_readable;
return do_big_num(num, human_readable, NULL);
}
static inline char *
big_dnum(double dnum, int decimal_digits)
{
return do_big_dnum(dnum, 0, decimal_digits);
}
static inline char *
comma_dnum(double dnum, int decimal_digits)
{
extern int human_readable;
return do_big_dnum(dnum, human_readable != 0, decimal_digits);
}
static inline char *
human_dnum(double dnum, int decimal_digits)
{
extern int human_readable;
return do_big_dnum(dnum, human_readable, decimal_digits);
}

2709
io.c
View File

File diff suppressed because it is too large Load Diff

2
io.h
View File

@@ -1,5 +1,5 @@
/*
* Copyright (C) 2007-2019 Wayne Davison
* Copyright (C) 2007-2008 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,71 +0,0 @@
/* Inline functions for rsync.
*
* Copyright (C) 2007-2022 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.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, visit the http://fsf.org website.
*/
static inline int
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)
{
return isprint(*(unsigned char *)ptr);
}
static inline int
isSpace(const char *ptr)
{
return isspace(*(unsigned char *)ptr);
}
static inline int
isAlNum(const char *ptr)
{
return isalnum(*(unsigned char *)ptr);
}
static inline int
isLower(const char *ptr)
{
return islower(*(unsigned char *)ptr);
}
static inline int
isUpper(const char *ptr)
{
return isupper(*(unsigned char *)ptr);
}
static inline int
toLower(const char *ptr)
{
return tolower(*(unsigned char *)ptr);
}
static inline int
toUpper(const char *ptr)
{
return toupper(*(unsigned char *)ptr);
}

View File

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

View File

@@ -3,7 +3,7 @@
*
* Copyright (C) 1998 Andrew Tridgell
* Copyright (C) 2002 Martin Pool
* Copyright (C) 2004-2020 Wayne Davison
* Copyright (C) 2004, 2005, 2006 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
@@ -20,28 +20,17 @@
*/
#include "rsync.h"
#include "itypes.h"
static char number_separator;
char get_number_separator(void)
#ifndef HAVE_STRDUP
char *strdup(char *s)
{
if (!number_separator) {
char buf[32];
snprintf(buf, sizeof buf, "%f", 3.14);
if (strchr(buf, '.') != NULL)
number_separator = ',';
else
number_separator = '.';
}
return number_separator;
}
char get_decimal_point(void)
{
return get_number_separator() == ',' ? '.' : ',';
int len = strlen(s) + 1;
char *ret = (char *)malloc(len);
if (ret)
memcpy(ret, s, len);
return ret;
}
#endif
#ifndef HAVE_GETCWD
char *getcwd(char *buf, int size)
@@ -87,7 +76,7 @@ char get_decimal_point(void)
#ifndef HAVE_STRPBRK
/**
* Find the first occurrence in @p s of any character in @p accept.
* Find the first ocurrence in @p s of any character in @p accept.
*
* Derived from glibc
**/
@@ -162,111 +151,3 @@ int sys_gettimeofday(struct timeval *tv)
return gettimeofday(tv);
#endif
}
/* Return the int64 number as a string. If the human_flag arg is non-zero,
* we may output the number in K, M, G, or T units. If we don't add a unit
* suffix, we will append the fract string, if it is non-NULL. We can
* return up to 4 buffers at a time. */
char *do_big_num(int64 num, int human_flag, const char *fract)
{
static char bufs[4][128]; /* more than enough room */
static unsigned int n;
char *s;
int len, negated;
if (human_flag && !number_separator)
(void)get_number_separator();
n = (n + 1) % (sizeof bufs / sizeof bufs[0]);
if (human_flag > 1) {
int mult = human_flag == 2 ? 1000 : 1024;
if (num >= mult || num <= -mult) {
double dnum = (double)num / mult;
char units;
if (num < 0)
dnum = -dnum;
if (dnum < mult)
units = 'K';
else if ((dnum /= mult) < mult)
units = 'M';
else if ((dnum /= mult) < mult)
units = 'G';
else if ((dnum /= mult) < mult)
units = 'T';
else {
dnum /= mult;
units = 'P';
}
if (num < 0)
dnum = -dnum;
snprintf(bufs[n], sizeof bufs[0], "%.2f%c", dnum, units);
return bufs[n];
}
}
s = bufs[n] + sizeof bufs[0] - 1;
if (fract) {
len = strlen(fract);
s -= len;
strlcpy(s, fract, len + 1);
} else
*s = '\0';
len = 0;
if (!num)
*--s = '0';
if (num < 0) {
/* A maximum-size negated number can't fit as a positive,
* so do one digit in negated form to start us off. */
*--s = (char)(-(num % 10)) + '0';
num = -(num / 10);
len++;
negated = 1;
} else
negated = 0;
while (num) {
if (human_flag) {
if (len == 3) {
*--s = number_separator;
len = 1;
} else
len++;
}
*--s = (char)(num % 10) + '0';
num /= 10;
}
if (negated)
*--s = '-';
return s;
}
/* Return the double number as a string. If the human_flag option is > 1,
* we may output the number in K, M, G, or T units. The buffer we use for
* our result is either a single static buffer defined here, or a buffer
* we get from do_big_num(). */
char *do_big_dnum(double dnum, int human_flag, int decimal_digits)
{
static char tmp_buf[128];
#if SIZEOF_INT64 >= 8
char *fract;
snprintf(tmp_buf, sizeof tmp_buf, "%.*f", decimal_digits, dnum);
if (!human_flag || (dnum < 1000.0 && dnum > -1000.0))
return tmp_buf;
for (fract = tmp_buf+1; isDigit(fract); fract++) {}
return do_big_num((int64)dnum, human_flag, fract);
#else
/* A big number might lose digits converting to a too-short int64,
* so let's just return the raw double conversion. */
snprintf(tmp_buf, sizeof tmp_buf, "%.*f", decimal_digits, dnum);
return tmp_buf;
#endif
}

View File

@@ -1,72 +0,0 @@
/*
* An implementation of getpass for systems that lack one.
*
* Copyright (C) 2013 Roman Donchenko
*
* 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.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, visit the http://fsf.org website.
*/
#include <stdio.h>
#include <string.h>
#include <termios.h>
#include "rsync.h"
char *getpass(const char *prompt)
{
static char password[256];
BOOL tty_changed = False, read_success;
struct termios tty_old, tty_new;
FILE *in = stdin, *out = stderr;
FILE *tty = fopen("/dev/tty", "w+");
if (tty)
in = out = tty;
if (tcgetattr(fileno(in), &tty_old) == 0) {
tty_new = tty_old;
tty_new.c_lflag &= ~(ECHO | ISIG);
if (tcsetattr(fileno(in), TCSAFLUSH, &tty_new) == 0)
tty_changed = True;
}
if (!tty_changed)
fputs("(WARNING: will be visible) ", out);
fputs(prompt, out);
fflush(out);
read_success = fgets(password, sizeof password, in) != NULL;
/* Print the newline that hasn't been echoed. */
fputc('\n', out);
if (tty_changed)
tcsetattr(fileno(in), TCSAFLUSH, &tty_old);
if (tty)
fclose(tty);
if (read_success) {
/* Remove the trailing newline. */
size_t password_len = strlen(password);
if (password_len && password[password_len - 1] == '\n')
password[password_len - 1] = '\0';
return password;
}
return NULL;
}

View File

@@ -1,37 +0,0 @@
/* Keep this simple so both C and ASM can use it */
/* These allow something like CFLAGS=-DDISABLE_SHA512_DIGEST */
#ifdef DISABLE_SHA256_DIGEST
#undef SHA256_DIGEST_LENGTH
#endif
#ifdef DISABLE_SHA512_DIGEST
#undef SHA512_DIGEST_LENGTH
#endif
#define MD4_DIGEST_LEN 16
#define MD5_DIGEST_LEN 16
#if defined SHA512_DIGEST_LENGTH
#define MAX_DIGEST_LEN SHA512_DIGEST_LENGTH
#elif defined SHA256_DIGEST_LENGTH
#define MAX_DIGEST_LEN SHA256_DIGEST_LENGTH
#elif defined SHA_DIGEST_LENGTH
#define MAX_DIGEST_LEN SHA_DIGEST_LENGTH
#else
#define MAX_DIGEST_LEN MD5_DIGEST_LEN
#endif
#define CSUM_CHUNK 64
#define CSUM_gone -1
#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
#define CSUM_XXH3_64 7
#define CSUM_XXH3_128 8
#define CSUM_SHA1 9
#define CSUM_SHA256 10
#define CSUM_SHA512 11

View File

@@ -1,701 +0,0 @@
/*
* 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.
*/
#include "config.h"
#include "md-defines.h"
#ifdef USE_MD5_ASM /* { */
#ifdef __APPLE__
#define md5_process_asm _md5_process_asm
#endif
.text
.align 16
.globl md5_process_asm
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
#endif /* } USE_MD5_ASM */

View File

@@ -2,7 +2,6 @@
* RFC 1321 compliant MD5 implementation
*
* Copyright (C) 2001-2003 Christophe Devine
* Copyright (C) 2007-2022 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
@@ -147,13 +146,6 @@ static void md5_process(md_context *ctx, const uchar data[CSUM_CHUNK])
ctx->D += D;
}
#ifdef USE_MD5_ASM
#if CSUM_CHUNK != 64
#error The MD5 ASM code does not support CSUM_CHUNK != 64
#endif
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;
@@ -178,26 +170,17 @@ void md5_update(md_context *ctx, const uchar *input, uint32 length)
left = 0;
}
#ifdef USE_MD5_ASM /* { */
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);
}
static const uchar md5_padding[CSUM_CHUNK] = { 0x80 };
static uchar md5_padding[CSUM_CHUNK] = { 0x80 };
void md5_result(md_context *ctx, uchar digest[MD5_DIGEST_LEN])
{
@@ -224,8 +207,6 @@ void md5_result(md_context *ctx, uchar digest[MD5_DIGEST_LEN])
SIVALu(digest, 12, ctx->D);
}
#ifdef TEST_MD5 /* { */
void get_md5(uchar *out, const uchar *input, int n)
{
md_context ctx;
@@ -234,6 +215,8 @@ void get_md5(uchar *out, const uchar *input, int n)
md5_result(&ctx, out);
}
#ifdef TEST_MD5
#include <stdlib.h>
#include <stdio.h>
@@ -318,4 +301,4 @@ int main(int argc, char *argv[])
return 0;
}
#endif /* } */
#endif

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-2020 Wayne Davison
* Copyright (C) 2005-2008 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,8 +193,6 @@ 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;
@@ -203,6 +201,7 @@ 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,10 +1,10 @@
/* The include file for both the MD4 and MD5 routines. */
#ifdef USE_OPENSSL
#include <openssl/sha.h>
#include <openssl/evp.h>
#endif
#include "md-defines.h"
#define MD4_DIGEST_LEN 16
#define MD5_DIGEST_LEN 16
#define MAX_DIGEST_LEN MD5_DIGEST_LEN
#define CSUM_CHUNK 64
typedef struct {
uint32 A, B, C, D;
@@ -17,6 +17,10 @@ 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);
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);

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-2019 Wayne Davison
* Copyright (C) 2003, 2006 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

@@ -33,7 +33,7 @@ pool_alloc, pool_free, pool_free_old, pool_talloc, pool_tfree, pool_create, pool
.SH SYNOPSIS
.B #include "pool_alloc.h"
\fBstruct alloc_pool *pool_create(size_t \fIsize\fB, size_t \fIquantum\fB, void (*\fIbomb\fB)(char*,char*,int), int \fIflags\fB);
\fBstruct alloc_pool *pool_create(size_t \fIsize\fB, size_t \fIquantum\fB, void (*\fIbomb\fB)(char *), int \fIflags\fB);
\fBvoid pool_destroy(struct alloc_pool *\fIpool\fB);
@@ -95,39 +95,25 @@ for
.I quantum
will produce a quantum that should meet maximal alignment
on most platforms.
Unless
.B POOL_NO_QALIGN
If
.B POOL_QALIGN
is set in the
.IR flags ,
allocations will be aligned to addresses that are a
multiple of
.IR quantum .
A
.B NULL
may be specified for the
.I bomb
function pointer if it is not needed. (See the
.B pool_alloc()
function for how it is used.)
If
.B POOL_CLEAR
is set in the
.IR flags ,
all allocations from the pool will be initialized to zeros.
If either
.B POOL_PREPEND
or
.B POOL_INTERN
is specified in the
.IR flags ,
each extent's data structure will be allocated at the start of the
.IR size -length
buffer (rather than as a separate, non-pool allocation), with the
former extending the
.I size
to hold the structure, and the latter subtracting the structure's
length from the indicated
.IR size .
You may specify a
.B NULL
for the
.I bomb
function pointer if you don't wish to use it. (See the
.B pool_alloc()
function for how it is used.)
.P
.B pool_destroy()
destroys an allocation
@@ -145,8 +131,8 @@ is
.BR 0 ,
.I quantum
bytes will be allocated.
If the pool has been created without
.BR POOL_NO_QALIGN ,
If the pool has been created with
.BR POOL_QALIGN ,
every chunk of memory that is returned will be suitably aligned.
You can use this with the default
.I quantum
@@ -183,7 +169,7 @@ an extent), its memory will be completely freed back to the system.
If
.I addr
is
.BR NULL ,
.BR 0 ,
no memory will be freed, but subsequent allocations will come
from a new extent.
.P

View File

@@ -2,19 +2,18 @@
#define POOL_DEF_EXTENT (32 * 1024)
#define POOL_QALIGN_P2 (1<<16) /* power-of-2 qalign */
struct alloc_pool
{
size_t size; /* extent size */
size_t quantum; /* allocation quantum */
struct pool_extent *extents; /* top extent is "live" */
void (*bomb)(const char*, const char*, int); /* called if malloc fails */
void (*bomb)(); /* function to call if
* malloc fails */
int flags;
/* statistical data */
unsigned long e_created; /* extents created */
unsigned long e_freed; /* extents destroyed */
unsigned long e_freed; /* extents detroyed */
int64 n_allocated; /* calls to alloc */
int64 n_freed; /* calls to free */
int64 b_allocated; /* cum. bytes allocated */
@@ -23,18 +22,16 @@ struct alloc_pool
struct pool_extent
{
struct pool_extent *next;
void *start; /* starting address */
size_t free; /* free bytecount */
size_t bound; /* trapped free bytes */
size_t bound; /* bytes bound by padding,
* overhead and freed */
struct pool_extent *next;
};
struct align_test {
uchar foo;
union {
int64 i;
void *p;
} bar;
void *foo;
int64 bar;
};
#define MINALIGN offsetof(struct align_test, bar)
@@ -42,47 +39,24 @@ struct align_test {
/* Temporarily cast a void* var into a char* var when adding an offset (to
* keep some compilers from complaining about the pointer arithmetic). */
#define PTR_ADD(b,o) ( (void*) ((char*)(b) + (o)) )
#define PTR_SUB(b,o) ( (void*) ((char*)(b) - (o)) )
alloc_pool_t
pool_create(size_t size, size_t quantum, void (*bomb)(const char*, const char*, int), int flags)
pool_create(size_t size, size_t quantum, void (*bomb)(const char *), int flags)
{
struct alloc_pool *pool;
struct alloc_pool *pool;
if ((MINALIGN & (MINALIGN - 1)) != (0)) {
if (bomb)
(*bomb)("Compiler error: MINALIGN is not a power of 2", __FILE__, __LINE__);
return NULL;
}
if (!(pool = new0(struct alloc_pool)))
return NULL;
if (!size)
size = POOL_DEF_EXTENT;
if (!quantum)
quantum = MINALIGN;
if (!(pool = new(struct alloc_pool)))
return pool;
memset(pool, 0, sizeof (struct alloc_pool));
pool->size = size /* round extent size to min alignment reqs */
? (size + MINALIGN - 1) & ~(MINALIGN - 1)
: POOL_DEF_EXTENT;
if (flags & POOL_INTERN) {
if (size <= sizeof (struct pool_extent))
size = quantum;
else
size -= sizeof (struct pool_extent);
flags |= POOL_PREPEND;
pool->size -= sizeof (struct pool_extent);
flags |= POOL_APPEND;
}
if (quantum <= 1)
flags = (flags | POOL_NO_QALIGN) & ~POOL_QALIGN_P2;
else if (!(flags & POOL_NO_QALIGN)) {
if (size % quantum)
size += quantum - size % quantum;
/* If quantum is a power of 2, we'll avoid using modulus. */
if (!(quantum & (quantum - 1)))
flags |= POOL_QALIGN_P2;
}
pool->size = size;
pool->quantum = quantum;
pool->quantum = quantum ? quantum : MINALIGN;
pool->bomb = bomb;
pool->flags = flags;
@@ -93,21 +67,17 @@ void
pool_destroy(alloc_pool_t p)
{
struct alloc_pool *pool = (struct alloc_pool *) p;
struct pool_extent *cur, *next;
struct pool_extent *cur, *next;
if (!pool)
return;
for (cur = pool->extents; cur; cur = next) {
next = cur->next;
if (pool->flags & POOL_PREPEND)
free(PTR_SUB(cur->start, sizeof (struct pool_extent)));
else {
free(cur->start);
free(cur->start);
if (!(pool->flags & POOL_APPEND))
free(cur);
}
}
free(pool);
}
@@ -120,40 +90,45 @@ pool_alloc(alloc_pool_t p, size_t len, const char *bomb_msg)
if (!len)
len = pool->quantum;
else if (pool->flags & POOL_QALIGN_P2) {
if (len & (pool->quantum - 1))
len += pool->quantum - (len & (pool->quantum - 1));
} else if (!(pool->flags & POOL_NO_QALIGN)) {
if (len % pool->quantum)
len += pool->quantum - len % pool->quantum;
}
else if (pool->quantum > 1 && len % pool->quantum)
len += pool->quantum - len % pool->quantum;
if (len > pool->size)
goto bomb_out;
if (!pool->extents || len > pool->extents->free) {
void *start;
size_t asize;
void *start;
size_t free;
size_t bound;
size_t skew;
size_t asize;
struct pool_extent *ext;
free = pool->size;
bound = 0;
asize = pool->size;
if (pool->flags & POOL_PREPEND)
if (pool->flags & POOL_APPEND)
asize += sizeof (struct pool_extent);
if (!(start = new_array(char, asize)))
goto bomb_out;
if (pool->flags & POOL_CLEAR)
memset(start, 0, asize);
memset(start, 0, free);
if (pool->flags & POOL_PREPEND) {
ext = start;
start = PTR_ADD(start, sizeof (struct pool_extent));
} else if (!(ext = new(struct pool_extent)))
if (pool->flags & POOL_APPEND)
ext = PTR_ADD(start, free);
else if (!(ext = new(struct pool_extent)))
goto bomb_out;
if (pool->flags & POOL_QALIGN && pool->quantum > 1
&& (skew = (size_t)PTR_ADD(start, free) % pool->quantum)) {
bound += skew;
free -= skew;
}
ext->start = start;
ext->free = pool->size;
ext->bound = 0;
ext->free = free;
ext->bound = bound;
ext->next = pool->extents;
pool->extents = ext;
@@ -169,7 +144,7 @@ pool_alloc(alloc_pool_t p, size_t len, const char *bomb_msg)
bomb_out:
if (pool->bomb)
(*pool->bomb)(bomb_msg, __FILE__, __LINE__);
(*pool->bomb)(bomb_msg);
return NULL;
}
@@ -185,24 +160,10 @@ pool_free(alloc_pool_t p, size_t len, void *addr)
if (!pool)
return;
if (!addr) {
/* A NULL addr starts a fresh extent for new allocations. */
if ((cur = pool->extents) != NULL && cur->free != pool->size) {
cur->bound += cur->free;
cur->free = 0;
}
return;
}
if (!len)
len = pool->quantum;
else if (pool->flags & POOL_QALIGN_P2) {
if (len & (pool->quantum - 1))
len += pool->quantum - (len & (pool->quantum - 1));
} else if (!(pool->flags & POOL_NO_QALIGN)) {
if (len % pool->quantum)
len += pool->quantum - len % pool->quantum;
}
else if (pool->quantum > 1 && len % pool->quantum)
len += pool->quantum - len % pool->quantum;
pool->n_freed++;
pool->b_freed += len;
@@ -218,12 +179,19 @@ pool_free(alloc_pool_t p, size_t len, void *addr)
if (!prev) {
/* The "live" extent is kept ready for more allocations. */
if (cur->free + cur->bound + len >= pool->size) {
size_t skew;
if (pool->flags & POOL_CLEAR) {
memset(PTR_ADD(cur->start, cur->free), 0,
pool->size - cur->free);
}
cur->free = pool->size;
cur->bound = 0;
if (pool->flags & POOL_QALIGN && pool->quantum > 1
&& (skew = (size_t)PTR_ADD(cur->start, cur->free) % pool->quantum)) {
cur->bound += skew;
cur->free -= skew;
}
} else if (addr == PTR_ADD(cur->start, cur->free)) {
if (pool->flags & POOL_CLEAR)
memset(addr, 0, len);
@@ -235,12 +203,9 @@ pool_free(alloc_pool_t p, size_t len, void *addr)
if (cur->free + cur->bound >= pool->size) {
prev->next = cur->next;
if (pool->flags & POOL_PREPEND)
free(PTR_SUB(cur->start, sizeof (struct pool_extent)));
else {
free(cur->start);
free(cur->start);
if (!(pool->flags & POOL_APPEND))
free(cur);
}
pool->e_freed++;
} else if (prev != pool->extents) {
/* Move the extent to be the first non-live extent. */
@@ -277,11 +242,18 @@ pool_free_old(alloc_pool_t p, void *addr)
prev->next = NULL;
next = cur;
} else {
size_t skew;
/* The most recent live extent can just be reset. */
if (pool->flags & POOL_CLEAR)
memset(addr, 0, pool->size - cur->free);
cur->free = pool->size;
cur->bound = 0;
if (pool->flags & POOL_QALIGN && pool->quantum > 1
&& (skew = (size_t)PTR_ADD(cur->start, cur->free) % pool->quantum)) {
cur->bound += skew;
cur->free -= skew;
}
next = cur->next;
cur->next = NULL;
}
@@ -292,12 +264,9 @@ pool_free_old(alloc_pool_t p, void *addr)
while ((cur = next) != NULL) {
next = cur->next;
if (pool->flags & POOL_PREPEND)
free(PTR_SUB(cur->start, sizeof (struct pool_extent)));
else {
free(cur->start);
free(cur->start);
if (!(pool->flags & POOL_APPEND))
free(cur);
}
pool->e_freed++;
}
}
@@ -344,7 +313,7 @@ int
pool_stats(alloc_pool_t p, int fd, int summarize)
{
struct alloc_pool *pool = (struct alloc_pool *) p;
struct pool_extent *cur;
struct pool_extent *cur;
char buf[BUFSIZ];
int ret = 0;

View File

@@ -1,13 +1,13 @@
#include <stddef.h>
#define POOL_CLEAR (1<<0) /* zero fill allocations */
#define POOL_NO_QALIGN (1<<1) /* don't align data to quanta */
#define POOL_QALIGN (1<<1) /* align data to quanta */
#define POOL_INTERN (1<<2) /* Allocate extent structures */
#define POOL_PREPEND (1<<3) /* or prepend to extent data */
#define POOL_APPEND (1<<3) /* or appended to extent data */
typedef void *alloc_pool_t;
alloc_pool_t pool_create(size_t size, size_t quantum, void (*bomb)(const char*, const char*, int), int flags);
alloc_pool_t pool_create(size_t size, size_t quantum, void (*bomb)(const char *), int flags);
void pool_destroy(alloc_pool_t pool);
void *pool_alloc(alloc_pool_t pool, size_t size, const char *bomb_msg);
void pool_free(alloc_pool_t pool, size_t size, void *addr);

View File

File diff suppressed because it is too large Load Diff

View File

File diff suppressed because it is too large Load Diff

View File

@@ -3,7 +3,7 @@
* Version 2.2.x
* Portable SMB ACL interface
* Copyright (C) Jeremy Allison 2000
* Copyright (C) 2007-2022 Wayne Davison
* Copyright (C) 2007-2008 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
@@ -139,9 +139,7 @@ typedef struct acl *SMB_ACL_ENTRY_T;
/* Based on the Solaris & UnixWare code. */
#ifndef __TANDEM
#undef GROUP
#endif
#include <sys/aclv.h>
/* SVR4.2 ES/MP ACLs */
@@ -232,7 +230,7 @@ struct new_acl_entry{
#define SMB_ACL_ENTRY_T struct new_acl_entry*
#define SMB_ACL_T struct acl_entry_link*
#define SMB_ACL_TAG_T unsigned short
#define SMB_ACL_TYPE_T int

View File

@@ -2,7 +2,7 @@
* Extended attribute support for rsync.
*
* Copyright (C) 2004 Red Hat, Inc.
* Copyright (C) 2003-2022 Wayne Davison
* Copyright (C) 2003-2008 Wayne Davison
* Written by Jay Fenlason.
*
* This program is free software; you can redistribute it and/or modify
@@ -24,10 +24,6 @@
#ifdef SUPPORT_XATTRS
#ifdef HAVE_OSX_XATTRS
#define GETXATTR_FETCH_LIMIT (64*1024*1024)
#endif
#if defined HAVE_LINUX_XATTRS
ssize_t sys_lgetxattr(const char *path, const char *name, void *value, size_t size)
@@ -59,24 +55,7 @@ ssize_t sys_llistxattr(const char *path, char *list, size_t size)
ssize_t sys_lgetxattr(const char *path, const char *name, void *value, size_t size)
{
ssize_t len = getxattr(path, name, value, size, 0, XATTR_NOFOLLOW);
/* If we're retrieving data, handle resource forks > 64MB specially */
if (value != NULL && len == GETXATTR_FETCH_LIMIT && (size_t)len < size) {
/* getxattr will only return 64MB of data at a time, need to call again with a new offset */
u_int32_t offset = len;
size_t data_retrieved = len;
while (data_retrieved < size) {
len = getxattr(path, name, (char*)value + offset, size - data_retrieved, offset, XATTR_NOFOLLOW);
if (len <= 0)
break;
data_retrieved += len;
offset += (u_int32_t)len;
}
len = data_retrieved;
}
return len;
return getxattr(path, name, value, size, 0, XATTR_NOFOLLOW);
}
ssize_t sys_fgetxattr(int filedes, const char *name, void *value, size_t size)
@@ -126,18 +105,9 @@ ssize_t sys_llistxattr(const char *path, char *list, size_t size)
unsigned char keylen;
ssize_t off, len = extattr_list_link(path, EXTATTR_NAMESPACE_USER, list, size);
if (len <= 0 || size == 0)
if (len <= 0 || (size_t)len > size)
return len;
if ((size_t)len >= size) {
/* FreeBSD extattr_list_xx() returns 'size' as 'len' in case there are
more data available, truncating the output, we solve this by signalling
ERANGE in case len == size so that the code in xattrs.c will retry with
a bigger buffer */
errno = ERANGE;
return -1;
}
/* FreeBSD puts a single-byte length before each string, with no '\0'
* terminator. We need to change this into a series of null-terminted
* strings. Since the size is the same, we can simply transform the
@@ -145,7 +115,7 @@ ssize_t sys_llistxattr(const char *path, char *list, size_t size)
for (off = 0; off < len; off += keylen + 1) {
keylen = ((unsigned char*)list)[off];
if (off + keylen >= len) {
/* Should be impossible, but bugs happen! */
/* Should be impossible, but kernel bugs happen! */
errno = EINVAL;
return -1;
}
@@ -156,151 +126,6 @@ ssize_t sys_llistxattr(const char *path, char *list, size_t size)
return len;
}
#elif HAVE_SOLARIS_XATTRS
static ssize_t read_xattr(int attrfd, void *buf, size_t buflen)
{
STRUCT_STAT sb;
ssize_t ret;
if (fstat(attrfd, &sb) < 0)
ret = -1;
else if (sb.st_size > SSIZE_MAX) {
errno = ERANGE;
ret = -1;
} else if (buflen == 0)
ret = sb.st_size;
else if (sb.st_size > buflen) {
errno = ERANGE;
ret = -1;
} else {
size_t bufpos;
for (bufpos = 0; bufpos < sb.st_size; ) {
ssize_t cnt = read(attrfd, (char*)buf + bufpos, sb.st_size - bufpos);
if (cnt <= 0) {
if (cnt < 0 && errno == EINTR)
continue;
bufpos = -1;
break;
}
bufpos += cnt;
}
ret = bufpos;
}
close(attrfd);
return ret;
}
ssize_t sys_lgetxattr(const char *path, const char *name, void *value, size_t size)
{
int attrfd;
if ((attrfd = attropen(path, name, O_RDONLY)) < 0) {
errno = ENOATTR;
return -1;
}
return read_xattr(attrfd, value, size);
}
ssize_t sys_fgetxattr(int filedes, const char *name, void *value, size_t size)
{
int attrfd;
if ((attrfd = openat(filedes, name, O_RDONLY|O_XATTR, 0)) < 0) {
errno = ENOATTR;
return -1;
}
return read_xattr(attrfd, value, size);
}
int sys_lsetxattr(const char *path, const char *name, const void *value, size_t size)
{
int attrfd;
size_t bufpos;
mode_t mode = S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP;
if ((attrfd = attropen(path, name, O_CREAT|O_TRUNC|O_WRONLY, mode)) < 0)
return -1;
for (bufpos = 0; bufpos < size; ) {
ssize_t cnt = write(attrfd, (char*)value + bufpos, size);
if (cnt <= 0) {
if (cnt < 0 && errno == EINTR)
continue;
bufpos = -1;
break;
}
bufpos += cnt;
}
close(attrfd);
return bufpos > 0 ? 0 : -1;
}
int sys_lremovexattr(const char *path, const char *name)
{
int attrdirfd;
int ret;
if ((attrdirfd = attropen(path, ".", O_RDONLY)) < 0)
return -1;
ret = unlinkat(attrdirfd, name, 0);
close(attrdirfd);
return ret;
}
ssize_t sys_llistxattr(const char *path, char *list, size_t size)
{
int attrdirfd;
DIR *dirp;
struct dirent *dp;
ssize_t ret = 0;
if ((attrdirfd = attropen(path, ".", O_RDONLY)) < 0) {
errno = ENOTSUP;
return -1;
}
if ((dirp = fdopendir(attrdirfd)) == NULL) {
close(attrdirfd);
return -1;
}
while ((dp = readdir(dirp))) {
int len = strlen(dp->d_name);
if (dp->d_name[0] == '.' && (len == 1 || (len == 2 && dp->d_name[1] == '.')))
continue;
if (len == 11 && dp->d_name[0] == 'S' && strncmp(dp->d_name, "SUNWattr_r", 10) == 0
&& (dp->d_name[10] == 'o' || dp->d_name[10] == 'w'))
continue;
ret += len + 1;
if ((size_t)ret > size) {
if (size == 0)
continue;
ret = -1;
errno = ERANGE;
break;
}
memcpy(list, dp->d_name, len+1);
list += len+1;
}
closedir(dirp);
close(attrdirfd);
return ret;
}
#else
#error You need to create xattr compatibility functions.

View File

@@ -1,9 +1,9 @@
#ifdef SUPPORT_XATTRS
#if defined HAVE_SYS_XATTR_H
#include <sys/xattr.h>
#elif defined HAVE_ATTR_XATTR_H
#if defined HAVE_ATTR_XATTR_H
#include <attr/xattr.h>
#elif defined HAVE_SYS_XATTR_H
#include <sys/xattr.h>
#elif defined HAVE_SYS_EXTATTR_H
#include <sys/extattr.h>
#endif

1078
loadparm.c
View File

File diff suppressed because it is too large Load Diff

372
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-2022 Wayne Davison
* Copyright (C) 2003-2009 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
@@ -20,9 +20,9 @@
*/
#include "rsync.h"
#include "itypes.h"
#include "inums.h"
#include "ifuncs.h"
extern int verbose;
extern int dry_run;
extern int am_daemon;
extern int am_server;
@@ -31,18 +31,16 @@ extern int am_generator;
extern int local_server;
extern int quiet;
extern int module_id;
extern int msg_fd_out;
extern int allow_8bit_chars;
extern int protocol_version;
extern int always_checksum;
extern int preserve_mtimes;
extern int msgs2stderr;
extern int preserve_times;
extern int progress_is_active;
extern int stdout_format_has_i;
extern int stdout_format_has_o_or_i;
extern int logfile_format_has_i;
extern int logfile_format_has_o_or_i;
extern int receiver_symlink_times;
extern int64 total_data_written;
extern int64 total_data_read;
extern mode_t orig_umask;
extern char *auth_user;
extern char *stdout_format;
@@ -57,10 +55,6 @@ extern iconv_t ic_recv;
extern char curr_dir[MAXPATHLEN];
extern char *full_module_path;
extern unsigned int module_dirlen;
extern char sender_file_sum[MAX_DIGEST_LEN];
extern const char undetermined_hostname[];
extern struct name_num_item *xfer_sum_nni, *file_sum_nni;
static int log_initialised;
static int logfile_was_closed;
@@ -68,15 +62,10 @@ static FILE *logfile_fp;
struct stats stats;
int got_xfer_error = 0;
int output_needs_newline = 0;
int send_msgs_to_gen = 0;
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" },
@@ -96,13 +85,13 @@ struct {
{ RERR_MALLOC , "error allocating core memory buffers" },
{ RERR_PARTIAL , "some files/attrs were not transferred (see previous errors)" },
{ RERR_VANISHED , "some files vanished before they could be transferred" },
{ RERR_DEL_LIMIT , "the --max-delete limit stopped deletions" },
{ RERR_TIMEOUT , "timeout in data send/receive" },
{ RERR_CONTIMEOUT , "timeout waiting for daemon connection" },
{ RERR_CMD_FAILED , "remote shell failed" },
{ RERR_CMD_KILLED , "remote shell killed" },
{ RERR_CMD_RUN , "remote command could not be run" },
{ RERR_CMD_NOTFOUND,"remote command not found" },
{ RERR_DEL_LIMIT , "the --max-delete limit stopped deletions" },
{ 0, NULL }
};
@@ -124,7 +113,8 @@ static void logit(int priority, const char *buf)
if (logfile_was_closed)
logfile_reopen();
if (logfile_fp) {
fprintf(logfile_fp, "%s [%d] %s", timestring(time(NULL)), (int)getpid(), buf);
fprintf(logfile_fp, "%s [%d] %s",
timestring(time(NULL)), (int)getpid(), buf);
fflush(logfile_fp);
} else {
syslog(priority, "%s", buf);
@@ -133,16 +123,21 @@ 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(lp_syslog_tag(module_id), options, lp_syslog_facility(module_id));
openlog("rsyncd", options, lp_syslog_facility(module_id));
#else
openlog(lp_syslog_tag(module_id), options);
openlog("rsyncd", options);
#endif
#ifndef LOG_NDELAY
@@ -162,16 +157,14 @@ 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) /* Note: a restart only happens with am_daemon */
if (!restart)
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);
@@ -181,8 +174,7 @@ 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)
|| strcmp(lp_syslog_tag(-1), lp_syslog_tag(module_id)) != 0)
else if (lp_syslog_facility(-1) != lp_syslog_facility(module_id))
closelog();
else
return; /* unchanged syslog settings */
@@ -204,7 +196,6 @@ 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,26 +213,25 @@ void logfile_reopen(void)
}
}
static void filtered_fwrite(FILE *f, const char *in_buf, int in_len, int use_isprint, char end_char)
static void filtered_fwrite(FILE *f, const char *buf, int len, int use_isprint)
{
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)
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)
exit_cleanup(RERR_MESSAGEIO);
ob = outbuf;
fprintf(f, "\\#%03o", *(uchar*)s);
buf = s + 1;
}
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 (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)
if (buf != end && fwrite(buf, end - buf, 1, f) != 1)
exit_cleanup(RERR_MESSAGEIO);
}
@@ -250,8 +240,8 @@ static void filtered_fwrite(FILE *f, const char *in_buf, int in_len, int use_isp
* can happen with certain fatal conditions. */
void rwrite(enum logcode code, const char *buf, int len, int is_utf8)
{
char trailing_CR_or_NL;
FILE *f = msgs2stderr == 1 ? stderr : stdout;
int trailing_CR_or_NL;
FILE *f = NULL;
#ifdef ICONV_OPTION
iconv_t ic = is_utf8 && ic_recv != (iconv_t)-1 ? ic_recv : ic_chck;
#else
@@ -263,15 +253,7 @@ void rwrite(enum logcode code, const char *buf, int len, int is_utf8)
if (len < 0)
exit_cleanup(RERR_MESSAGEIO);
if (msgs2stderr == 1) {
/* 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) {
if (am_server && msg_fd_out >= 0) {
assert(!is_utf8);
/* Pass the message to our sibling in native charset. */
send_msg((enum msgcode)code, buf, len, 0);
@@ -306,28 +288,10 @@ void rwrite(enum logcode code, const char *buf, int len, int is_utf8)
} else if (code == FLOG)
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 (quiet && code == FINFO)
return;
if (am_server && msgs2stderr != 1 && (msgs2stderr != 2 || f != stderr)) {
if (am_server) {
enum msgcode msg = (enum msgcode)code;
if (protocol_version < 30) {
if (msg == MSG_ERROR)
@@ -338,25 +302,34 @@ 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 > 0) {
if (am_daemon) {
/* TODO: can we send the error to the user somehow? */
return;
}
}
switch (code) {
case FERROR_XFER:
got_xfer_error = 1;
/* FALL THROUGH */
case FERROR:
case FWARNING:
f = stderr;
break;
case FINFO:
f = am_server ? stderr : stdout;
break;
default:
exit_cleanup(RERR_MESSAGEIO);
}
if (output_needs_newline) {
if (progress_is_active && !am_server) {
fputc('\n', f);
output_needs_newline = 0;
progress_is_active = 0;
}
trailing_CR_or_NL = len && (buf[len-1] == '\n' || buf[len-1] == '\r') ? buf[--len] : '\0';
if (len && buf[0] == '\r') {
fputc('\r', f);
buf++;
len--;
}
trailing_CR_or_NL = len && (buf[len-1] == '\n' || buf[len-1] == '\r')
? buf[--len] : 0;
#ifdef ICONV_CONST
if (ic != (iconv_t)-1) {
@@ -365,39 +338,27 @@ void rwrite(enum logcode code, const char *buf, int len, int is_utf8)
int ierrno;
INIT_CONST_XBUF(outbuf, convbuf);
INIT_XBUF(inbuf, (char*)buf, len, (size_t)-1);
INIT_XBUF(inbuf, (char*)buf, len, -1);
while (inbuf.len) {
iconvbufs(ic, &inbuf, &outbuf, inbuf.pos ? 0 : ICB_INIT);
iconvbufs(ic, &inbuf, &outbuf, 0);
ierrno = errno;
if (outbuf.len) {
char trailing = inbuf.len ? '\0' : trailing_CR_or_NL;
filtered_fwrite(f, convbuf, outbuf.len, 0, trailing);
if (trailing) {
trailing_CR_or_NL = '\0';
fflush(f);
}
filtered_fwrite(f, convbuf, outbuf.len, 0);
outbuf.len = 0;
}
/* 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);
if (!ierrno || ierrno == E2BIG)
continue;
fprintf(f, "\\#%03o", CVAL(inbuf.buf, inbuf.pos++));
inbuf.len--;
}
} else
#endif
{
filtered_fwrite(f, buf, len, !allow_8bit_chars, trailing_CR_or_NL);
if (trailing_CR_or_NL)
fflush(f);
filtered_fwrite(f, buf, len, !allow_8bit_chars);
if (trailing_CR_or_NL) {
fputc(trailing_CR_or_NL, f);
fflush(f);
}
}
@@ -456,17 +417,12 @@ void rsyserr(enum logcode code, int errcode, const char *format, ...)
char buf[BIGPATHBUFLEN];
size_t len;
/* snprintf returns the would-have-been length on truncation, so
* each cumulative call must be guarded; if not, sizeof buf - len
* can underflow when promoted to size_t and the next call writes
* past the buffer. */
len = snprintf(buf, sizeof buf, RSYNC_NAME ": [%s] ", who_am_i());
strlcpy(buf, RSYNC_NAME ": ", sizeof buf);
len = (sizeof RSYNC_NAME ": ") - 1;
if (len < sizeof buf) {
va_start(ap, format);
len += vsnprintf(buf + len, sizeof buf - len, format, ap);
va_end(ap);
}
va_start(ap, format);
len += vsnprintf(buf + len, sizeof buf - len, format, ap);
va_end(ap);
if (len < sizeof buf) {
len += snprintf(buf + len, sizeof buf - len,
@@ -480,12 +436,12 @@ void rsyserr(enum logcode code, int errcode, const char *format, ...)
void rflush(enum logcode code)
{
FILE *f;
FILE *f = NULL;
if (am_daemon || code == FLOG)
return;
if (!am_server && (code == FINFO || code == FCLIENT))
if (code == FINFO && !am_server)
f = stdout;
else
f = stderr;
@@ -493,15 +449,10 @@ void rflush(enum logcode code)
fflush(f);
}
void remember_initial_stats(void)
{
initial_data_read = total_data_read;
initial_data_written = total_data_written;
}
/* A generic logging routine for send/recv, with parameter substitiution. */
static void log_formatted(enum logcode code, const char *format, const char *op,
struct file_struct *file, const char *fname, int iflags,
struct file_struct *file, const char *fname,
struct stats *initial_stats, int iflags,
const char *hlink)
{
char buf[MAXPATHLEN+1024], buf2[MAXPATHLEN], fmt[32];
@@ -524,45 +475,30 @@ static void log_formatted(enum logcode code, const char *format, const char *op,
buf[total] = '\0';
for (p = buf; (p = strchr(p, '%')) != NULL; ) {
int humanize = 0;
s = p++;
c = fmt + 1;
while (*p == '\'') {
humanize++;
p++;
}
if (*p == '-')
*c++ = *p++;
while (isDigit(p) && c - fmt < (int)(sizeof fmt) - 8)
*c++ = *p++;
while (*p == '\'') {
humanize++;
p++;
}
if (!*p)
break;
*c = '\0';
n = NULL;
/* Note for %h and %a: it doesn't matter what fd we pass to
* client_{name,addr} because rsync_module will already have
* forced the answer to be cached (assuming, of course, for %h
* that lp_reverse_lookup(module_id) is true). */
switch (*p) {
case 'h':
if (am_daemon) {
n = lp_reverse_lookup(module_id)
? client_name(0) : undetermined_hostname;
}
if (am_daemon)
n = client_name(0);
break;
case 'a':
if (am_daemon)
n = client_addr(0);
break;
case 'l':
strlcat(fmt, "s", sizeof fmt);
strlcat(fmt, ".0f", sizeof fmt);
snprintf(buf2, sizeof buf2, fmt,
do_big_num(F_LENGTH(file), humanize, NULL));
(double)F_LENGTH(file));
n = buf2;
break;
case 'U':
@@ -582,8 +518,9 @@ static void log_formatted(enum logcode code, const char *format, const char *op,
}
break;
case 'p':
strlcat(fmt, "d", sizeof fmt);
snprintf(buf2, sizeof buf2, fmt, (int)getpid());
strlcat(fmt, "ld", sizeof fmt);
snprintf(buf2, sizeof buf2, fmt,
(long)getpid());
n = buf2;
break;
case 'M':
@@ -670,33 +607,28 @@ static void log_formatted(enum logcode code, const char *format, const char *op,
n = auth_user;
break;
case 'b':
case 'c':
if (!(iflags & ITEM_TRANSFER))
b = 0;
else if ((!!am_sender) ^ (*p == 'c'))
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));
if (am_sender) {
b = stats.total_written -
initial_stats->total_written;
} else {
b = stats.total_read -
initial_stats->total_read;
}
strlcat(fmt, ".0f", sizeof fmt);
snprintf(buf2, sizeof buf2, fmt, (double)b);
n = buf2;
break;
case 'C':
n = NULL;
if (S_ISREG(file->mode)) {
if (always_checksum)
n = sum_as_hex(file_sum_nni->num, F_SUM(file), 1);
else if (iflags & ITEM_TRANSFER)
n = sum_as_hex(xfer_sum_nni->num, sender_file_sum, 0);
}
if (!n) {
int sum_len = csum_len_for_type(always_checksum ? file_sum_nni->num : xfer_sum_nni->num,
always_checksum);
memset(buf2, ' ', sum_len*2);
buf2[sum_len*2] = '\0';
n = buf2;
case 'c':
if (!am_sender) {
b = stats.total_written -
initial_stats->total_written;
} else {
b = stats.total_read -
initial_stats->total_read;
}
strlcat(fmt, ".0f", sizeof fmt);
snprintf(buf2, sizeof buf2, fmt, (double)b);
n = buf2;
break;
case 'i':
if (iflags & ITEM_DELETED) {
@@ -705,14 +637,14 @@ 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)) {
c[1] = 'L';
c[3] = '.';
c[4] = !(iflags & ITEM_REPORT_TIME) ? '.'
: !preserve_mtimes || !receiver_symlink_times
: !preserve_times || !receiver_symlink_times
|| (iflags & ITEM_REPORT_TIMEFAIL) ? 'T' : 't';
} else {
c[1] = S_ISDIR(file->mode) ? 'd'
@@ -720,15 +652,13 @@ static void log_formatted(enum logcode code, const char *format, const char *op,
: IS_DEVICE(file->mode) ? 'D' : 'f';
c[3] = !(iflags & ITEM_REPORT_SIZE) ? '.' : 's';
c[4] = !(iflags & ITEM_REPORT_TIME) ? '.'
: !preserve_mtimes ? 'T' : 't';
: !preserve_times ? 'T' : 't';
}
c[2] = !(iflags & ITEM_REPORT_CHANGE) ? '.' : 'c';
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|ITEM_REPORT_CRTIME)) ? '.'
: BITS_SET(iflags, ITEM_REPORT_ATIME|ITEM_REPORT_CRTIME) ? 'b'
: iflags & ITEM_REPORT_ATIME ? 'u' : 'n';
c[8] = !(iflags & ITEM_REPORT_ATIME) ? '.' : 'u';
c[9] = !(iflags & ITEM_REPORT_ACL) ? '.' : 'a';
c[10] = !(iflags & ITEM_REPORT_XATTR) ? '.' : 'x';
c[11] = '\0';
@@ -798,12 +728,10 @@ int log_format_has(const char *format, char esc)
return 0;
for (p = format; (p = strchr(p, '%')) != NULL; ) {
for (p++; *p == '\''; p++) {} /*SHARED ITERATOR*/
if (*p == '-')
if (*++p == '-')
p++;
while (isDigit(p))
p++;
while (*p == '\'') p++;
if (!*p)
break;
if (*p == esc)
@@ -815,70 +743,67 @@ int log_format_has(const char *format, char esc)
/* Log the transfer of a file. If the code is FCLIENT, the output just goes
* to stdout. If it is FLOG, it just goes to the log file. Otherwise we
* output to both. */
void log_item(enum logcode code, struct file_struct *file, int iflags, const char *hlink)
void log_item(enum logcode code, struct file_struct *file,
struct stats *initial_stats, int iflags, const char *hlink)
{
const char *s_or_r = am_sender ? "send" : "recv";
if (code != FLOG && stdout_format && !am_server)
log_formatted(FCLIENT, stdout_format, s_or_r, file, NULL, iflags, hlink);
if (code != FCLIENT && logfile_format && *logfile_format)
log_formatted(FLOG, logfile_format, s_or_r, file, NULL, iflags, hlink);
if (code != FLOG && stdout_format && !am_server) {
log_formatted(FCLIENT, stdout_format, s_or_r,
file, NULL, initial_stats, iflags, hlink);
}
if (code != FCLIENT && logfile_format && *logfile_format) {
log_formatted(FLOG, logfile_format, s_or_r,
file, NULL, initial_stats, 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
|| stdout_format_has_i > 1 || (INFO_GTE(NAME, 2) && stdout_format_has_i));
|| stdout_format_has_i > 1 || (verbose > 1 && stdout_format_has_i));
int local_change = iflags & ITEM_LOCAL_CHANGE && significant_flags;
if (am_server) {
if (logfile_name && !dry_run && see_item
&& (significant_flags || logfile_format_has_i))
log_item(FLOG, file, iflags, buf);
log_item(FLOG, file, &stats, iflags, buf);
} else if (see_item || local_change || *buf
|| (S_ISDIR(file->mode) && significant_flags)) {
enum logcode code = significant_flags || logfile_format_has_i ? FINFO : FCLIENT;
log_item(code, file, iflags, buf);
log_item(code, file, &stats, iflags, buf);
}
}
void log_delete(const char *fname, int mode)
{
static struct file_struct *file = NULL;
static struct {
union file_extras ex[4]; /* just in case... */
struct file_struct file;
} x;
int len = strlen(fname);
const char *fmt;
if (!file) {
int extra_len = (file_extra_cnt + 2) * EXTRA_LEN;
char *bp;
#if EXTRA_ROUNDING > 0
if (extra_len & (EXTRA_ROUNDING * EXTRA_LEN))
extra_len = (extra_len | (EXTRA_ROUNDING * EXTRA_LEN)) + EXTRA_LEN;
#endif
x.file.mode = mode;
bp = new_array0(char, FILE_STRUCT_LEN + extra_len + 1);
bp += extra_len;
file = (struct file_struct *)bp;
}
file->mode = mode;
if (am_server && protocol_version >= 29 && len < MAXPATHLEN) {
if (!verbose && !stdout_format)
;
else if (am_server && protocol_version >= 29 && len < MAXPATHLEN) {
if (S_ISDIR(mode))
len++; /* directories include trailing null */
send_msg(MSG_DELETED, fname, len, am_generator);
} else if (!INFO_GTE(DEL, 1) && !stdout_format)
;
else {
} else {
fmt = stdout_format_has_o_or_i ? stdout_format : "deleting %n";
log_formatted(FCLIENT, fmt, "del.", file, fname, ITEM_DELETED, NULL);
log_formatted(FCLIENT, fmt, "del.", &x.file, fname, &stats,
ITEM_DELETED, NULL);
}
if (!logfile_name || dry_run || !logfile_format)
return;
fmt = logfile_format_has_o_or_i ? logfile_format : "deleting %n";
log_formatted(FLOG, fmt, "del.", file, fname, ITEM_DELETED, NULL);
log_formatted(FLOG, fmt, "del.", &x.file, fname, &stats, ITEM_DELETED, NULL);
}
/*
@@ -889,15 +814,12 @@ void log_delete(const char *fname, int mode)
*/
void log_exit(int code, const char *file, int line)
{
/* 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));
}
if (code != 0 && am_server != 2) {
if (code == 0) {
rprintf(FLOG,"sent %.0f bytes received %.0f bytes total size %.0f\n",
(double)stats.total_written,
(double)stats.total_read,
(double)stats.total_size);
} else if (am_server != 2) {
const char *name;
name = rerr_name(code);
@@ -907,10 +829,10 @@ void log_exit(int code, const char *file, int line)
/* VANISHED is not an error, only a warning */
if (code == RERR_VANISHED) {
rprintf(FWARNING, "rsync warning: %s (code %d) at %s(%d) [%s=%s]\n",
name, code, src_file(file), line, who_am_i(), rsync_version());
name, code, file, line, who_am_i(), RSYNC_VERSION);
} else {
rprintf(FERROR, "rsync error: %s (code %d) at %s(%d) [%s=%s]\n",
name, code, src_file(file), line, who_am_i(), rsync_version());
name, code, file, line, who_am_i(), RSYNC_VERSION);
}
}
}

View File

@@ -1,21 +0,0 @@
dnl AC_HAVE_TYPE(TYPE,INCLUDES)
AC_DEFUN([AC_HAVE_TYPE], [
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
])

View File

@@ -1,27 +0,0 @@
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
])

View File

@@ -1,45 +0,0 @@
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

@@ -1,23 +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"
])

892
main.c
View File

File diff suppressed because it is too large Load Diff

161
match.c
View File

@@ -3,7 +3,7 @@
*
* Copyright (C) 1996 Andrew Tridgell
* Copyright (C) 1996 Paul Mackerras
* Copyright (C) 2003-2023 Wayne Davison
* Copyright (C) 2003-2009 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
@@ -20,16 +20,13 @@
*/
#include "rsync.h"
#include "inums.h"
extern int verbose;
extern int do_progress;
extern int checksum_seed;
extern int append_mode;
extern struct name_num_item *xfer_sum_nni;
extern int xfer_sum_len;
int updating_basis_file;
char sender_file_sum[MAX_DIGEST_LEN];
static int false_alarms;
static int hash_hits;
@@ -67,6 +64,8 @@ static void build_hash_table(struct sum_struct *s)
if (hash_table)
free(hash_table);
hash_table = new_array(int32, tablesize);
if (!hash_table)
out_of_memory("build_hash_table");
alloc_size = tablesize;
}
@@ -102,15 +101,16 @@ 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;
if (DEBUG_GTE(DELTASUM, 2) && i >= 0) {
if (verbose > 2 && i >= 0) {
rprintf(FINFO,
"match at %s last_match=%s j=%d len=%ld n=%ld\n",
big_num(offset), big_num(last_match), i,
"match at %.0f last_match=%.0f j=%d len=%ld n=%ld\n",
(double)offset, (double)last_match, i,
(long)s->sums[i].len, (long)n);
}
@@ -132,7 +132,7 @@ static void matched(int f, struct sum_struct *s, struct map_struct *buf, OFF_T o
else
last_match = offset;
if (buf && INFO_GTE(PROGRESS, 1))
if (buf && do_progress)
show_progress(last_match, buf->file_size);
}
@@ -142,21 +142,18 @@ static void hash_search(int f,struct sum_struct *s,
{
OFF_T offset, aligned_offset, end;
int32 k, want_i, aligned_i, backup;
char sum2[MAX_DIGEST_LEN];
char sum2[SUM_LENGTH];
uint32 s1, s2, sum;
int more;
schar *map;
// prevent possible memory leaks
memset(sum2, 0, sizeof sum2);
/* want_i is used to encourage adjacent matches, allowing the RLL
* coding of the output to work more efficiently. */
want_i = 0;
if (DEBUG_GTE(DELTASUM, 2)) {
rprintf(FINFO, "hash search b=%ld len=%s\n",
(long)s->blength, big_num(len));
if (verbose > 2) {
rprintf(FINFO, "hash search b=%ld len=%.0f\n",
(long)s->blength, (double)len);
}
k = (int32)MIN(len, (OFF_T)s->blength);
@@ -166,55 +163,41 @@ static void hash_search(int f,struct sum_struct *s,
sum = get_checksum1((char *)map, k);
s1 = sum & 0xFFFF;
s2 = sum >> 16;
if (DEBUG_GTE(DELTASUM, 3))
if (verbose > 3)
rprintf(FINFO, "sum=%.8x k=%ld\n", sum, (long)k);
offset = aligned_offset = aligned_i = 0;
end = len + 1 - s->sums[s->count-1].len;
if (DEBUG_GTE(DELTASUM, 3)) {
rprintf(FINFO, "hash search s->blength=%ld len=%s count=%s\n",
(long)s->blength, big_num(len), big_num(s->count));
if (verbose > 3) {
rprintf(FINFO, "hash search s->blength=%ld len=%.0f count=%.0f\n",
(long)s->blength, (double)len, (double)s->count);
}
do {
int done_csum2 = 0;
uint32 hash_entry;
int32 i, *prev;
int32 i;
if (DEBUG_GTE(DELTASUM, 4)) {
rprintf(FINFO, "offset=%s sum=%04x%04x\n",
big_num(offset), s2 & 0xFFFF, s1 & 0xFFFF);
if (verbose > 4) {
rprintf(FINFO, "offset=%.0f sum=%04x%04x\n",
(double)offset, s2 & 0xFFFF, s1 & 0xFFFF);
}
if (tablesize == TRADITIONAL_TABLESIZE) {
hash_entry = SUM2HASH2(s1,s2);
if ((i = hash_table[hash_entry]) < 0)
if ((i = hash_table[SUM2HASH2(s1,s2)]) < 0)
goto null_hash;
sum = (s1 & 0xffff) | (s2 << 16);
} else {
sum = (s1 & 0xffff) | (s2 << 16);
hash_entry = BIG_SUM2HASH(sum);
if ((i = hash_table[hash_entry]) < 0)
if ((i = hash_table[BIG_SUM2HASH(sum)]) < 0)
goto null_hash;
}
prev = &hash_table[hash_entry];
hash_hits++;
do {
int32 l;
/* When updating in-place, the chunk's offset must be
* 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)) {
*prev = s->sums[i].chain;
continue;
}
prev = &s->sums[i].chain;
if (sum != s->sums[i].sum1)
continue;
@@ -223,10 +206,16 @@ static void hash_search(int f,struct sum_struct *s,
if (l != s->sums[i].len)
continue;
if (DEBUG_GTE(DELTASUM, 3)) {
/* in-place: ensure chunk's offset is either >= our
* offset or that the data didn't move. */
if (updating_basis_file && s->sums[i].offset < offset
&& !(s->sums[i].flags & SUMFLG_SAME_OFFSET))
continue;
if (verbose > 3) {
rprintf(FINFO,
"potential match at %s i=%ld sum=%08x\n",
big_num(offset), (long)i, sum);
"potential match at %.0f i=%ld sum=%08x\n",
(double)offset, (long)i, sum);
}
if (!done_csum2) {
@@ -235,7 +224,7 @@ static void hash_search(int f,struct sum_struct *s,
done_csum2 = 1;
}
if (memcmp(sum2, sum2_at(s, i), s->s2length) != 0) {
if (memcmp(sum2,s->sums[i].sum2,s->s2length) != 0) {
false_alarms++;
continue;
}
@@ -249,37 +238,14 @@ static void hash_search(int f,struct sum_struct *s,
aligned_offset += s->blength;
aligned_i++;
}
if ((offset == aligned_offset
|| (sum == 0 && l == s->blength && aligned_offset + l <= len))
&& aligned_i < s->count) {
if (offset == aligned_offset && aligned_i < s->count) {
if (i != aligned_i) {
if (sum != s->sums[aligned_i].sum1
|| l != s->sums[aligned_i].len
|| memcmp(sum2, sum2_at(s, aligned_i), s->s2length) != 0)
|| memcmp(sum2, s->sums[aligned_i].sum2, s->s2length) != 0)
goto check_want_i;
i = aligned_i;
}
if (offset != aligned_offset) {
/* We've matched some zeros in a spot that is also zeros
* further along in the basis file, if we find zeros ahead
* in the sender's file, we'll output enough literal data
* to re-align with the basis file, and get back to seeking
* instead of writing. */
backup = (int32)(aligned_offset - last_match);
if (backup < 0)
backup = 0;
map = (schar *)map_ptr(buf, aligned_offset - backup, l + backup)
+ backup;
sum = get_checksum1((char *)map, l);
if (sum != s->sums[i].sum1)
goto check_want_i;
get_checksum2((char *)map, l, sum2);
if (memcmp(sum2, sum2_at(s, i), s->s2length) != 0)
goto check_want_i;
/* OK, we have a re-alignment match. Bump the offset
* forward to the new match point. */
offset = aligned_offset;
}
/* This identical chunk is in the same spot in the old and new file. */
s->sums[i].flags |= SUMFLG_SAME_OFFSET;
want_i = i;
@@ -290,10 +256,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, sum2_at(s, want_i), 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;
@@ -319,7 +285,8 @@ 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);
@@ -361,19 +328,22 @@ 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)
{
char file_sum[MAX_DIGEST_LEN];
int sum_len;
last_match = 0;
false_alarms = 0;
hash_hits = 0;
matches = 0;
data_transfer = 0;
sum_init(xfer_sum_nni, checksum_seed);
sum_init(checksum_seed);
if (append_mode > 0) {
if (append_mode == 2) {
OFF_T j = 0;
for (j = CHUNK_SIZE; j < s->flength; j += CHUNK_SIZE) {
if (buf && INFO_GTE(PROGRESS, 1))
if (buf && do_progress)
show_progress(last_match, buf->file_size);
sum_update(map_ptr(buf, last_match, CHUNK_SIZE),
CHUNK_SIZE);
@@ -381,7 +351,7 @@ void match_sums(int f, struct sum_struct *s, struct map_struct *buf, OFF_T len)
}
if (last_match < s->flength) {
int32 n = (int32)(s->flength - last_match);
if (buf && INFO_GTE(PROGRESS, 1))
if (buf && do_progress)
show_progress(last_match, buf->file_size);
sum_update(map_ptr(buf, last_match, n), n);
}
@@ -393,12 +363,12 @@ void match_sums(int f, struct sum_struct *s, struct map_struct *buf, OFF_T len)
if (len > 0 && s->count > 0) {
build_hash_table(s);
if (DEBUG_GTE(DELTASUM, 2))
if (verbose > 2)
rprintf(FINFO,"built hash table\n");
hash_search(f, s, buf, len);
if (DEBUG_GTE(DELTASUM, 2))
if (verbose > 2)
rprintf(FINFO,"done hash search\n");
} else {
OFF_T j;
@@ -408,27 +378,18 @@ void match_sums(int f, struct sum_struct *s, struct map_struct *buf, OFF_T len)
matched(f, s, buf, len, -1);
}
sum_end(sender_file_sum);
sum_len = sum_end(file_sum);
/* If we had a read error, send a bad checksum. */
if (buf && buf->status != 0)
file_sum[0]++;
/* 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 < xfer_sum_len && sender_file_sum[i] == 0; i++) {}
memset(sender_file_sum, 0, xfer_sum_len);
if (i == xfer_sum_len)
sender_file_sum[i-1]++;
}
if (DEBUG_GTE(DELTASUM, 2))
if (verbose > 2)
rprintf(FINFO,"sending file_sum\n");
write_buf(f, sender_file_sum, xfer_sum_len);
write_buf(f, file_sum, sum_len);
if (DEBUG_GTE(DELTASUM, 2)) {
if (verbose > 2)
rprintf(FINFO, "false_alarms=%d hash_hits=%d matches=%d\n",
false_alarms, hash_hits, matches);
}
total_hash_hits += hash_hits;
total_false_alarms += false_alarms;
@@ -438,11 +399,11 @@ void match_sums(int f, struct sum_struct *s, struct map_struct *buf, OFF_T len)
void match_report(void)
{
if (!DEBUG_GTE(DELTASUM, 1))
if (verbose <= 1)
return;
rprintf(FINFO,
"total: matches=%d hash_hits=%d false_alarms=%d data=%s\n",
"total: matches=%d hash_hits=%d false_alarms=%d data=%.0f\n",
total_matches, total_hash_hits, total_false_alarms,
big_num(stats.literal_data));
(double)stats.literal_data);
}

View File

@@ -1,42 +0,0 @@
#!/bin/sh
if [ $# != 1 ]; then
echo "Usage: $0 NAME.NUM.md" 1>&2
exit 1
fi
inname="$1"
srcdir=`dirname "$0"`
flagfile="$srcdir/.md2man-works"
force_flagfile="$srcdir/.md2man-force"
if [ ! -f "$flagfile" ]; then
# We test our smallest manpage just to see if the python setup works.
if "$srcdir/md-convert" --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
if [ -f "$force_flagfile" ]; then
opt='--force-link-text'
else
opt=''
fi
"$srcdir/md-convert" $opt "$srcdir/$inname"

View File

@@ -1,667 +0,0 @@
#!/usr/bin/env python3
# This script transforms markdown files into html and (optionally) nroff. The
# output files are written into the current directory named for the input file
# without the .md suffix and either the .html suffix or no suffix.
#
# If the input .md file has a section number at the end of the name (e.g.,
# rsync.1.md) a nroff file is also output (PROJ.NUM.md -> PROJ.NUM).
#
# The markdown 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. Then, the html.parser is used as a state machine that lets us tweak
# the html and (optionally) output nroff data based on the html tags.
#
# If the string @USE_GFM_PARSER@ exists in the file, the string is removed and
# a github-flavored-markup parser is used to parse the file.
#
# The man-page .md files also get the vars @VERSION@, @BINDIR@, and @LIBDIR@
# substituted. Some of these values depend on the Makefile $(prefix) (see the
# generated Makefile). If the maintainer wants to build files for /usr/local
# while creating release-ready man-page files for /usr, use the environment to
# set RSYNC_OVERRIDE_PREFIX=/usr.
# Copyright (C) 2020 - 2021 Wayne Davison
#
# This program is freely redistributable.
import os, sys, re, argparse, subprocess, time
from html.parser import HTMLParser
VALID_PAGES = 'README INSTALL COPYING rsync.1 rrsync.1 rsync-ssl.1 rsyncd.conf.5'.split()
CONSUMES_TXT = set('h1 h2 h3 p li pre'.split())
HTML_START = """\
<html><head>
<title>%TITLE%</title>
<meta charset="UTF-8"/>
<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;
}
a.tgt { font-face: symbol; font-weight: 400; font-size: 70%; visibility: hidden; text-decoration: none; color: #ddd; padding: 0 4px; border: 0; }
a.tgt:after { content: '🔗'; }
a.tgt:hover { color: #444; background-color: #eaeaea; }
h1:hover > a.tgt, h2:hover > a.tgt, h3:hover > a.tgt, dt:hover > a.tgt { visibility: visible; }
code {
font-family: 'Roboto Mono', monospace;
font-weight: bold;
white-space: pre;
}
pre code {
display: block;
font-weight: normal;
}
blockquote pre code {
background: #f1f1f1;
}
dd p:first-of-type {
margin-block-start: 0em;
}
</style>
</head><body>
"""
TABLE_STYLE = """\
table {
border-color: grey;
border-spacing: 0;
}
tr {
border-top: 1px solid grey;
}
tr:nth-child(2n) {
background-color: #f6f8fa;
}
th, td {
border: 1px solid #dfe2e5;
text-align: center;
padding-left: 1em;
padding-right: 1em;
}
"""
MAN_HTML_END = """\
<div style="float: right"><p><i>%s</i></p></div>
"""
HTML_END = """\
</body></html>
"""
MAN_START = r"""
.TH "%s" "%s" "%s" "%s" "User Commands"
.\" prefix=%s
""".lstrip()
MAN_END = """\
"""
NORM_FONT = ('\1', r"\fP")
BOLD_FONT = ('\2', r"\fB")
UNDR_FONT = ('\3', r"\fI")
NBR_DASH = ('\4', r"\-")
NBR_SPACE = ('\xa0', r"\ ")
FILENAME_RE = re.compile(r'^(?P<fn>(?P<srcdir>.+/)?(?P<name>(?P<prog>[^/]+?)(\.(?P<sect>\d+))?)\.md)$')
ASSIGNMENT_RE = re.compile(r'^(\w+)=(.+)')
VER_RE = re.compile(r'^#define\s+RSYNC_VERSION\s+"(\d.+?)"', re.M)
TZ_RE = re.compile(r'^#define\s+MAINTAINER_TZ_OFFSET\s+(-?\d+(\.\d+)?)', re.M)
VAR_REF_RE = re.compile(r'\$\{(\w+)\}')
VERSION_RE = re.compile(r' (\d[.\d]+)[, ]')
BIN_CHARS_RE = re.compile(r'[\1-\7]+')
LONG_OPT_DASH_RE = re.compile(r'(--\w[-\w]+)')
SPACE_DOUBLE_DASH_RE = re.compile(r'\s--(\s)')
NON_SPACE_SINGLE_DASH_RE = re.compile(r'(^|\W)-')
WHITESPACE_RE = re.compile(r'\s')
CODE_BLOCK_RE = re.compile(r'[%s]([^=%s]+)[=%s]' % (BOLD_FONT[0], NORM_FONT[0], NORM_FONT[0]))
NBR_DASH_RE = re.compile(r'[%s]' % NBR_DASH[0])
INVALID_TARGET_CHARS_RE = re.compile(r'[^-A-Za-z0-9._]')
INVALID_START_CHAR_RE = re.compile(r'^([^A-Za-z0-9])')
MANIFY_LINESTART_RE = re.compile(r"^(['.])", flags=re.M)
md_parser = None
env_subs = { }
warning_count = 0
def main():
for mdfn in args.mdfiles:
parse_md_file(mdfn)
if args.test:
print("The test was successful.")
def parse_md_file(mdfn):
fi = FILENAME_RE.match(mdfn)
if not fi:
die('Failed to parse a md input file name:', mdfn)
fi = argparse.Namespace(**fi.groupdict())
fi.want_manpage = not not fi.sect
if fi.want_manpage:
fi.title = fi.prog + '(' + fi.sect + ') manpage'
else:
fi.title = fi.prog + ' for rsync'
if fi.want_manpage:
if not env_subs:
find_man_substitutions()
prog_ver = 'rsync ' + env_subs['VERSION']
if fi.prog != 'rsync':
prog_ver = fi.prog + ' from ' + prog_ver
fi.man_headings = (fi.prog, fi.sect, env_subs['date'], prog_ver, env_subs['prefix'])
with open(mdfn, 'r', encoding='utf-8') as fh:
txt = fh.read()
use_gfm_parser = '@USE_GFM_PARSER@' in txt
if use_gfm_parser:
txt = txt.replace('@USE_GFM_PARSER@', '')
if fi.want_manpage:
txt = (txt.replace('@VERSION@', env_subs['VERSION'])
.replace('@BINDIR@', env_subs['bindir'])
.replace('@LIBDIR@', env_subs['libdir']))
if use_gfm_parser:
if not gfm_parser:
die('Input file requires cmarkgfm parser:', mdfn)
fi.html_in = gfm_parser(txt)
else:
fi.html_in = md_parser(txt)
txt = None
TransformHtml(fi)
if args.test:
return
output_list = [ (fi.name + '.html', fi.html_out) ]
if fi.want_manpage:
output_list += [ (fi.name, fi.man_out) ]
for fn, txt in output_list:
if args.dest and args.dest != '.':
fn = os.path.join(args.dest, fn)
if os.path.lexists(fn):
os.unlink(fn)
print("Wrote:", fn)
with open(fn, 'w', encoding='utf-8') as fh:
fh.write(txt)
def find_man_substitutions():
srcdir = os.path.dirname(sys.argv[0]) + '/'
mtime = 0
git_dir = srcdir + '.git'
if os.path.lexists(git_dir):
mtime = int(subprocess.check_output(['git', '--git-dir', git_dir, 'log', '-1', '--format=%at']))
# Allow "prefix" to be overridden via the environment:
env_subs['prefix'] = os.environ.get('RSYNC_OVERRIDE_PREFIX', None)
if args.test:
env_subs['VERSION'] = '1.0.0'
env_subs['bindir'] = '/usr/bin'
env_subs['libdir'] = '/usr/lib/rsync'
tz_offset = 0
else:
for fn in (srcdir + 'version.h', 'Makefile'):
try:
st = os.lstat(fn)
except OSError:
die('Failed to find', srcdir + fn)
if not mtime:
mtime = st.st_mtime
with open(srcdir + 'version.h', 'r', encoding='utf-8') as fh:
txt = fh.read()
m = VER_RE.search(txt)
env_subs['VERSION'] = m.group(1)
m = TZ_RE.search(txt) # the tzdata lib may not be installed, so we use a simple hour offset
tz_offset = float(m.group(1)) * 60 * 60
with open('Makefile', 'r', encoding='utf-8') as fh:
for line in fh:
m = ASSIGNMENT_RE.match(line)
if not m:
continue
var, val = (m.group(1), m.group(2))
if var == 'prefix' and env_subs[var] is not None:
continue
while VAR_REF_RE.search(val):
val = VAR_REF_RE.sub(lambda m: env_subs[m.group(1)], val)
env_subs[var] = val
if var == 'srcdir':
break
env_subs['date'] = time.strftime('%d %b %Y', time.gmtime(mtime + tz_offset)).lstrip('0')
if 'SOURCE_DATE_EPOCH' in os.environ:
env_subs['date'] = time.strftime('%d %b %Y', time.gmtime(int(os.environ.get('SOURCE_DATE_EPOCH', time.time()))))
def html_via_commonmark(txt):
return commonmark.HtmlRenderer().render(commonmark.Parser().parse(txt))
class TransformHtml(HTMLParser):
def __init__(self, fi):
HTMLParser.__init__(self, convert_charrefs=True)
self.fn = fi.fn
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.replace('%TITLE%', fi.title) ],
man_out = [ ],
txt = '',
want_manpage = fi.want_manpage,
created_hashtags = set(),
derived_hashtags = set(),
referenced_hashtags = set(),
bad_hashtags = set(),
latest_targets = [ ],
opt_prefix = 'opt',
a_href = None,
a_href_external = False,
a_txt_start = None,
after_a_tag = False,
target_suf = '',
)
if st.want_manpage:
st.man_out.append(MAN_START % fi.man_headings)
if '</table>' in fi.html_in:
st.html_out[0] = st.html_out[0].replace('</style>', TABLE_STYLE + '</style>')
self.feed(fi.html_in)
fi.html_in = None
if st.want_manpage:
st.html_out.append(MAN_HTML_END % env_subs['date'])
st.html_out.append(HTML_END)
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
for tgt, txt in st.derived_hashtags:
derived = txt2target(txt, tgt)
if derived not in st.created_hashtags:
txt = BIN_CHARS_RE.sub('', txt.replace(NBR_DASH[0], '-').replace(NBR_SPACE[0], ' '))
warn('Unknown derived hashtag link in', self.fn, 'based on:', (tgt, txt))
for bad in st.bad_hashtags:
if bad in st.created_hashtags:
warn('Missing "#" in hashtag link in', self.fn + ':', bad)
else:
warn('Unknown non-hashtag link in', self.fn + ':', bad)
for bad in st.referenced_hashtags - st.created_hashtags:
warn('Unknown hashtag link in', self.fn + ':', '#' + bad)
def handle_UE(self):
st = self.state
if st.txt.startswith(('.', ',', '!', '?', ';', ':')):
st.man_out[-1] = ".UE " + st.txt[0] + "\n"
st.txt = st.txt[1:]
st.after_a_tag = False
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>')
elif tag == 'p':
st.at_first_tag_in_dd = True # Kluge to suppress a .P at the start of an li.
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':
if st.want_manpage:
tag = 'u' # Change it into underline to be more like the manpage
st.txt += UNDR_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')
elif tag == 'hr':
st.man_out.append(".l\n")
st.html_out.append("<hr />")
return
elif tag == 'a':
st.a_href = None
for var, val in attrs_list:
if var == 'href':
if val.startswith(('https://', 'http://', 'mailto:', 'ftp:')):
if st.after_a_tag:
self.handle_UE()
st.man_out.append(manify(st.txt.strip()) + "\n")
st.man_out.append(".UR " + val + "\n")
st.txt = ''
st.a_href = val
st.a_href_external = True
elif '#' in val:
pg, tgt = val.split('#', 1)
if pg and pg not in VALID_PAGES or '#' in tgt:
st.bad_hashtags.add(val)
elif tgt in ('', 'opt', 'dopt'):
st.a_href = val
st.a_href_external = False
elif pg == '':
st.referenced_hashtags.add(tgt)
if tgt in st.latest_targets:
warn('Found link to the current section in', self.fn + ':', val)
elif val not in VALID_PAGES:
st.bad_hashtags.add(val)
st.a_txt_start = len(st.txt)
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 st.after_a_tag:
self.handle_UE()
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':
tgt = txt
target_suf = ''
if tgt.startswith('NEWS for '):
m = VERSION_RE.search(tgt)
if m:
tgt = m.group(1)
st.target_suf = '-' + tgt
self.add_targets(tag, tgt)
elif tag == 'h2':
st.man_out.append(st.p_macro + '.SH "' + manify(txt) + '"\n')
self.add_targets(tag, txt, st.target_suf)
st.opt_prefix = 'dopt' if txt == 'DAEMON OPTIONS' else 'opt'
elif tag == 'h3':
st.man_out.append(st.p_macro + '.SS "' + manify(txt) + '"\n')
self.add_targets(tag, txt, st.target_suf)
elif tag == 'p':
if st.dt_from == 'p':
tag = 'dt'
st.man_out.append('.IP "' + manify(txt) + '"\n')
if txt.startswith(BOLD_FONT[0]):
self.add_targets(tag, txt)
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':
if st.want_manpage:
tag = 'u' # Change it into underline to be more like the manpage
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
elif tag == 'hr':
return
elif tag == 'a':
if st.a_href_external:
st.txt = st.txt.strip()
if args.force_link_text or st.a_href != st.txt:
st.man_out.append(manify(st.txt) + "\n")
st.man_out.append(".UE\n") # This might get replaced with a punctuation version in handle_UE()
st.after_a_tag = True
st.a_href_external = False
st.txt = ''
elif st.a_href:
atxt = st.txt[st.a_txt_start:]
find = 'href="' + st.a_href + '"'
for j in range(len(st.html_out)-1, 0, -1):
if find in st.html_out[j]:
pg, tgt = st.a_href.split('#', 1)
derived = txt2target(atxt, tgt)
if pg == '':
if derived in st.latest_targets:
warn('Found link to the current section in', self.fn + ':', st.a_href)
st.derived_hashtags.add((tgt, atxt))
st.html_out[j] = st.html_out[j].replace(find, 'href="' + pg + '#' + derived + '"')
break
else:
die('INTERNAL ERROR: failed to find href in html data:', find)
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, txt):
st = self.state
if '](' in txt:
warn('Malformed link in', self.fn + ':', txt)
if args.debug:
self.output_debug('DATA', (txt,))
if st.in_pre:
html = htmlify(txt)
else:
txt = LONG_OPT_DASH_RE.sub(lambda x: x.group(1).replace('-', NBR_DASH[0]), txt)
txt = SPACE_DOUBLE_DASH_RE.sub(NBR_SPACE[0] + r'--\1', txt).replace('--', NBR_DASH[0]*2)
txt = NON_SPACE_SINGLE_DASH_RE.sub(r'\1' + NBR_DASH[0], txt)
html = htmlify(txt)
if st.in_code:
txt = WHITESPACE_RE.sub(NBR_SPACE[0], txt)
html = html.replace(NBR_DASH[0], '-').replace(NBR_SPACE[0], ' ') # <code> is non-breaking in CSS
st.html_out.append(html.replace(NBR_SPACE[0], '&nbsp;').replace(NBR_DASH[0], '-&#8288;'))
st.txt += txt
def add_targets(self, tag, txt, suf=None):
st = self.state
tag = '<' + tag + '>'
targets = CODE_BLOCK_RE.findall(txt)
if not targets:
targets = [ txt ]
tag_pos = 0
for txt in targets:
txt = txt2target(txt, st.opt_prefix)
if not txt:
continue
if suf:
txt += suf
if txt in st.created_hashtags:
for j in range(2, 1000):
chk = txt + '-' + str(j)
if chk not in st.created_hashtags:
print('Made link target unique:', chk)
txt = chk
break
if tag_pos == 0:
tag_pos -= 1
while st.html_out[tag_pos] != tag:
tag_pos -= 1
st.html_out[tag_pos] = tag[:-1] + ' id="' + txt + '">'
st.html_out.append('<a href="#' + txt + '" class="tgt"></a>')
tag_pos -= 1 # take into account the append
else:
st.html_out[tag_pos] = '<span id="' + txt + '"></span>' + st.html_out[tag_pos]
st.created_hashtags.add(txt)
st.latest_targets = targets
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 txt2target(txt, opt_prefix):
txt = txt.strip().rstrip(':')
m = CODE_BLOCK_RE.search(txt)
if m:
txt = m.group(1)
txt = NBR_DASH_RE.sub('-', txt)
txt = BIN_CHARS_RE.sub('', txt)
txt = INVALID_TARGET_CHARS_RE.sub('_', txt)
if opt_prefix and txt.startswith('-'):
txt = opt_prefix + txt
else:
txt = INVALID_START_CHAR_RE.sub(r't\1', txt)
return txt
def manify(txt):
return MANIFY_LINESTART_RE.sub(r'\&\1', txt.replace('\\', '\\\\')
.replace(NBR_SPACE[0], NBR_SPACE[1])
.replace(NBR_DASH[0], NBR_DASH[1])
.replace(NORM_FONT[0], NORM_FONT[1])
.replace(BOLD_FONT[0], BOLD_FONT[1])
.replace(UNDR_FONT[0], UNDR_FONT[1]))
def htmlify(txt):
return txt.replace('&', '&amp;').replace('<', '&lt;').replace('>', '&gt;').replace('"', '&quot;')
def warn(*msg):
print(*msg, file=sys.stderr)
global warning_count
warning_count += 1
def die(*msg):
warn(*msg)
sys.exit(1)
if __name__ == '__main__':
parser = argparse.ArgumentParser(description="Convert markdown into html and (optionally) nroff. Each input filename must have a .md suffix, which is changed to .html for the output filename. If the input filename ends with .num.md (e.g. foo.1.md) then a nroff file is also output with the input filename's .md suffix removed (e.g. foo.1).", add_help=False)
parser.add_argument('--test', action='store_true', help="Just test the parsing without outputting any files.")
parser.add_argument('--dest', metavar='DIR', help="Create files in DIR instead of the current directory.")
parser.add_argument('--force-link-text', action='store_true', help="Don't remove the link text if it matches the link href. Useful when nroff doesn't understand .UR and .UE.")
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("mdfiles", metavar='FILE.md', nargs='+', help="One or more .md files to convert.")
args = parser.parse_args()
try:
import cmarkgfm
md_parser = cmarkgfm.markdown_to_html
gfm_parser = cmarkgfm.github_flavored_markdown_to_html
except:
try:
import commonmark
md_parser = html_via_commonmark
except:
die("Failed to find cmarkgfm or commonmark for python3.")
gfm_parser = None
main()
if warning_count:
sys.exit(1)

1
md2man
View File

@@ -1 +0,0 @@
md-convert

View File

@@ -1,22 +0,0 @@
#!/bin/sh
srcdir=`dirname $0`
if [ ! -f git-version.h ]; then
touch git-version.h
fi
if test -d "$srcdir/.git" || test -f "$srcdir/.git"; then
gitver=`git describe --abbrev=8 2>/dev/null`
# NOTE: I'm avoiding "|" in sed since I'm not sure if sed -r is portable and "\|" fails on some OSes.
verchk=`echo "$gitver-" | sed -n '/^v3\.[0-9][0-9]*\.[0-9][0-9]*\(pre[0-9]*\)*-/p'`
if [ -n "$verchk" ]; then
echo "#define RSYNC_GITVER \"$gitver\"" >git-version.h.new
if ! diff git-version.h.new git-version.h >/dev/null; then
echo "Updating git-version.h"
mv git-version.h.new git-version.h
else
rm git-version.h.new
fi
fi
fi

View File

@@ -1,40 +0,0 @@
#!/usr/bin/awk -f
BEGIN {
while ((getline i < "proto.h") > 0) old_protos = old_protos ? old_protos "\n" i : i
close("proto.h")
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"
system("touch proto.h-tstamp")
}

48
mkproto.pl Normal file
View File

@@ -0,0 +1,48 @@
# 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;

2222
options.c
View File

File diff suppressed because it is too large Load Diff

View File

@@ -1,12 +0,0 @@
TARGETS := all install install-ssl-daemon install-all install-strip conf gen reconfigure restatus \
proto man clean cleantests distclean test check check29 check30 installcheck splint \
doxygen doxygen-upload finddead rrsync
.PHONY: $(TARGETS) auto-prep
$(TARGETS): auto-prep
make -C build $@
auto-prep:
@if test x`packaging/prep-auto-dir` = x; then echo "auto-build-save is not setup"; exit 1; fi
@echo 'Build branch: '`readlink build/.branch | tr % /`

6
packaging/bin/gpg Executable file
View File

@@ -0,0 +1,6 @@
#!/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,148 +0,0 @@
#!/usr/bin/env python3
# This script outputs either perl or python code that parses all possible options
# that the code in options.c might send to the server. The resulting code is then
# included in the rrsync script.
import re, argparse
short_no_arg = { }
short_with_num = { '@': 1 }
long_opts = { # 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,
'munge-links': 0,
'no-munge-links': -1,
'one-file-system': 0,
'owner': 0,
'perms': 0,
'recursive': 0,
'stderr': 1,
'times': 0,
'copy-devices': -1,
'write-devices': -1,
}
def main():
last_long_opt = None
with open('../options.c') as fh:
for line in fh:
m = re.search(r"argstr\[x\+\+\] = '([^.ie])'", line)
if m:
short_no_arg[m.group(1)] = 1
last_long_opt = None
continue
m = re.search(r'asprintf\([^,]+, "-([a-zA-Z0-9])\%l?[ud]"', line)
if m:
short_with_num[m.group(1)] = 1
last_long_opt = None
continue
m = re.search(r'args\[ac\+\+\] = "--([^"=]+)"', line)
if m:
last_long_opt = m.group(1)
if last_long_opt not in long_opts:
long_opts[last_long_opt] = 0
else:
last_long_opt = None
continue
if last_long_opt:
m = re.search(r'args\[ac\+\+\] = safe_arg\("", ([^[("\s]+)\);', line)
if m:
long_opts[last_long_opt] = 2
last_long_opt = None
continue
if 'args[ac++] = ' in line:
last_long_opt = None
m = re.search(r'return "--([^"]+-dest)";', line)
if m:
long_opts[m.group(1)] = 2
last_long_opt = None
continue
m = re.search(r'asprintf\([^,]+, "--([^"=]+)=', line)
if not m:
m = re.search(r'args\[ac\+\+\] = "--([^"=]+)=', line)
if not m:
m = re.search(r'args\[ac\+\+\] = safe_arg\("--([^"=]+)"', line)
if not m:
m = re.search(r'fmt = .*: "--([^"=]+)=', line)
if m:
long_opts[m.group(1)] = 1
last_long_opt = None
long_opts['files-from'] = 3
txt = """\
### START of options data produced by the cull-options script. ###
# To disable a short-named option, add its letter to this string:
"""
txt += str_assign('short_disabled', 's') + "\n"
txt += '# These are also disabled when the restricted dir is not "/":\n'
txt += str_assign('short_disabled_subdir', 'KLk') + "\n"
txt += '# These are all possible short options that we will accept (when not disabled above):\n'
txt += str_assign('short_no_arg', ''.join(sorted(short_no_arg)), 'DO NOT REMOVE ANY')
txt += str_assign('short_with_num', ''.join(sorted(short_with_num)), 'DO NOT REMOVE ANY')
txt += """
# To disable a long-named option, change its value to a -1. The values mean:
# 0 = the option has no arg; 1 = the arg doesn't need any checking; 2 = only
# check the arg when receiving; and 3 = always check the arg.
"""
print(txt, end='')
if args.python:
print("long_opts = {")
sep = ':'
else:
print("our %long_opt = (")
sep = ' =>'
for opt in sorted(long_opts):
if opt.startswith(('min-', 'max-')):
val = 1
else:
val = long_opts[opt]
print(' ', repr(opt) + sep, str(val) + ',')
if args.python:
print("}")
else:
print(");")
print("\n### END of options data produced by the cull-options script. ###")
def str_assign(name, val, comment=None):
comment = ' # ' + comment if comment else ''
if args.python:
return name + ' = ' + repr(val) + comment + "\n"
return 'our $' + name + ' = ' + repr(val) + ';' + comment + "\n"
if __name__ == '__main__':
parser = argparse.ArgumentParser(description="Output culled rsync options for rrsync.", add_help=False)
out_group = parser.add_mutually_exclusive_group()
out_group.add_argument('--perl', action='store_true', help="Output perl code.")
out_group.add_argument('--python', action='store_true', help="Output python code (the default).")
parser.add_argument('--help', '-h', action='help', help="Output this help message and exit.")
args = parser.parse_args()
if not args.perl:
args.python = True
main()
# vim: sw=4 et

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