Compare commits

..

118 Commits

Author SHA1 Message Date
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
215 changed files with 18165 additions and 34550 deletions

View File

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

18
.gitignore vendored
View File

@@ -12,17 +12,10 @@ config.h.in
config.h.in.old
config.log
config.status
aclocal.m4
/proto.h
/proto.h-tstamp
/rsync*.1
/rsync*.5
/rsync*.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*
@@ -30,13 +23,11 @@ aclocal.m4
/getgroups
/gmon.out
/rsync
/stunnel-rsyncd.conf
/shconfig
/testdir
/tests-dont-exist
/testtmp
/tls
/testrun
/trimslash
/t_unsafe
/wildtest
@@ -47,9 +38,4 @@ aclocal.m4
/support/savetransfer
/testsuite/chown-fake.test
/testsuite/devices-fake.test
/testsuite/xattrs-hlink.test
/patches
/patches.gen
/build
/auto-build-save
.deps

View File

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

View File

@@ -1,13 +1,13 @@
To build and install rsync:
$ ./configure
$ make
# make install
$ ./configure
$ make
# make install
You may set the installation directory and other parameters by options
to ./configure. To see them, use:
$ ./configure --help
$ ./configure --help
Configure tries to figure out if the local system uses group "nobody" or
"nogroup" by looking in the /etc/group file. (This is only used for the
@@ -17,7 +17,7 @@ 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,
cut-down copy of release 1.6.4 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.
@@ -25,17 +25,6 @@ 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
---------

View File

@@ -1,65 +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@
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
SIMD_x86_64=simd-checksum-x86_64.o
ASM_x86_64=lib/md5-asm-x86_64.o
GENFILES=configure.sh aclocal.m4 config.h.in proto.h proto.h-tstamp rsync.1 rsync.1.html \
rsync-ssl.1 rsync-ssl.1.html rsyncd.conf.5 rsyncd.conf.5.html
HEADERS=byteorder.h config.h errcode.h proto.h rsync.h ifuncs.h itypes.h inums.h \
lib/pool_alloc.h lib/mdigest.h lib/md-defines.h version.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 \
util.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 \
fileio.o batch.o clientname.o chmod.o acls.o xattrs.o
OBJS3=progress.o pipe.o @ASM@
OBJS3=progress.o pipe.o
DAEMON_OBJ = params.o loadparm.o clientserver.o access.o connection.o authenticate.o
popt_OBJS=popt/findme.o popt/popt.o popt/poptconfig.o \
popt/popthelp.o popt/poptparse.o
OBJS=$(OBJS1) $(OBJS2) $(OBJS3) @SIMD@ $(DAEMON_OBJ) $(LIBOBJ) @BUILD_ZLIB@ @BUILD_POPT@
OBJS=$(OBJS1) $(OBJS2) $(OBJS3) $(DAEMON_OBJ) $(LIBOBJ) $(ZLIBOBJ) @BUILD_POPT@
TLS_OBJ = tls.o syscall.o t_stub.o lib/compat.o lib/snprintf.o lib/permstring.o lib/sysxattrs.o @BUILD_POPT@
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) wildtest$(EXEEXT)
trimslash$(EXEEXT) t_unsafe$(EXEEXT) wildtest$(EXEEXT)
CHECK_SYMLINKS = testsuite/chown-fake.test testsuite/devices-fake.test testsuite/xattrs-hlink.test
CHECK_SYMLINKS = testsuite/chown-fake.test testsuite/devices-fake.test
# Objects for CHECK_PROGS to clean
CHECK_OBJS=tls.o testrun.o getgroups.o getfsdev.o t_stub.o t_unsafe.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:
@@ -67,29 +59,16 @@ CHECK_OBJS=tls.o testrun.o getgroups.o getfsdev.o t_stub.o t_unsafe.o trimslash.
$(CC) -I. -I$(srcdir) $(CFLAGS) $(CPPFLAGS) -c $< @CC_SHOBJ_FLAG@
@OBJ_RESTORE@
.PHONY: all
all: Makefile rsync$(EXEEXT) stunnel-rsyncd.conf @MAKE_MAN@
all: Makefile rsync$(EXEEXT) @MAKE_MAN@
.PHONY: install
install: all
-${MKDIR_P} ${DESTDIR}${bindir}
-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
-mkdir -p ${DESTDIR}${mandir}/man1
-mkdir -p ${DESTDIR}${mandir}/man5
if test -f rsync.1; then ${INSTALLMAN} -m 644 rsync.1 ${DESTDIR}${mandir}/man1; fi
if test -f rsync-ssl.1; then ${INSTALLMAN} -m 644 rsync-ssl.1 ${DESTDIR}${mandir}/man1; fi
if test -f rsyncd.conf.5; then ${INSTALLMAN} -m 644 rsyncd.conf.5 ${DESTDIR}${mandir}/man5; fi
install-ssl-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-client install-ssl-daemon
install-strip:
$(MAKE) INSTALL_STRIP='-s' install
@@ -98,23 +77,10 @@ rsync$(EXEEXT): $(OBJS)
$(OBJS): $(HEADERS)
$(CHECK_OBJS): $(HEADERS)
tls.o xattrs.o: lib/sysxattrs.h
options.o: latest-year.h help-rsync.h help-rsyncd.h
exclude.o: 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; \
@@ -132,46 +98,32 @@ rounding.h: rounding.c rsync.h proto.h
fi
@rm -f rounding.out
simd-checksum-x86_64.o: simd-checksum-x86_64.cpp
@$(srcdir)/cmdormsg disable-simd $(CXX) -I. $(CXXFLAGS) $(CPPFLAGS) -c -o $@ $(srcdir)/simd-checksum-x86_64.cpp
lib/md5-asm-x86_64.o: lib/md5-asm-x86_64.S config.h lib/md-defines.h
@$(srcdir)/cmdormsg disable-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 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 util.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)
.PHONY: conf
conf: configure.sh config.h.in
.PHONY: gen
gen: conf proto.h man
.PHONY: gensend
gensend: gen
rsync -aic $(GENFILES) $${SAMBA_HOST-samba.org}:/home/ftp/pub/rsync/generated-files/
rsync -aivzc $(GENFILES) samba.org:/home/ftp/pub/rsync/generated-files/
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
configure.sh config.h.in: configure.in aclocal.m4
@if test -f configure.sh; then cp -p configure.sh configure.sh.old; else touch configure.sh.old; fi
@if test -f config.h.in; then cp -p config.h.in config.h.in.old; else touch config.h.in.old; fi
autoconf -o configure.sh
@@ -198,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
@@ -222,46 +169,38 @@ 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 config.h 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
perl $(srcdir)/mkproto.pl $(srcdir)/*.c $(srcdir)/lib/compat.c
.PHONY: man
man: rsync.1 rsync-ssl.1 rsyncd.conf.5
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 md2man version.h Makefile
@$(srcdir)/maybe-make-man $(srcdir) rsync.1.md
rsync.1: rsync.yo
yodl2man -o rsync.1 $(srcdir)/rsync.yo
-$(srcdir)/tweak_manpage rsync.1
rsync-ssl.1: rsync-ssl.1.md md2man version.h Makefile
@$(srcdir)/maybe-make-man $(srcdir) rsync-ssl.1.md
rsyncd.conf.5: rsyncd.conf.yo
yodl2man -o rsyncd.conf.5 $(srcdir)/rsyncd.conf.yo
-$(srcdir)/tweak_manpage rsyncd.conf.5
rsyncd.conf.5: rsyncd.conf.5.md md2man version.h Makefile
@$(srcdir)/maybe-make-man $(srcdir) rsyncd.conf.5.md
.PHONY: clean
clean: cleantests
rm -f *~ $(OBJS) $(CHECK_PROGS) $(CHECK_OBJS) $(CHECK_SYMLINKS) \
rounding rounding.h *.old rsync*.1 rsync*.5 rsync*.html
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
rm -f Makefile config.h config.status
rm -f stunnel-rsyncd.conf
rm -f lib/dummy popt/dummy zlib/dummy
rm -f $(srcdir)/Makefile $(srcdir)/config.h $(srcdir)/config.status
rm -f $(srcdir)/lib/dummy $(srcdir)/popt/dummy $(srcdir)/zlib/dummy
@@ -274,14 +213,14 @@ distclean: clean
# this target is really just for my use. It only works on a limited
# range of machines and is used to produce a list of potentially
# dead (ie. unused) functions in the code. (tridge)
.PHONY: finddead
finddead:
nm *.o */*.o |grep 'U ' | awk '{print $$2}' | sort -u > nmused.txt
nm *.o */*.o |grep 'T ' | awk '{print $$3}' | sort -u > nmfns.txt
comm -13 nmused.txt nmfns.txt
# 'check' is the GNU name, 'test' is the name for everybody else :-)
.PHONY: test
.PHONY: check test
test: check
# There seems to be no standard way to specify some variables as
@@ -294,19 +233,13 @@ test: check
# catch Bash-isms earlier even if we're running on GNU. Of course, we
# might lose in the future where POSIX diverges from old sh.
.PHONY: check
check: all $(CHECK_PROGS) $(CHECK_SYMLINKS)
rsync_bin=`pwd`/rsync$(EXEEXT) $(srcdir)/runtests.sh
.PHONY: check29
check29: all $(CHECK_PROGS) $(CHECK_SYMLINKS)
rsync_bin=`pwd`/rsync$(EXEEXT) $(srcdir)/runtests.sh --protocol=29
.PHONY: check30
check30: all $(CHECK_PROGS) $(CHECK_SYMLINKS)
rsync_bin=`pwd`/rsync$(EXEEXT) $(srcdir)/runtests.sh --protocol=30
wildtest.o: wildtest.c 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)
@@ -316,14 +249,10 @@ testsuite/chown-fake.test:
testsuite/devices-fake.test:
ln -s devices.test $(srcdir)/testsuite/devices-fake.test
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)
POSIXLY_CORRECT=1 TOOLDIR=`pwd` rsync_bin="$(bindir)/rsync$(EXEEXT)" srcdir="$(srcdir)" $(srcdir)/runtests.sh
@@ -334,12 +263,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 \
$${SAMBA_HOST-samba.org}:/home/httpd/html/rsync/doxygen/head/
samba.org:/home/httpd/html/rsync/doxygen/head/

55
NEWS Normal file
View File

@@ -0,0 +1,55 @@
NEWS for rsync 3.0.6 (8 May 2009)
Protocol: 30 (unchanged)
Changes since 3.0.5:
BUG FIXES:
- Fixed a --read-batch hang when rsync is reading a batch file that was
created from an incremental-recursion transfer.
- Fixed the daemon's socket code to handle the simultaneous arrival of
multiple connections.
- Fix --safe-links/--copy-unsafe-links to properly handle symlinks that
have consecutive slashes in the value.
- Fixed the parsing of an [IPv6_LITERAL_ADDR] when a USER@ is prefixed.
- The sender now skips a (bogus) symlink that has a 0-length value, which
avoids a transfer error in the receiver.
- Fixed a case where the sender could die with a tag-0 error if there was
an I/O during the sending of the file list.
- Fixed the rrsync script to avoid a server-side problem when -e is at the
start of the short options.
- Fixed a problem where a vanished directory could turn into an exit code
23 instead of the proper exit code 24.
- Fixed the --iconv conversion of symlinks when doing a local copy.
- Fixed a problem where --one-file-system was not stopping deletions on the
receiving side when a mount-point directory did not match a directory in
the transfer.
- Fixed the dropping of an ACL mask when no named ACL values were present.
- Fixed an ACL/xattr corruption issue where the --backup option could cause
rsync to associate the wrong ACL/xattr information with received files.
- Fixed the use of --xattrs with --only-write-batch.
- Fixed the use of --dry-run with --read-batch.
- Fixed configure's erroneous use of target.
- Fixed configure's --disable-debug option.
- Fixed a run-time issue for systems that can't find iconv_open() by adding
the --disable-iconv-open configure option.
- Complain and die if the user tries to combine --remove-source-files (or
the deprecated --remove-sent-files) with --read-batch.
- Fixed an failure transferring special files from Solaris to Linux.

4214
NEWS.md
View File

File diff suppressed because it is too large Load Diff

3031
OLDNEWS Normal file
View File

File diff suppressed because it is too large Load Diff

View File

@@ -65,7 +65,7 @@ WEB SITE
The main rsync web site is here:
> https://rsync.samba.org/
http://rsync.samba.org/
You'll find a FAQ list, downloads, resources, HTML versions of the
manpages, etc.
@@ -80,7 +80,7 @@ list, and there is also an announcement-only mailing list for those that
want official announcements. See the mailing-list page for full
details:
> https://rsync.samba.org/lists.html
http://rsync.samba.org/lists.html
BUG REPORTS
@@ -88,55 +88,53 @@ BUG REPORTS
To visit this web page for full the details on bug reporting:
> https://rsync.samba.org/bugtracking.html
http://rsync.samba.org/bugzilla.html
That page contains links to the current bug list, and information on how
to report a bug well. You might also like to try searching the Internet
for the error message you've received, or looking in the mailing list
archives at:
> 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 .
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 and on samba's site. Feel free to access it here:
source code repository then you can use git:
> https://github.com/WayneD/rsync
A backup git repo is available on the samba site:
> git clone git://git.samba.org/rsync.git
git clone git://git.samba.org/rsync.git
See the download page for full details on all the ways to grab the
source:
source, including nightly tar files, web-browsing of the git repository,
etc.:
> https://rsync.samba.org/download.html
http://rsync.samba.org/download.html
COPYRIGHT
---------
Rsync was originally written by Andrew Tridgell and is currently
maintained by Wayne Davison. It has been improved by many developers
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 in this
distribution, or at:
> https://www.fsf.org/licenses/gpl.html
http://www.fsf.org/licenses/gpl.html
AVAILABILITY
------------
The main web site for rsync is https://rsync.samba.org/
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/

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/
-- --

View File

@@ -2,7 +2,7 @@
* Routines to authenticate access to a daemon (hosts allow/deny).
*
* Copyright (C) 1998 Andrew Tridgell
* Copyright (C) 2004-2020 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,50 +19,15 @@
*/
#include "rsync.h"
#include "ifuncs.h"
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;
/* 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;
@@ -91,7 +56,7 @@ static void make_mask(char *mask, int plen, int addrlen)
return;
}
static int match_address(const char *addr, const char *tok)
static int match_address(char *addr, char *tok)
{
char *p;
struct addrinfo hints, *resa, *rest;
@@ -105,16 +70,24 @@ static int match_address(const char *addr, const 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;
@@ -157,7 +130,8 @@ static int match_address(const char *addr, const char *tok)
break;
#ifdef INET6
case PF_INET6: {
case PF_INET6:
{
struct sockaddr_in6 *sin6a, *sin6t;
sin6a = (struct sockaddr_in6 *)resa->ai_addr;
@@ -169,19 +143,20 @@ static int match_address(const char *addr, const char *tok)
addrlen = 16;
#ifdef HAVE_SOCKADDR_IN6_SCOPE_ID
if (sin6t->sin6_scope_id && sin6a->sin6_scope_id != sin6t->sin6_scope_id) {
if (sin6t->sin6_scope_id &&
sin6a->sin6_scope_id != sin6t->sin6_scope_id) {
ret = 0;
goto out;
}
#endif
break;
}
}
#endif
default:
rprintf(FLOG, "unknown family %u\n", rest->ai_family);
ret = 0;
goto out;
rprintf(FLOG, "unknown family %u\n", rest->ai_family);
ret = 0;
goto out;
}
bits = -1;
@@ -235,15 +210,20 @@ static int match_address(const char *addr, const 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;
}
@@ -253,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)
@@ -276,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
])

198
acls.c
View File

@@ -3,7 +3,7 @@
*
* Copyright (C) 1996 Andrew Tridgell
* Copyright (C) 1996 Paul Mackerras
* Copyright (C) 2006-2020 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
@@ -31,8 +31,6 @@ extern int list_only;
extern int orig_umask;
extern int numeric_ids;
extern int inc_recurse;
extern int preserve_devices;
extern int preserve_specials;
/* Flags used to indicate what items are being transmitted for an entry. */
#define XMIT_USER_OBJ (1<<0)
@@ -48,7 +46,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
@@ -117,11 +115,10 @@ static int calc_sacl_entries(const rsync_acl *racl)
/* A System ACL always gets user/group/other permission entries. */
return racl->names.count
#ifdef ACLS_NEED_MASK
+ 1
+ 4;
#else
+ (racl->mask_obj != NO_ENTRY)
+ (racl->mask_obj != NO_ENTRY) + 3;
#endif
+ 3;
}
/* Extracts and returns the permission bits from the ACL. This cannot be
@@ -135,21 +132,16 @@ static int rsync_acl_get_perms(const rsync_acl *racl)
/* Removes the permission-bit entries from the ACL because these
* can be reconstructed from the file's mode. */
static void rsync_acl_strip_perms(stat_x *sxp)
static void rsync_acl_strip_perms(rsync_acl *racl)
{
rsync_acl *racl = sxp->acc_acl;
racl->user_obj = NO_ENTRY;
if (racl->mask_obj == NO_ENTRY)
racl->group_obj = NO_ENTRY;
else {
int group_perms = (sxp->st.st_mode >> 3) & 7;
if (racl->group_obj == group_perms)
if (racl->group_obj == racl->mask_obj)
racl->group_obj = NO_ENTRY;
#ifndef HAVE_SOLARIS_ACLS
if (racl->names.count != 0 && racl->mask_obj == group_perms)
if (racl->names.count != 0)
racl->mask_obj = NO_ENTRY;
#endif
}
racl->other_obj = NO_ENTRY;
}
@@ -168,6 +160,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 +324,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;
@@ -343,6 +340,15 @@ static BOOL unpack_smb_acl(SMB_ACL_T sacl, rsync_acl *racl)
/* Truncate the temporary list now that its idas have been saved. */
temp_ida_list.count = 0;
#ifdef ACLS_NEED_MASK
if (!racl->names.count && racl->mask_obj != NO_ENTRY) {
/* Throw away a superfluous mask, but mask off the
* group perms with it first. */
racl->group_obj &= racl->mask_obj;
racl->mask_obj = NO_ENTRY;
}
#endif
return True;
}
@@ -418,7 +424,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) );
@@ -490,19 +496,15 @@ static int get_rsync_acl(const char *fname, rsync_acl *racl,
}
racl->user_obj = IVAL(buf, 0);
if (racl->user_obj == NO_ENTRY)
racl->user_obj = (mode >> 6) & 7;
racl->group_obj = IVAL(buf, 4);
if (racl->group_obj == NO_ENTRY)
racl->group_obj = (mode >> 3) & 7;
racl->mask_obj = IVAL(buf, 8);
racl->other_obj = IVAL(buf, 12);
if (racl->other_obj == NO_ENTRY)
racl->other_obj = mode & 7;
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);
@@ -538,24 +540,6 @@ static int get_rsync_acl(const char *fname, rsync_acl *racl,
int get_acl(const char *fname, stat_x *sxp)
{
sxp->acc_acl = create_racl();
if (S_ISREG(sxp->st.st_mode) || S_ISDIR(sxp->st.st_mode)) {
/* Everyone supports this. */
} else if (S_ISLNK(sxp->st.st_mode)) {
return 0;
} else if (IS_SPECIAL(sxp->st.st_mode)) {
#ifndef NO_SPECIAL_ACLS
if (!preserve_specials)
#endif
return 0;
} else if (IS_DEVICE(sxp->st.st_mode)) {
#ifndef NO_DEVICE_ACLS
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) {
free_acl(sxp);
@@ -577,7 +561,7 @@ int get_acl(const char *fname, stat_x *sxp)
/* === Send functions === */
/* Send the ida list over the file descriptor. */
static void send_ida_entries(int f, const ida_entries *idal)
static void send_ida_entries(const ida_entries *idal, int f)
{
id_access *ida;
size_t count = idal->count;
@@ -589,9 +573,9 @@ static void send_ida_entries(int f, const ida_entries *idal)
const char *name;
if (ida->access & NAME_IS_USER) {
xbits |= XFLAG_NAME_IS_USER;
name = numeric_ids ? NULL : add_uid(ida->id);
name = add_uid(ida->id);
} else
name = numeric_ids ? NULL : add_gid(ida->id);
name = add_gid(ida->id);
write_varint(f, ida->id);
if (inc_recurse && name) {
int len = strlen(name);
@@ -603,8 +587,8 @@ static void send_ida_entries(int f, const ida_entries *idal)
}
}
static void send_rsync_acl(int f, rsync_acl *racl, SMB_ACL_TYPE_T type,
item_list *racl_list)
static void send_rsync_acl(rsync_acl *racl, SMB_ACL_TYPE_T type,
item_list *racl_list, int f)
{
int ndx = find_matching_rsync_acl(racl, type, racl_list);
@@ -637,7 +621,7 @@ static void send_rsync_acl(int f, rsync_acl *racl, SMB_ACL_TYPE_T type,
if (flags & XMIT_OTHER_OBJ)
write_varint(f, racl->other_obj);
if (flags & XMIT_NAME_LIST)
send_ida_entries(f, &racl->names);
send_ida_entries(&racl->names, f);
/* Give the allocated data to the new list object. */
*new_racl = *racl;
@@ -647,28 +631,28 @@ static void send_rsync_acl(int f, rsync_acl *racl, SMB_ACL_TYPE_T type,
/* Send the ACL from the stat_x structure down the indicated file descriptor.
* This also frees the ACL data. */
void send_acl(int f, stat_x *sxp)
void send_acl(stat_x *sxp, int f)
{
if (!sxp->acc_acl) {
sxp->acc_acl = create_racl();
rsync_acl_fake_perms(sxp->acc_acl, sxp->st.st_mode);
}
/* Avoid sending values that can be inferred from other data. */
rsync_acl_strip_perms(sxp);
rsync_acl_strip_perms(sxp->acc_acl);
send_rsync_acl(f, sxp->acc_acl, SMB_ACL_TYPE_ACCESS, &access_acl_list);
send_rsync_acl(sxp->acc_acl, SMB_ACL_TYPE_ACCESS, &access_acl_list, f);
if (S_ISDIR(sxp->st.st_mode)) {
if (!sxp->def_acl)
sxp->def_acl = create_racl();
send_rsync_acl(f, sxp->def_acl, SMB_ACL_TYPE_DEFAULT, &default_acl_list);
send_rsync_acl(sxp->def_acl, SMB_ACL_TYPE_DEFAULT, &default_acl_list, f);
}
}
/* === Receive functions === */
static uint32 recv_acl_access(int f, uchar *name_follows_ptr)
static uint32 recv_acl_access(uchar *name_follows_ptr, int f)
{
uint32 access = read_varint(f);
@@ -693,18 +677,23 @@ static uint32 recv_acl_access(int f, uchar *name_follows_ptr)
return access;
}
static uchar recv_ida_entries(int f, ida_entries *ent)
static uchar recv_ida_entries(ida_entries *ent, int f)
{
uchar computed_mask_bits = 0;
int i, count = read_varint(f);
ent->idas = count ? new_array(id_access, count) : NULL;
if (count) {
if (!(ent->idas = new_array(id_access, count)))
out_of_memory("recv_ida_entries");
} else
ent->idas = NULL;
ent->count = count;
for (i = 0; i < count; i++) {
uchar has_name;
id_t id = read_varint(f);
uint32 access = recv_acl_access(f, &has_name);
uint32 access = recv_acl_access(&has_name, f);
if (has_name) {
if (access & NAME_IS_USER)
@@ -727,7 +716,7 @@ static uchar recv_ida_entries(int f, ida_entries *ent)
return computed_mask_bits & ~NO_ENTRY;
}
static int recv_rsync_acl(int f, item_list *racl_list, SMB_ACL_TYPE_T type, mode_t mode)
static int recv_rsync_acl(item_list *racl_list, SMB_ACL_TYPE_T type, int f)
{
uchar computed_mask_bits = 0;
acl_duo *duo_item;
@@ -742,7 +731,7 @@ static int recv_rsync_acl(int f, item_list *racl_list, SMB_ACL_TYPE_T type, mode
if (ndx != 0)
return ndx - 1;
ndx = racl_list->count;
duo_item = EXPAND_ITEM_LIST(racl_list, acl_duo, 1000);
duo_item->racl = empty_rsync_acl;
@@ -750,28 +739,22 @@ static int recv_rsync_acl(int f, item_list *racl_list, SMB_ACL_TYPE_T type, mode
flags = read_byte(f);
if (flags & XMIT_USER_OBJ)
duo_item->racl.user_obj = recv_acl_access(f, NULL);
duo_item->racl.user_obj = recv_acl_access(NULL, f);
if (flags & XMIT_GROUP_OBJ)
duo_item->racl.group_obj = recv_acl_access(f, NULL);
duo_item->racl.group_obj = recv_acl_access(NULL, f);
if (flags & XMIT_MASK_OBJ)
duo_item->racl.mask_obj = recv_acl_access(f, NULL);
duo_item->racl.mask_obj = recv_acl_access(NULL, f);
if (flags & XMIT_OTHER_OBJ)
duo_item->racl.other_obj = recv_acl_access(f, NULL);
duo_item->racl.other_obj = recv_acl_access(NULL, f);
if (flags & XMIT_NAME_LIST)
computed_mask_bits |= recv_ida_entries(f, &duo_item->racl.names);
computed_mask_bits |= recv_ida_entries(&duo_item->racl.names, f);
#ifdef HAVE_OSX_ACLS
/* If we received a superfluous mask, throw it away. */
duo_item->racl.mask_obj = NO_ENTRY;
#else
if (duo_item->racl.names.count && duo_item->racl.mask_obj == NO_ENTRY) {
/* Mask must be non-empty with lists. */
if (type == SMB_ACL_TYPE_ACCESS)
computed_mask_bits = (mode >> 3) & 7;
else
computed_mask_bits |= duo_item->racl.group_obj & ~NO_ENTRY;
duo_item->racl.mask_obj = computed_mask_bits;
}
if (duo_item->racl.names.count && duo_item->racl.mask_obj == NO_ENTRY) /* Must be non-empty with lists. */
duo_item->racl.mask_obj = (computed_mask_bits | duo_item->racl.group_obj) & ~NO_ENTRY;
#endif
duo_item->sacl = NULL;
@@ -780,12 +763,12 @@ static int recv_rsync_acl(int f, item_list *racl_list, SMB_ACL_TYPE_T type, mode
}
/* Receive the ACL info the sender has included for this file-list entry. */
void receive_acl(int f, struct file_struct *file)
void receive_acl(struct file_struct *file, int f)
{
F_ACL(file) = recv_rsync_acl(f, &access_acl_list, SMB_ACL_TYPE_ACCESS, file->mode);
F_ACL(file) = recv_rsync_acl(&access_acl_list, SMB_ACL_TYPE_ACCESS, f);
if (S_ISDIR(file->mode))
F_DIR_DEFACL(file) = recv_rsync_acl(f, &default_acl_list, SMB_ACL_TYPE_DEFAULT, 0);
F_DIR_DEFACL(file) = recv_rsync_acl(&default_acl_list, SMB_ACL_TYPE_DEFAULT, f);
}
static int cache_rsync_acl(rsync_acl *racl, SMB_ACL_TYPE_T type, item_list *racl_list)
@@ -813,12 +796,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);
}
}
@@ -895,14 +880,12 @@ static mode_t change_sacl_perms(SMB_ACL_T sacl, rsync_acl *racl, mode_t old_mode
COE2( store_access_in_entry,((mode >> 3) & 7, entry) );
break;
case SMB_ACL_MASK:
#ifndef HAVE_SOLARIS_ACLS
#ifndef ACLS_NEED_MASK
/* mask is only empty when we don't need it. */
if (racl->mask_obj == NO_ENTRY)
break;
#endif
COE2( store_access_in_entry,((mode >> 3) & 7, entry) );
#endif
break;
case SMB_ACL_OTHER:
COE2( store_access_in_entry,(mode & 7, entry) );
@@ -915,7 +898,7 @@ static mode_t change_sacl_perms(SMB_ACL_T sacl, rsync_acl *racl, mode_t old_mode
rsyserr(FERROR_XFER, errno, "change_sacl_perms: %s()",
errfun);
}
return (mode_t)-1;
return (mode_t)~0;
}
#ifdef SMB_ACL_LOSES_SPECIAL_MODE_BITS
@@ -982,8 +965,9 @@ static int set_rsync_acl(const char *fname, acl_duo *duo_item,
mode = 0; /* eliminate compiler warning */
#else
if (type == SMB_ACL_TYPE_ACCESS) {
cur_mode = change_sacl_perms(duo_item->sacl, &duo_item->racl, cur_mode, mode);
if (cur_mode == (mode_t)-1)
cur_mode = change_sacl_perms(duo_item->sacl, &duo_item->racl,
cur_mode, mode);
if (cur_mode == (mode_t)~0)
return 0;
}
#endif
@@ -999,17 +983,17 @@ static int set_rsync_acl(const char *fname, acl_duo *duo_item,
return 0;
}
/* Given a fname, this sets extended access ACL entries, the default ACL (for a
* dir), and the regular mode bits on the file. Call this with fname set to
* NULL to just check if the ACL is different.
/* Set ACL on indicated filename.
*
* If the ACL operation has a side-effect of changing the file's mode, the
* sxp->st.st_mode value will be changed to match.
* This sets extended access ACL entries and default ACL. If convenient,
* it sets permission bits along with the access ACL and signals having
* done so by modifying sxp->st.st_mode.
*
* Returns 0 for an unchanged ACL, 1 for changed, -1 for failed. */
int set_acl(const char *fname, const struct file_struct *file, stat_x *sxp, mode_t new_mode)
* Returns 1 for unchanged, 0 for changed, -1 for failed. Call this
* with fname set to NULL to just check if the ACL is unchanged. */
int set_acl(const char *fname, const struct file_struct *file, stat_x *sxp)
{
int changed = 0;
int unchanged = 1;
int32 ndx;
BOOL eq;
@@ -1023,18 +1007,18 @@ int set_acl(const char *fname, const struct file_struct *file, stat_x *sxp, mode
acl_duo *duo_item = access_acl_list.items;
duo_item += ndx;
eq = sxp->acc_acl
&& rsync_acl_equal_enough(sxp->acc_acl, &duo_item->racl, new_mode);
&& rsync_acl_equal_enough(sxp->acc_acl, &duo_item->racl, file->mode);
if (!eq) {
changed = 1;
unchanged = 0;
if (!dry_run && fname
&& set_rsync_acl(fname, duo_item, SMB_ACL_TYPE_ACCESS,
sxp, new_mode) < 0)
return -1;
sxp, file->mode) < 0)
unchanged = -1;
}
}
if (!S_ISDIR(new_mode))
return changed;
if (!S_ISDIR(sxp->st.st_mode))
return unchanged;
ndx = F_DIR_DEFACL(file);
if (ndx >= 0 && (size_t)ndx < default_acl_list.count) {
@@ -1042,15 +1026,16 @@ int set_acl(const char *fname, const struct file_struct *file, stat_x *sxp, mode
duo_item += ndx;
eq = sxp->def_acl && rsync_acl_equal(sxp->def_acl, &duo_item->racl);
if (!eq) {
changed = 1;
if (unchanged > 0)
unchanged = 0;
if (!dry_run && fname
&& set_rsync_acl(fname, duo_item, SMB_ACL_TYPE_DEFAULT,
sxp, new_mode) < 0)
return -1;
sxp, file->mode) < 0)
unchanged = -1;
}
}
return changed;
return unchanged;
}
/* Non-incremental recursion needs to convert all the received IDs.
@@ -1093,21 +1078,20 @@ int default_perms_for_dir(const char *dir)
if (sacl == NULL) {
/* Couldn't get an ACL. Darn. */
switch (errno) {
case EINVAL:
/* If SMB_ACL_TYPE_DEFAULT isn't valid, then the ACLs must be non-POSIX. */
break;
#ifdef ENOTSUP
case ENOTSUP:
#endif
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));
@@ -1127,7 +1111,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-2020 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,10 +19,7 @@
*/
#include "rsync.h"
#include "itypes.h"
#include "ifuncs.h"
extern int read_only;
extern char *password_file;
/***************************************************************************
@@ -72,48 +69,32 @@ static void gen_challenge(const char *addr, char *challenge)
SIVAL(input, 20, tv.tv_usec);
SIVAL(input, 24, getpid());
sum_init(-1, 0);
sum_init(0);
sum_update(input, sizeof input);
len = sum_end(digest);
base64_encode(digest, len, challenge, 0);
}
/* 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)
{
char buf[MAX_DIGEST_LEN];
int len;
sum_init(-1, 0);
sum_update(in, strlen(in));
sum_update(challenge, strlen(challenge));
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)
static int get_secret(int module, const char *user, char *secret, int len)
{
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;
int fd, ok = 1;
const char *p;
char ch, *s;
if (!fname || !*fname || (fh = fopen(fname, "r")) == NULL)
return "no secrets file";
if (!fname || !*fname)
return 0;
if (do_fstat(fileno(fh), &st) == -1) {
rsyserr(FLOG, errno, "fstat(%s)", fname);
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) {
@@ -125,94 +106,112 @@ static const char *check_secret(int module, const char *user, const char *group,
}
}
if (!ok) {
fclose(fh);
return "ignoring secrets file";
rprintf(FLOG, "continuing without secrets file\n");
close(fd);
return 0;
}
if (*user == '#') {
/* Reject attempt to match a comment. */
fclose(fh);
return "invalid username";
close(fd);
return 0;
}
/* 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;
/* 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 (!*ptr || strncmp(s, *ptr, len) != 0 || s[len] != ':')
continue;
generate_hash(s+len+1, challenge, pass2);
if (strcmp(pass, pass2) == 0) {
err = NULL;
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;
}
err = "password mismatch";
*ptr = NULL; /* Don't look for name again. */
if (*s == '\r')
continue;
s++;
len--;
}
*s = '\0';
close(fd);
fclose(fh);
force_memzero(line, sizeof line);
force_memzero(pass2, sizeof pass2);
return err;
return 1;
}
static const char *getpassf(const char *filename)
{
STRUCT_STAT st;
char buffer[512], *p;
int n;
int fd, n, ok = 1;
const char *envpw = getenv("RSYNC_PASSWORD");
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() == 0 && st.st_uid != 0) {
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 ((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);
}
rprintf(FERROR, "ERROR: failed to read a password from %s\n", filename);
exit_cleanup(RERR_SYNTAX);
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)
{
char buf[MAX_DIGEST_LEN];
int len;
sum_init(0);
sum_update(in, strlen(in));
sum_update(challenge, strlen(challenge));
len = sum_end(buf);
base64_encode(buf, len, out, 0);
}
/* Possibly negotiate authentication with the client. Use "leader" to
@@ -227,12 +226,9 @@ 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];
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)
@@ -242,7 +238,7 @@ char *auth_server(int f_in, int f_out, int module, const char *host,
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",
@@ -251,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(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 {
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(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);
}
@@ -356,12 +298,12 @@ void auth_client(int fd, const char *user, const char *challenge)
/* XXX: cyeoh says that getpass is deprecated, because
* it may return a truncated password on some systems,
* and it is not in the LSB.
*
* Andrew Klein says that getpassphrase() is present
* on Solaris and reads up to 256 characters.
*
* OpenBSD has a readpassphrase() that might be more suitable.
*/
*
* Andrew Klein says that getpassphrase() is present
* on Solaris and reads up to 256 characters.
*
* OpenBSD has a readpassphrase() that might be more suitable.
*/
pass = getpass("Password: ");
}

510
backup.c
View File

@@ -2,7 +2,7 @@
* Backup handling code.
*
* Copyright (C) 1999 Andrew Tridgell
* 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
@@ -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(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(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(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(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(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,34 +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(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)) {
rprintf(FINFO, "not backing up unsafe symlink \"%s\" -> \"%s\"\n",
fname, sl);
if (verbose) {
rprintf(FINFO, "ignoring unsafe symlink %s -> %s\n",
full_fname(buf), sl);
}
ret = 2;
kept = 1;
} else {
if (do_symlink(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)) {
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();
@@ -312,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();
@@ -347,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);
}

167
batch.c
View File

@@ -3,7 +3,7 @@
*
* Copyright (C) 1999 Weiss
* Copyright (C) 2004 Chris Shoemaker
* Copyright (C) 2004-2020 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;
@@ -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-2020 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
@@ -22,7 +22,7 @@
/* 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
@@ -32,101 +32,21 @@
#define CVAL(buf,pos) (((unsigned char *)(buf))[pos])
#define UVAL(buf,pos) ((uint32)CVAL(buf,pos))
#define SCVAL(buf,pos,val) (CVAL(buf,pos) = (val))
#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;
}
static inline void
SIVALu(uchar *buf, int pos, uint32 val)
{
CVAL(buf, pos) = val;
CVAL(buf, pos + 1) = val >> 8;
CVAL(buf, pos + 2) = val >> 16;
CVAL(buf, pos + 3) = val >> 24;
}
static inline int64
IVAL64(const char *buf, int pos)
{
return IVALu((uchar*)buf, pos) | (int64)IVALu((uchar*)buf, pos + 4) << 32;
}
static inline void
SIVAL64(char *buf, int pos, int64 val)
{
SIVALu((uchar*)buf, pos, val);
SIVALu((uchar*)buf, pos + 4, val >> 32);
}
#else /* !CAREFUL_ALIGNMENT */
/* This handles things for architectures like the 386 that can handle alignment errors.
* 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. */
static inline uint32
IVALu(const uchar *buf, int pos)
{
union {
const uchar *b;
const uint32 *num;
} u;
u.b = buf + pos;
return *u.num;
}
static inline void
SIVALu(uchar *buf, int pos, uint32 val)
{
union {
uchar *b;
uint32 *num;
} u;
u.b = buf + pos;
*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)
{
return IVALu((uchar*)buf, pos);
}
static inline void
SIVAL(char *buf, int pos, uint32 val)
{
SIVALu((uchar*)buf, pos, val);
}
#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)))
#else
/* this handles things for architectures like the 386 that can handle
alignment errors */
/*
WARNING: This section is dependent on the length of int32
being correct. set CAREFUL_ALIGNMENT if it is not.
*/
#define IVAL(buf,pos) (*(uint32 *)((char *)(buf) + (pos)))
#define SIVAL(buf,pos,val) IVAL(buf,pos)=((uint32)(val))
#endif

View File

@@ -1,7 +1,7 @@
/*
* Allow an arbitrary sequence of case labels.
* End-of-run cleanup helper code used by cleanup.c.
*
* Copyright (C) 2006-2020 Wayne Davison
* Copyright (C) 2006-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
@@ -17,76 +17,63 @@
* 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 produces the next "case N:" statement in sequence. */
/* This is included by cleanup.c multiple times, once for every segement in
* the _exit_cleanup() code. This produces the next "case N:" statement in
* sequence and increments the cleanup_step variable by 1. This ensures that
* our case statements never get out of whack due to added/removed steps. */
#if !defined CASE_N_STATE_0
#define CASE_N_STATE_0
#if !defined EXIT_CLEANUP_CASE_0
#define EXIT_CLEANUP_CASE_0
case 0:
#elif !defined CASE_N_STATE_1
#define CASE_N_STATE_1
/* FALLTHROUGH */
#elif !defined EXIT_CLEANUP_CASE_1
#define EXIT_CLEANUP_CASE_1
case 1:
#elif !defined CASE_N_STATE_2
#define CASE_N_STATE_2
/* FALLTHROUGH */
#elif !defined EXIT_CLEANUP_CASE_2
#define EXIT_CLEANUP_CASE_2
case 2:
#elif !defined CASE_N_STATE_3
#define CASE_N_STATE_3
/* FALLTHROUGH */
#elif !defined EXIT_CLEANUP_CASE_3
#define EXIT_CLEANUP_CASE_3
case 3:
#elif !defined CASE_N_STATE_4
#define CASE_N_STATE_4
/* FALLTHROUGH */
#elif !defined EXIT_CLEANUP_CASE_4
#define EXIT_CLEANUP_CASE_4
case 4:
#elif !defined CASE_N_STATE_5
#define CASE_N_STATE_5
/* FALLTHROUGH */
#elif !defined EXIT_CLEANUP_CASE_5
#define EXIT_CLEANUP_CASE_5
case 5:
#elif !defined CASE_N_STATE_6
#define CASE_N_STATE_6
/* FALLTHROUGH */
#elif !defined EXIT_CLEANUP_CASE_6
#define EXIT_CLEANUP_CASE_6
case 6:
#elif !defined CASE_N_STATE_7
#define CASE_N_STATE_7
/* FALLTHROUGH */
#elif !defined EXIT_CLEANUP_CASE_7
#define EXIT_CLEANUP_CASE_7
case 7:
#elif !defined CASE_N_STATE_8
#define CASE_N_STATE_8
/* FALLTHROUGH */
#elif !defined EXIT_CLEANUP_CASE_8
#define EXIT_CLEANUP_CASE_8
case 8:
#elif !defined CASE_N_STATE_9
#define CASE_N_STATE_9
/* FALLTHROUGH */
#elif !defined EXIT_CLEANUP_CASE_9
#define EXIT_CLEANUP_CASE_9
case 9:
#elif !defined CASE_N_STATE_10
#define CASE_N_STATE_10
/* FALLTHROUGH */
#elif !defined EXIT_CLEANUP_CASE_10
#define EXIT_CLEANUP_CASE_10
case 10:
#elif !defined CASE_N_STATE_11
#define CASE_N_STATE_11
/* FALLTHROUGH */
#elif !defined EXIT_CLEANUP_CASE_11
#define EXIT_CLEANUP_CASE_11
case 11:
#elif !defined CASE_N_STATE_12
#define CASE_N_STATE_12
/* FALLTHROUGH */
#elif !defined EXIT_CLEANUP_CASE_12
#define EXIT_CLEANUP_CASE_12
case 12:
#elif !defined CASE_N_STATE_13
#define CASE_N_STATE_13
/* FALLTHROUGH */
#elif !defined EXIT_CLEANUP_CASE_13
#define EXIT_CLEANUP_CASE_13
case 13:
#elif !defined CASE_N_STATE_14
#define CASE_N_STATE_14
/* FALLTHROUGH */
#elif !defined EXIT_CLEANUP_CASE_14
#define EXIT_CLEANUP_CASE_14
case 14:
#elif !defined CASE_N_STATE_15
#define CASE_N_STATE_15
/* FALLTHROUGH */
#elif !defined EXIT_CLEANUP_CASE_15
#define EXIT_CLEANUP_CASE_15
case 15:
#elif !defined CASE_N_STATE_16
#define CASE_N_STATE_16
/* FALLTHROUGH */
#elif !defined EXIT_CLEANUP_CASE_16
#define EXIT_CLEANUP_CASE_16
case 16:
#else
#error Need to add more case statements!
#endif
cleanup_step++;

View File

@@ -3,20 +3,13 @@
*
* Copyright (C) 1996 Andrew Tridgell
* Copyright (C) 1996 Paul Mackerras
* Copyright (C) 2004-2020 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,238 +21,48 @@
#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;
struct name_num_obj valid_checksums = {
"checksum", NULL, NULL, 0, 0, {
#ifdef SUPPORT_XXH3
{ CSUM_XXH3_128, "xxh128", NULL },
{ CSUM_XXH3_64, "xxh3", NULL },
#endif
#ifdef SUPPORT_XXHASH
{ CSUM_XXH64, "xxh64", NULL },
{ CSUM_XXH64, "xxhash", NULL },
#endif
{ CSUM_MD5, "md5", NULL },
{ CSUM_MD4, "md4", NULL },
{ CSUM_NONE, "none", NULL },
{ 0, NULL, NULL }
}
};
int csum_length = SHORT_SUM_LENGTH; /* initial value */
int xfersum_type = 0; /* used for the file transfer checksums */
int checksum_type = 0; /* used for the pre-transfer (--checksum) checksums */
int parse_csum_name(const char *name, int len)
{
struct name_num_item *nni;
if (len < 0 && name)
len = strlen(name);
if (!name || (len == 4 && strncasecmp(name, "auto", 4) == 0)) {
if (protocol_version >= 30)
return CSUM_MD5;
if (protocol_version >= 27)
return CSUM_MD4_OLD;
if (protocol_version >= 21)
return CSUM_MD4_BUSTED;
return CSUM_MD4_ARCHAIC;
}
nni = get_nni_by_name(&valid_checksums, name, len);
if (!nni) {
rprintf(FERROR, "unknown checksum name: %s\n", name);
exit_cleanup(RERR_UNSUPPORTED);
}
return nni->num;
}
static const char *checksum_name(int num)
{
struct name_num_item *nni = get_nni_by_num(&valid_checksums, num);
return nni ? nni->name : num < CSUM_MD4 ? "md4" : "UNKNOWN";
}
void parse_checksum_choice(int final_call)
{
if (valid_checksums.negotiated_name)
xfersum_type = checksum_type = valid_checksums.negotiated_num;
else {
char *cp = checksum_choice ? strchr(checksum_choice, ',') : NULL;
if (cp) {
xfersum_type = parse_csum_name(checksum_choice, cp - checksum_choice);
checksum_type = parse_csum_name(cp+1, -1);
} else
xfersum_type = checksum_type = parse_csum_name(checksum_choice, -1);
if (am_server && checksum_choice)
validate_choice_vs_env(NSTR_CHECKSUM, xfersum_type, checksum_type);
}
if (xfersum_type == CSUM_NONE)
whole_file = 1;
/* Snag the checksum name for both write_batch's option output & the following debug output. */
if (valid_checksums.negotiated_name)
checksum_choice = valid_checksums.negotiated_name;
else if (checksum_choice == NULL)
checksum_choice = checksum_name(xfersum_type);
if (final_call && DEBUG_GTE(NSTR, am_server ? 3 : 1)) {
rprintf(FINFO, "%s%s checksum: %s\n",
am_server ? "Server" : "Client",
valid_checksums.negotiated_name ? " negotiated" : "",
checksum_choice);
}
}
int csum_len_for_type(int cst, BOOL flist_csum)
{
switch (cst) {
case CSUM_NONE:
return 1;
case CSUM_MD4_ARCHAIC:
/* The oldest checksum code is rather weird: the file-list code only sent
* 2-byte checksums, but all other checksums were full MD4 length. */
return flist_csum ? 2 : MD4_DIGEST_LEN;
case CSUM_MD4:
case CSUM_MD4_OLD:
case CSUM_MD4_BUSTED:
return MD4_DIGEST_LEN;
case CSUM_MD5:
return MD5_DIGEST_LEN;
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:
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 HAVE_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
void get_checksum2(char *buf, int32 len, char *sum)
{
switch (xfersum_type) {
#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: {
MD5_CTX m5;
md_context m;
if (protocol_version >= 30) {
uchar seedbuf[4];
MD5_Init(&m5);
if (proper_seed_order) {
if (checksum_seed) {
SIVALu(seedbuf, 0, checksum_seed);
MD5_Update(&m5, seedbuf, 4);
}
MD5_Update(&m5, (uchar *)buf, len);
} else {
MD5_Update(&m5, (uchar *)buf, len);
if (checksum_seed) {
SIVALu(seedbuf, 0, checksum_seed);
MD5_Update(&m5, seedbuf, 4);
}
}
MD5_Final((uchar *)sum, &m5);
break;
}
case CSUM_MD4:
#ifdef USE_OPENSSL
{
MD4_CTX m4;
MD4_Init(&m4);
MD4_Update(&m4, (uchar *)buf, len);
md5_begin(&m);
md5_update(&m, (uchar *)buf, len);
if (checksum_seed) {
uchar seedbuf[4];
SIVALu(seedbuf, 0, checksum_seed);
MD4_Update(&m4, seedbuf, 4);
SIVAL(seedbuf, 0, checksum_seed);
md5_update(&m, seedbuf, 4);
}
MD4_Final((uchar *)sum, &m4);
break;
}
#endif
case CSUM_MD4_OLD:
case CSUM_MD4_BUSTED:
case CSUM_MD4_ARCHAIC: {
md_context m;
md5_result(&m, (uchar *)sum);
} else {
int32 i;
static char *buf1;
static int32 len1;
@@ -271,6 +74,8 @@ void get_checksum2(char *buf, int32 len, char *sum)
free(buf1);
buf1 = new_array(char, len+4);
len1 = len;
if (!buf1)
out_of_memory("get_checksum2");
}
memcpy(buf1, buf, len);
@@ -288,21 +93,18 @@ 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 || xfersum_type > 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;
@@ -312,125 +114,38 @@ void file_checksum(const char *fname, const STRUCT_STAT *st_p, char *sum)
if (fd == -1)
return;
buf = map_file(fd, len, MAX_MAP_SIZE, CHUNK_SIZE);
buf = map_file(fd, size, MAX_MAP_SIZE, CSUM_CHUNK);
switch (checksum_type) {
#ifdef SUPPORT_XXHASH
case CSUM_XXH64: {
static XXH64_state_t* state = NULL;
if (!state && !(state = XXH64_createState()))
out_of_memory("file_checksum");
if (protocol_version >= 30) {
md5_begin(&m);
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);
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)
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: {
MD5_CTX m5;
MD5_Init(&m5);
for (i = 0; i + CHUNK_SIZE <= len; i += CHUNK_SIZE)
MD5_Update(&m5, (uchar *)map_ptr(buf, i, CHUNK_SIZE), CHUNK_SIZE);
remainder = (int32)(len - i);
if (remainder > 0)
MD5_Update(&m5, (uchar *)map_ptr(buf, i, remainder), remainder);
MD5_Final((uchar *)sum, &m5);
break;
}
case CSUM_MD4:
#ifdef USE_OPENSSL
{
MD4_CTX m4;
MD4_Init(&m4);
for (i = 0; i + CHUNK_SIZE <= len; i += CHUNK_SIZE)
MD4_Update(&m4, (uchar *)map_ptr(buf, i, CHUNK_SIZE), CHUNK_SIZE);
remainder = (int32)(len - i);
if (remainder > 0)
MD4_Update(&m4, (uchar *)map_ptr(buf, i, remainder), remainder);
MD4_Final((uchar *)sum, &m4);
break;
}
#endif
case CSUM_MD4_OLD:
case CSUM_MD4_BUSTED:
case CSUM_MD4_ARCHAIC: {
md_context m;
md5_update(&m, (uchar *)map_ptr(buf, i, remainder), remainder);
md5_result(&m, (uchar *)sum);
} else {
mdfour_begin(&m);
for (i = 0; i + CHUNK_SIZE <= len; i += CHUNK_SIZE)
mdfour_update(&m, (uchar *)map_ptr(buf, i, CHUNK_SIZE), CHUNK_SIZE);
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 || checksum_type > 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",
checksum_name(checksum_type), checksum_type);
exit_cleanup(RERR_UNSUPPORTED);
}
close(fd);
@@ -438,72 +153,19 @@ void file_checksum(const char *fname, const STRUCT_STAT *st_p, char *sum)
}
static int32 sumresidue;
static union {
md_context md;
#ifdef USE_OPENSSL
MD4_CTX m4;
#endif
MD5_CTX m5;
} ctx;
#ifdef SUPPORT_XXHASH
static XXH64_state_t* xxh64_state;
#endif
#ifdef SUPPORT_XXH3
static XXH3_state_t* xxh3_state;
#endif
static int cursum_type;
static md_context md;
void sum_init(int csum_type, int seed)
void sum_init(int seed)
{
char s[4];
if (csum_type < 0)
csum_type = parse_csum_name(NULL, 0);
cursum_type = csum_type;
switch (csum_type) {
#ifdef SUPPORT_XXHASH
case CSUM_XXH64:
if (!xxh64_state && !(xxh64_state = XXH64_createState()))
out_of_memory("sum_init");
XXH64_reset(xxh64_state, 0);
break;
#endif
#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_Init(&ctx.m5);
break;
case CSUM_MD4:
#ifdef USE_OPENSSL
MD4_Init(&ctx.m4);
#else
mdfour_begin(&ctx.md);
sumresidue = 0;
#endif
break;
case CSUM_MD4_OLD:
case CSUM_MD4_BUSTED:
case CSUM_MD4_ARCHAIC:
mdfour_begin(&ctx.md);
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);
}
}
@@ -517,109 +179,47 @@ void sum_init(int csum_type, int seed)
**/
void sum_update(const char *p, int32 len)
{
switch (cursum_type) {
#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.m5, (uchar *)p, len);
break;
case CSUM_MD4:
#ifdef USE_OPENSSL
MD4_Update(&ctx.m4, (uchar *)p, len);
break;
#endif
case CSUM_MD4_OLD:
case CSUM_MD4_BUSTED:
case CSUM_MD4_ARCHAIC:
if (len + sumresidue < CSUM_CHUNK) {
memcpy(ctx.md.buffer + sumresidue, p, len);
sumresidue += len;
break;
}
if (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);
if (protocol_version >= 30) {
md5_update(&md, (uchar *)p, len);
return;
}
if (len + sumresidue < CSUM_CHUNK) {
memcpy(md.buffer + sumresidue, p, len);
sumresidue += len;
return;
}
if (sumresidue) {
int32 i = CSUM_CHUNK - sumresidue;
memcpy(md.buffer + sumresidue, p, i);
mdfour_update(&md, (uchar *)md.buffer, CSUM_CHUNK);
len -= i;
p += i;
}
while (len >= CSUM_CHUNK) {
mdfour_update(&md, (uchar *)p, CSUM_CHUNK);
len -= CSUM_CHUNK;
p += CSUM_CHUNK;
}
sumresidue = len;
if (sumresidue)
memcpy(md.buffer, p, sumresidue);
}
/* NOTE: all the callers of sum_end() pass in a pointer to a buffer that is
* MAX_DIGEST_LEN in size, so even if the csum-len is shorter that that (i.e.
* CSUM_MD4_ARCHAIC), we don't have to worry about limiting the data we write
* into the "sum" buffer. */
int sum_end(char *sum)
{
switch (cursum_type) {
#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_Final((uchar *)sum, &ctx.m5);
break;
case CSUM_MD4:
#ifdef USE_OPENSSL
MD4_Final((uchar *)sum, &ctx.m4);
break;
#endif
case CSUM_MD4_OLD:
mdfour_update(&ctx.md, (uchar *)ctx.md.buffer, sumresidue);
mdfour_result(&ctx.md, (uchar *)sum);
break;
case CSUM_MD4_BUSTED:
case CSUM_MD4_ARCHAIC:
if (sumresidue)
mdfour_update(&ctx.md, (uchar *)ctx.md.buffer, sumresidue);
mdfour_result(&ctx.md, (uchar *)sum);
break;
case CSUM_NONE:
*sum = '\0';
break;
default: /* paranoia to prevent missing case values */
exit_cleanup(RERR_UNSUPPORTED);
if (protocol_version >= 30) {
md5_result(&md, (uchar *)sum);
return MD5_DIGEST_LEN;
}
return csum_len_for_type(cursum_type, 0);
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++;
}

159
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,14 @@
#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 +81,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;
@@ -102,104 +93,75 @@ pid_t cleanup_child_pid = -1;
**/
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 cleanup_step = 0;
static int exit_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 error code when recursing. */
code = exit_code;
/* If this is the exit at the end of the run, the server side
* should not attempt to output a message (see log_exit()). */
* should not attempt to output a message (see log.c). */
if (am_server && code == 0)
am_server = 2;
/* Some of our actions might cause a recursive call back here, so we
* keep track of where we are in the cleanup and never repeat a step. */
switch (switch_step) {
#include "case_N.h" /* case 0: */
switch_step++;
switch (cleanup_step) {
#include "case_N.h" /* case 0: cleanup_step++; */
first_code = code;
exit_code = unmodified_code = code;
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, file, line);
"_exit_cleanup(code=%d, file=%s, line=%d): entered\n",
code, file, line);
}
/* FALLTHROUGH */
#include "case_N.h"
switch_step++;
if (cleanup_child_pid != -1) {
int status;
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)
io_flush(FULL_FLUSH);
io_flush(FULL_FLUSH);
/* FALLTHROUGH */
#include "case_N.h"
switch_step++;
if (cleanup_fname)
do_unlink(cleanup_fname);
if (exit_code)
if (code)
kill_all(SIGUSR1);
if (cleanup_pid && cleanup_pid == getpid()) {
char *pidf = lp_pid_file();
@@ -207,64 +169,32 @@ 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)))) {
#ifdef HAVE_USLEEP /* A tiny delay just in case both sender & receiver are sending a msg at the same time. */
if (am_server && exit_code)
usleep(50);
#endif
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)" : "");
"_exit_cleanup(code=%d, file=%s, line=%d): "
"about to call exit(%d)\n",
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();
@@ -273,15 +203,12 @@ NORETURN void _exit_cleanup(int code, const char *file, int line)
break;
}
if (called_from_signal_handler)
_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-2020 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);
/* 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))
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,216 +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:
assert(0);
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 an proxy protocol header (V1 or V2). Returns 1 on success or 0 on failure. */
int read_proxy_protocol_header(int fd)
{
union {
struct {
char line[108];
} v1;
struct {
char sig[PROXY_V2_SIG_SIZE];
char ver_cmd;
char fam;
char len[2];
union {
struct {
char src_addr[4];
char dst_addr[4];
char src_port[2];
char dst_port[2];
} ip4;
struct {
char src_addr[16];
char dst_addr[16];
char src_port[2];
char dst_port[2];
} ip6;
struct {
char src_addr[108];
char dst_addr[108];
} unx;
} addr;
} v2;
} hdr;
read_buf(fd, (char*)&hdr, PROXY_V2_SIG_SIZE);
if (memcmp(hdr.v2.sig, proxyv2sig, PROXY_V2_SIG_SIZE) == 0) { /* Proxy V2 */
int ver, cmd, size;
read_buf(fd, (char*)&hdr + PROXY_V2_SIG_SIZE, PROXY_V2_HEADER_SIZE - PROXY_V2_SIG_SIZE);
ver = (hdr.v2.ver_cmd & 0xf0) >> 4;
cmd = (hdr.v2.ver_cmd & 0x0f);
size = (hdr.v2.len[0] << 8) + hdr.v2.len[1];
if (ver != 2 || size + PROXY_V2_HEADER_SIZE > (int)sizeof hdr)
return 0;
/* Grab all the remaining data in the binary request. */
read_buf(fd, (char*)&hdr + PROXY_V2_HEADER_SIZE, size);
switch (cmd) {
case CMD_PROXY:
switch (hdr.v2.fam) {
case PROXY_FAM_TCPv4:
if (size != sizeof hdr.v2.addr.ip4)
return 0;
inet_ntop(AF_INET, hdr.v2.addr.ip4.src_addr, ipaddr_buf, sizeof ipaddr_buf);
return valid_ipaddr(ipaddr_buf);
case PROXY_FAM_TCPv6:
if (size != sizeof hdr.v2.addr.ip6)
return 0;
inet_ntop(AF_INET6, hdr.v2.addr.ip6.src_addr, ipaddr_buf, sizeof ipaddr_buf);
return valid_ipaddr(ipaddr_buf);
default:
break;
}
/* For an unsupported protocol we'll ignore the proxy data (leaving ipaddr_buf unset)
* and accept the connection, which will get handled as a normal socket addr. */
return 1;
case CMD_LOCAL:
return 1;
default:
break;
}
return 0;
}
if (memcmp(hdr.v1.line, "PROXY", 5) == 0) { /* Proxy V1 */
char *endc, *sp, *p = hdr.v1.line + PROXY_V2_SIG_SIZE;
int port_chk;
*p = '\0';
if (!strchr(hdr.v1.line, '\n')) {
while (1) {
read_buf(fd, p, 1);
if (*p++ == '\n')
break;
if (p - hdr.v1.line >= (int)sizeof hdr.v1.line - 1)
return 0;
}
*p = '\0';
}
endc = strchr(hdr.v1.line, '\r');
if (!endc || endc[1] != '\n' || endc[2])
return 0;
*endc = '\0';
p = hdr.v1.line + 5;
if (!isSpace(p++))
return 0;
if (strncmp(p, "TCP4", 4) == 0)
p += 4;
else if (strncmp(p, "TCP6", 4) == 0)
p += 4;
else if (strncmp(p, "UNKNOWN", 7) == 0)
return 1;
else
return 0;
if (!isSpace(p++))
return 0;
if ((sp = strchr(p, ' ')) == NULL)
return 0;
*sp = '\0';
if (!valid_ipaddr(p))
return 0;
strlcpy(ipaddr_buf, p, sizeof ipaddr_buf); /* It will always fit when valid. */
p = sp + 1;
if ((sp = strchr(p, ' ')) == NULL)
return 0;
*sp = '\0';
if (!valid_ipaddr(p))
return 0;
/* Ignore destination address. */
p = sp + 1;
if ((sp = strchr(p, ' ')) == NULL)
return 0;
*sp = '\0';
port_chk = strtol(p, &endc, 10);
if (*endc || port_chk == 0)
return 0;
/* Ignore source port. */
p = sp + 1;
port_chk = strtol(p, &endc, 10);
if (*endc || port_chk == 0)
return 0;
/* Ignore destination port. */
return 1;
}
return 0;
}
/**
* Get the sockaddr for the client.
@@ -314,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);
@@ -325,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
@@ -349,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) {
@@ -378,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
@@ -388,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
@@ -420,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;
@@ -455,74 +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 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 (strchr(s, ':') == NULL && strchr(s, '.') != NULL) {
if ((!saw_double_colon && count != 6) || (saw_double_colon && count > 6))
return 0;
ipv4_at_end = 1;
break;
}
if (!isHexDigit(s++)) /* Need 1-4 hex digits */
return 0;
if (isHexDigit(s) && isHexDigit(++s) && isHexDigit(++s) && isHexDigit(++s))
return 0;
if (*s == ':') {
if (!*++s)
return 0;
if (*s == ':') {
if (saw_double_colon)
return 0;
saw_double_colon = 1;
s++;
}
}
}
if (!ipv4_at_end)
return !*s;
}
/* IPv4 */
for (i = 0; i < 4; i++) {
long n;
char *end;
if (i && *s++ != '.')
return 0;
n = strtol(s, &end, 10);
if (n > 255 || n < 0 || end <= s || end > s+3)
return 0;
s = end;
}
return !*s;
}

View File

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

558
compat.c
View File

@@ -3,7 +3,7 @@
*
* Copyright (C) Andrew Tridgell 1996
* Copyright (C) Paul Mackerras 1996
* Copyright (C) 2004-2020 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,8 +20,12 @@
*/
#include "rsync.h"
#include "itypes.h"
int remote_protocol = 0;
int file_extra_cnt = 0; /* count of file-list extras that everyone gets */
int inc_recurse = 0;
extern int verbose;
extern int am_server;
extern int am_sender;
extern int local_server;
@@ -29,11 +33,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;
@@ -42,40 +44,24 @@ extern int protocol_version;
extern int protect_args;
extern int preserve_uid;
extern int preserve_gid;
extern int preserve_atimes;
extern int preserve_acls;
extern int preserve_xattrs;
extern int xfer_flags_as_varint;
extern int need_messages_from_generator;
extern int delete_mode, delete_before, delete_during, delete_after;
extern int do_compression;
extern int do_compression_level;
extern char *shell_cmd;
extern char *partial_dir;
extern char *dest_option;
extern char *files_from;
extern char *filesfrom_host;
extern const char *checksum_choice;
extern const char *compress_choice;
extern filter_rule_list filter_list;
extern 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;
int remote_protocol = 0;
int file_extra_cnt = 0; /* count of file-list extras that everyone gets */
int inc_recurse = 0;
int compat_flags = 0;
int use_safe_inc_flist = 0;
int want_xattr_optim = 0;
int proper_seed_order = 0;
int inplace_partial = 0;
int do_negotiated_strings = 0;
/* These index values are for the file-list's extra-attribute array. */
int pathname_ndx, depth_ndx, atimes_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 */
@@ -84,31 +70,9 @@ int sender_symlink_iconv = 0; /* sender should convert symlink content */
int filesfrom_convert = 0;
#endif
#define MAX_NSTR_STRLEN 256
struct name_num_obj valid_compressions = {
"compress", NULL, NULL, 0, 0, {
#ifdef SUPPORT_ZSTD
{ CPRES_ZSTD, "zstd", NULL },
#endif
#ifdef SUPPORT_LZ4
{ CPRES_LZ4, "lz4", NULL },
#endif
{ CPRES_ZLIBX, "zlibx", NULL },
{ CPRES_ZLIB, "zlib", NULL },
{ CPRES_NONE, "none", NULL },
{ 0, NULL, NULL }
}
};
#define CF_INC_RECURSE (1<<0)
#define CF_SYMLINK_TIMES (1<<1)
#define CF_SYMLINK_ICONV (1<<2)
#define CF_SAFE_FLIST (1<<3)
#define CF_AVOID_XATTR_OPTIM (1<<4)
#define CF_CHKSUM_SEED_FIX (1<<5)
#define CF_INPLACE_PARTIAL_DIR (1<<6)
#define CF_VARINT_FLIST_FLAGS (1<<7)
static const char *client_info;
@@ -163,400 +127,12 @@ void set_allow_inc_recurse(void)
allow_inc_recurse = 0;
}
void parse_compress_choice(int final_call)
{
if (valid_compressions.negotiated_name)
do_compression = valid_compressions.negotiated_num;
else if (compress_choice) {
struct name_num_item *nni = get_nni_by_name(&valid_compressions, compress_choice, -1);
if (!nni) {
rprintf(FERROR, "unknown compress name: %s\n", compress_choice);
exit_cleanup(RERR_UNSUPPORTED);
}
do_compression = nni->num;
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_name)
compress_choice = valid_compressions.negotiated_name;
else if (compress_choice == NULL) {
struct name_num_item *nni = get_nni_by_num(&valid_compressions, do_compression);
compress_choice = nni ? nni->name : "UNKNOWN";
}
if (final_call && DEBUG_GTE(NSTR, am_server ? 3 : 1)
&& (do_compression != CPRES_NONE || do_compression_level != CLVL_NOT_SPECIFIED)) {
rprintf(FINFO, "%s%s compress: %s (level %d)\n",
am_server ? "Server" : "Client",
valid_compressions.negotiated_name ? " negotiated" : "",
compress_choice, do_compression_level);
}
}
struct name_num_item *get_nni_by_name(struct name_num_obj *nno, const char *name, int len)
{
struct name_num_item *nni;
if (len < 0)
len = strlen(name);
for (nni = nno->list; nni->name; nni++) {
if (strncasecmp(name, nni->name, len) == 0 && nni->name[len] == '\0')
return nni;
}
return NULL;
}
struct name_num_item *get_nni_by_num(struct name_num_obj *nno, int num)
{
struct name_num_item *nni;
for (nni = nno->list; nni->name; nni++) {
if (num == nni->num)
return nni;
}
return NULL;
}
static void init_nno_saw(struct name_num_obj *nno, int val)
{
struct name_num_item *nni;
int cnt;
if (!nno->saw_len) {
for (nni = nno->list; nni->name; nni++) {
if (nni->num >= nno->saw_len)
nno->saw_len = nni->num + 1;
}
}
if (!nno->saw) {
nno->saw = new_array0(uchar, nno->saw_len);
/* We'll take this opportunity to make sure that the main_name values are set right. */
for (cnt = 1, nni = nno->list; nni->name; nni++, cnt++) {
if (nno->saw[nni->num])
nni->main_name = nno->list[nno->saw[nni->num]-1].name;
else
nno->saw[nni->num] = cnt;
}
}
memset(nno->saw, val, nno->saw_len);
}
/* Simplify the user-provided string so that it contains valid names without any duplicates.
* It also sets the "saw" flags to a 1-relative count of which name was seen first. */
static int parse_nni_str(struct name_num_obj *nno, const char *from, char *tobuf, int tobuf_len)
{
char *to = tobuf, *tok = NULL;
int 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_name) {
to = tok + strlcpy(tok, nni->main_name, tobuf_len - (tok - tobuf));
if (to - tobuf >= tobuf_len) {
to = tok - 1;
break;
}
}
} else
to = tok - (tok != tobuf);
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;
}
/* 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)
{
struct name_num_item *ret = NULL;
if (len < 0)
len = read_vstring(f_in, tmpbuf, MAX_NSTR_STRLEN);
if (DEBUG_GTE(NSTR, am_server ? 3 : 2)) {
if (am_server)
rprintf(FINFO, "Client %s list (on server): %s\n", nno->type, tmpbuf);
else
rprintf(FINFO, "Server %s list (on client): %s\n", nno->type, tmpbuf);
}
if (len > 0) {
struct name_num_item *nni;
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_name = ret->main_name ? ret->main_name : ret->name;
nno->negotiated_num = ret->num;
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) {
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->main_name) {
if (!dup_markup)
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. */
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_name = valid_compressions.negotiated_name = 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 (am_sender) /* This is most likely in the in64 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)
@@ -584,7 +160,7 @@ 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);
}
@@ -611,29 +187,21 @@ void setup_protocol(int f_out,int f_in)
if (read_batch)
check_batch_flags();
#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);
}
}
@@ -648,78 +216,56 @@ 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) {
int compat_flags;
if (am_server) {
compat_flags = allow_inc_recurse ? CF_INC_RECURSE : 0;
#ifdef CAN_SET_SYMLINK_TIMES
#if defined HAVE_LUTIMES && defined HAVE_UTIMES
compat_flags |= CF_SYMLINK_TIMES;
#endif
#ifdef ICONV_OPTION
compat_flags |= CF_SYMLINK_ICONV;
#endif
if (local_server || strchr(client_info, 'f') != NULL)
compat_flags |= CF_SAFE_FLIST;
if (local_server || strchr(client_info, 'x') != NULL)
compat_flags |= CF_AVOID_XATTR_OPTIM;
if (local_server || strchr(client_info, 'C') != NULL)
compat_flags |= CF_CHKSUM_SEED_FIX;
if (local_server || strchr(client_info, 'I') != NULL)
compat_flags |= CF_INPLACE_PARTIAL_DIR;
if (local_server || strchr(client_info, 'v') != NULL) {
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;
if (am_sender) {
receiver_symlink_times = am_server
? strchr(client_info, 'L') != NULL
: !!(compat_flags & CF_SYMLINK_TIMES);
}
#ifdef CAN_SET_SYMLINK_TIMES
#if defined HAVE_LUTIMES && defined HAVE_UTIMES
else
receiver_symlink_times = 1;
#endif
@@ -731,31 +277,25 @@ void setup_protocol(int f_out,int f_in)
if (inc_recurse && !allow_inc_recurse) {
/* This should only be able to happen in a batch. */
fprintf(stderr,
"Incompatible options specified for inc-recursive %s.\n",
read_batch ? "batch file" : "connection");
"Incompatible options specified for inc-recursive %s.\n",
read_batch ? "batch file" : "connection");
exit_cleanup(RERR_SYNTAX);
}
use_safe_inc_flist = (compat_flags & CF_SAFE_FLIST) || protocol_version >= 31;
need_messages_from_generator = 1;
if (compat_flags & CF_INPLACE_PARTIAL_DIR)
inplace_partial = 1;
#ifdef CAN_SET_SYMLINK_TIMES
#if defined HAVE_LUTIMES && defined HAVE_UTIMES
} 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);
}
@@ -768,21 +308,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 checksum_type & xfersum_type */
parse_compress_choice(1); /* Sets do_compression */
if (write_batch && !am_server)
write_batch_shell_file();
init_flist();
}

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

File diff suppressed because it is too large Load Diff

2613
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

@@ -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 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,67 +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 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 use_chroot True
BOOL write_only False
BOOL3 munge_symlinks Unset
BOOL3 numeric_ids Unset
BOOL3 open_noatime 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-2020 Wayne Davison
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* 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(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(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(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_symlinks++;
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

830
exclude.c
View File

File diff suppressed because it is too large Load Diff

154
fileio.c
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-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,58 +20,35 @@
*/
#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 char last_byte;
static OFF_T sparse_seek = 0;
static OFF_T sparse_past_write = 0;
int sparse_end(int f, OFF_T size)
int sparse_end(int f)
{
int ret;
sparse_past_write = 0;
if (!sparse_seek)
return 0;
#ifdef HAVE_FTRUNCATE
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);
ret = ret <= 0 ? -1 : 0;
}
#endif
do_lseek(f, sparse_seek-1, SEEK_CUR);
sparse_seek = 0;
return ret;
do {
ret = write(f, "", 1);
} while (ret < 0 && errno == EINTR);
return ret <= 0 ? -1 : 0;
}
/* 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;
@@ -79,45 +56,32 @@ static int write_sparse(int f, int use_seek, OFF_T offset, const char *buf, int
for (l1 = 0; l1 < len && buf[l1] == 0; l1++) {}
for (l2 = 0; l2 < len-l1 && buf[len-(l2+1)] == 0; l2++) {}
/* XXX Riddle me this: why does this function SLOW DOWN when I
* remove the following (unneeded) line?? Core Duo weirdness? */
last_byte = buf[len-1];
sparse_seek += l1;
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;
@@ -139,10 +103,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;
@@ -150,13 +116,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) {
@@ -182,47 +149,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;
}
@@ -231,8 +176,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;
@@ -247,23 +193,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;
@@ -283,8 +232,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;
@@ -293,7 +242,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;
@@ -307,9 +256,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;
@@ -319,9 +269,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;

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

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
}
}

168
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-2020 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,23 +21,23 @@
*/
#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;
extern int maybe_ATTRS_REPORT;
extern int unsort_ndx;
extern char *basis_dir[MAX_BASIS_DIRS+1];
extern char *basis_dir[];
extern struct file_list *cur_flist;
#ifdef SUPPORT_HARD_LINKS
@@ -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,25 @@ 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, SIZEOF_INT64 == 8);
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) {
if (!dev_node || dev_node->key != dev) {
/* 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);
if (!(tbl = dev_node->data))
tbl = dev_node->data = hashtable_create(512, SIZEOF_INT64 == 8);
} 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 +111,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 (*)()) 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 +185,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 +205,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 +217,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 +269,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 +287,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 +306,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 +322,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 +331,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 +339,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,19 +355,10 @@ 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));
return -1;
}
/* A new hard-link will get a new dev & inode, so approximate
* those values in dry-run mode by zeroing them. */
memset(&prev_st, 0, sizeof prev_st);
rsyserr(FERROR_XFER, errno, "stat %s failed",
full_fname(prev_name));
return -1;
}
if (statret < 0 && basis_dir[0] != NULL) {
@@ -387,21 +366,26 @@ 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;
@@ -437,8 +421,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,
@@ -457,7 +449,7 @@ int hard_link_one(struct file_struct *file, const char *fname,
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 +476,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 +494,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,7 +512,14 @@ 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)
@@ -524,22 +528,12 @@ void finish_hard_link(struct file_struct *file, const char *fname, int fin_ndx,
if (inc_recurse) {
int gnum = F_HL_GNUM(file);
struct ht_int32_node *node = hashtable_find(prior_hlinks, gnum, NULL);
if (node == NULL) {
rprintf(FERROR, "Unable to find a hlink node for %d (%s)\n", gnum, f_name(file, prev_name));
exit_cleanup(RERR_MESSAGEIO);
}
if (node->data == NULL) {
rprintf(FERROR, "Hlink node data for %d is NULL (%s)\n", gnum, f_name(file, prev_name));
exit_cleanup(RERR_MESSAGEIO);
}
if (CVAL(node->data, 0) != 0) {
rprintf(FERROR, "Hlink node data for %d already has path=%s (%s)\n",
gnum, (char*)node->data, f_name(file, prev_name));
exit_cleanup(RERR_MESSAGEIO);
}
struct ht_int32_node *node = hashtable_find(prior_hlinks, gnum, 0);
assert(node != NULL && node->data != NULL);
assert(CVAL(node->data, 0) == 0);
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-2020 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,40 +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)
{
#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(do_malloc, 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);
}

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);
}

2614
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,65 +0,0 @@
/* Inline functions for rsync.
*
* Copyright (C) 2007-2020 Wayne Davison
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* 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
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 "2020"

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,9 +20,6 @@
*/
#include "rsync.h"
#include "itypes.h"
static char number_separator;
#ifndef HAVE_STRDUP
char *strdup(char *s)
@@ -79,7 +76,7 @@ static char number_separator;
#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
**/
@@ -154,122 +151,3 @@ int sys_gettimeofday(struct timeval *tv)
return gettimeofday(tv);
#endif
}
#define HUMANIFY(mult) \
do { \
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 { \
dnum /= mult; \
units = 'T'; \
} \
if (num < 0) \
dnum = -dnum; \
snprintf(bufs[n], sizeof bufs[0], "%.2f%c", dnum, units); \
return bufs[n]; \
} \
} while (0)
/* 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) {
char buf[32];
snprintf(buf, sizeof buf, "%f", 3.14);
if (strchr(buf, '.') != NULL)
number_separator = ',';
else
number_separator = '.';
}
n = (n + 1) % (sizeof bufs / sizeof bufs[0]);
if (human_flag > 1) {
if (human_flag == 2)
HUMANIFY(1000);
else
HUMANIFY(1024);
}
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

@@ -295,8 +295,9 @@ int getaddrinfo(const char *node,
res);
} else if (hints.ai_flags & AI_NUMERICHOST) {
struct in_addr ip;
if (inet_pton(AF_INET, node, &ip) <= 0)
if (!inet_aton(node, &ip)) {
return EAI_FAIL;
}
return getaddr_info_single_addr(service,
ntohl(ip.s_addr),
&hints,

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,17 +0,0 @@
/* Keep this simple so both C and ASM can use it */
#define MD4_DIGEST_LEN 16
#define MD5_DIGEST_LEN 16
#define MAX_DIGEST_LEN MD5_DIGEST_LEN
#define CSUM_CHUNK 64
#define CSUM_NONE 0
#define CSUM_MD4_ARCHAIC 1
#define CSUM_MD4_BUSTED 2
#define CSUM_MD4_OLD 3
#define CSUM_MD4 4
#define CSUM_MD5 5
#define CSUM_XXH64 6
#define CSUM_XXH3_64 7
#define CSUM_XXH3_128 8

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"
#if !defined USE_OPENSSL && CSUM_CHUNK == 64
#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_OPENSSL ... */

View File

@@ -2,7 +2,6 @@
* RFC 1321 compliant MD5 implementation
*
* Copyright (C) 2001-2003 Christophe Devine
* Copyright (C) 2007-2020 Wayne Davison
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -20,7 +19,6 @@
#include "rsync.h"
#ifndef USE_OPENSSL
void md5_begin(md_context *ctx)
{
ctx->A = 0x67452301;
@@ -40,22 +38,22 @@ static void md5_process(md_context *ctx, const uchar data[CSUM_CHUNK])
C = ctx->C;
D = ctx->D;
X[0] = IVALu(data, 0);
X[1] = IVALu(data, 4);
X[2] = IVALu(data, 8);
X[3] = IVALu(data, 12);
X[4] = IVALu(data, 16);
X[5] = IVALu(data, 20);
X[6] = IVALu(data, 24);
X[7] = IVALu(data, 28);
X[8] = IVALu(data, 32);
X[9] = IVALu(data, 36);
X[10] = IVALu(data, 40);
X[11] = IVALu(data, 44);
X[12] = IVALu(data, 48);
X[13] = IVALu(data, 52);
X[14] = IVALu(data, 56);
X[15] = IVALu(data, 60);
X[0] = IVAL(data, 0);
X[1] = IVAL(data, 4);
X[2] = IVAL(data, 8);
X[3] = IVAL(data, 12);
X[4] = IVAL(data, 16);
X[5] = IVAL(data, 20);
X[6] = IVAL(data, 24);
X[7] = IVAL(data, 28);
X[8] = IVAL(data, 32);
X[9] = IVAL(data, 36);
X[10] = IVAL(data, 40);
X[11] = IVAL(data, 44);
X[12] = IVAL(data, 48);
X[13] = IVAL(data, 52);
X[14] = IVAL(data, 56);
X[15] = IVAL(data, 60);
#define S(x,n) ((x << n) | ((x & 0xFFFFFFFF) >> (32 - n)))
@@ -148,10 +146,6 @@ static void md5_process(md_context *ctx, const uchar data[CSUM_CHUNK])
ctx->D += D;
}
#if defined HAVE_ASM && CSUM_CHUNK == 64
extern void md5_process_asm(md_context *ctx, const void *data, size_t num);
#endif
void md5_update(md_context *ctx, const uchar *input, uint32 length)
{
uint32 left, fill;
@@ -176,20 +170,11 @@ void md5_update(md_context *ctx, const uchar *input, uint32 length)
left = 0;
}
#if defined HAVE_ASM && CSUM_CHUNK == 64
if (length >= CSUM_CHUNK) {
uint32 chunks = length / CSUM_CHUNK;
md5_process_asm(ctx, input, chunks);
length -= chunks * CSUM_CHUNK;
input += chunks * CSUM_CHUNK;
}
#else
while (length >= CSUM_CHUNK) {
md5_process(ctx, input);
length -= CSUM_CHUNK;
input += CSUM_CHUNK;
}
#endif
if (length)
memcpy(ctx->buffer + left, input, length);
@@ -207,8 +192,8 @@ void md5_result(md_context *ctx, uchar digest[MD5_DIGEST_LEN])
| (ctx->totalN2 << 3);
low = (ctx->totalN << 3);
SIVALu(msglen, 0, low);
SIVALu(msglen, 4, high);
SIVAL(msglen, 0, low);
SIVAL(msglen, 4, high);
last = ctx->totalN & 0x3F;
padn = last < 56 ? 56 - last : 120 - last;
@@ -216,14 +201,11 @@ void md5_result(md_context *ctx, uchar digest[MD5_DIGEST_LEN])
md5_update(ctx, md5_padding, padn);
md5_update(ctx, msglen, 8);
SIVALu(digest, 0, ctx->A);
SIVALu(digest, 4, ctx->B);
SIVALu(digest, 8, ctx->C);
SIVALu(digest, 12, ctx->D);
SIVAL(digest, 0, ctx->A);
SIVAL(digest, 4, ctx->B);
SIVAL(digest, 8, ctx->C);
SIVAL(digest, 12, ctx->D);
}
#endif
#ifdef TEST_MD5
void get_md5(uchar *out, const uchar *input, int n)
{
@@ -233,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>

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/md4.h"
#include "openssl/md5.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,13 +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]);
#ifndef USE_OPENSSL
#define MD5_CTX md_context
#define MD5_Init md5_begin
#define MD5_Update md5_update
#define MD5_Final(digest, cptr) md5_result(cptr, digest)
void 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]);
#endif
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

@@ -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,8 +2,6 @@
#define POOL_DEF_EXTENT (32 * 1024)
#define POOL_QALIGN_P2 (1<<16) /* power-of-2 qalign */
struct alloc_pool
{
size_t size; /* extent size */
@@ -15,7 +13,7 @@ struct alloc_pool
/* 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 */
@@ -24,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)
@@ -47,42 +43,20 @@ struct align_test {
alloc_pool_t
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\n");
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_ADD(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;
@@ -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_ADD(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_ADD(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,9 +1,9 @@
#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;

View File

File diff suppressed because it is too large Load Diff

View File

@@ -2,7 +2,7 @@
* Unix SMB/CIFS implementation.
* Based on the Samba ACL support code.
* Copyright (C) Jeremy Allison 2000.
* Copyright (C) 2007-2020 Wayne Davison
* Copyright (C) 2007-2008 Wayne Davison
*
* The permission functions have been changed to get/set all bits via
* one call. Some functions that rsync doesn't need were also removed.
@@ -450,7 +450,7 @@ SMB_ACL_T sys_acl_get_file(const char *path_p, SMB_ACL_TYPE_T type)
*
* Note: we assume that the acl() system call returned a
* well formed ACL which is sorted so that all of the
* access ACL entries precede any default ACL entries
* access ACL entries preceed any default ACL entries
*/
for (naccess = 0; naccess < count; naccess++) {
if (acl_d->acl[naccess].a_type & ACL_DEFAULT)
@@ -873,10 +873,6 @@ int sys_acl_get_tag_type(SMB_ACL_ENTRY_T entry_d, SMB_ACL_TAG_T *type_p)
#define INITIAL_ACL_SIZE 16
#ifndef NACLENTRIES
#define NACLENTRIES 0
#endif
SMB_ACL_T sys_acl_get_file(const char *path_p, SMB_ACL_TYPE_T type)
{
SMB_ACL_T acl_d;
@@ -913,7 +909,7 @@ SMB_ACL_T sys_acl_get_file(const char *path_p, SMB_ACL_TYPE_T type)
sys_acl_free_acl(acl_d);
if ((count = acl(path_p, ACL_CNT, NACLENTRIES, NULL)) < 0) {
if ((count = acl(path_p, ACL_CNT, 0, NULL)) < 0) {
return NULL;
}
@@ -932,7 +928,7 @@ SMB_ACL_T sys_acl_get_file(const char *path_p, SMB_ACL_TYPE_T type)
*
* Note: we assume that the acl() system call returned a
* well formed ACL which is sorted so that all of the
* access ACL entries precede any default ACL entries
* access ACL entries preceed any default ACL entries
*/
for (naccess = 0; naccess < count; naccess++) {
if (acl_d->acl[naccess].a_type & ACL_DEFAULT)
@@ -1095,7 +1091,7 @@ struct hpux_acl_types {
* structures.
* Inputs:
*
* acl_count - Count of ACLs in the array of ACL structures.
* acl_count - Count of ACLs in the array of ACL strucutres.
* aclp - Array of ACL structures.
* acl_type_count - Pointer to acl_types structure. Should already be
* allocated.
@@ -1256,7 +1252,7 @@ static int hpux_acl_sort(int acl_count, int calclass, struct acl *aclp)
{
#if !defined(HAVE_HPUX_ACLSORT)
/*
* The aclsort() system call is available on the latest HPUX General
* The aclsort() system call is availabe on the latest HPUX General
* Patch Bundles. So for HPUX, we developed our version of acl_sort
* function. Because, we don't want to update to a new
* HPUX GR bundle just for aclsort() call.
@@ -1311,7 +1307,7 @@ or DEF_USER_OBJ or DEF_GROUP_OBJ or DEF_OTHER_OBJ\n"));
* Sorting crieteria - First sort by ACL type. If there are multiple entries of
* same ACL type, sort by ACL id.
*
* I am using the trivial kind of sorting method here because, performance isn't
* I am using the trival kind of sorting method here because, performance isn't
* really effected by the ACLs feature. More over there aren't going to be more
* than 17 entries on HPUX.
*/
@@ -1819,11 +1815,7 @@ SMB_ACL_T sys_acl_get_file( const char *path_p, SMB_ACL_TYPE_T type)
/* AIX has no DEFAULT */
if ( type == SMB_ACL_TYPE_DEFAULT ) {
#ifdef ENOTSUP
errno = ENOTSUP;
#else
errno = ENOSYS;
#endif
return NULL;
}
@@ -2785,11 +2777,6 @@ int no_acl_syscall_error(int err)
return 1;
}
#endif
if (err == EINVAL) {
/* If the type of SMB_ACL_TYPE_ACCESS or SMB_ACL_TYPE_DEFAULT
* isn't valid, then the ACLs must be non-POSIX. */
return 1;
}
return 0;
}

View File

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

@@ -2,7 +2,7 @@
* Extended attribute support for rsync.
*
* Copyright (C) 2004 Red Hat, Inc.
* Copyright (C) 2003-2019 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, 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)
@@ -147,150 +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, 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, 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;
if ((ret += len+1) > 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

1074
loadparm.c
View File

File diff suppressed because it is too large Load Diff

331
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-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
@@ -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,20 +31,18 @@ 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_times;
extern int msgs2stderr;
extern int xfersum_type;
extern int checksum_type;
extern int uid_ndx;
extern int gid_ndx;
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;
@@ -54,13 +52,11 @@ extern char *logfile_name;
extern iconv_t ic_chck;
#endif
#ifdef ICONV_OPTION
extern iconv_t ic_recv;
extern iconv_t ic_send, ic_recv;
#endif
extern char curr_dir[MAXPATHLEN];
extern char curr_dir[];
extern char *full_module_path;
extern unsigned int module_dirlen;
extern char sender_file_sum[MAX_DIGEST_LEN];
extern const char undetermined_hostname[];
static int log_initialised;
static int logfile_was_closed;
@@ -68,15 +64,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 +87,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 +115,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 +125,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 +159,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 +176,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 +198,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 +215,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 +242,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 ? 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 +255,7 @@ void rwrite(enum logcode code, const char *buf, int len, int is_utf8)
if (len < 0)
exit_cleanup(RERR_MESSAGEIO);
if (msgs2stderr) {
/* 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 +290,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) {
if (am_server) {
enum msgcode msg = (enum msgcode)code;
if (protocol_version < 30) {
if (msg == MSG_ERROR)
@@ -338,27 +304,35 @@ 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;
}
f = stderr;
}
if (output_needs_newline) {
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 (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--;
}
#ifdef ICONV_CONST
if (ic != (iconv_t)-1) {
xbuf outbuf, inbuf;
@@ -366,34 +340,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) {
filtered_fwrite(f, convbuf, outbuf.len, 0, 0);
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);
}
}
@@ -452,7 +419,8 @@ void rsyserr(enum logcode code, int errcode, const char *format, ...)
char buf[BIGPATHBUFLEN];
size_t len;
len = snprintf(buf, sizeof buf, RSYNC_NAME ": [%s] ", who_am_i());
strlcpy(buf, RSYNC_NAME ": ", sizeof buf);
len = (sizeof RSYNC_NAME ": ") - 1;
va_start(ap, format);
len += vsnprintf(buf + len, sizeof buf - len, format, ap);
@@ -470,12 +438,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;
@@ -483,15 +451,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];
@@ -514,45 +477,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':
@@ -572,8 +520,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':
@@ -660,33 +609,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(checksum_type, F_SUM(file), 1);
else if (iflags & ITEM_TRANSFER)
n = sum_as_hex(xfersum_type, sender_file_sum, 0);
}
if (!n) {
int sum_len = csum_len_for_type(always_checksum ? checksum_type : xfersum_type,
always_checksum);
memset(buf2, ' ', sum_len*2);
buf2[sum_len*2] = '\0';
n = buf2;
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) {
@@ -695,7 +639,7 @@ static void log_formatted(enum logcode code, const char *format, const char *op,
}
n = c = buf2 + MAXPATHLEN - 32;
c[0] = iflags & ITEM_LOCAL_CHANGE
? iflags & ITEM_XNAME_FOLLOWS ? 'h' : 'c'
? iflags & ITEM_XNAME_FOLLOWS ? 'h' : 'c'
: !(iflags & ITEM_TRANSFER) ? '.'
: !local_server && *op == 's' ? '<' : '>';
if (S_ISLNK(file->mode)) {
@@ -716,8 +660,7 @@ static void log_formatted(enum logcode code, const char *format, const char *op,
c[5] = !(iflags & ITEM_REPORT_PERMS) ? '.' : 'p';
c[6] = !(iflags & ITEM_REPORT_OWNER) ? '.' : 'o';
c[7] = !(iflags & ITEM_REPORT_GROUP) ? '.' : 'g';
c[8] = !(iflags & ITEM_REPORT_ATIME) ? '.'
: S_ISLNK(file->mode) ? 'U' : 'u';
c[8] = !(iflags & ITEM_REPORT_ATIME) ? '.' : 'u';
c[9] = !(iflags & ITEM_REPORT_ACL) ? '.' : 'a';
c[10] = !(iflags & ITEM_REPORT_XATTR) ? '.' : 'x';
c[11] = '\0';
@@ -787,12 +730,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)
@@ -804,30 +745,36 @@ 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);
}
}
@@ -836,28 +783,29 @@ void log_delete(const char *fname, int mode)
static struct {
union file_extras ex[4]; /* just in case... */
struct file_struct file;
} x; /* Zero-initialized due to static declaration. */
} x;
int len = strlen(fname);
const char *fmt;
x.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.", &x.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.", &x.file, fname, ITEM_DELETED, NULL);
log_formatted(FLOG, fmt, "del.", &x.file, fname, &stats, ITEM_DELETED, NULL);
}
/*
@@ -868,15 +816,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);

View File

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

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"
])

675
main.c
View File

File diff suppressed because it is too large Load Diff

193
match.c
View File

@@ -3,7 +3,7 @@
*
* Copyright (C) 1996 Andrew Tridgell
* Copyright (C) 1996 Paul Mackerras
* 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
@@ -20,14 +20,13 @@
*/
#include "rsync.h"
#include "inums.h"
extern int verbose;
extern int do_progress;
extern int checksum_seed;
extern int append_mode;
extern int xfersum_type;
int updating_basis_file;
char sender_file_sum[MAX_DIGEST_LEN];
static int false_alarms;
static int hash_hits;
@@ -65,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;
}
@@ -89,7 +90,8 @@ static void build_hash_table(struct sum_struct *s)
static OFF_T last_match;
/* Transmit a literal and/or match token.
/**
* Transmit a literal and/or match token.
*
* This delightfully-named function is called either when we find a
* match and need to transmit all the unmatched data leading up to it,
@@ -97,18 +99,19 @@ static OFF_T last_match;
* transmit it. As a result of this second case, it is called even if
* we have not matched at all!
*
* 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)
* @param i If >0, the number of a matched token. If 0, indicates we
* have only literal data.
**/
static void matched(int f, struct sum_struct *s, struct map_struct *buf,
OFF_T offset, 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);
}
@@ -130,7 +133,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);
}
@@ -138,8 +141,8 @@ static void matched(int f, struct sum_struct *s, struct map_struct *buf, OFF_T o
static void hash_search(int f,struct sum_struct *s,
struct map_struct *buf, OFF_T len)
{
OFF_T offset, aligned_offset, end;
int32 k, want_i, aligned_i, backup;
OFF_T offset, end;
int32 k, want_i, backup;
char sum2[SUM_LENGTH];
uint32 s1, s2, sum;
int more;
@@ -149,9 +152,9 @@ static void hash_search(int f,struct sum_struct *s,
* 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);
@@ -161,55 +164,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;
offset = 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;
@@ -218,10 +207,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) {
@@ -237,62 +232,39 @@ static void hash_search(int f,struct sum_struct *s,
/* When updating in-place, the best possible match is
* one with an identical offset, so we prefer that over
* the adjacent want_i optimization. */
* the following want_i optimization. */
if (updating_basis_file) {
/* All the generator's chunks start at blength boundaries. */
while (aligned_offset < offset) {
aligned_offset += s->blength;
aligned_i++;
}
if ((offset == aligned_offset
|| (sum == 0 && l == s->blength && aligned_offset + l <= len))
&& aligned_i < s->count) {
if (i != aligned_i) {
if (sum != s->sums[aligned_i].sum1
|| l != s->sums[aligned_i].len
|| memcmp(sum2, s->sums[aligned_i].sum2, s->s2length) != 0)
goto check_want_i;
i = aligned_i;
int32 i2;
for (i2 = i; i2 >= 0; i2 = s->sums[i2].chain) {
if (s->sums[i2].offset != offset)
continue;
if (i2 != i) {
if (sum != s->sums[i2].sum1)
break;
if (memcmp(sum2, s->sums[i2].sum2,
s->s2length) != 0)
break;
i = i2;
}
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, s->sums[i].sum2, 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. */
/* This chunk was at the same offset on
* both the sender and the receiver. */
s->sums[i].flags |= SUMFLG_SAME_OFFSET;
want_i = i;
goto set_want_i;
}
}
check_want_i:
/* we've found a match, but now check to see
* if want_i can hint at a better match. */
if (i != want_i && want_i < s->count
&& (!updating_basis_file || s->sums[want_i].offset >= offset
|| s->sums[want_i].flags & SUMFLG_SAME_OFFSET)
&& sum == s->sums[want_i].sum1
&& memcmp(sum2, s->sums[want_i].sum2, s->s2length) == 0) {
&& (!updating_basis_file || s->sums[want_i].offset >= offset
|| s->sums[want_i].flags & SUMFLG_SAME_OFFSET)
&& sum == s->sums[want_i].sum1
&& memcmp(sum2, s->sums[want_i].sum2, s->s2length) == 0) {
/* we've found an adjacent match - the RLL coder
* will be happy */
i = want_i;
}
set_want_i:
want_i = i + 1;
matched(f,s,buf,offset,i);
@@ -314,7 +286,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);
@@ -356,6 +329,7 @@ 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;
@@ -364,13 +338,13 @@ void match_sums(int f, struct sum_struct *s, struct map_struct *buf, OFF_T len)
matches = 0;
data_transfer = 0;
sum_init(xfersum_type, 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);
@@ -378,7 +352,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);
}
@@ -390,12 +364,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;
@@ -405,27 +379,18 @@ void match_sums(int f, struct sum_struct *s, struct map_struct *buf, OFF_T len)
matched(f, s, buf, len, -1);
}
sum_len = 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 < sum_len && sender_file_sum[i] == 0; i++) {}
memset(sender_file_sum, 0, sum_len);
if (i == sum_len)
sender_file_sum[i-1]++;
}
if (DEBUG_GTE(DELTASUM, 2))
if (verbose > 2)
rprintf(FINFO,"sending file_sum\n");
write_buf(f, sender_file_sum, 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;
@@ -435,11 +400,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,40 +0,0 @@
#!/bin/sh
if [ x"$2" = x ]; then
echo "Usage: $0 SRC_DIR NAME.NUM.md" 1>&2
exit 1
fi
srcdir="$1"
inname="$2"
flagfile="$srcdir/.md2man-works"
if [ ! -d "$srcdir" ]; then
echo "The specified SRC_DIR is not a directory: $srcdir" 1>&2
exit 1
fi
if [ ! -f "$flagfile" ]; then
# We test our smallest manpage just to see if the python setup works.
if "$srcdir/md2man" --test "$srcdir/rsync-ssl.1.md" >/dev/null 2>&1; then
touch $flagfile
else
outname=`echo "$inname" | sed 's/\.md$//'`
if [ -f "$outname" ]; then
exit 0
elif [ -f "$srcdir/$outname" ]; then
echo "Copying $srcdir/$outname"
cp -p "$srcdir/$outname" .
exit 0
else
echo "ERROR: $outname cannot be created."
if [ -f "$HOME/build_farm/build_test.fns" ]; then
exit 0 # No exit errorno to avoid a build failure in the samba build farm
else
exit 1
fi
fi
fi
fi
"$srcdir/md2man" "$srcdir/$inname"

387
md2man
View File

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

View File

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

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;

1739
options.c
View File

File diff suppressed because it is too large Load Diff

View File

@@ -1,11 +0,0 @@
TARGETS := all install install-ssl-daemon install-all install-strip conf gen gensend reconfigure restatus \
proto man clean cleantests distclean test check check29 check30 installcheck splint doxygen doxygen-upload
.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,174 +0,0 @@
#!/usr/bin/env -S python3 -B
# This script turns one or more diff files in the patches dir (which is
# expected to be a checkout of the rsync-patches git repo) into a branch
# in the main rsync git checkout. This allows the applied patch to be
# merged with the latest rsync changes and tested. To update the diff
# with the resulting changes, see the patch-update script.
import os, sys, re, argparse, glob
sys.path = ['packaging'] + sys.path
from pkglib import *
def main():
global created, info, local_branch
cur_branch, args.base_branch = check_git_state(args.base_branch, not args.skip_check, args.patches_dir)
local_branch = get_patch_branches(args.base_branch)
if args.delete_local_branches:
for name in sorted(local_branch):
branch = f"patch/{args.base_branch}/{name}"
cmd_chk(['git', 'branch', '-D', branch])
local_branch = set()
if args.add_missing:
for fn in sorted(glob.glob(f"{args.patches_dir}/*.diff")):
name = re.sub(r'\.diff$', '', re.sub(r'.+/', '', fn))
if name not in local_branch and fn not in args.patch_files:
args.patch_files.append(fn)
if not args.patch_files:
return
for fn in args.patch_files:
if not fn.endswith('.diff'):
die(f"Filename is not a .diff file: {fn}")
if not os.path.isfile(fn):
die(f"File not found: {fn}")
scanned = set()
info = { }
patch_list = [ ]
for fn in args.patch_files:
m = re.match(r'^(?P<dir>.*?)(?P<name>[^/]+)\.diff$', fn)
patch = argparse.Namespace(**m.groupdict())
if patch.name in scanned:
continue
patch.fn = fn
lines = [ ]
commit_hash = None
with open(patch.fn, 'r', encoding='utf-8') as fh:
for line in fh:
m = re.match(r'^based-on: (\S+)', line)
if m:
commit_hash = m[1]
break
if (re.match(r'^index .*\.\..* \d', line)
or re.match(r'^diff --git ', line)
or re.match(r'^--- (old|a)/', line)):
break
lines.append(re.sub(r'\s*\Z', "\n", line, 1))
info_txt = ''.join(lines).strip() + "\n"
lines = None
parent = args.base_branch
patches = re.findall(r'patch -p1 <%s/(\S+)\.diff' % args.patches_dir, info_txt)
if patches:
last = patches.pop()
if last != patch.name:
warn(f"No identity patch line in {patch.fn}")
patches.append(last)
if patches:
parent = patches.pop()
if parent not in scanned:
diff_fn = patch.dir + parent + '.diff'
if not os.path.isfile(diff_fn):
die(f"Failed to find parent of {patch.fn}: {parent}")
# Add parent to args.patch_files so that we will look for the
# parent's parent. Any duplicates will be ignored.
args.patch_files.append(diff_fn)
else:
warn(f"No patch lines found in {patch.fn}")
info[patch.name] = [ parent, info_txt, commit_hash ]
patch_list.append(patch)
created = set()
for patch in patch_list:
create_branch(patch)
cmd_chk(['git', 'checkout', args.base_branch])
def create_branch(patch):
if patch.name in created:
return
created.add(patch.name)
parent, info_txt, commit_hash = info[patch.name]
parent = argparse.Namespace(dir=patch.dir, name=parent, fn=patch.dir + parent + '.diff')
if parent.name == args.base_branch:
parent_branch = commit_hash if commit_hash else args.base_branch
else:
create_branch(parent)
parent_branch = '/'.join(['patch', args.base_branch, parent.name])
branch = '/'.join(['patch', args.base_branch, patch.name])
print("\n" + '=' * 64)
print(f"Processing {branch} ({parent_branch})")
if patch.name in local_branch:
cmd_chk(['git', 'branch', '-D', branch])
cmd_chk(['git', 'checkout', '-b', branch, parent_branch])
info_fn = 'PATCH.' + patch.name
with open(info_fn, 'w', encoding='utf-8') as fh:
fh.write(info_txt)
cmd_chk(['git', 'add', info_fn])
with open(patch.fn, 'r', encoding='utf-8') as fh:
patch_txt = fh.read()
cmd_run('patch -p1'.split(), input=patch_txt)
for fn in glob.glob('*.orig') + glob.glob('*/*.orig'):
os.unlink(fn)
pos = 0
new_file_re = re.compile(r'\nnew file mode (?P<mode>\d+)\s+--- /dev/null\s+\+\+\+ b/(?P<fn>.+)')
while True:
m = new_file_re.search(patch_txt, pos)
if not m:
break
os.chmod(m['fn'], int(m['mode'], 8))
cmd_chk(['git', 'add', m['fn']])
pos = m.end()
while True:
cmd_chk('git status'.split())
ans = input('Press Enter to commit, Ctrl-C to abort, or type a wild-name to add a new file: ')
if ans == '':
break
cmd_chk("git add " + ans, shell=True)
while True:
s = cmd_run(['git', 'commit', '-a', '-m', f"Creating branch from {patch.name}.diff."])
if not s.returncode:
break
s = cmd_run(['/bin/zsh'])
if s.returncode:
die('Aborting due to shell error code')
if __name__ == '__main__':
parser = argparse.ArgumentParser(description="Create a git patch branch from an rsync patch file.", add_help=False)
parser.add_argument('--branch', '-b', dest='base_branch', metavar='BASE_BRANCH', default='master', help="The branch the patch is based on. Default: master.")
parser.add_argument('--add-missing', '-a', action='store_true', help="Add a branch for every patches/*.diff that doesn't have a branch.")
parser.add_argument('--skip-check', action='store_true', help="Skip the check that ensures starting with a clean branch.")
parser.add_argument('--delete', dest='delete_local_branches', action='store_true', help="Delete all the local patch/BASE/* branches, not just the ones that are being recreated.")
parser.add_argument('--patches-dir', '-p', metavar='DIR', default='patches', help="Override the location of the rsync-patches dir. Default: patches.")
parser.add_argument('patch_files', metavar='patches/DIFF_FILE', nargs='*', help="Specify what patch diff files to process. Default: all of them.")
parser.add_argument("--help", "-h", action="help", help="Output this help message and exit.")
args = parser.parse_args()
main()
# vim: sw=4 et ft=python

View File

@@ -1,29 +1,15 @@
#!/usr/bin/env perl
#!/usr/bin/perl
# This script outputs some perl code that parses all possible options
# that the code in options.c might send to the server. This perl code
# is included in the rrsync script.
use strict;
our %short_no_arg;
our %short_with_num = ( '@' => 1 );
our %long_opt = ( # These include some extra long-args that BackupPC uses:
'block-size' => 1,
'daemon' => -1,
'debug' => 1,
our %short_with_num;
our %long_opt = (
'no-i-r' => 0,
'fake-super' => 0,
'fuzzy' => 0,
'group' => 0,
'hard-links' => 0,
'ignore-times' => 0,
'info' => 1,
'links' => 0,
'log-file' => 3,
'one-file-system' => 0,
'owner' => 0,
'perms' => 0,
'recursive' => 0,
'times' => 0,
'write-devices' => -1,
);
our $last_long_opt;
@@ -38,15 +24,15 @@ while (<IN>) {
undef $last_long_opt;
} elsif (/\Qargs[ac++]\E = "--([^"=]+)"/) {
$last_long_opt = $1;
$long_opt{$1} = 0 unless exists $long_opt{$1};
$long_opt{$1} = 0;
} elsif (defined($last_long_opt)
&& /\Qargs[ac++]\E = ([^["\s]+);/) {
&& /\Qargs[ac++]\E = ([^["\s]+);/ && $1 ne 'dest_option') {
$long_opt{$last_long_opt} = 2;
undef $last_long_opt;
} elsif (/return "--([^"]+-dest)";/) {
} elsif (/dest_option = "--([^"]+)"/) {
$long_opt{$1} = 2;
undef $last_long_opt;
} elsif (/\Qasprintf(\E[^,]+, "--([^"=]+)=/ || /\Qargs[ac++]\E = "--([^"=]+)=/ || /fmt = .*: "--([^"=]+)=/) {
} elsif (/\Qasprintf(\E[^,]+, "--([^"=]+)=/ || /\Qargs[ac++]\E = "--([^"=]+)=/) {
$long_opt{$1} = 1;
undef $last_long_opt;
}
@@ -77,8 +63,7 @@ foreach my $opt (sort keys %long_opt) {
my $val = $long_opt{$opt};
$val = 1 if $opt =~ /^(max-|min-)/;
$val = 3 if $opt eq 'files-from';
$val = q"$only eq 'r' ? -1 : " . $val if $opt =~ /^(remove-|log-file)/;
$val = q"$only eq 'w' ? -1 : " . $val if $opt eq 'sender';
$val = '$ro ? -1 : ' . $val if $opt =~ /^remove-/;
print " '$opt' => $val,\n";
}

18
packaging/extern-squish Executable file
View File

@@ -0,0 +1,18 @@
#!/usr/bin/perl
# This script finds extraneous "extern" variables in the *.c files.
# Run it from inside the main rsync directory.
use strict;
my @files = glob('*.c');
foreach my $fn (@files) {
open(IN, '<', $fn) or die;
undef $/; $_ = <IN>; $/ = "\n";
close IN;
my @externs = /^extern .*?([^[\s(*;&.]+)(?:\[.*?\])?;/mg;
foreach my $find (@externs) {
my @matches = /(?<!\sstruct )\b(\Q$find\E)\b/g;
print $fn, ': ', $find, "\n" if @matches == 1;
}
}

View File

@@ -1,22 +1,17 @@
Summary: A fast, versatile, remote (and local) file-copying tool
Name: rsync
Version: 3.2.2
Version: 3.0.6
%define fullversion %{version}
Release: 1
%define srcdir src
Group: Applications/Internet
License: GPL
Source0: https://rsync.samba.org/ftp/rsync/%{srcdir}/rsync-%{fullversion}.tar.gz
#Source1: https://rsync.samba.org/ftp/rsync/%{srcdir}/rsync-patches-%{fullversion}.tar.gz
URL: https://rsync.samba.org/
Source0: http://rsync.samba.org/ftp/rsync/%{srcdir}/rsync-%{fullversion}.tar.gz
#Source1: http://rsync.samba.org/ftp/rsync/%{srcdir}/rsync-patches-%{fullversion}.tar.gz
URL: http://rsync.samba.org/
Prefix: %{_prefix}
BuildRoot: /var/tmp/%{name}-root
%package ssl-daemon
Summary: An stunnel config file to support ssl rsync daemon connections.
Group: Applications/Internet
Requires: rsync, stunnel >= 4
License: GPL
%description
Rsync is a fast and extraordinarily versatile file copying tool. It can
@@ -29,17 +24,12 @@ differences between the source files and the existing files in the
destination. Rsync is widely used for backups and mirroring and as an
improved copy command for everyday use.
%description ssl-daemon
Provides a config file for stunnel that will (if you start your stunnel
service) cause stunnel to listen for ssl rsync-daemon connections and run
"rsync --daemon" to handle them.
%prep
# Choose one -- setup source only, or setup source + rsync-patches:
%setup -q -n rsync-%{fullversion}
#%setup -q -b1 -n rsync-%{fullversion}
# If you you used "%setup -q -b1 ...", choose the patches you wish to apply:
# If you you used "%setup -q -b1", choose the patches you wish to apply:
#patch -p1 <patches/acls.diff
#patch -p1 <patches/xattrs.diff
#patch -p1 <patches/remote-option.diff
@@ -56,32 +46,29 @@ make
%install
rm -rf $RPM_BUILD_ROOT
make install install-ssl-daemon DESTDIR=$RPM_BUILD_ROOT
mkdir -p $RPM_BUILD_ROOT/etc/xinetd.d $RPM_BUILD_ROOT/etc/rsync-ssl/certs
%makeinstall
mkdir -p $RPM_BUILD_ROOT/etc/xinetd.d
install -m 644 packaging/lsb/rsync.xinetd $RPM_BUILD_ROOT/etc/xinetd.d/rsync
#install -p -m 755 support/rsyncdb $RPM_BUILD_ROOT/usr/bin/rsyncdb
%clean
rm -rf $RPM_BUILD_ROOT
%files
%defattr(-,root,root)
%doc COPYING NEWS.md README.md support/ tech_report.tex
%doc COPYING NEWS OLDNEWS README support/ tech_report.tex
%config(noreplace) /etc/xinetd.d/rsync
%{_prefix}/bin/rsync
%{_prefix}/bin/rsync-ssl
%{_prefix}/bin/rsync*
%{_mandir}/man1/rsync.1*
%{_mandir}/man1/rsync-ssl.1*
%{_mandir}/man5/rsyncd.conf.5*
%files ssl-daemon
%config(noreplace) /etc/stunnel/rsyncd.conf
%dir /etc/rsync-ssl/certs
%changelog
* Sat Jul 04 2020 Wayne Davison <wayne@opencoder.net>
Released 3.2.2.
* Fri May 08 2009 Wayne Davison <wayned@samba.org>
Released 3.0.6.
* Fri Mar 21 2008 Wayne Davison <wayne@opencoder.net>
* Fri Mar 21 2008 Wayne Davison <wayned@samba.org>
Added installation of /etc/xinetd.d/rsync file and some commented-out
lines that demonstrate how to use the rsync-patches tar file.

View File

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

121
packaging/nightly-rsync Executable file
View File

@@ -0,0 +1,121 @@
#!/usr/bin/perl
use strict;
# This script expects the directory ~/samba-rsync-ftp to exist and to be a
# copy of the /home/ftp/pub/rsync dir on samba.org. It also requires a
# pristine CVS checkout of rsync (don't use your normal rsync build dir
# unless you're 100% sure that there are not unchecked-in changes).
#
# If this is run with -ctu, it will make an updated "nightly" tar file in
# the nightly dir. It will also remove any old tar files, regenerate the
# HTML man pages in the nightly dir, and then rsync the changes to the
# samba.org server.
use Getopt::Long;
use Date::Format;
# Where the local copy of /home/ftp/pub/rsync/dev/nightly should be updated.
our $dest = $ENV{HOME} . '/samba-rsync-ftp/dev/nightly';
our $nightly_symlink = "$dest/rsync-HEAD.tar.gz";
our($make_tar, $upload, $help_opt);
&Getopt::Long::Configure('bundling');
&usage if !&GetOptions(
'make-tar|t' => \$make_tar,
'upload|u' => \$upload,
'help|h' => \$help_opt,
) || $help_opt;
our $name = time2str('rsync-HEAD-%Y%m%d-%H%M%Z', time, 'GMT');
our $ztoday = time2str('%d %b %Y', time);
our $today = $ztoday;
our $gen_target = $upload ? 'gensend' : 'gen';
die "$dest does not exist\n" unless -d $dest;
die "There is no .git dir in the current directory.\n" unless -d '.git';
die "There is no rsync checkout in the current directory.\n" unless -f 'rsyncd.conf.yo';
if ($make_tar) {
open(IN, '-|', 'git status') or die $!;
my $status = join('', <IN>);
close IN;
die "The checkout is not clean:\n", $status unless $status =~ /\nnothing to commit \(working directory clean\)/;
die "The checkout is not on the master branch.\n" unless $status =~ /^# On branch master\n/;
system "make $gen_target" and die "make $gen_target failed!\n";
my @extra_files;
open(IN, '<', 'Makefile.in') or die "Couldn't open Makefile.in: $!\n";
while (<IN>) {
if (s/^GENFILES=//) {
while (s/\\$//) {
$_ .= <IN>;
}
@extra_files = split(' ', $_);
last;
}
}
close IN;
print "Creating $name.tar.gz\n";
system "rsync -a @extra_files $name/";
system "git archive --format=tar --prefix=$name/ HEAD | tar xf -";
system "support/git-set-file-times --prefix=$name/";
system "fakeroot tar czf $dest/$name.tar.gz $name; rm -rf $name";
unlink($nightly_symlink);
symlink("$name.tar.gz", $nightly_symlink);
}
foreach my $fn (qw( rsync.yo rsyncd.conf.yo )) {
my $yo_tmp = "$dest/$fn";
(my $html_fn = "$dest/$fn") =~ s/\.yo/.html/;
open(IN, '<', $fn) or die $!;
undef $/; $_ = <IN>; $/ = "\n";
close IN;
s/^(manpage\([^)]+\)\(\d+\)\()[^)]+(\).*)/$1$today$2/m;
#s/^(This man ?page is current for version) \S+ (of rsync)/$1 $version $2/m;
open(OUT, '>', $yo_tmp) or die $!;
print OUT $_;
close OUT;
system 'yodl2html', '-o', $html_fn, $yo_tmp;
unlink($yo_tmp);
}
chdir($dest) or die $!;
my $cnt = 0;
open(PIPE, '-|', 'ls -1t rsync-HEAD-*') or die $!;
while (<PIPE>) {
chomp;
next if $cnt++ < 10;
unlink($_);
}
close PIPE;
system 'ls -ltr';
if ($upload) {
my $opt = '';
if (defined $ENV{RSYNC_PARTIAL_DIR}) {
$opt = " -f 'R $ENV{RSYNC_PARTIAL_DIR}'";
}
system "rsync$opt -aviHP --delete-after . samba.org:/home/ftp/pub/rsync/dev/nightly";
}
exit;
sub usage
{
die <<EOT;
Usage: nightly-rsync [OPTIONS]
-t, --make-tar create a new tar file in $dest
-u, --upload upload the revised nightly dir to samba.org
-h, --help display this help
EOT
}

View File

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

View File

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

View File

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

View File

@@ -1,39 +0,0 @@
#!/bin/sh -e
# This script will setup the build dir based on the current git branch and the
# directory auto-build-save/$BRANCH. We don't use a symlink for the build dir
# because we want to maximize the ccache reuse, so all builds must happen in
# the same real dir. When a dir is moved out of auto-build-save/$BRANCH to the
# build dir, it is replaced with a symlink so that it can still be found under
# that dir. The build dir also gets a .branch -> $BRANCH symlink so that we
# can figure out the current build dir's branch.
# To get started, just clone the rsync git repo and create the auto-build-save
# dir. If you have an existing git checkout and it is not in a pristine state,
# run "make distclean" before creating the auto-build-save dir.
auto_top='auto-build-save'
if test -d $auto_top -a -d .git; then
desired_branch=`git rev-parse --abbrev-ref HEAD | tr / %`
auto_dir="$auto_top/$desired_branch"
if test -d build; then
cur_branch=`readlink build/.branch`
else
cur_branch='/'
fi
if test "$desired_branch" != "$cur_branch"; then
if test "$cur_branch" != /; then
rm -f "$auto_top/$cur_branch"
mv build "$auto_top/$cur_branch"
fi
test -d "$auto_dir" || mkdir "$auto_dir"
test -h "$auto_dir/.branch" || ln -s "$desired_branch" "$auto_dir/.branch"
mv "$auto_dir" build
ln -s ../build "$auto_dir"
fi
if test ! -h Makefile; then
rm -f Makefile
ln -s packaging/auto-Makefile Makefile
fi
echo $desired_branch
fi

View File

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

View File

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

View File

@@ -1,31 +0,0 @@
[Unit]
Description=fast remote file copy program daemon
ConditionPathExists=/etc/rsyncd.conf
After=network.target
Documentation=man:rsync(1) man:rsyncd.conf(5)
[Service]
ExecStart=/usr/bin/rsync --daemon --no-detach
RestartSec=1
# Citing README.md:
#
# [...] Using ssh is recommended for its security features.
#
# Alternatively, rsync can run in `daemon' mode, listening on a socket.
# This is generally used for public file distribution, [...]
#
# So let's assume some extra security is more than welcome here. We do full
# system protection (which makes /usr, /boot, & /etc read-only) and hide
# devices. To override these defaults, it's best to do so in the drop-in
# directory, often done via `systemctl edit rsync.service`. The file needs
# just the bare minimum of the right [heading] and override values.
# See systemd.unit(5) and search for "drop-in" for full details.
ProtectSystem=full
#ProtectHome=on|off|read-only
PrivateDevices=on
NoNewPrivileges=on
[Install]
WantedBy=multi-user.target

View File

@@ -1,10 +0,0 @@
[Unit]
Description=socket for fast remote file copy program daemon
Conflicts=rsync.service
[Socket]
ListenStream=873
Accept=true
[Install]
WantedBy=sockets.target

View File

@@ -1,28 +0,0 @@
[Unit]
Description=fast remote file copy program daemon
After=network.target
[Service]
ExecStart=-/usr/bin/rsync --daemon
StandardInput=socket
StandardOutput=inherit
StandardError=journal
# Citing README.md:
#
# [...] Using ssh is recommended for its security features.
#
# Alternatively, rsync can run in `daemon' mode, listening on a socket.
# This is generally used for public file distribution, [...]
#
# So let's assume some extra security is more than welcome here. We do full
# system protection (which makes /usr, /boot, & /etc read-only) and hide
# devices. To override these defaults, it's best to do so in the drop-in
# directory, often done via `systemctl edit rsync@.service`. The file needs
# just the bare minimum of the right [heading] and override values.
# See systemd.unit(5) and search for "drop-in" for full details.
ProtectSystem=full
#ProtectHome=on|off|read-only
PrivateDevices=on
NoNewPrivileges=on

View File

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

View File

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

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