mirror of
https://github.com/RsyncProject/rsync.git
synced 2026-05-25 15:25:30 -04:00
Compare commits
40 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
d596d389fe | ||
|
|
bc2337717e | ||
|
|
3df40f044a | ||
|
|
d11a5b80c1 | ||
|
|
deea1f70bd | ||
|
|
a91e678324 | ||
|
|
25a22d8501 | ||
|
|
fac9e234ae | ||
|
|
f3d87ee972 | ||
|
|
9bed85542c | ||
|
|
5b979530a7 | ||
|
|
7ec8baaa7e | ||
|
|
8c2c008984 | ||
|
|
719a29e1cf | ||
|
|
4a95d61251 | ||
|
|
fc088e30c8 | ||
|
|
aef51b4c68 | ||
|
|
7790ee3684 | ||
|
|
ed12c8eb21 | ||
|
|
91dd3d0d48 | ||
|
|
95d1d2a9a4 | ||
|
|
a808346dbe | ||
|
|
fa181223d8 | ||
|
|
9ed569486f | ||
|
|
2fa069d85f | ||
|
|
a25aed50e6 | ||
|
|
302e4346c2 | ||
|
|
8e5eafccdf | ||
|
|
e88b92bade | ||
|
|
f8722dba56 | ||
|
|
ee03cb99d9 | ||
|
|
92d706a274 | ||
|
|
581c830c56 | ||
|
|
9e58ef45f3 | ||
|
|
05bd05a7a1 | ||
|
|
89b6b4ce4b | ||
|
|
68cdc3b791 | ||
|
|
209371b891 | ||
|
|
6fd2662982 | ||
|
|
1fdf0302c0 |
23
.cirrus.yml
23
.cirrus.yml
@@ -1,23 +0,0 @@
|
||||
freebsd_task:
|
||||
name: FreeBSD
|
||||
freebsd_instance:
|
||||
image_family: freebsd-13-1
|
||||
env:
|
||||
PATH: /usr/local/bin:$PATH
|
||||
prep_script:
|
||||
- dd if=/dev/zero of=/tmp/zpool bs=1M count=1024
|
||||
- zpool create -m `pwd`/testtmp zpool /tmp/zpool
|
||||
- pkg install -y bash autotools m4 xxhash zstd liblz4 wget
|
||||
- wget -O git-version.h https://gist.githubusercontent.com/WayneD/c11243fa374fc64d4e42f2855c8e3827/raw/rsync-git-version.h
|
||||
configure_script:
|
||||
- CPPFLAGS=-I/usr/local/include/ LDFLAGS=-L/usr/local/lib/ ./configure --disable-md2man
|
||||
make_script:
|
||||
- make
|
||||
install_script:
|
||||
- make install
|
||||
info_script:
|
||||
- rsync --version
|
||||
test_script:
|
||||
- RSYNC_EXPECT_SKIPPED=acls-default,acls,crtimes,protected-regular make check
|
||||
ssl_file_list_script:
|
||||
- rsync-ssl --no-motd download.samba.org::rsyncftp/ || true
|
||||
1
.gitattributes
vendored
1
.gitattributes
vendored
@@ -1 +0,0 @@
|
||||
* text=auto eol=lf
|
||||
125
.github/workflows/build.yml
vendored
125
.github/workflows/build.yml
vendored
@@ -1,125 +0,0 @@
|
||||
name: build
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [ master ]
|
||||
paths-ignore: [ .cirrus.yml ]
|
||||
pull_request:
|
||||
branches: [ master ]
|
||||
paths-ignore: [ .cirrus.yml ]
|
||||
schedule:
|
||||
- cron: '42 8 * * *'
|
||||
|
||||
jobs:
|
||||
|
||||
ubuntu-build:
|
||||
runs-on: ubuntu-20.04
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- name: prep
|
||||
run: |
|
||||
sudo apt-get install acl libacl1-dev attr libattr1-dev liblz4-dev libzstd-dev libxxhash-dev python3-cmarkgfm openssl wget
|
||||
wget -O git-version.h https://gist.githubusercontent.com/WayneD/c11243fa374fc64d4e42f2855c8e3827/raw/rsync-git-version.h
|
||||
echo "/usr/local/bin" >>$GITHUB_PATH
|
||||
- name: configure
|
||||
run: ./configure --with-rrsync
|
||||
- name: make
|
||||
run: make
|
||||
- name: install
|
||||
run: sudo make install
|
||||
- name: info
|
||||
run: rsync --version
|
||||
- name: check
|
||||
run: sudo RSYNC_EXPECT_SKIPPED=crtimes make check
|
||||
- name: check30
|
||||
run: sudo RSYNC_EXPECT_SKIPPED=crtimes make check30
|
||||
- name: check29
|
||||
run: sudo RSYNC_EXPECT_SKIPPED=crtimes make check29
|
||||
- name: ssl file list
|
||||
run: rsync-ssl --no-motd download.samba.org::rsyncftp/ || true
|
||||
- name: save artifact
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: ubuntu-bin
|
||||
path: |
|
||||
rsync
|
||||
rsync-ssl
|
||||
rsync.1
|
||||
rsync-ssl.1
|
||||
rsyncd.conf.5
|
||||
rrsync.1
|
||||
rrsync
|
||||
|
||||
macos-build:
|
||||
runs-on: macos-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- name: prep
|
||||
run: |
|
||||
brew install automake openssl xxhash zstd lz4 wget
|
||||
sudo pip3 install commonmark
|
||||
wget -O git-version.h https://gist.githubusercontent.com/WayneD/c11243fa374fc64d4e42f2855c8e3827/raw/rsync-git-version.h
|
||||
echo "/usr/local/bin" >>$GITHUB_PATH
|
||||
- name: configure
|
||||
run: CPPFLAGS=-I/usr/local/opt/openssl/include/ LDFLAGS=-L/usr/local/opt/openssl/lib/ ./configure --with-rrsync
|
||||
- name: make
|
||||
run: make
|
||||
- name: install
|
||||
run: sudo make install
|
||||
- name: info
|
||||
run: rsync --version
|
||||
- name: check
|
||||
run: sudo RSYNC_EXPECT_SKIPPED=acls-default,chmod-temp-dir,chown-fake,devices-fake,dir-sgid,protected-regular,xattrs-hlink,xattrs make check
|
||||
- name: ssl file list
|
||||
run: rsync-ssl --no-motd download.samba.org::rsyncftp/ || true
|
||||
- name: save artifact
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: macos-bin
|
||||
path: |
|
||||
rsync
|
||||
rsync-ssl
|
||||
rsync.1
|
||||
rsync-ssl.1
|
||||
rsyncd.conf.5
|
||||
rrsync.1
|
||||
rrsync
|
||||
|
||||
cygwin-build:
|
||||
runs-on: windows-2022
|
||||
if: (github.event_name == 'schedule' || contains(github.event.head_commit.message, '[buildall]'))
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- name: cygwin
|
||||
run: choco install -y --no-progress cygwin cyg-get
|
||||
- name: prep
|
||||
run: |
|
||||
cyg-get make autoconf automake gcc-core attr libattr-devel python39 python39-pip libzstd-devel liblz4-devel libssl-devel libxxhash0 libxxhash-devel
|
||||
curl.exe -o git-version.h https://gist.githubusercontent.com/WayneD/c11243fa374fc64d4e42f2855c8e3827/raw/rsync-git-version.h
|
||||
echo "C:/tools/cygwin/bin" >>$Env:GITHUB_PATH
|
||||
- name: commonmark
|
||||
run: bash -c 'python3 -mpip install --user commonmark'
|
||||
- name: configure
|
||||
run: bash -c './configure --with-rrsync'
|
||||
- name: make
|
||||
run: bash -c 'make'
|
||||
- name: install
|
||||
run: bash -c 'make install'
|
||||
- name: info
|
||||
run: bash -c '/usr/local/bin/rsync --version'
|
||||
- name: check
|
||||
run: bash -c 'RSYNC_EXPECT_SKIPPED=acls-default,acls,chown,devices,dir-sgid,protected-regular make check'
|
||||
- name: ssl file list
|
||||
run: bash -c 'PATH="/usr/local/bin:$PATH" rsync-ssl --no-motd download.samba.org::rsyncftp/ || true'
|
||||
- name: save artifact
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: cygwin-bin
|
||||
path: |
|
||||
rsync.exe
|
||||
rsync-ssl
|
||||
rsync.1
|
||||
rsync-ssl.1
|
||||
rsyncd.conf.5
|
||||
rrsync.1
|
||||
rrsync
|
||||
23
.gitignore
vendored
23
.gitignore
vendored
@@ -12,35 +12,22 @@ config.h.in
|
||||
config.h.in.old
|
||||
config.log
|
||||
config.status
|
||||
aclocal.m4
|
||||
/proto.h
|
||||
/proto.h-tstamp
|
||||
/rsync*.[15]
|
||||
/rrsync
|
||||
/rrsync*.1
|
||||
/rsync*.html
|
||||
/rrsync*.html
|
||||
/help-rsync*.h
|
||||
/default-cvsignore.h
|
||||
/default-dont-compress.h
|
||||
/daemon-parm.h
|
||||
/.md2man-works
|
||||
/rsync.1
|
||||
/rsyncd.conf.5
|
||||
/autom4te*.cache
|
||||
/confdefs.h
|
||||
/conftest*
|
||||
/dox
|
||||
/getgroups
|
||||
/gists
|
||||
/gmon.out
|
||||
/rsync
|
||||
/stunnel-rsyncd.conf
|
||||
/shconfig
|
||||
/git-version.h
|
||||
/testdir
|
||||
/tests-dont-exist
|
||||
/testtmp
|
||||
/tls
|
||||
/testrun
|
||||
/trimslash
|
||||
/t_unsafe
|
||||
/wildtest
|
||||
@@ -51,10 +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
|
||||
/*.exe
|
||||
|
||||
17
COPYING
17
COPYING
@@ -1,16 +1,7 @@
|
||||
REGARDING OPENSSL AND XXHASH
|
||||
|
||||
In addition, as a special exception, the copyright holders give
|
||||
permission to dynamically link rsync with the OpenSSL and xxhash
|
||||
libraries when those libraries are being distributed in compliance
|
||||
with their license terms, and to distribute a dynamically linked
|
||||
combination of rsync and these libraries. This is also considered
|
||||
to be covered under the GPL's System Libraries exception.
|
||||
|
||||
GNU GENERAL PUBLIC LICENSE
|
||||
Version 3, 29 June 2007
|
||||
|
||||
Copyright (C) 2007 Free Software Foundation, Inc. <https://fsf.org/>
|
||||
Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
|
||||
Everyone is permitted to copy and distribute verbatim copies
|
||||
of this license document, but changing it is not allowed.
|
||||
|
||||
@@ -654,7 +645,7 @@ the "copyright" line and a pointer to where the full notice is found.
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
Also add information on how to contact you by electronic and paper mail.
|
||||
|
||||
@@ -673,11 +664,11 @@ might be different; for a GUI interface, you would use an "about box".
|
||||
You should also get your employer (if you work as a programmer) or school,
|
||||
if any, to sign a "copyright disclaimer" for the program, if necessary.
|
||||
For more information on this, and how to apply and follow the GNU GPL, see
|
||||
<https://www.gnu.org/licenses/>.
|
||||
<http://www.gnu.org/licenses/>.
|
||||
|
||||
The GNU General Public License does not permit incorporating your program
|
||||
into proprietary programs. If your program is a subroutine library, you
|
||||
may consider it more useful to permit linking proprietary applications with
|
||||
the library. If this is what you want to do, use the GNU Lesser General
|
||||
Public License instead of this License. But first, please read
|
||||
<https://www.gnu.org/licenses/why-not-lgpl.html>.
|
||||
<http://www.gnu.org/philosophy/why-not-lgpl.html>.
|
||||
|
||||
63
INSTALL
Normal file
63
INSTALL
Normal file
@@ -0,0 +1,63 @@
|
||||
To build and install rsync:
|
||||
|
||||
$ ./configure
|
||||
$ make
|
||||
# make install
|
||||
|
||||
You may set the installation directory and other parameters by options
|
||||
to ./configure. To see them, use:
|
||||
|
||||
$ ./configure --help
|
||||
|
||||
Configure tries to figure out if the local system uses group "nobody" or
|
||||
"nogroup" by looking in the /etc/group file. (This is only used for the
|
||||
default group of an rsync daemon, which attempts to run with "nobody"
|
||||
user and group permissions.) You can change the default user and group
|
||||
for the daemon by editing the NOBODY_USER and NOBODY_GROUP defines in
|
||||
config.h, or just override them in your /etc/rsyncd.conf file.
|
||||
|
||||
As of 2.4.7, rsync uses Eric Troan's popt option-parsing library. A
|
||||
cut-down copy of 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.
|
||||
|
||||
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.
|
||||
|
||||
RPM NOTES
|
||||
---------
|
||||
|
||||
Under packaging you will find .spec files for several distributions.
|
||||
The .spec file in packaging/lsb can be used for Linux systems that
|
||||
adhere to the Linux Standards Base (e.g., RedHat and others).
|
||||
|
||||
HP-UX NOTES
|
||||
-----------
|
||||
|
||||
The HP-UX 10.10 "bundled" C compiler seems not to be able to cope with
|
||||
ANSI C. You may see this error message in config.log if ./configure
|
||||
fails:
|
||||
|
||||
(Bundled) cc: "configure", line 2162: error 1705: Function prototypes are an ANSI feature.
|
||||
|
||||
Install gcc or HP's "ANSI/C Compiler".
|
||||
|
||||
MAC OSX NOTES
|
||||
-------------
|
||||
|
||||
Some versions of Mac OS X (Darwin) seem to have an IPv6 stack, but do
|
||||
not completely implement the "New Sockets" API.
|
||||
|
||||
<http://www.ipv6.org/impl/mac.html> says that Apple started to support
|
||||
IPv6 in 10.2 (Jaguar). If your build fails, try again after running
|
||||
configure with --disable-ipv6.
|
||||
|
||||
IBM AIX NOTES
|
||||
-------------
|
||||
|
||||
IBM AIX has a largefile problem with mkstemp. See IBM PR-51921.
|
||||
The workaround is to append the below to config.h
|
||||
#ifdef _LARGE_FILES
|
||||
#undef HAVE_SECURE_MKSTEMP
|
||||
#endif
|
||||
242
INSTALL.md
242
INSTALL.md
@@ -1,242 +0,0 @@
|
||||
# How to build and install rsync
|
||||
|
||||
When building rsync, you'll want to install various libraries in order to get
|
||||
all the features enabled. The configure script will alert you when the
|
||||
newest libraries are missing and tell you the appropriate `--disable-LIB`
|
||||
option to use if you want to just skip that feature. What follows are various
|
||||
support libraries that you may want to install to build rsync with the maximum
|
||||
features (the impatient can skip down to the package summary):
|
||||
|
||||
## The basic setup
|
||||
|
||||
You need to have a C compiler installed and optionally a C++ compiler in order
|
||||
to try to build some hardware-accelerated checksum routines. Rsync also needs
|
||||
a modern awk, which might be provided via gawk or nawk on some OSes.
|
||||
|
||||
## Autoconf & manpages
|
||||
|
||||
If you're installing from the git repo (instead of a release tar file) you'll
|
||||
also need the GNU autotools (autoconf & automake) and your choice of 2 python3
|
||||
markdown libraries: cmarkgfm or commonmark (needed to generate the manpages).
|
||||
If your OS doesn't provide a python3-cmarkgfm or python3-commonmark package,
|
||||
you can run the following to install the commonmark python library for your
|
||||
build user (after installing python3's pip package):
|
||||
|
||||
> python3 -mpip install --user commonmark
|
||||
|
||||
You can test if you've got it fixed by running (from the rsync checkout):
|
||||
|
||||
> ./md-convert --test rsync-ssl.1.md
|
||||
|
||||
Alternately, you can avoid generating the manpages by fetching the very latest
|
||||
versions (that match the latest git source) from the [generated-files][6] dir.
|
||||
One way to do that is to run:
|
||||
|
||||
> ./prepare-source fetchgen
|
||||
|
||||
[6]: https://download.samba.org/pub/rsync/generated-files/
|
||||
|
||||
## ACL support
|
||||
|
||||
To support copying ACL file information, make sure you have an acl
|
||||
development library installed. It also helps to have the helper programs
|
||||
installed to manipulate ACLs and to run the rsync testsuite.
|
||||
|
||||
## Xattr support
|
||||
|
||||
To support copying xattr file information, make sure you have an attr
|
||||
development library installed. It also helps to have the helper programs
|
||||
installed to manipulate xattrs and to run the rsync testsuite.
|
||||
|
||||
## xxhash
|
||||
|
||||
The [xxHash library][1] provides extremely fast checksum functions that can
|
||||
make the "rsync algorithm" run much more quickly, especially when matching
|
||||
blocks in large files. Installing this development library adds xxhash
|
||||
checksums as the default checksum algorithm. You'll need at least v0.8.0
|
||||
if you want rsync to include the full range of its checksum algorithms.
|
||||
|
||||
[1]: https://cyan4973.github.io/xxHash/
|
||||
|
||||
## zstd
|
||||
|
||||
The [zstd library][2] compression algorithm that uses less CPU than
|
||||
the default zlib algorithm at the same compression level. Note that you
|
||||
need at least version 1.4, so you might need to skip the zstd compression if
|
||||
you can only install a 1.3 release. Installing this development library
|
||||
adds zstd compression as the default compression algorithm.
|
||||
|
||||
[2]: http://facebook.github.io/zstd/
|
||||
|
||||
## lz4
|
||||
|
||||
The [lz4 library][3] compression algorithm that uses very little CPU, though
|
||||
it also has the smallest compression ratio of other algorithms. Installing
|
||||
this development library adds lz4 compression as an available compression
|
||||
algorithm.
|
||||
|
||||
[3]: https://lz4.github.io/lz4/
|
||||
|
||||
## openssl crypto
|
||||
|
||||
The [openssl crypto library][4] provides some hardware accelerated checksum
|
||||
algorithms for MD4 and MD5. Installing this development library makes rsync
|
||||
use the (potentially) faster checksum routines when computing MD4 & MD5
|
||||
checksums.
|
||||
|
||||
[4]: https://www.openssl.org/docs/man1.0.2/man3/crypto.html
|
||||
|
||||
## Package summary
|
||||
|
||||
To help you get the libraries installed, here are some package install commands
|
||||
for various OSes. The commands are split up to correspond with the above
|
||||
items, but feel free to combine the package names into a single install, if you
|
||||
like.
|
||||
|
||||
- For Debian and Ubuntu (Debian Buster users may want to briefly(?) enable
|
||||
buster-backports to update zstd from 1.3 to 1.4):
|
||||
|
||||
> sudo apt install -y gcc g++ gawk autoconf automake python3-cmarkgfm
|
||||
> sudo apt install -y acl libacl1-dev
|
||||
> sudo apt install -y attr libattr1-dev
|
||||
> sudo apt install -y libxxhash-dev
|
||||
> sudo apt install -y libzstd-dev
|
||||
> sudo apt install -y liblz4-dev
|
||||
> sudo apt install -y libssl-dev
|
||||
|
||||
- For CentOS (use EPEL for python3-pip):
|
||||
|
||||
> sudo yum -y install epel-release
|
||||
> sudo yum -y install gcc g++ gawk autoconf automake python3-pip
|
||||
> sudo yum -y install acl libacl-devel
|
||||
> sudo yum -y install attr libattr-devel
|
||||
> sudo yum -y install xxhash-devel
|
||||
> sudo yum -y install libzstd-devel
|
||||
> sudo yum -y install lz4-devel
|
||||
> sudo yum -y install openssl-devel
|
||||
> python3 -mpip install --user commonmark
|
||||
|
||||
- For Fedora 33:
|
||||
|
||||
> sudo dnf -y install acl libacl-devel
|
||||
> sudo dnf -y install attr libattr-devel
|
||||
> sudo dnf -y install xxhash-devel
|
||||
> sudo dnf -y install libzstd-devel
|
||||
> sudo dnf -y install lz4-devel
|
||||
> sudo dnf -y install openssl-devel
|
||||
|
||||
- For FreeBSD (this assumes that the python3 version is 3.7):
|
||||
|
||||
> sudo pkg install -y autotools python3 py37-CommonMark
|
||||
> sudo pkg install -y xxhash
|
||||
> sudo pkg install -y zstd
|
||||
> sudo pkg install -y liblz4
|
||||
|
||||
- For macOS:
|
||||
|
||||
> brew install automake
|
||||
> brew install xxhash
|
||||
> brew install zstd
|
||||
> brew install lz4
|
||||
> brew install openssl
|
||||
|
||||
- For Cygwin (with all cygwin programs stopped, run the appropriate setup program from a cmd shell):
|
||||
|
||||
> setup-x86_64 --quiet-mode -P make,gawk,autoconf,automake,gcc-core,python38,python38-pip
|
||||
> setup-x86_64 --quiet-mode -P attr,libattr-devel
|
||||
> setup-x86_64 --quiet-mode -P libzstd-devel
|
||||
> setup-x86_64 --quiet-mode -P liblz4-devel
|
||||
> setup-x86_64 --quiet-mode -P libssl-devel
|
||||
|
||||
Sometimes cygwin has commonmark packaged and sometimes it doesn't. Now that
|
||||
its python38 has stabilized, you could install python38-commonmark. Or just
|
||||
avoid the issue by running this from a bash shell as your build user:
|
||||
|
||||
> python3 -mpip install --user commonmark
|
||||
|
||||
## Build and install
|
||||
|
||||
After installing the various libraries, you need to configure, build, and
|
||||
install the source:
|
||||
|
||||
> ./configure
|
||||
> make
|
||||
> sudo make install
|
||||
|
||||
The default install path is /usr/local/bin, but you can set the installation
|
||||
directory and other parameters using options to ./configure. To see them, use:
|
||||
|
||||
> ./configure --help
|
||||
|
||||
Configure tries to figure out if the local system uses group "nobody" or
|
||||
"nogroup" by looking in the /etc/group file. (This is only used for the
|
||||
default group of an rsync daemon, which attempts to run with "nobody"
|
||||
user and group permissions.) You can change the default user and group
|
||||
for the daemon by editing the NOBODY_USER and NOBODY_GROUP defines in
|
||||
config.h, or just override them in your /etc/rsyncd.conf file.
|
||||
|
||||
As of 2.4.7, rsync uses Eric Troan's popt option-parsing library. A
|
||||
cut-down copy of a recent release is included in the rsync distribution,
|
||||
and will be used if there is no popt library on your build host, or if
|
||||
the `--with-included-popt` option is passed to ./configure.
|
||||
|
||||
If you configure using `--enable-maintainer-mode`, then rsync will try
|
||||
to pop up an xterm on DISPLAY=:0 if it crashes. You might find this
|
||||
useful, but it should be turned off for production builds.
|
||||
|
||||
If you want to automatically use a separate "build" directory based on
|
||||
the current git branch name, start with a pristine git checkout and run
|
||||
"mkdir auto-build-save" before you run the first ./configure command.
|
||||
That will cause a fresh build dir to spring into existence along with a
|
||||
special Makefile symlink that allows you to run "make" and "./configure"
|
||||
from the source dir (the "build" dir gets auto switched based on branch).
|
||||
This is helpful when using the branch-from-patch and patch-update scripts
|
||||
to maintain the official rsync patches. If you ever need to build from
|
||||
a "detached head" git position then you'll need to manually chdir into
|
||||
the build dir to run make. I also like to create 2 more symlinks in the
|
||||
source dir: `ln -s build/rsync . ; ln -s build/testtmp .`
|
||||
|
||||
## Make compatibility
|
||||
|
||||
Note that Makefile.in has a rule that uses a wildcard in a prerequisite. If
|
||||
your make has a problem with this rule, you will see an error like this:
|
||||
|
||||
Don't know how to make ./*.c
|
||||
|
||||
You can change the "proto.h-tstamp" target in Makefile.in to list all the \*.c
|
||||
filenames explicitly in order to avoid this issue.
|
||||
|
||||
## RPM notes
|
||||
|
||||
Under packaging you will find .spec files for several distributions.
|
||||
The .spec file in packaging/lsb can be used for Linux systems that
|
||||
adhere to the Linux Standards Base (e.g., RedHat and others).
|
||||
|
||||
## HP-UX notes
|
||||
|
||||
The HP-UX 10.10 "bundled" C compiler seems not to be able to cope with
|
||||
ANSI C. You may see this error message in config.log if ./configure
|
||||
fails:
|
||||
|
||||
(Bundled) cc: "configure", line 2162: error 1705: Function prototypes are an ANSI feature.
|
||||
|
||||
Install gcc or HP's "ANSI/C Compiler".
|
||||
|
||||
## Mac OS X notes
|
||||
|
||||
Some versions of Mac OS X (Darwin) seem to have an IPv6 stack, but do
|
||||
not completely implement the "New Sockets" API.
|
||||
|
||||
[This site][5] says that Apple started to support IPv6 in 10.2 (Jaguar). If
|
||||
your build fails, try again after running configure with `--disable-ipv6`.
|
||||
|
||||
[5]: http://www.ipv6.org/impl/mac.html
|
||||
|
||||
## IBM AIX notes
|
||||
|
||||
IBM AIX has a largefile problem with mkstemp. See IBM PR-51921.
|
||||
The workaround is to append the following to config.h:
|
||||
|
||||
> #ifdef _LARGE_FILES
|
||||
> #undef HAVE_SECURE_MKSTEMP
|
||||
> #endif
|
||||
248
Makefile.in
248
Makefile.in
@@ -1,68 +1,57 @@
|
||||
# The Makefile for rsync (configure creates it from Makefile.in).
|
||||
# Makefile for rsync. This is processed by configure to produce the final
|
||||
# Makefile
|
||||
|
||||
prefix=@prefix@
|
||||
datarootdir=@datarootdir@
|
||||
exec_prefix=@exec_prefix@
|
||||
bindir=@bindir@
|
||||
libdir=@libdir@/rsync
|
||||
mandir=@mandir@
|
||||
with_rrsync=@with_rrsync@
|
||||
|
||||
LIBS=@LIBS@
|
||||
CC=@CC@
|
||||
AWK=@AWK@
|
||||
CFLAGS=@CFLAGS@
|
||||
CPPFLAGS=@CPPFLAGS@
|
||||
CXX=@CXX@
|
||||
CXXFLAGS=@CXXFLAGS@
|
||||
EXEEXT=@EXEEXT@
|
||||
LDFLAGS=@LDFLAGS@
|
||||
LIBOBJDIR=lib/
|
||||
|
||||
INSTALLCMD=@INSTALL@
|
||||
INSTALLMAN=@INSTALL@
|
||||
|
||||
srcdir=@srcdir@
|
||||
MKDIR_P=@MKDIR_P@
|
||||
VPATH=$(srcdir)
|
||||
SHELL=/bin/sh
|
||||
|
||||
VERSION=@VERSION@
|
||||
|
||||
.SUFFIXES:
|
||||
.SUFFIXES: .c .o
|
||||
|
||||
ROLL_SIMD_x86_64=simd-checksum-x86_64.o
|
||||
ROLL_ASM_x86_64=simd-checksum-avx2.o
|
||||
MD5_ASM_x86_64=lib/md5-asm-x86_64.o
|
||||
|
||||
GENFILES=configure.sh aclocal.m4 config.h.in rsync.1 rsync.1.html \
|
||||
rsync-ssl.1 rsync-ssl.1.html rsyncd.conf.5 rsyncd.conf.5.html \
|
||||
@GEN_RRSYNC@
|
||||
HEADERS=byteorder.h config.h errcode.h proto.h rsync.h ifuncs.h itypes.h inums.h \
|
||||
lib/pool_alloc.h lib/mdigest.h lib/md-defines.h
|
||||
GENFILES=configure.sh config.h.in proto.h proto.h-tstamp rsync.1 rsyncd.conf.5
|
||||
HEADERS=byteorder.h config.h errcode.h proto.h rsync.h ifuncs.h lib/pool_alloc.h
|
||||
LIBOBJ=lib/wildmatch.o lib/compat.o lib/snprintf.o lib/mdfour.o lib/md5.o \
|
||||
lib/permstring.o lib/pool_alloc.o lib/sysacls.o lib/sysxattrs.o @LIBOBJS@
|
||||
zlib_OBJS=zlib/deflate.o zlib/inffast.o zlib/inflate.o zlib/inftrees.o \
|
||||
ZLIBOBJ=zlib/deflate.o zlib/inffast.o zlib/inflate.o zlib/inftrees.o \
|
||||
zlib/trees.o zlib/zutil.o zlib/adler32.o zlib/compress.o zlib/crc32.o
|
||||
OBJS1=flist.o rsync.o generator.o receiver.o cleanup.o sender.o exclude.o \
|
||||
util1.o util2.o main.o checksum.o match.o syscall.o log.o backup.o delete.o
|
||||
util.o main.o checksum.o match.o syscall.o log.o backup.o
|
||||
OBJS2=options.o io.o compat.o hlink.o token.o uidlist.o socket.o hashtable.o \
|
||||
usage.o fileio.o batch.o clientname.o chmod.o acls.o xattrs.o
|
||||
OBJS3=progress.o pipe.o @MD5_ASM@ @ROLL_SIMD@ @ROLL_ASM@
|
||||
fileio.o batch.o clientname.o chmod.o acls.o xattrs.o
|
||||
OBJS3=progress.o pipe.o
|
||||
DAEMON_OBJ = params.o loadparm.o clientserver.o access.o connection.o authenticate.o
|
||||
popt_OBJS=popt/findme.o popt/popt.o popt/poptconfig.o \
|
||||
popt/popthelp.o popt/poptparse.o
|
||||
OBJS=$(OBJS1) $(OBJS2) $(OBJS3) $(DAEMON_OBJ) $(LIBOBJ) @BUILD_ZLIB@ @BUILD_POPT@
|
||||
OBJS=$(OBJS1) $(OBJS2) $(OBJS3) $(DAEMON_OBJ) $(LIBOBJ) $(ZLIBOBJ) @BUILD_POPT@
|
||||
|
||||
TLS_OBJ = tls.o syscall.o util2.o t_stub.o lib/compat.o lib/snprintf.o lib/permstring.o lib/sysxattrs.o @BUILD_POPT@
|
||||
TLS_OBJ = tls.o syscall.o lib/compat.o lib/snprintf.o lib/permstring.o lib/sysxattrs.o @BUILD_POPT@
|
||||
|
||||
# Programs we must have to run the test cases
|
||||
CHECK_PROGS = rsync$(EXEEXT) tls$(EXEEXT) getgroups$(EXEEXT) getfsdev$(EXEEXT) \
|
||||
testrun$(EXEEXT) trimslash$(EXEEXT) t_unsafe$(EXEEXT) 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:
|
||||
@@ -70,34 +59,15 @@ 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@
|
||||
|
||||
# NOTE: consider running "packaging/smart-make" instead of "make" to auto-handle
|
||||
# any changes to configure.sh and the main Makefile prior to a "make all".
|
||||
all: Makefile rsync$(EXEEXT) stunnel-rsyncd.conf @MAKE_RRSYNC@ @MAKE_MAN@
|
||||
.PHONY: all
|
||||
all: conf_stop make_stop rsync$(EXEEXT) @MAKE_MAN@
|
||||
|
||||
.PHONY: install
|
||||
install: all
|
||||
-$(MKDIR_P) $(DESTDIR)$(bindir)
|
||||
$(INSTALLCMD) $(INSTALL_STRIP) -m 755 rsync$(EXEEXT) $(DESTDIR)$(bindir)
|
||||
$(INSTALLCMD) -m 755 $(srcdir)/rsync-ssl $(DESTDIR)$(bindir)
|
||||
-$(MKDIR_P) $(DESTDIR)$(mandir)/man1
|
||||
-$(MKDIR_P) $(DESTDIR)$(mandir)/man5
|
||||
if test -f rsync.1; then $(INSTALLMAN) -m 644 rsync.1 $(DESTDIR)$(mandir)/man1; fi
|
||||
if test -f rsync-ssl.1; then $(INSTALLMAN) -m 644 rsync-ssl.1 $(DESTDIR)$(mandir)/man1; fi
|
||||
if test -f rsyncd.conf.5; then $(INSTALLMAN) -m 644 rsyncd.conf.5 $(DESTDIR)$(mandir)/man5; fi
|
||||
if test "$(with_rrsync)" = yes; then \
|
||||
$(INSTALLCMD) -m 755 rrsync $(DESTDIR)$(bindir); \
|
||||
if test -f rrsync.1; then $(INSTALLMAN) -m 644 rrsync.1 $(DESTDIR)$(mandir)/man1; fi; \
|
||||
fi
|
||||
|
||||
install-ssl-daemon: stunnel-rsyncd.conf
|
||||
-$(MKDIR_P) $(DESTDIR)/etc/stunnel
|
||||
$(INSTALLCMD) -m 644 stunnel-rsyncd.conf $(DESTDIR)/etc/stunnel/rsyncd.conf
|
||||
@if ! ls /etc/rsync-ssl/certs/server.* >/dev/null 2>/dev/null; then \
|
||||
echo "Note that you'll need to install the certificate used by /etc/stunnel/rsyncd.conf"; \
|
||||
fi
|
||||
|
||||
install-all: install install-ssl-daemon
|
||||
-mkdir -p ${DESTDIR}${bindir}
|
||||
${INSTALLCMD} ${INSTALL_STRIP} -m 755 rsync$(EXEEXT) ${DESTDIR}${bindir}
|
||||
-mkdir -p ${DESTDIR}${mandir}/man1
|
||||
-mkdir -p ${DESTDIR}${mandir}/man5
|
||||
if test -f rsync.1; then ${INSTALLMAN} -m 644 rsync.1 ${DESTDIR}${mandir}/man1; fi
|
||||
if test -f rsyncd.conf.5; then ${INSTALLMAN} -m 644 rsyncd.conf.5 ${DESTDIR}${mandir}/man5; fi
|
||||
|
||||
install-strip:
|
||||
$(MAKE) INSTALL_STRIP='-s' install
|
||||
@@ -105,27 +75,12 @@ install-strip:
|
||||
rsync$(EXEEXT): $(OBJS)
|
||||
$(CC) $(CFLAGS) $(LDFLAGS) -o $@ $(OBJS) $(LIBS)
|
||||
|
||||
rrsync: support/rrsync
|
||||
cp -p $(srcdir)/support/rrsync rrsync
|
||||
|
||||
$(OBJS): $(HEADERS)
|
||||
$(CHECK_OBJS): $(HEADERS)
|
||||
tls.o xattrs.o: lib/sysxattrs.h
|
||||
usage.o: version.h latest-year.h help-rsync.h help-rsyncd.h git-version.h default-cvsignore.h
|
||||
loadparm.o: default-dont-compress.h daemon-parm.h
|
||||
|
||||
flist.o: rounding.h
|
||||
|
||||
default-cvsignore.h default-dont-compress.h: rsync.1.md define-from-md.awk
|
||||
$(AWK) -f $(srcdir)/define-from-md.awk -v hfile=$@ $(srcdir)/rsync.1.md
|
||||
|
||||
help-rsync.h help-rsyncd.h: rsync.1.md help-from-md.awk
|
||||
$(AWK) -f $(srcdir)/help-from-md.awk -v hfile=$@ $(srcdir)/rsync.1.md
|
||||
|
||||
daemon-parm.h: daemon-parm.txt daemon-parm.awk
|
||||
$(AWK) -f $(srcdir)/daemon-parm.awk $(srcdir)/daemon-parm.txt
|
||||
|
||||
rounding.h: rounding.c rsync.h proto.h
|
||||
rounding.h: rounding.c rsync.h
|
||||
@for r in 0 1 3; do \
|
||||
if $(CC) $(CFLAGS) $(CPPFLAGS) $(LDFLAGS) -o rounding -DEXTRA_ROUNDING=$$r -I. $(srcdir)/rounding.c >rounding.out 2>&1; then \
|
||||
echo "#define EXTRA_ROUNDING $$r" >rounding.h; \
|
||||
@@ -143,59 +98,34 @@ rounding.h: rounding.c rsync.h proto.h
|
||||
fi
|
||||
@rm -f rounding.out
|
||||
|
||||
git-version.h: ALWAYS_RUN
|
||||
$(srcdir)/mkgitver
|
||||
|
||||
.PHONY: ALWAYS_RUN
|
||||
ALWAYS_RUN:
|
||||
|
||||
simd-checksum-x86_64.o: simd-checksum-x86_64.cpp
|
||||
@$(srcdir)/cmd-or-msg disable-roll-simd $(CXX) -I. $(CXXFLAGS) $(CPPFLAGS) -c -o $@ $(srcdir)/simd-checksum-x86_64.cpp
|
||||
|
||||
simd-checksum-avx2.o: simd-checksum-avx2.S
|
||||
@$(srcdir)/cmd-or-msg disable-roll-asm $(CC) $(CFLAGS) -I. @NOEXECSTACK@ -c -o $@ $(srcdir)/simd-checksum-avx2.S
|
||||
|
||||
lib/md5-asm-x86_64.o: lib/md5-asm-x86_64.S lib/md-defines.h
|
||||
@$(srcdir)/cmd-or-msg disable-md5-asm $(CC) -I. @NOEXECSTACK@ -c -o $@ $(srcdir)/lib/md5-asm-x86_64.S
|
||||
|
||||
tls$(EXEEXT): $(TLS_OBJ)
|
||||
$(CC) $(CFLAGS) $(LDFLAGS) -o $@ $(TLS_OBJ) $(LIBS)
|
||||
|
||||
testrun$(EXEEXT): testrun.o
|
||||
$(CC) $(CFLAGS) $(LDFLAGS) -o $@ testrun.o
|
||||
|
||||
getgroups$(EXEEXT): getgroups.o
|
||||
$(CC) $(CFLAGS) $(LDFLAGS) -o $@ getgroups.o $(LIBS)
|
||||
|
||||
getfsdev$(EXEEXT): getfsdev.o
|
||||
$(CC) $(CFLAGS) $(LDFLAGS) -o $@ getfsdev.o $(LIBS)
|
||||
|
||||
TRIMSLASH_OBJ = trimslash.o syscall.o util2.o t_stub.o lib/compat.o lib/snprintf.o
|
||||
TRIMSLASH_OBJ = trimslash.o syscall.o lib/compat.o lib/snprintf.o
|
||||
trimslash$(EXEEXT): $(TRIMSLASH_OBJ)
|
||||
$(CC) $(CFLAGS) $(LDFLAGS) -o $@ $(TRIMSLASH_OBJ) $(LIBS)
|
||||
|
||||
T_UNSAFE_OBJ = t_unsafe.o syscall.o util1.o util2.o t_stub.o lib/compat.o lib/snprintf.o lib/wildmatch.o
|
||||
T_UNSAFE_OBJ = t_unsafe.o syscall.o util.o t_stub.o lib/compat.o lib/snprintf.o lib/wildmatch.o
|
||||
t_unsafe$(EXEEXT): $(T_UNSAFE_OBJ)
|
||||
$(CC) $(CFLAGS) $(LDFLAGS) -o $@ $(T_UNSAFE_OBJ) $(LIBS)
|
||||
|
||||
.PHONY: conf
|
||||
conf: configure.sh config.h.in
|
||||
gen: conf proto.h man
|
||||
|
||||
.PHONY: gen
|
||||
gen: conf proto.h man git-version.h
|
||||
|
||||
.PHONY: gensend
|
||||
gensend: gen
|
||||
if ! diff git-version.h $(srcdir)/gists/rsync-git-version.h >/dev/null; then \
|
||||
./rsync -ai git-version.h $(srcdir)/gists/rsync-git-version.h && \
|
||||
(cd $(srcdir)/gists && git commit --allow-empty-message -m '' rsync-git-version.h && git push) ; \
|
||||
fi
|
||||
rsync -aic $(GENFILES) git-version.h $${SAMBA_HOST-samba.org}:/home/ftp/pub/rsync/generated-files/ || true
|
||||
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
|
||||
conf_stop: configure.sh config.h.in
|
||||
|
||||
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
|
||||
@@ -203,109 +133,86 @@ configure.sh config.h.in: configure.ac aclocal.m4
|
||||
@if diff configure.sh configure.sh.old >/dev/null 2>&1; then \
|
||||
echo "configure.sh is unchanged."; \
|
||||
rm configure.sh.old; \
|
||||
else \
|
||||
echo "configure.sh has CHANGED."; \
|
||||
fi
|
||||
@if diff config.h.in config.h.in.old >/dev/null 2>&1; then \
|
||||
echo "config.h.in is unchanged."; \
|
||||
rm config.h.in.old; \
|
||||
else \
|
||||
echo "config.h.in has CHANGED."; \
|
||||
fi
|
||||
@if test -f configure.sh.old || test -f config.h.in.old; then \
|
||||
if test "$(MAKECMDGOALS)" = reconfigure; then \
|
||||
echo 'Continuing with "make reconfigure".'; \
|
||||
else \
|
||||
echo 'You may need to run:'; \
|
||||
echo ' make reconfigure'; \
|
||||
exit 1; \
|
||||
fi \
|
||||
@if test -f configure.sh.old -o -f config.h.in.old; then \
|
||||
echo 'Configure files changed -- perhaps run:'; \
|
||||
echo ' make reconfigure'; \
|
||||
exit 1; \
|
||||
fi
|
||||
|
||||
.PHONY: reconfigure
|
||||
reconfigure: configure.sh
|
||||
./config.status --recheck
|
||||
./config.status
|
||||
|
||||
.PHONY: restatus
|
||||
restatus:
|
||||
./config.status
|
||||
make_stop: Makefile
|
||||
|
||||
Makefile: Makefile.in config.status configure.sh config.h.in
|
||||
Makefile: Makefile.in config.status
|
||||
@if test -f Makefile; then cp -p Makefile Makefile.old; else touch Makefile.old; fi
|
||||
@./config.status
|
||||
@if diff Makefile Makefile.old >/dev/null 2>&1; then \
|
||||
echo "Makefile is unchanged."; \
|
||||
rm Makefile.old; \
|
||||
else \
|
||||
if test "$(MAKECMDGOALS)" = reconfigure; then \
|
||||
echo 'Continuing with "make reconfigure".'; \
|
||||
else \
|
||||
echo "Makefile updated -- rerun your make command."; \
|
||||
exit 1; \
|
||||
fi \
|
||||
echo "Makefile updated -- rerun your make command."; \
|
||||
exit 1; \
|
||||
fi
|
||||
|
||||
stunnel-rsyncd.conf: $(srcdir)/stunnel-rsyncd.conf.in Makefile
|
||||
sed 's;\@bindir\@;$(bindir);g' <$(srcdir)/stunnel-rsyncd.conf.in >stunnel-rsyncd.conf
|
||||
|
||||
.PHONY: proto
|
||||
proto: proto.h-tstamp
|
||||
|
||||
proto.h: proto.h-tstamp
|
||||
@if test -f proto.h; then :; else cp -p $(srcdir)/proto.h .; fi
|
||||
|
||||
proto.h-tstamp: $(srcdir)/*.c $(srcdir)/lib/compat.c daemon-parm.h
|
||||
$(AWK) -f $(srcdir)/mkproto.awk $(srcdir)/*.c $(srcdir)/lib/compat.c daemon-parm.h
|
||||
proto.h-tstamp: $(srcdir)/*.c $(srcdir)/lib/compat.c
|
||||
perl $(srcdir)/mkproto.pl $(srcdir)/*.c $(srcdir)/lib/compat.c
|
||||
|
||||
.PHONY: man
|
||||
man: rsync.1 rsync-ssl.1 rsyncd.conf.5 @MAKE_RRSYNC_1@
|
||||
man: rsync.1 rsyncd.conf.5
|
||||
@if test -f rsync.1; then :; else cp -p $(srcdir)/rsync.1 .; fi
|
||||
@if test -f rsyncd.conf.5; then :; else cp -p $(srcdir)/rsyncd.conf.5 .; fi
|
||||
|
||||
rsync.1: rsync.1.md md-convert version.h Makefile
|
||||
@$(srcdir)/maybe-make-man rsync.1.md
|
||||
rsync.1: rsync.yo
|
||||
yodl2man -o rsync.1 $(srcdir)/rsync.yo
|
||||
-$(srcdir)/tweak_manpage rsync.1
|
||||
|
||||
rsync-ssl.1: rsync-ssl.1.md md-convert version.h Makefile
|
||||
@$(srcdir)/maybe-make-man rsync-ssl.1.md
|
||||
rsyncd.conf.5: rsyncd.conf.yo
|
||||
yodl2man -o rsyncd.conf.5 $(srcdir)/rsyncd.conf.yo
|
||||
-$(srcdir)/tweak_manpage rsyncd.conf.5
|
||||
|
||||
rsyncd.conf.5: rsyncd.conf.5.md md-convert version.h Makefile
|
||||
@$(srcdir)/maybe-make-man rsyncd.conf.5.md
|
||||
|
||||
rrsync.1: support/rrsync.1.md md-convert Makefile
|
||||
@$(srcdir)/maybe-make-man support/rrsync.1.md
|
||||
|
||||
.PHONY: clean
|
||||
clean: cleantests
|
||||
rm -f *~ $(OBJS) $(CHECK_PROGS) $(CHECK_OBJS) $(CHECK_SYMLINKS) @MAKE_RRSYNC@ \
|
||||
git-version.h rounding rounding.h *.old rsync*.1 rsync*.5 @MAKE_RRSYNC_1@ \
|
||||
*.html daemon-parm.h help-*.h default-*.h proto.h proto.h-tstamp
|
||||
rm -f *~ $(OBJS) $(CHECK_PROGS) $(CHECK_OBJS) $(CHECK_SYMLINKS) \
|
||||
rounding rounding.h *.old
|
||||
|
||||
.PHONY: cleantests
|
||||
cleantests:
|
||||
rm -rf ./testtmp*
|
||||
|
||||
# We try to delete built files from both the source and build
|
||||
# directories, just in case somebody previously configured things in
|
||||
# the source directory.
|
||||
.PHONY: distclean
|
||||
distclean: clean
|
||||
for dir in $(srcdir) . ; do \
|
||||
(cd "$$dir" && rm -rf Makefile config.h config.status stunnel-rsyncd.conf \
|
||||
lib/dummy popt/dummy zlib/dummy config.cache config.log shconfig \
|
||||
$(GENFILES) autom4te.cache) ; \
|
||||
done
|
||||
rm -f Makefile config.h config.status
|
||||
rm -f lib/dummy popt/dummy zlib/dummy
|
||||
rm -f $(srcdir)/Makefile $(srcdir)/config.h $(srcdir)/config.status
|
||||
rm -f $(srcdir)/lib/dummy $(srcdir)/popt/dummy $(srcdir)/zlib/dummy
|
||||
rm -f config.cache config.log
|
||||
rm -f $(srcdir)/config.cache $(srcdir)/config.log
|
||||
rm -f shconfig $(srcdir)/shconfig
|
||||
rm -f $(GENFILES)
|
||||
rm -rf autom4te.cache
|
||||
|
||||
# this target is really just for my use. It only works on a limited
|
||||
# range of machines and is used to produce a list of potentially
|
||||
# dead (ie. unused) functions in the code. (tridge)
|
||||
.PHONY: finddead
|
||||
finddead:
|
||||
nm *.o */*.o |grep 'U ' | awk '{print $$2}' | sort -u > nmused.txt
|
||||
nm *.o */*.o |grep 'T ' | awk '{print $$3}' | sort -u > nmfns.txt
|
||||
comm -13 nmused.txt nmfns.txt
|
||||
@rm nmused.txt nmfns.txt
|
||||
|
||||
# 'check' is the GNU name, 'test' is the name for everybody else :-)
|
||||
.PHONY: test
|
||||
.PHONY: check test
|
||||
|
||||
test: check
|
||||
|
||||
# There seems to be no standard way to specify some variables as
|
||||
@@ -318,19 +225,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)
|
||||
|
||||
@@ -340,14 +241,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
|
||||
|
||||
@@ -358,12 +255,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/
|
||||
|
||||
64
NEWS
Normal file
64
NEWS
Normal file
@@ -0,0 +1,64 @@
|
||||
NEWS for rsync 3.0.4 (6 Sep 2008)
|
||||
Protocol: 30 (unchanged)
|
||||
Changes since 3.0.3:
|
||||
|
||||
BUG FIXES:
|
||||
|
||||
- Fixed a bug in the hard-linking code where it would sometimes try to
|
||||
allocate 0 bytes of memory (which fails on some OSes, such as AIX).
|
||||
|
||||
- Fixed the hard-linking of files from a device that has a device number
|
||||
of 0 (which seems to be a common device number on NetBSD).
|
||||
|
||||
- Fixed the handling of a --partial-dir that cannot be created. This
|
||||
particularly impacts the --delay-updates option (since the files cannot
|
||||
be delayed without a partial-dir), and was potentially destructive if
|
||||
the --remove-source-files was also specified.
|
||||
|
||||
- Fixed a couple issues in the --fake-super handling of xattrs when the
|
||||
destination files have root-level attributes (e.g. selinux values) that
|
||||
a non-root copy can't affect.
|
||||
|
||||
- Improved the keep-alive check in the generator to fire consistently in
|
||||
incremental-recursion mode when --timeout is enabled.
|
||||
|
||||
- The --iconv option now converts the content of a symlink too, instead
|
||||
of leaving it in the wrong character-set (requires 3.0.4 on both sides
|
||||
of the transfer).
|
||||
|
||||
- When using --iconv, if a filename fails to convert on the receiving side,
|
||||
this no longer makes deletions in the root-dir of the transfer fail
|
||||
silently (the user now gets a warning about deletions being disabled
|
||||
due to IO error as long as --ignore-errors was not specified).
|
||||
|
||||
- When using --iconv, if a server-side receiver can't convert a filename,
|
||||
the error message sent back to the client no longer mangles the name
|
||||
with the wrong charset conversion.
|
||||
|
||||
- Fixed a potential alignment issue in the IRIX ACL code when allocating
|
||||
the initial "struct acl" object. Also, cast mallocs to avoid warnings.
|
||||
|
||||
- Changed some errors that were going to stdout to go to stderr.
|
||||
|
||||
- Made human_num() and human_dnum() able to output a negative number
|
||||
(rather than outputting a cryptic string of punctuation).
|
||||
|
||||
ENHANCEMENTS:
|
||||
|
||||
- Rsync will avoid sending an -e option to the server if an older protocol
|
||||
is requested (and thus the option would not be useful). This lets the
|
||||
user specify the --protocol=29 option to access an overly-restrictive
|
||||
server that is rejecting the protocol-30 use of -e to the server.
|
||||
|
||||
- Improved the message output for an RERR_PARTIAL exit.
|
||||
|
||||
DEVELOPER RELATED:
|
||||
|
||||
- The Makefile will not halt for just a timestamp change on the Makefile
|
||||
or the configure files, only for actual changes in content.
|
||||
|
||||
- Changed some commands in the testsuite's xattrs.test that called "rsync"
|
||||
instead of "$RSYNC".
|
||||
|
||||
- Enhanced the release scripts to be able to handle a branch release and
|
||||
to do even more consistency checks on the files.
|
||||
@@ -23,18 +23,8 @@ options. To get a complete list of supported options type:
|
||||
|
||||
rsync --help
|
||||
|
||||
See the [manpage][0] for more detailed information.
|
||||
See the manpage for more detailed information.
|
||||
|
||||
[0]: https://download.samba.org/pub/rsync/rsync.1
|
||||
|
||||
BUILDING AND INSTALLING
|
||||
-----------------------
|
||||
|
||||
If you need to build rsync yourself, check out the [INSTALL][1] page for
|
||||
information on what libraries and packages you can use to get the maximum
|
||||
features in your build.
|
||||
|
||||
[1]: https://github.com/WayneD/rsync/blob/master/INSTALL.md
|
||||
|
||||
SETUP
|
||||
-----
|
||||
@@ -65,17 +55,17 @@ RSYNC DAEMONS
|
||||
-------------
|
||||
|
||||
Rsync can also talk to "rsync daemons" which can provide anonymous or
|
||||
authenticated rsync. See the rsyncd.conf(5) manpage for details on how
|
||||
to setup an rsync daemon. See the rsync(1) manpage for info on how to
|
||||
authenticated rsync. See the rsyncd.conf(5) man page for details on how
|
||||
to setup an rsync daemon. See the rsync(1) man page for info on how to
|
||||
connect to an rsync daemon.
|
||||
|
||||
|
||||
WEB SITE
|
||||
--------
|
||||
|
||||
For more information, visit the [main rsync web site][2].
|
||||
The main rsync web site is here:
|
||||
|
||||
[2]: https://rsync.samba.org/
|
||||
http://rsync.samba.org/
|
||||
|
||||
You'll find a FAQ list, downloads, resources, HTML versions of the
|
||||
manpages, etc.
|
||||
@@ -87,58 +77,64 @@ MAILING LISTS
|
||||
There is a mailing list for the discussion of rsync and its applications
|
||||
that is open to anyone to join. New releases are announced on this
|
||||
list, and there is also an announcement-only mailing list for those that
|
||||
want official announcements. See the [mailing-list page][3] for full
|
||||
details.
|
||||
want official announcements. See the mailing-list page for full
|
||||
details:
|
||||
|
||||
[3]: https://rsync.samba.org/lists.html
|
||||
http://rsync.samba.org/lists.html
|
||||
|
||||
|
||||
BUG REPORTS
|
||||
-----------
|
||||
|
||||
The [bug-tracking web page][4] has full details on bug reporting.
|
||||
To visit this web page for full the details on bug reporting:
|
||||
|
||||
[4]: https://rsync.samba.org/bug-tracking.html
|
||||
http://rsync.samba.org/bugzilla.html
|
||||
|
||||
That page contains links to the current bug list, and information on how to
|
||||
do a good job when reporting a bug. You might also like to try searching
|
||||
the Internet for the error message you've received, or looking in the
|
||||
[mailing list archives][5].
|
||||
That page contains links to the current bug list, and information on how
|
||||
to report a bug well. You might also like to try searching the Internet
|
||||
for the error message you've received, or looking in the mailing list
|
||||
archives at:
|
||||
|
||||
[5]: https://mail-archive.com/rsync@lists.samba.org/
|
||||
http://mail-archive.com/rsync@lists.samba.org/
|
||||
|
||||
To send a bug report, follow the instructions on the bug-tracking
|
||||
page of the web site.
|
||||
|
||||
Alternately, email your bug report to <rsync@lists.samba.org>.
|
||||
Alternately, email your bug report to rsync@lists.samba.org .
|
||||
|
||||
|
||||
GIT REPOSITORY
|
||||
--------------
|
||||
|
||||
If you want to get the very latest version of rsync direct from the
|
||||
source code repository, then you will need to use git. The git repo
|
||||
is hosted [on GitHub][6] and [on Samba's site][7].
|
||||
source code repository then you can use git:
|
||||
|
||||
[6]: https://github.com/WayneD/rsync
|
||||
[7]: https://git.samba.org/?p=rsync.git;a=summary
|
||||
git clone git://git.samba.org/rsync.git
|
||||
|
||||
See [the download page][8] for full details on all the ways to grab the
|
||||
source.
|
||||
See the download page for full details on all the ways to grab the
|
||||
source, including nightly tar files, web-browsing of the git repository,
|
||||
etc.:
|
||||
|
||||
[8]: https://rsync.samba.org/download.html
|
||||
http://rsync.samba.org/download.html
|
||||
|
||||
|
||||
COPYRIGHT
|
||||
---------
|
||||
|
||||
Rsync was originally written by Andrew Tridgell and 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][9] in this
|
||||
distribution, or at [the Free Software Foundation][10].
|
||||
the GNU General Public License, found in the file COPYING in this
|
||||
distribution, or at:
|
||||
|
||||
[9]: https://github.com/WayneD/rsync/blob/master/COPYING
|
||||
[10]: https://www.fsf.org/licenses/gpl.html
|
||||
http://www.fsf.org/licenses/gpl.html
|
||||
|
||||
|
||||
AVAILABILITY
|
||||
------------
|
||||
|
||||
The main web site for rsync is http://rsync.samba.org/
|
||||
The main ftp site is ftp://rsync.samba.org/pub/rsync/
|
||||
This is also available as rsync://rsync.samba.org/rsyncftp/
|
||||
12
SECURITY.md
12
SECURITY.md
@@ -1,12 +0,0 @@
|
||||
# Security Policy
|
||||
|
||||
## Supported Versions
|
||||
|
||||
Only the current release of the software is actively supported. If you need
|
||||
help backporting fixes into an older release, feel free to ask.
|
||||
|
||||
## Reporting a Vulnerability
|
||||
|
||||
Email your vulnerability information to rsync's maintainer:
|
||||
|
||||
Wayne Davison <wayne@opencoder.net>
|
||||
16
TODO
16
TODO
@@ -49,7 +49,7 @@ Create test makefile target for some tests
|
||||
|
||||
RELATED PROJECTS -----------------------------------------------------
|
||||
rsyncsh
|
||||
https://rsync.samba.org/rsync-and-debian/
|
||||
http://rsync.samba.org/rsync-and-debian/
|
||||
rsyncable gzip patch
|
||||
rsyncsplit as alternative to real integration with gzip?
|
||||
reverse rsync over HTTP Range
|
||||
@@ -66,8 +66,8 @@ Use chroot only if supported
|
||||
If running as non-root, then don't fail, just give a warning.
|
||||
(There was a thread about this a while ago?)
|
||||
|
||||
https://lists.samba.org/pipermail/rsync/2001-August/thread.html
|
||||
https://lists.samba.org/pipermail/rsync/2001-September/thread.html
|
||||
http://lists.samba.org/pipermail/rsync/2001-August/thread.html
|
||||
http://lists.samba.org/pipermail/rsync/2001-September/thread.html
|
||||
|
||||
-- --
|
||||
|
||||
@@ -94,7 +94,7 @@ Handling IPv6 on old machines
|
||||
platforms that have a half-working implementation, so redefining
|
||||
these functions clashes with system headers, and leaving them out
|
||||
breaks. This affects at least OSF/1, RedHat 5, and Cobalt, which
|
||||
are moderately important.
|
||||
are moderately improtant.
|
||||
|
||||
Perhaps the simplest solution would be to have two different files
|
||||
implementing the same interface, and choose either the new or the
|
||||
@@ -204,7 +204,7 @@ Create more granular verbosity 2003/05/15
|
||||
fine grained selection of statistical reporting and what
|
||||
actions are logged.
|
||||
|
||||
https://lists.samba.org/archive/rsync/2003-May/006059.html
|
||||
http://lists.samba.org/archive/rsync/2003-May/006059.html
|
||||
|
||||
-- --
|
||||
|
||||
@@ -236,7 +236,7 @@ Memory accounting
|
||||
|
||||
At exit, show how much memory was used for the file list, etc.
|
||||
|
||||
We also do a weird exponential-growth allocation in flist.c. I'm
|
||||
Also we do a wierd exponential-growth allocation in flist.c. I'm
|
||||
not sure this makes sense with modern mallocs. At any rate it will
|
||||
make us allocate a huge amount of memory for large file lists.
|
||||
|
||||
@@ -287,7 +287,7 @@ Perhaps flush stdout like syslog
|
||||
|
||||
Perhaps flush stdout after each filename, so that people trying to
|
||||
monitor progress in a log file can do so more easily. See
|
||||
https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=48108
|
||||
http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=48108
|
||||
|
||||
-- --
|
||||
|
||||
@@ -495,7 +495,7 @@ rsyncsh
|
||||
-- --
|
||||
|
||||
|
||||
https://rsync.samba.org/rsync-and-debian/
|
||||
http://rsync.samba.org/rsync-and-debian/
|
||||
|
||||
|
||||
-- --
|
||||
|
||||
101
access.c
101
access.c
@@ -2,7 +2,7 @@
|
||||
* Routines to authenticate access to a daemon (hosts allow/deny).
|
||||
*
|
||||
* Copyright (C) 1998 Andrew Tridgell
|
||||
* Copyright (C) 2004-2022 Wayne Davison
|
||||
* Copyright (C) 2004-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,58 +19,15 @@
|
||||
*/
|
||||
|
||||
#include "rsync.h"
|
||||
#include "ifuncs.h"
|
||||
#ifdef HAVE_NETGROUP_H
|
||||
#include <netgroup.h>
|
||||
#endif
|
||||
|
||||
static int allow_forward_dns;
|
||||
|
||||
extern const char undetermined_hostname[];
|
||||
|
||||
static int match_hostname(const char **host_ptr, const char *addr, const char *tok)
|
||||
static int match_hostname(char *host, char *tok)
|
||||
{
|
||||
struct hostent *hp;
|
||||
unsigned int i;
|
||||
const char *host = *host_ptr;
|
||||
|
||||
if (!host || !*host)
|
||||
return 0;
|
||||
|
||||
#ifdef HAVE_INNETGR
|
||||
if (*tok == '@' && tok[1])
|
||||
return innetgr(tok + 1, host, NULL, NULL);
|
||||
#endif
|
||||
|
||||
/* First check if the reverse-DNS-determined hostname matches. */
|
||||
if (iwildmatch(tok, host))
|
||||
return 1;
|
||||
|
||||
if (!allow_forward_dns)
|
||||
return 0;
|
||||
|
||||
/* Fail quietly if tok is an address or wildcarded entry, not a simple hostname. */
|
||||
if (!tok[strspn(tok, ".0123456789")] || tok[strcspn(tok, ":/*?[")])
|
||||
return 0;
|
||||
|
||||
/* Now try forward-DNS on the token (config-specified hostname) and see if the IP matches. */
|
||||
if (!(hp = gethostbyname(tok)))
|
||||
return 0;
|
||||
|
||||
for (i = 0; hp->h_addr_list[i] != NULL; i++) {
|
||||
if (strcmp(addr, inet_ntoa(*(struct in_addr*)(hp->h_addr_list[i]))) == 0) {
|
||||
/* If reverse lookups are off, we'll use the conf-specified
|
||||
* hostname in preference to UNDETERMINED. */
|
||||
if (host == undetermined_hostname)
|
||||
*host_ptr = strdup(tok);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
return wildmatch(tok, host);
|
||||
}
|
||||
|
||||
static int match_binary(const char *b1, const char *b2, const char *mask, int addrlen)
|
||||
static int match_binary(char *b1, char *b2, char *mask, int addrlen)
|
||||
{
|
||||
int i;
|
||||
|
||||
@@ -99,7 +56,7 @@ static void make_mask(char *mask, int plen, int addrlen)
|
||||
return;
|
||||
}
|
||||
|
||||
static int match_address(const char *addr, const char *tok)
|
||||
static int match_address(char *addr, char *tok)
|
||||
{
|
||||
char *p;
|
||||
struct addrinfo hints, *resa, *rest;
|
||||
@@ -113,16 +70,24 @@ static int match_address(const char *addr, 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;
|
||||
@@ -165,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;
|
||||
@@ -177,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;
|
||||
@@ -243,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;
|
||||
}
|
||||
@@ -261,21 +233,16 @@ static int access_match(const char *list, const char *addr, const char **host_pt
|
||||
return 0;
|
||||
}
|
||||
|
||||
int allow_access(const char *addr, const char **host_ptr, int i)
|
||||
int allow_access(char *addr, char *host, char *allow_list, char *deny_list)
|
||||
{
|
||||
const char *allow_list = lp_hosts_allow(i);
|
||||
const char *deny_list = lp_hosts_deny(i);
|
||||
|
||||
if (allow_list && !*allow_list)
|
||||
allow_list = NULL;
|
||||
if (deny_list && !*deny_list)
|
||||
deny_list = NULL;
|
||||
|
||||
allow_forward_dns = lp_forward_lookup(i);
|
||||
|
||||
/* If we match an allow-list item, we always allow access. */
|
||||
if (allow_list) {
|
||||
if (access_match(allow_list, addr, host_ptr))
|
||||
if (access_match(allow_list, addr, host))
|
||||
return 1;
|
||||
/* For an allow-list w/o a deny-list, disallow non-matches. */
|
||||
if (!deny_list)
|
||||
@@ -284,7 +251,7 @@ int allow_access(const char *addr, const char **host_ptr, int i)
|
||||
|
||||
/* If we match a deny-list item (and got past any allow-list
|
||||
* items), we always disallow access. */
|
||||
if (deny_list && access_match(deny_list, addr, host_ptr))
|
||||
if (deny_list && access_match(deny_list, addr, host))
|
||||
return 0;
|
||||
|
||||
/* Allow all other access. */
|
||||
|
||||
92
aclocal.m4
vendored
Normal file
92
aclocal.m4
vendored
Normal 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
|
||||
])
|
||||
246
acls.c
246
acls.c
@@ -3,7 +3,7 @@
|
||||
*
|
||||
* Copyright (C) 1996 Andrew Tridgell
|
||||
* Copyright (C) 1996 Paul Mackerras
|
||||
* Copyright (C) 2006-2022 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
|
||||
@@ -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
|
||||
|
||||
@@ -90,9 +88,6 @@ static const rsync_acl empty_rsync_acl = {
|
||||
static item_list access_acl_list = EMPTY_ITEM_LIST;
|
||||
static item_list default_acl_list = EMPTY_ITEM_LIST;
|
||||
|
||||
static size_t prior_access_count = (size_t)-1;
|
||||
static size_t prior_default_count = (size_t)-1;
|
||||
|
||||
/* === Calculations on ACL types === */
|
||||
|
||||
static const char *str_acl_type(SMB_ACL_TYPE_T type)
|
||||
@@ -117,11 +112,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 +129,15 @@ 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)
|
||||
racl->mask_obj = NO_ENTRY;
|
||||
#endif
|
||||
racl->mask_obj = NO_ENTRY;
|
||||
}
|
||||
racl->other_obj = NO_ENTRY;
|
||||
}
|
||||
@@ -168,6 +156,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 +320,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 +336,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 +420,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 +492,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);
|
||||
@@ -519,7 +517,6 @@ static int get_rsync_acl(const char *fname, rsync_acl *racl,
|
||||
|
||||
sys_acl_free_acl(sacl);
|
||||
if (!ok) {
|
||||
rsyserr(FERROR_XFER, errno, "get_acl: unpack_smb_acl(%s)", fname);
|
||||
return -1;
|
||||
}
|
||||
} else if (no_acl_syscall_error(errno)) {
|
||||
@@ -539,24 +536,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);
|
||||
@@ -578,7 +557,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;
|
||||
@@ -590,9 +569,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);
|
||||
@@ -604,8 +583,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);
|
||||
|
||||
@@ -638,7 +617,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;
|
||||
@@ -648,28 +627,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);
|
||||
|
||||
@@ -694,18 +673,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)
|
||||
@@ -728,7 +712,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;
|
||||
@@ -743,7 +727,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;
|
||||
@@ -751,29 +735,29 @@ 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;
|
||||
(void)mode;
|
||||
#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) {
|
||||
/* If we received a superfluous mask, throw it away. */
|
||||
if (duo_item->racl.mask_obj != NO_ENTRY) {
|
||||
/* Mask off the group perms with it first. */
|
||||
duo_item->racl.group_obj &= duo_item->racl.mask_obj | NO_ENTRY;
|
||||
duo_item->racl.mask_obj = NO_ENTRY;
|
||||
}
|
||||
} else if (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;
|
||||
@@ -782,12 +766,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)
|
||||
@@ -810,45 +794,14 @@ static int cache_rsync_acl(rsync_acl *racl, SMB_ACL_TYPE_T type, item_list *racl
|
||||
|
||||
/* Turn the ACL data in stat_x into cached ACL data, setting the index
|
||||
* values in the file struct. */
|
||||
void cache_tmp_acl(struct file_struct *file, stat_x *sxp)
|
||||
void cache_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);
|
||||
}
|
||||
}
|
||||
|
||||
static void uncache_duo_acls(item_list *duo_list, size_t start)
|
||||
{
|
||||
acl_duo *duo_item = duo_list->items;
|
||||
acl_duo *duo_start = duo_item + start;
|
||||
|
||||
duo_item += duo_list->count;
|
||||
duo_list->count = start;
|
||||
|
||||
while (duo_item-- > duo_start) {
|
||||
rsync_acl_free(&duo_item->racl);
|
||||
if (duo_item->sacl)
|
||||
sys_acl_free_acl(duo_item->sacl);
|
||||
}
|
||||
}
|
||||
|
||||
void uncache_tmp_acls(void)
|
||||
{
|
||||
if (prior_access_count != (size_t)-1) {
|
||||
uncache_duo_acls(&access_acl_list, prior_access_count);
|
||||
prior_access_count = (size_t)-1;
|
||||
}
|
||||
|
||||
if (prior_default_count != (size_t)-1) {
|
||||
uncache_duo_acls(&default_acl_list, prior_default_count);
|
||||
prior_default_count = (size_t)-1;
|
||||
F_DIR_DEFACL(file) = cache_rsync_acl(sxp->def_acl,
|
||||
SMB_ACL_TYPE_DEFAULT, &default_acl_list);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -897,14 +850,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) );
|
||||
@@ -917,7 +868,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
|
||||
@@ -984,8 +935,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
|
||||
@@ -1001,17 +953,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;
|
||||
|
||||
@@ -1025,18 +977,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) {
|
||||
@@ -1044,15 +996,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.
|
||||
@@ -1095,21 +1048,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));
|
||||
@@ -1129,7 +1081,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);
|
||||
}
|
||||
|
||||
|
||||
387
authenticate.c
387
authenticate.c
@@ -2,7 +2,7 @@
|
||||
* Support rsync daemon authentication.
|
||||
*
|
||||
* Copyright (C) 1998-2000 Andrew Tridgell
|
||||
* Copyright (C) 2002-2022 Wayne Davison
|
||||
* Copyright (C) 2002-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,12 +19,8 @@
|
||||
*/
|
||||
|
||||
#include "rsync.h"
|
||||
#include "itypes.h"
|
||||
#include "ifuncs.h"
|
||||
|
||||
extern int read_only;
|
||||
extern char *password_file;
|
||||
extern struct name_num_obj valid_auth_checksums;
|
||||
|
||||
/***************************************************************************
|
||||
encode a buffer using base64 - simple and slow algorithm. null terminates
|
||||
@@ -73,13 +69,136 @@ static void gen_challenge(const char *addr, char *challenge)
|
||||
SIVAL(input, 20, tv.tv_usec);
|
||||
SIVAL(input, 24, getpid());
|
||||
|
||||
len = sum_init(valid_auth_checksums.negotiated_nni, 0);
|
||||
sum_init(0);
|
||||
sum_update(input, sizeof input);
|
||||
sum_end(digest);
|
||||
len = sum_end(digest);
|
||||
|
||||
base64_encode(digest, len, challenge, 0);
|
||||
}
|
||||
|
||||
|
||||
/* Return the secret for a user from the secret file, null terminated.
|
||||
* Maximum length is len (not counting the null). */
|
||||
static int get_secret(int module, const char *user, char *secret, int len)
|
||||
{
|
||||
const char *fname = lp_secrets_file(module);
|
||||
STRUCT_STAT st;
|
||||
int fd, ok = 1;
|
||||
const char *p;
|
||||
char ch, *s;
|
||||
|
||||
if (!fname || !*fname)
|
||||
return 0;
|
||||
|
||||
if ((fd = open(fname, O_RDONLY)) < 0)
|
||||
return 0;
|
||||
|
||||
if (do_stat(fname, &st) == -1) {
|
||||
rsyserr(FLOG, errno, "stat(%s)", fname);
|
||||
ok = 0;
|
||||
} else if (lp_strict_modes(module)) {
|
||||
if ((st.st_mode & 06) != 0) {
|
||||
rprintf(FLOG, "secrets file must not be other-accessible (see strict modes option)\n");
|
||||
ok = 0;
|
||||
} else if (MY_UID() == 0 && st.st_uid != 0) {
|
||||
rprintf(FLOG, "secrets file must be owned by root when running as root (see strict modes)\n");
|
||||
ok = 0;
|
||||
}
|
||||
}
|
||||
if (!ok) {
|
||||
rprintf(FLOG, "continuing without secrets file\n");
|
||||
close(fd);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (*user == '#') {
|
||||
/* Reject attempt to match a comment. */
|
||||
close(fd);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Try to find a line that starts with the user name and a ':'. */
|
||||
p = user;
|
||||
while (1) {
|
||||
if (read(fd, &ch, 1) != 1) {
|
||||
close(fd);
|
||||
return 0;
|
||||
}
|
||||
if (ch == '\n')
|
||||
p = user;
|
||||
else if (p) {
|
||||
if (*p == ch)
|
||||
p++;
|
||||
else if (!*p && ch == ':')
|
||||
break;
|
||||
else
|
||||
p = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
/* Slurp the secret into the "secret" buffer. */
|
||||
s = secret;
|
||||
while (len > 0) {
|
||||
if (read(fd, s, 1) != 1 || *s == '\n')
|
||||
break;
|
||||
if (*s == '\r')
|
||||
continue;
|
||||
s++;
|
||||
len--;
|
||||
}
|
||||
*s = '\0';
|
||||
close(fd);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static const char *getpassf(const char *filename)
|
||||
{
|
||||
STRUCT_STAT st;
|
||||
char buffer[512], *p;
|
||||
int fd, n, ok = 1;
|
||||
const char *envpw = getenv("RSYNC_PASSWORD");
|
||||
|
||||
if (!filename)
|
||||
return NULL;
|
||||
|
||||
if ((fd = open(filename,O_RDONLY)) < 0) {
|
||||
rsyserr(FWARNING, errno, "could not open password file \"%s\"",
|
||||
filename);
|
||||
if (envpw)
|
||||
rprintf(FINFO, "falling back to RSYNC_PASSWORD environment variable.\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (do_stat(filename, &st) == -1) {
|
||||
rsyserr(FWARNING, errno, "stat(%s)", filename);
|
||||
ok = 0;
|
||||
} else if ((st.st_mode & 06) != 0) {
|
||||
rprintf(FWARNING, "password file must not be other-accessible\n");
|
||||
ok = 0;
|
||||
} else if (MY_UID() == 0 && st.st_uid != 0) {
|
||||
rprintf(FWARNING, "password file must be owned by root when running as root\n");
|
||||
ok = 0;
|
||||
}
|
||||
if (!ok) {
|
||||
close(fd);
|
||||
rprintf(FWARNING, "continuing without password file\n");
|
||||
if (envpw)
|
||||
rprintf(FINFO, "falling back to RSYNC_PASSWORD environment variable.\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
n = read(fd, buffer, sizeof buffer - 1);
|
||||
close(fd);
|
||||
if (n > 0) {
|
||||
buffer[n] = '\0';
|
||||
if ((p = strtok(buffer, "\n\r")) != NULL)
|
||||
return strdup(p);
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Generate an MD4 hash created from the combination of the password
|
||||
* and the challenge string and return it base64-encoded. */
|
||||
static void generate_hash(const char *in, const char *challenge, char *out)
|
||||
@@ -87,135 +206,14 @@ static void generate_hash(const char *in, const char *challenge, char *out)
|
||||
char buf[MAX_DIGEST_LEN];
|
||||
int len;
|
||||
|
||||
len = sum_init(valid_auth_checksums.negotiated_nni, 0);
|
||||
sum_init(0);
|
||||
sum_update(in, strlen(in));
|
||||
sum_update(challenge, strlen(challenge));
|
||||
sum_end(buf);
|
||||
len = sum_end(buf);
|
||||
|
||||
base64_encode(buf, len, out, 0);
|
||||
}
|
||||
|
||||
/* Return the secret for a user from the secret file, null terminated.
|
||||
* Maximum length is len (not counting the null). */
|
||||
static const char *check_secret(int module, const char *user, const char *group,
|
||||
const char *challenge, const char *pass)
|
||||
{
|
||||
char line[1024];
|
||||
char pass2[MAX_DIGEST_LEN*2];
|
||||
const char *fname = lp_secrets_file(module);
|
||||
STRUCT_STAT st;
|
||||
int ok = 1;
|
||||
int user_len = strlen(user);
|
||||
int group_len = group ? strlen(group) : 0;
|
||||
char *err;
|
||||
FILE *fh;
|
||||
|
||||
if (!fname || !*fname || (fh = fopen(fname, "r")) == NULL)
|
||||
return "no secrets file";
|
||||
|
||||
if (do_fstat(fileno(fh), &st) == -1) {
|
||||
rsyserr(FLOG, errno, "fstat(%s)", fname);
|
||||
ok = 0;
|
||||
} else if (lp_strict_modes(module)) {
|
||||
if ((st.st_mode & 06) != 0) {
|
||||
rprintf(FLOG, "secrets file must not be other-accessible (see strict modes option)\n");
|
||||
ok = 0;
|
||||
} else if (MY_UID() == ROOT_UID && st.st_uid != ROOT_UID) {
|
||||
rprintf(FLOG, "secrets file must be owned by root when running as root (see strict modes)\n");
|
||||
ok = 0;
|
||||
}
|
||||
}
|
||||
if (!ok) {
|
||||
fclose(fh);
|
||||
return "ignoring secrets file";
|
||||
}
|
||||
|
||||
if (*user == '#') {
|
||||
/* Reject attempt to match a comment. */
|
||||
fclose(fh);
|
||||
return "invalid username";
|
||||
}
|
||||
|
||||
/* Try to find a line that starts with the user (or @group) name and a ':'. */
|
||||
err = "secret not found";
|
||||
while ((user || group) && fgets(line, sizeof line, fh) != NULL) {
|
||||
const char **ptr, *s = strtok(line, "\n\r");
|
||||
int len;
|
||||
if (!s)
|
||||
continue;
|
||||
if (*s == '@') {
|
||||
ptr = &group;
|
||||
len = group_len;
|
||||
s++;
|
||||
} else {
|
||||
ptr = &user;
|
||||
len = user_len;
|
||||
}
|
||||
if (!*ptr || strncmp(s, *ptr, len) != 0 || s[len] != ':')
|
||||
continue;
|
||||
generate_hash(s+len+1, challenge, pass2);
|
||||
if (strcmp(pass, pass2) == 0) {
|
||||
err = NULL;
|
||||
break;
|
||||
}
|
||||
err = "password mismatch";
|
||||
*ptr = NULL; /* Don't look for name again. */
|
||||
}
|
||||
|
||||
fclose(fh);
|
||||
|
||||
force_memzero(line, sizeof line);
|
||||
force_memzero(pass2, sizeof pass2);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
static const char *getpassf(const char *filename)
|
||||
{
|
||||
STRUCT_STAT st;
|
||||
char buffer[512], *p;
|
||||
int n;
|
||||
|
||||
if (!filename)
|
||||
return NULL;
|
||||
|
||||
if (strcmp(filename, "-") == 0) {
|
||||
n = fgets(buffer, sizeof buffer, stdin) == NULL ? -1 : (int)strlen(buffer);
|
||||
} else {
|
||||
int fd;
|
||||
|
||||
if ((fd = open(filename,O_RDONLY)) < 0) {
|
||||
rsyserr(FERROR, errno, "could not open password file %s", filename);
|
||||
exit_cleanup(RERR_SYNTAX);
|
||||
}
|
||||
|
||||
if (do_stat(filename, &st) == -1) {
|
||||
rsyserr(FERROR, errno, "stat(%s)", filename);
|
||||
exit_cleanup(RERR_SYNTAX);
|
||||
}
|
||||
if ((st.st_mode & 06) != 0) {
|
||||
rprintf(FERROR, "ERROR: password file must not be other-accessible\n");
|
||||
exit_cleanup(RERR_SYNTAX);
|
||||
}
|
||||
if (MY_UID() == ROOT_UID && st.st_uid != ROOT_UID) {
|
||||
rprintf(FERROR, "ERROR: password file must be owned by root when running as root\n");
|
||||
exit_cleanup(RERR_SYNTAX);
|
||||
}
|
||||
|
||||
n = read(fd, buffer, sizeof buffer - 1);
|
||||
close(fd);
|
||||
}
|
||||
|
||||
if (n > 0) {
|
||||
buffer[n] = '\0';
|
||||
if ((p = strtok(buffer, "\n\r")) != NULL)
|
||||
return strdup(p);
|
||||
}
|
||||
|
||||
rprintf(FERROR, "ERROR: failed to read a password from %s\n", filename);
|
||||
exit_cleanup(RERR_SYNTAX);
|
||||
}
|
||||
|
||||
/* Possibly negotiate authentication with the client. Use "leader" to
|
||||
* start off the auth if necessary.
|
||||
*
|
||||
@@ -228,23 +226,19 @@ char *auth_server(int f_in, int f_out, int module, const char *host,
|
||||
char *users = lp_auth_users(module);
|
||||
char challenge[MAX_DIGEST_LEN*2];
|
||||
char line[BIGPATHBUFLEN];
|
||||
const char **auth_uid_groups = NULL;
|
||||
int auth_uid_groups_cnt = -1;
|
||||
const char *err = NULL;
|
||||
int group_match = -1;
|
||||
char secret[512];
|
||||
char pass2[MAX_DIGEST_LEN*2];
|
||||
char *tok, *pass;
|
||||
char opt_ch = '\0';
|
||||
|
||||
/* if no auth list then allow anyone in! */
|
||||
if (!users || !*users)
|
||||
return "";
|
||||
|
||||
negotiate_daemon_auth(f_out, 0);
|
||||
gen_challenge(addr, challenge);
|
||||
|
||||
io_printf(f_out, "%s%s\n", leader, challenge);
|
||||
|
||||
if (!read_line_old(f_in, line, sizeof line, 0)
|
||||
if (!read_line_old(f_in, line, sizeof line)
|
||||
|| (pass = strchr(line, ' ')) == NULL) {
|
||||
rprintf(FLOG, "auth failed on module %s from %s (%s): "
|
||||
"invalid challenge response\n",
|
||||
@@ -253,94 +247,40 @@ char *auth_server(int f_in, int f_out, int module, const char *host,
|
||||
}
|
||||
*pass++ = '\0';
|
||||
|
||||
users = strdup(users);
|
||||
if (!(users = strdup(users)))
|
||||
out_of_memory("auth_server");
|
||||
|
||||
for (tok = strtok(users, " ,\t"); tok; tok = strtok(NULL, " ,\t")) {
|
||||
char *opts;
|
||||
/* See if the user appended :deny, :ro, or :rw. */
|
||||
if ((opts = strchr(tok, ':')) != NULL) {
|
||||
*opts++ = '\0';
|
||||
opt_ch = isUpper(opts) ? toLower(opts) : *opts;
|
||||
if (opt_ch == 'r') { /* handle ro and rw */
|
||||
opt_ch = isUpper(opts+1) ? toLower(opts+1) : opts[1];
|
||||
if (opt_ch == 'o')
|
||||
opt_ch = 'r';
|
||||
else if (opt_ch != 'w')
|
||||
opt_ch = '\0';
|
||||
} else if (opt_ch != 'd') /* if it's not deny, ignore it */
|
||||
opt_ch = '\0';
|
||||
} else
|
||||
opt_ch = '\0';
|
||||
if (*tok != '@') {
|
||||
/* Match the username */
|
||||
if (wildmatch(tok, line))
|
||||
break;
|
||||
} else {
|
||||
#ifdef HAVE_GETGROUPLIST
|
||||
int j;
|
||||
/* See if authorizing user is a real user, and if so, see
|
||||
* if it is in a group that matches tok+1 wildmat. */
|
||||
if (auth_uid_groups_cnt < 0) {
|
||||
item_list gid_list = EMPTY_ITEM_LIST;
|
||||
uid_t auth_uid;
|
||||
if (!user_to_uid(line, &auth_uid, False)
|
||||
|| getallgroups(auth_uid, &gid_list) != NULL)
|
||||
auth_uid_groups_cnt = 0;
|
||||
else {
|
||||
gid_t *gid_array = gid_list.items;
|
||||
auth_uid_groups_cnt = gid_list.count;
|
||||
auth_uid_groups = new_array(const char *, auth_uid_groups_cnt);
|
||||
for (j = 0; j < auth_uid_groups_cnt; j++)
|
||||
auth_uid_groups[j] = gid_to_group(gid_array[j]);
|
||||
}
|
||||
}
|
||||
for (j = 0; j < auth_uid_groups_cnt; j++) {
|
||||
if (auth_uid_groups[j] && wildmatch(tok+1, auth_uid_groups[j])) {
|
||||
group_match = j;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (group_match >= 0)
|
||||
break;
|
||||
#else
|
||||
rprintf(FLOG, "your computer doesn't support getgrouplist(), so no @group authorization is possible.\n");
|
||||
#endif
|
||||
}
|
||||
if (wildmatch(tok, line))
|
||||
break;
|
||||
}
|
||||
|
||||
free(users);
|
||||
|
||||
if (!tok)
|
||||
err = "no matching rule";
|
||||
else if (opt_ch == 'd')
|
||||
err = "denied by rule";
|
||||
else {
|
||||
const char *group = group_match >= 0 ? auth_uid_groups[group_match] : NULL;
|
||||
err = check_secret(module, line, group, challenge, pass);
|
||||
}
|
||||
|
||||
force_memzero(challenge, sizeof challenge);
|
||||
force_memzero(pass, strlen(pass));
|
||||
|
||||
if (auth_uid_groups) {
|
||||
int j;
|
||||
for (j = 0; j < auth_uid_groups_cnt; j++) {
|
||||
if (auth_uid_groups[j])
|
||||
free((char*)auth_uid_groups[j]);
|
||||
}
|
||||
free(auth_uid_groups);
|
||||
}
|
||||
|
||||
if (err) {
|
||||
rprintf(FLOG, "auth failed on module %s from %s (%s) for %s: %s\n",
|
||||
lp_name(module), host, addr, line, err);
|
||||
if (!tok) {
|
||||
rprintf(FLOG, "auth failed on module %s from %s (%s): "
|
||||
"unauthorized user\n",
|
||||
lp_name(module), host, addr);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (opt_ch == 'r')
|
||||
read_only = 1;
|
||||
else if (opt_ch == 'w')
|
||||
read_only = 0;
|
||||
memset(secret, 0, sizeof secret);
|
||||
if (!get_secret(module, line, secret, sizeof secret - 1)) {
|
||||
memset(secret, 0, sizeof secret);
|
||||
rprintf(FLOG, "auth failed on module %s from %s (%s): "
|
||||
"missing secret for user \"%s\"\n",
|
||||
lp_name(module), host, addr, line);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
generate_hash(secret, challenge, pass2);
|
||||
memset(secret, 0, sizeof secret);
|
||||
|
||||
if (strcmp(pass, pass2) != 0) {
|
||||
rprintf(FLOG, "auth failed on module %s from %s (%s): "
|
||||
"password mismatch\n",
|
||||
lp_name(module), host, addr);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return strdup(line);
|
||||
}
|
||||
@@ -352,19 +292,18 @@ void auth_client(int fd, const char *user, const char *challenge)
|
||||
|
||||
if (!user || !*user)
|
||||
user = "nobody";
|
||||
negotiate_daemon_auth(-1, 1);
|
||||
|
||||
if (!(pass = getpassf(password_file))
|
||||
&& !(pass = getenv("RSYNC_PASSWORD"))) {
|
||||
/* XXX: cyeoh says that getpass is deprecated, because
|
||||
* it may return a truncated password on some systems,
|
||||
* and it is not in the LSB.
|
||||
*
|
||||
* Andrew Klein says that getpassphrase() is present
|
||||
* on Solaris and reads up to 256 characters.
|
||||
*
|
||||
* OpenBSD has a readpassphrase() that might be more suitable.
|
||||
*/
|
||||
*
|
||||
* Andrew Klein says that getpassphrase() is present
|
||||
* on Solaris and reads up to 256 characters.
|
||||
*
|
||||
* OpenBSD has a readpassphrase() that might be more suitable.
|
||||
*/
|
||||
pass = getpass("Password: ");
|
||||
}
|
||||
|
||||
|
||||
517
backup.c
517
backup.c
@@ -2,7 +2,7 @@
|
||||
* Backup handling code.
|
||||
*
|
||||
* Copyright (C) 1999 Andrew Tridgell
|
||||
* Copyright (C) 2003-2022 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
|
||||
@@ -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,242 +34,209 @@ 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_acl(file, &sx);
|
||||
free_acl(&sx);
|
||||
}
|
||||
#endif
|
||||
#ifdef SUPPORT_XATTRS
|
||||
if (preserve_xattrs) {
|
||||
get_xattr(rel, &sx);
|
||||
cache_xattr(file, &sx);
|
||||
free_xattr(&sx);
|
||||
}
|
||||
#endif
|
||||
set_file_attrs(fbuf, file, NULL, NULL, 0);
|
||||
unmake_file(file);
|
||||
}
|
||||
}
|
||||
*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);
|
||||
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);
|
||||
cache_tmp_acl(file, &sx);
|
||||
cache_acl(file, &sx);
|
||||
free_acl(&sx);
|
||||
}
|
||||
#endif
|
||||
#ifdef SUPPORT_XATTRS
|
||||
if (preserve_xattrs) {
|
||||
get_xattr(fname, &sx);
|
||||
cache_tmp_xattr(file, &sx);
|
||||
cache_xattr(file, &sx);
|
||||
free_xattr(&sx);
|
||||
}
|
||||
#endif
|
||||
@@ -277,79 +244,119 @@ 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 (safe_symlinks && unsafe_symlink(sl, buf)) {
|
||||
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)) {
|
||||
if (INFO_GTE(NONREG, 1))
|
||||
rprintf(FINFO, "make_bak: skipping non-regular file %s\n", fname);
|
||||
if (!kept && !S_ISREG(file->mode)) {
|
||||
rprintf(FINFO, "make_bak: skipping non-regular file %s\n",
|
||||
fname);
|
||||
unmake_file(file);
|
||||
#ifdef SUPPORT_ACLS
|
||||
uncache_tmp_acls();
|
||||
#endif
|
||||
#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();
|
||||
#endif
|
||||
#ifdef SUPPORT_XATTRS
|
||||
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);
|
||||
}
|
||||
|
||||
158
batch.c
158
batch.c
@@ -3,7 +3,7 @@
|
||||
*
|
||||
* Copyright (C) 1999 Weiss
|
||||
* Copyright (C) 2004 Chris Shoemaker
|
||||
* Copyright (C) 2004-2022 Wayne Davison
|
||||
* Copyright (C) 2004-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
|
||||
@@ -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,40 @@ void check_batch_flags(void)
|
||||
append_mode = 2;
|
||||
}
|
||||
|
||||
static int write_arg(const char *arg)
|
||||
static void write_arg(int fd, char *arg)
|
||||
{
|
||||
const char *x, *s;
|
||||
int len, err = 0;
|
||||
char *x, *s;
|
||||
|
||||
if (*arg == '-' && (x = strchr(arg, '=')) != NULL) {
|
||||
err |= write(batch_sh_fd, arg, x - arg + 1) != x - arg + 1;
|
||||
write(fd, arg, x - arg + 1);
|
||||
arg += x - arg + 1;
|
||||
}
|
||||
|
||||
if (strpbrk(arg, " \"'&;|[]()$#!*?^\\") != NULL) {
|
||||
err |= write(batch_sh_fd, "'", 1) != 1;
|
||||
write(fd, "'", 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;
|
||||
write(fd, s, x - s + 1);
|
||||
write(fd, "'", 1);
|
||||
}
|
||||
len = strlen(s);
|
||||
err |= write(batch_sh_fd, s, len) != len;
|
||||
err |= write(batch_sh_fd, "'", 1) != 1;
|
||||
return err;
|
||||
write(fd, s, strlen(s));
|
||||
write(fd, "'", 1);
|
||||
return;
|
||||
}
|
||||
|
||||
len = strlen(arg);
|
||||
err |= write(batch_sh_fd, arg, len) != len;
|
||||
|
||||
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;
|
||||
write(fd, arg, strlen(arg));
|
||||
}
|
||||
|
||||
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 +198,40 @@ 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;
|
||||
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]);
|
||||
write_arg(fd, argv[0]);
|
||||
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 +240,27 @@ void write_batch_shell_file(void)
|
||||
i++;
|
||||
continue;
|
||||
}
|
||||
write(fd, " ", 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) {
|
||||
write(fd, "--read-batch", 12);
|
||||
if (p[len] == '=') {
|
||||
write(fd, "=", 1);
|
||||
write_arg(fd, p + len + 1);
|
||||
}
|
||||
} else
|
||||
write_arg(fd, p);
|
||||
}
|
||||
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];
|
||||
write(fd, " ${1:-", 6);
|
||||
write_arg(fd, p);
|
||||
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) {
|
||||
rsyserr(FERROR, errno, "Batch file %s write error",
|
||||
filename);
|
||||
exit_cleanup(RERR_FILEIO);
|
||||
}
|
||||
batch_sh_fd = -1;
|
||||
}
|
||||
|
||||
115
byteorder.h
115
byteorder.h
@@ -2,7 +2,7 @@
|
||||
* Simple byteorder handling.
|
||||
*
|
||||
* Copyright (C) 1992-1995 Andrew Tridgell
|
||||
* Copyright (C) 2007-2022 Wayne Davison
|
||||
* Copyright (C) 2007-2008 Wayne Davison
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
@@ -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,100 +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
|
||||
|
||||
95
case_N.h
95
case_N.h
@@ -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++;
|
||||
|
||||
779
checksum.c
779
checksum.c
@@ -3,20 +3,13 @@
|
||||
*
|
||||
* Copyright (C) 1996 Andrew Tridgell
|
||||
* Copyright (C) 1996 Paul Mackerras
|
||||
* Copyright (C) 2004-2023 Wayne Davison
|
||||
* Copyright (C) 2004-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
|
||||
* 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,338 +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;
|
||||
|
||||
#define NNI_BUILTIN (1<<0)
|
||||
#define NNI_EVP (1<<1)
|
||||
#define NNI_EVP_OK (1<<2)
|
||||
int csum_length = SHORT_SUM_LENGTH; /* initial value */
|
||||
|
||||
struct name_num_item valid_checksums_items[] = {
|
||||
#ifdef SUPPORT_XXH3
|
||||
{ CSUM_XXH3_128, 0, "xxh128", NULL },
|
||||
{ CSUM_XXH3_64, 0, "xxh3", NULL },
|
||||
#endif
|
||||
#ifdef SUPPORT_XXHASH
|
||||
{ CSUM_XXH64, 0, "xxh64", NULL },
|
||||
{ CSUM_XXH64, 0, "xxhash", NULL },
|
||||
#endif
|
||||
{ CSUM_MD5, NNI_BUILTIN|NNI_EVP, "md5", NULL },
|
||||
{ CSUM_MD4, NNI_BUILTIN|NNI_EVP, "md4", NULL },
|
||||
#ifdef SHA_DIGEST_LENGTH
|
||||
{ CSUM_SHA1, NNI_EVP, "sha1", NULL },
|
||||
#endif
|
||||
{ CSUM_NONE, 0, "none", NULL },
|
||||
{ 0, 0, NULL, NULL }
|
||||
};
|
||||
|
||||
struct name_num_obj valid_checksums = {
|
||||
"checksum", NULL, 0, 0, valid_checksums_items
|
||||
};
|
||||
|
||||
struct name_num_item valid_auth_checksums_items[] = {
|
||||
#ifdef SHA512_DIGEST_LENGTH
|
||||
{ CSUM_SHA512, NNI_EVP, "sha512", NULL },
|
||||
#endif
|
||||
#ifdef SHA256_DIGEST_LENGTH
|
||||
{ CSUM_SHA256, NNI_EVP, "sha256", NULL },
|
||||
#endif
|
||||
#ifdef SHA_DIGEST_LENGTH
|
||||
{ CSUM_SHA1, NNI_EVP, "sha1", NULL },
|
||||
#endif
|
||||
{ CSUM_MD5, NNI_BUILTIN|NNI_EVP, "md5", NULL },
|
||||
{ CSUM_MD4, NNI_BUILTIN|NNI_EVP, "md4", NULL },
|
||||
{ 0, 0, NULL, NULL }
|
||||
};
|
||||
|
||||
struct name_num_obj valid_auth_checksums = {
|
||||
"daemon auth checksum", NULL, 0, 0, valid_auth_checksums_items
|
||||
};
|
||||
|
||||
/* These cannot make use of openssl, so they're marked just as built-in */
|
||||
struct name_num_item implied_checksum_md4 =
|
||||
{ CSUM_MD4, NNI_BUILTIN, "md4", NULL };
|
||||
struct name_num_item implied_checksum_md5 =
|
||||
{ CSUM_MD5, NNI_BUILTIN, "md5", NULL };
|
||||
|
||||
struct name_num_item *xfer_sum_nni; /* used for the transfer checksum2 computations */
|
||||
int xfer_sum_len;
|
||||
struct name_num_item *file_sum_nni; /* used for the pre-transfer --checksum computations */
|
||||
int file_sum_len, file_sum_extra_cnt;
|
||||
|
||||
#ifdef USE_OPENSSL
|
||||
const EVP_MD *xfer_sum_evp_md;
|
||||
const EVP_MD *file_sum_evp_md;
|
||||
EVP_MD_CTX *ctx_evp = NULL;
|
||||
#endif
|
||||
|
||||
static int initialized_choices = 0;
|
||||
|
||||
struct name_num_item *parse_csum_name(const char *name, int len)
|
||||
{
|
||||
struct name_num_item *nni;
|
||||
|
||||
if (len < 0 && name)
|
||||
len = strlen(name);
|
||||
|
||||
init_checksum_choices();
|
||||
|
||||
if (!name || (len == 4 && strncasecmp(name, "auto", 4) == 0)) {
|
||||
if (protocol_version >= 30) {
|
||||
if (!proper_seed_order)
|
||||
return &implied_checksum_md5;
|
||||
name = "md5";
|
||||
len = 3;
|
||||
} else {
|
||||
if (protocol_version >= 27)
|
||||
implied_checksum_md4.num = CSUM_MD4_OLD;
|
||||
else if (protocol_version >= 21)
|
||||
implied_checksum_md4.num = CSUM_MD4_BUSTED;
|
||||
else
|
||||
implied_checksum_md4.num = CSUM_MD4_ARCHAIC;
|
||||
return &implied_checksum_md4;
|
||||
}
|
||||
}
|
||||
|
||||
nni = get_nni_by_name(&valid_checksums, name, len);
|
||||
|
||||
if (!nni) {
|
||||
rprintf(FERROR, "unknown checksum name: %s\n", name);
|
||||
exit_cleanup(RERR_UNSUPPORTED);
|
||||
}
|
||||
|
||||
return nni;
|
||||
}
|
||||
|
||||
#ifdef USE_OPENSSL
|
||||
static const EVP_MD *csum_evp_md(struct name_num_item *nni)
|
||||
{
|
||||
const EVP_MD *emd;
|
||||
if (!(nni->flags & NNI_EVP))
|
||||
return NULL;
|
||||
|
||||
#ifdef USE_MD5_ASM
|
||||
if (nni->num == CSUM_MD5)
|
||||
emd = NULL;
|
||||
else
|
||||
#endif
|
||||
emd = EVP_get_digestbyname(nni->name);
|
||||
if (emd && !(nni->flags & NNI_EVP_OK)) { /* Make sure it works before we advertise it */
|
||||
if (!ctx_evp && !(ctx_evp = EVP_MD_CTX_create()))
|
||||
out_of_memory("csum_evp_md");
|
||||
/* Some routines are marked as legacy and are not enabled in the openssl.cnf file.
|
||||
* If we can't init the emd, we'll fall back to our built-in code. */
|
||||
if (EVP_DigestInit_ex(ctx_evp, emd, NULL) == 0)
|
||||
emd = NULL;
|
||||
else
|
||||
nni->flags = (nni->flags & ~NNI_BUILTIN) | NNI_EVP_OK;
|
||||
}
|
||||
if (!emd)
|
||||
nni->flags &= ~NNI_EVP;
|
||||
return emd;
|
||||
}
|
||||
#endif
|
||||
|
||||
void parse_checksum_choice(int final_call)
|
||||
{
|
||||
if (valid_checksums.negotiated_nni)
|
||||
xfer_sum_nni = file_sum_nni = valid_checksums.negotiated_nni;
|
||||
else {
|
||||
char *cp = checksum_choice ? strchr(checksum_choice, ',') : NULL;
|
||||
if (cp) {
|
||||
xfer_sum_nni = parse_csum_name(checksum_choice, cp - checksum_choice);
|
||||
file_sum_nni = parse_csum_name(cp+1, -1);
|
||||
} else
|
||||
xfer_sum_nni = file_sum_nni = parse_csum_name(checksum_choice, -1);
|
||||
if (am_server && checksum_choice)
|
||||
validate_choice_vs_env(NSTR_CHECKSUM, xfer_sum_nni->num, file_sum_nni->num);
|
||||
}
|
||||
xfer_sum_len = csum_len_for_type(xfer_sum_nni->num, 0);
|
||||
file_sum_len = csum_len_for_type(file_sum_nni->num, 0);
|
||||
#ifdef USE_OPENSSL
|
||||
xfer_sum_evp_md = csum_evp_md(xfer_sum_nni);
|
||||
file_sum_evp_md = csum_evp_md(file_sum_nni);
|
||||
#endif
|
||||
|
||||
file_sum_extra_cnt = (file_sum_len + EXTRA_LEN - 1) / EXTRA_LEN;
|
||||
|
||||
if (xfer_sum_nni->num == CSUM_NONE)
|
||||
whole_file = 1;
|
||||
|
||||
/* Snag the checksum name for both write_batch's option output & the following debug output. */
|
||||
if (valid_checksums.negotiated_nni)
|
||||
checksum_choice = valid_checksums.negotiated_nni->name;
|
||||
else if (checksum_choice == NULL)
|
||||
checksum_choice = xfer_sum_nni->name;
|
||||
|
||||
if (final_call && DEBUG_GTE(NSTR, am_server ? 3 : 1)) {
|
||||
rprintf(FINFO, "%s%s checksum: %s\n",
|
||||
am_server ? "Server" : "Client",
|
||||
valid_checksums.negotiated_nni ? " negotiated" : "",
|
||||
checksum_choice);
|
||||
}
|
||||
}
|
||||
|
||||
int csum_len_for_type(int cst, BOOL flist_csum)
|
||||
{
|
||||
switch (cst) {
|
||||
case CSUM_NONE:
|
||||
return 1;
|
||||
case CSUM_MD4_ARCHAIC:
|
||||
/* The oldest checksum code is rather weird: the file-list code only sent
|
||||
* 2-byte checksums, but all other checksums were full MD4 length. */
|
||||
return flist_csum ? 2 : MD4_DIGEST_LEN;
|
||||
case CSUM_MD4:
|
||||
case CSUM_MD4_OLD:
|
||||
case CSUM_MD4_BUSTED:
|
||||
return MD4_DIGEST_LEN;
|
||||
case CSUM_MD5:
|
||||
return MD5_DIGEST_LEN;
|
||||
#ifdef SHA_DIGEST_LENGTH
|
||||
case CSUM_SHA1:
|
||||
return SHA_DIGEST_LENGTH;
|
||||
#endif
|
||||
#ifdef SHA256_DIGEST_LENGTH
|
||||
case CSUM_SHA256:
|
||||
return SHA256_DIGEST_LENGTH;
|
||||
#endif
|
||||
#ifdef SHA512_DIGEST_LENGTH
|
||||
case CSUM_SHA512:
|
||||
return SHA512_DIGEST_LENGTH;
|
||||
#endif
|
||||
case CSUM_XXH64:
|
||||
case CSUM_XXH3_64:
|
||||
return 64/8;
|
||||
case CSUM_XXH3_128:
|
||||
return 128/8;
|
||||
default: /* paranoia to prevent missing case values */
|
||||
exit_cleanup(RERR_UNSUPPORTED);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Returns 0 if the checksum is not canonical (i.e. it includes a seed value).
|
||||
* Returns 1 if the public sum order matches our internal sum order.
|
||||
* Returns -1 if the public sum order is the reverse of our internal sum order.
|
||||
*/
|
||||
int canonical_checksum(int csum_type)
|
||||
{
|
||||
switch (csum_type) {
|
||||
case CSUM_NONE:
|
||||
case CSUM_MD4_ARCHAIC:
|
||||
case CSUM_MD4_OLD:
|
||||
case CSUM_MD4_BUSTED:
|
||||
break;
|
||||
case CSUM_MD4:
|
||||
case CSUM_MD5:
|
||||
case CSUM_SHA1:
|
||||
case CSUM_SHA256:
|
||||
case CSUM_SHA512:
|
||||
return -1;
|
||||
case CSUM_XXH64:
|
||||
case CSUM_XXH3_64:
|
||||
case CSUM_XXH3_128:
|
||||
return 1;
|
||||
default: /* paranoia to prevent missing case values */
|
||||
exit_cleanup(RERR_UNSUPPORTED);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifndef USE_ROLL_SIMD /* See simd-checksum-*.cpp. */
|
||||
/*
|
||||
a simple 32 bit checksum that can be updated from either end
|
||||
a simple 32 bit checksum that can be upadted from either end
|
||||
(inspired by Mark Adler's Adler-32 checksum)
|
||||
*/
|
||||
uint32 get_checksum1(char *buf1, int32 len)
|
||||
{
|
||||
int32 i;
|
||||
uint32 s1, s2;
|
||||
schar *buf = (schar *)buf1;
|
||||
int32 i;
|
||||
uint32 s1, s2;
|
||||
schar *buf = (schar *)buf1;
|
||||
|
||||
s1 = s2 = 0;
|
||||
for (i = 0; i < (len-4); i+=4) {
|
||||
s2 += 4*(s1 + buf[i]) + 3*buf[i+1] + 2*buf[i+2] + buf[i+3] + 10*CHAR_OFFSET;
|
||||
s1 += (buf[i+0] + buf[i+1] + buf[i+2] + buf[i+3] + 4*CHAR_OFFSET);
|
||||
}
|
||||
for (; i < len; i++) {
|
||||
s1 += (buf[i]+CHAR_OFFSET); s2 += s1;
|
||||
}
|
||||
return (s1 & 0xffff) + (s2 << 16);
|
||||
s1 = s2 = 0;
|
||||
for (i = 0; i < (len-4); i+=4) {
|
||||
s2 += 4*(s1 + buf[i]) + 3*buf[i+1] + 2*buf[i+2] + buf[i+3] +
|
||||
10*CHAR_OFFSET;
|
||||
s1 += (buf[i+0] + buf[i+1] + buf[i+2] + buf[i+3] + 4*CHAR_OFFSET);
|
||||
}
|
||||
for (; i < len; i++) {
|
||||
s1 += (buf[i]+CHAR_OFFSET); s2 += s1;
|
||||
}
|
||||
return (s1 & 0xffff) + (s2 << 16);
|
||||
}
|
||||
#endif
|
||||
|
||||
/* The "sum" buffer must be at least MAX_DIGEST_LEN bytes! */
|
||||
|
||||
void get_checksum2(char *buf, int32 len, char *sum)
|
||||
{
|
||||
#ifdef USE_OPENSSL
|
||||
if (xfer_sum_evp_md) {
|
||||
static EVP_MD_CTX *evp = NULL;
|
||||
md_context m;
|
||||
|
||||
if (protocol_version >= 30) {
|
||||
uchar seedbuf[4];
|
||||
if (!evp && !(evp = EVP_MD_CTX_create()))
|
||||
out_of_memory("get_checksum2");
|
||||
EVP_DigestInit_ex(evp, xfer_sum_evp_md, NULL);
|
||||
md5_begin(&m);
|
||||
md5_update(&m, (uchar *)buf, len);
|
||||
if (checksum_seed) {
|
||||
SIVALu(seedbuf, 0, checksum_seed);
|
||||
EVP_DigestUpdate(evp, seedbuf, 4);
|
||||
SIVAL(seedbuf, 0, checksum_seed);
|
||||
md5_update(&m, seedbuf, 4);
|
||||
}
|
||||
EVP_DigestUpdate(evp, (uchar *)buf, len);
|
||||
EVP_DigestFinal_ex(evp, (uchar *)sum, NULL);
|
||||
} else
|
||||
#endif
|
||||
switch (xfer_sum_nni->num) {
|
||||
#ifdef SUPPORT_XXHASH
|
||||
case CSUM_XXH64:
|
||||
SIVAL64(sum, 0, XXH64(buf, len, checksum_seed));
|
||||
break;
|
||||
#endif
|
||||
#ifdef SUPPORT_XXH3
|
||||
case CSUM_XXH3_64:
|
||||
SIVAL64(sum, 0, XXH3_64bits_withSeed(buf, len, checksum_seed));
|
||||
break;
|
||||
case CSUM_XXH3_128: {
|
||||
XXH128_hash_t digest = XXH3_128bits_withSeed(buf, len, checksum_seed);
|
||||
SIVAL64(sum, 0, digest.low64);
|
||||
SIVAL64(sum, 8, digest.high64);
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
case CSUM_MD5: {
|
||||
md_context m5;
|
||||
uchar seedbuf[4];
|
||||
md5_begin(&m5);
|
||||
if (proper_seed_order) {
|
||||
if (checksum_seed) {
|
||||
SIVALu(seedbuf, 0, checksum_seed);
|
||||
md5_update(&m5, seedbuf, 4);
|
||||
}
|
||||
md5_update(&m5, (uchar *)buf, len);
|
||||
} else {
|
||||
md5_update(&m5, (uchar *)buf, len);
|
||||
if (checksum_seed) {
|
||||
SIVALu(seedbuf, 0, checksum_seed);
|
||||
md5_update(&m5, seedbuf, 4);
|
||||
}
|
||||
}
|
||||
md5_result(&m5, (uchar *)sum);
|
||||
break;
|
||||
}
|
||||
case CSUM_MD4:
|
||||
case CSUM_MD4_OLD:
|
||||
case CSUM_MD4_BUSTED:
|
||||
case CSUM_MD4_ARCHAIC: {
|
||||
md_context m;
|
||||
md5_result(&m, (uchar *)sum);
|
||||
} else {
|
||||
int32 i;
|
||||
static char *buf1;
|
||||
static int32 len1;
|
||||
@@ -371,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);
|
||||
@@ -388,150 +93,59 @@ void get_checksum2(char *buf, int32 len, char *sum)
|
||||
* are multiples of 64. This is fixed by calling mdfour_update()
|
||||
* even when there are no more bytes.
|
||||
*/
|
||||
if (len - i > 0 || xfer_sum_nni->num > CSUM_MD4_BUSTED)
|
||||
if (len - i > 0 || protocol_version >= 27)
|
||||
mdfour_update(&m, (uchar *)(buf1+i), len-i);
|
||||
|
||||
mdfour_result(&m, (uchar *)sum);
|
||||
break;
|
||||
}
|
||||
default: /* paranoia to prevent missing case values */
|
||||
exit_cleanup(RERR_UNSUPPORTED);
|
||||
}
|
||||
}
|
||||
|
||||
void file_checksum(const char *fname, const STRUCT_STAT *st_p, char *sum)
|
||||
void file_checksum(char *fname, char *sum, OFF_T size)
|
||||
{
|
||||
struct map_struct *buf;
|
||||
OFF_T i, len = st_p->st_size;
|
||||
OFF_T i, len = size;
|
||||
md_context m;
|
||||
int32 remainder;
|
||||
int fd;
|
||||
|
||||
memset(sum, 0, MAX_DIGEST_LEN);
|
||||
|
||||
fd = do_open(fname, O_RDONLY, 0);
|
||||
if (fd == -1) {
|
||||
memset(sum, 0, file_sum_len);
|
||||
if (fd == -1)
|
||||
return;
|
||||
}
|
||||
|
||||
buf = map_file(fd, len, MAX_MAP_SIZE, CHUNK_SIZE);
|
||||
buf = map_file(fd, size, MAX_MAP_SIZE, CSUM_CHUNK);
|
||||
|
||||
#ifdef USE_OPENSSL
|
||||
if (file_sum_evp_md) {
|
||||
static EVP_MD_CTX *evp = NULL;
|
||||
if (!evp && !(evp = EVP_MD_CTX_create()))
|
||||
out_of_memory("file_checksum");
|
||||
if (protocol_version >= 30) {
|
||||
md5_begin(&m);
|
||||
|
||||
EVP_DigestInit_ex(evp, file_sum_evp_md, NULL);
|
||||
|
||||
for (i = 0; i + CHUNK_SIZE <= len; i += CHUNK_SIZE)
|
||||
EVP_DigestUpdate(evp, (uchar *)map_ptr(buf, i, CHUNK_SIZE), CHUNK_SIZE);
|
||||
for (i = 0; i + CSUM_CHUNK <= len; i += CSUM_CHUNK) {
|
||||
md5_update(&m, (uchar *)map_ptr(buf, i, CSUM_CHUNK),
|
||||
CSUM_CHUNK);
|
||||
}
|
||||
|
||||
remainder = (int32)(len - i);
|
||||
if (remainder > 0)
|
||||
EVP_DigestUpdate(evp, (uchar *)map_ptr(buf, i, remainder), remainder);
|
||||
|
||||
EVP_DigestFinal_ex(evp, (uchar *)sum, NULL);
|
||||
} else
|
||||
#endif
|
||||
switch (file_sum_nni->num) {
|
||||
#ifdef SUPPORT_XXHASH
|
||||
case CSUM_XXH64: {
|
||||
static XXH64_state_t* state = NULL;
|
||||
if (!state && !(state = XXH64_createState()))
|
||||
out_of_memory("file_checksum");
|
||||
|
||||
XXH64_reset(state, 0);
|
||||
|
||||
for (i = 0; i + CHUNK_SIZE <= len; i += CHUNK_SIZE)
|
||||
XXH64_update(state, (uchar *)map_ptr(buf, i, CHUNK_SIZE), CHUNK_SIZE);
|
||||
|
||||
remainder = (int32)(len - i);
|
||||
if (remainder > 0)
|
||||
XXH64_update(state, (uchar *)map_ptr(buf, i, remainder), remainder);
|
||||
|
||||
SIVAL64(sum, 0, XXH64_digest(state));
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
#ifdef SUPPORT_XXH3
|
||||
case CSUM_XXH3_64: {
|
||||
static XXH3_state_t* state = NULL;
|
||||
if (!state && !(state = XXH3_createState()))
|
||||
out_of_memory("file_checksum");
|
||||
|
||||
XXH3_64bits_reset(state);
|
||||
|
||||
for (i = 0; i + CHUNK_SIZE <= len; i += CHUNK_SIZE)
|
||||
XXH3_64bits_update(state, (uchar *)map_ptr(buf, i, CHUNK_SIZE), CHUNK_SIZE);
|
||||
|
||||
remainder = (int32)(len - i);
|
||||
if (remainder > 0)
|
||||
XXH3_64bits_update(state, (uchar *)map_ptr(buf, i, remainder), remainder);
|
||||
|
||||
SIVAL64(sum, 0, XXH3_64bits_digest(state));
|
||||
break;
|
||||
}
|
||||
case CSUM_XXH3_128: {
|
||||
XXH128_hash_t digest;
|
||||
static XXH3_state_t* state = NULL;
|
||||
if (!state && !(state = XXH3_createState()))
|
||||
out_of_memory("file_checksum");
|
||||
|
||||
XXH3_128bits_reset(state);
|
||||
|
||||
for (i = 0; i + CHUNK_SIZE <= len; i += CHUNK_SIZE)
|
||||
XXH3_128bits_update(state, (uchar *)map_ptr(buf, i, CHUNK_SIZE), CHUNK_SIZE);
|
||||
|
||||
remainder = (int32)(len - i);
|
||||
if (remainder > 0)
|
||||
XXH3_128bits_update(state, (uchar *)map_ptr(buf, i, remainder), remainder);
|
||||
|
||||
digest = XXH3_128bits_digest(state);
|
||||
SIVAL64(sum, 0, digest.low64);
|
||||
SIVAL64(sum, 8, digest.high64);
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
case CSUM_MD5: {
|
||||
md_context m5;
|
||||
|
||||
md5_begin(&m5);
|
||||
|
||||
for (i = 0; i + CHUNK_SIZE <= len; i += CHUNK_SIZE)
|
||||
md5_update(&m5, (uchar *)map_ptr(buf, i, CHUNK_SIZE), CHUNK_SIZE);
|
||||
|
||||
remainder = (int32)(len - i);
|
||||
if (remainder > 0)
|
||||
md5_update(&m5, (uchar *)map_ptr(buf, i, remainder), remainder);
|
||||
|
||||
md5_result(&m5, (uchar *)sum);
|
||||
break;
|
||||
}
|
||||
case CSUM_MD4:
|
||||
case CSUM_MD4_OLD:
|
||||
case CSUM_MD4_BUSTED:
|
||||
case CSUM_MD4_ARCHAIC: {
|
||||
md_context m;
|
||||
md5_update(&m, (uchar *)map_ptr(buf, i, remainder), remainder);
|
||||
|
||||
md5_result(&m, (uchar *)sum);
|
||||
} else {
|
||||
mdfour_begin(&m);
|
||||
|
||||
for (i = 0; i + CSUM_CHUNK <= len; i += CSUM_CHUNK)
|
||||
mdfour_update(&m, (uchar *)map_ptr(buf, i, CSUM_CHUNK), CSUM_CHUNK);
|
||||
for (i = 0; i + CSUM_CHUNK <= len; i += CSUM_CHUNK) {
|
||||
mdfour_update(&m, (uchar *)map_ptr(buf, i, CSUM_CHUNK),
|
||||
CSUM_CHUNK);
|
||||
}
|
||||
|
||||
/* Prior to version 27 an incorrect MD4 checksum was computed
|
||||
* by failing to call mdfour_tail() for block sizes that
|
||||
* are multiples of 64. This is fixed by calling mdfour_update()
|
||||
* even when there are no more bytes. */
|
||||
remainder = (int32)(len - i);
|
||||
if (remainder > 0 || file_sum_nni->num > CSUM_MD4_BUSTED)
|
||||
if (remainder > 0 || protocol_version >= 27)
|
||||
mdfour_update(&m, (uchar *)map_ptr(buf, i, remainder), remainder);
|
||||
|
||||
mdfour_result(&m, (uchar *)sum);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
rprintf(FERROR, "Invalid checksum-choice for --checksum: %s (%d)\n",
|
||||
file_sum_nni->name, file_sum_nni->num);
|
||||
exit_cleanup(RERR_UNSUPPORTED);
|
||||
}
|
||||
|
||||
close(fd);
|
||||
@@ -539,266 +153,73 @@ void file_checksum(const char *fname, const STRUCT_STAT *st_p, char *sum)
|
||||
}
|
||||
|
||||
static int32 sumresidue;
|
||||
static md_context ctx_md;
|
||||
#ifdef SUPPORT_XXHASH
|
||||
static XXH64_state_t* xxh64_state;
|
||||
#endif
|
||||
#ifdef SUPPORT_XXH3
|
||||
static XXH3_state_t* xxh3_state;
|
||||
#endif
|
||||
static struct name_num_item *cur_sum_nni;
|
||||
int cur_sum_len;
|
||||
static md_context md;
|
||||
|
||||
#ifdef USE_OPENSSL
|
||||
static const EVP_MD *cur_sum_evp_md;
|
||||
#endif
|
||||
|
||||
/* Initialize a hash digest accumulator. Data is supplied via
|
||||
* sum_update() and the resulting binary digest is retrieved via
|
||||
* sum_end(). This only supports one active sum at a time. */
|
||||
int sum_init(struct name_num_item *nni, int seed)
|
||||
void sum_init(int seed)
|
||||
{
|
||||
char s[4];
|
||||
|
||||
if (!nni)
|
||||
nni = parse_csum_name(NULL, 0);
|
||||
cur_sum_nni = nni;
|
||||
cur_sum_len = csum_len_for_type(nni->num, 0);
|
||||
#ifdef USE_OPENSSL
|
||||
cur_sum_evp_md = csum_evp_md(nni);
|
||||
#endif
|
||||
|
||||
#ifdef USE_OPENSSL
|
||||
if (cur_sum_evp_md) {
|
||||
if (!ctx_evp && !(ctx_evp = EVP_MD_CTX_create()))
|
||||
out_of_memory("file_checksum");
|
||||
EVP_DigestInit_ex(ctx_evp, cur_sum_evp_md, NULL);
|
||||
} else
|
||||
#endif
|
||||
switch (cur_sum_nni->num) {
|
||||
#ifdef SUPPORT_XXHASH
|
||||
case CSUM_XXH64:
|
||||
if (!xxh64_state && !(xxh64_state = XXH64_createState()))
|
||||
out_of_memory("sum_init");
|
||||
XXH64_reset(xxh64_state, 0);
|
||||
break;
|
||||
#endif
|
||||
#ifdef SUPPORT_XXH3
|
||||
case CSUM_XXH3_64:
|
||||
if (!xxh3_state && !(xxh3_state = XXH3_createState()))
|
||||
out_of_memory("sum_init");
|
||||
XXH3_64bits_reset(xxh3_state);
|
||||
break;
|
||||
case CSUM_XXH3_128:
|
||||
if (!xxh3_state && !(xxh3_state = XXH3_createState()))
|
||||
out_of_memory("sum_init");
|
||||
XXH3_128bits_reset(xxh3_state);
|
||||
break;
|
||||
#endif
|
||||
case CSUM_MD5:
|
||||
md5_begin(&ctx_md);
|
||||
break;
|
||||
case CSUM_MD4:
|
||||
mdfour_begin(&ctx_md);
|
||||
sumresidue = 0;
|
||||
break;
|
||||
case CSUM_MD4_OLD:
|
||||
case CSUM_MD4_BUSTED:
|
||||
case CSUM_MD4_ARCHAIC:
|
||||
mdfour_begin(&ctx_md);
|
||||
if (protocol_version >= 30)
|
||||
md5_begin(&md);
|
||||
else {
|
||||
mdfour_begin(&md);
|
||||
sumresidue = 0;
|
||||
SIVAL(s, 0, seed);
|
||||
sum_update(s, 4);
|
||||
break;
|
||||
case CSUM_NONE:
|
||||
break;
|
||||
default: /* paranoia to prevent missing case values */
|
||||
exit_cleanup(RERR_UNSUPPORTED);
|
||||
}
|
||||
|
||||
return cur_sum_len;
|
||||
}
|
||||
|
||||
/* Feed data into a hash digest accumulator. */
|
||||
/**
|
||||
* Feed data into an MD4 accumulator, md. The results may be
|
||||
* retrieved using sum_end(). md is used for different purposes at
|
||||
* different points during execution.
|
||||
*
|
||||
* @todo Perhaps get rid of md and just pass in the address each time.
|
||||
* Very slightly clearer and slower.
|
||||
**/
|
||||
void sum_update(const char *p, int32 len)
|
||||
{
|
||||
#ifdef USE_OPENSSL
|
||||
if (cur_sum_evp_md) {
|
||||
EVP_DigestUpdate(ctx_evp, (uchar *)p, len);
|
||||
} else
|
||||
#endif
|
||||
switch (cur_sum_nni->num) {
|
||||
#ifdef SUPPORT_XXHASH
|
||||
case CSUM_XXH64:
|
||||
XXH64_update(xxh64_state, p, len);
|
||||
break;
|
||||
#endif
|
||||
#ifdef SUPPORT_XXH3
|
||||
case CSUM_XXH3_64:
|
||||
XXH3_64bits_update(xxh3_state, p, len);
|
||||
break;
|
||||
case CSUM_XXH3_128:
|
||||
XXH3_128bits_update(xxh3_state, p, len);
|
||||
break;
|
||||
#endif
|
||||
case CSUM_MD5:
|
||||
md5_update(&ctx_md, (uchar *)p, len);
|
||||
break;
|
||||
case CSUM_MD4:
|
||||
case CSUM_MD4_OLD:
|
||||
case CSUM_MD4_BUSTED:
|
||||
case CSUM_MD4_ARCHAIC:
|
||||
if (len + sumresidue < CSUM_CHUNK) {
|
||||
memcpy(ctx_md.buffer + sumresidue, p, len);
|
||||
sumresidue += len;
|
||||
break;
|
||||
}
|
||||
|
||||
if (sumresidue) {
|
||||
int32 i = CSUM_CHUNK - sumresidue;
|
||||
memcpy(ctx_md.buffer + sumresidue, p, i);
|
||||
mdfour_update(&ctx_md, (uchar *)ctx_md.buffer, CSUM_CHUNK);
|
||||
len -= i;
|
||||
p += i;
|
||||
}
|
||||
|
||||
while (len >= CSUM_CHUNK) {
|
||||
mdfour_update(&ctx_md, (uchar *)p, CSUM_CHUNK);
|
||||
len -= CSUM_CHUNK;
|
||||
p += CSUM_CHUNK;
|
||||
}
|
||||
|
||||
sumresidue = len;
|
||||
if (sumresidue)
|
||||
memcpy(ctx_md.buffer, p, sumresidue);
|
||||
break;
|
||||
case CSUM_NONE:
|
||||
break;
|
||||
default: /* paranoia to prevent missing case values */
|
||||
exit_cleanup(RERR_UNSUPPORTED);
|
||||
}
|
||||
}
|
||||
|
||||
/* The sum buffer only needs to be as long as the current checksum's digest
|
||||
* len, not MAX_DIGEST_LEN. Note that for CSUM_MD4_ARCHAIC that is the full
|
||||
* MD4_DIGEST_LEN even if the file-list code is going to ignore all but the
|
||||
* first 2 bytes of it. */
|
||||
void sum_end(char *sum)
|
||||
{
|
||||
#ifdef USE_OPENSSL
|
||||
if (cur_sum_evp_md) {
|
||||
EVP_DigestFinal_ex(ctx_evp, (uchar *)sum, NULL);
|
||||
} else
|
||||
#endif
|
||||
switch (cur_sum_nni->num) {
|
||||
#ifdef SUPPORT_XXHASH
|
||||
case CSUM_XXH64:
|
||||
SIVAL64(sum, 0, XXH64_digest(xxh64_state));
|
||||
break;
|
||||
#endif
|
||||
#ifdef SUPPORT_XXH3
|
||||
case CSUM_XXH3_64:
|
||||
SIVAL64(sum, 0, XXH3_64bits_digest(xxh3_state));
|
||||
break;
|
||||
case CSUM_XXH3_128: {
|
||||
XXH128_hash_t digest = XXH3_128bits_digest(xxh3_state);
|
||||
SIVAL64(sum, 0, digest.low64);
|
||||
SIVAL64(sum, 8, digest.high64);
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
case CSUM_MD5:
|
||||
md5_result(&ctx_md, (uchar *)sum);
|
||||
break;
|
||||
case CSUM_MD4:
|
||||
case CSUM_MD4_OLD:
|
||||
mdfour_update(&ctx_md, (uchar *)ctx_md.buffer, sumresidue);
|
||||
mdfour_result(&ctx_md, (uchar *)sum);
|
||||
break;
|
||||
case CSUM_MD4_BUSTED:
|
||||
case CSUM_MD4_ARCHAIC:
|
||||
if (sumresidue)
|
||||
mdfour_update(&ctx_md, (uchar *)ctx_md.buffer, sumresidue);
|
||||
mdfour_result(&ctx_md, (uchar *)sum);
|
||||
break;
|
||||
case CSUM_NONE:
|
||||
*sum = '\0';
|
||||
break;
|
||||
default: /* paranoia to prevent missing case values */
|
||||
exit_cleanup(RERR_UNSUPPORTED);
|
||||
}
|
||||
}
|
||||
|
||||
#if defined SUPPORT_XXH3 || defined USE_OPENSSL
|
||||
static void verify_digest(struct name_num_item *nni, BOOL check_auth_list)
|
||||
{
|
||||
#ifdef SUPPORT_XXH3
|
||||
static int xxh3_result = 0;
|
||||
#endif
|
||||
#ifdef USE_OPENSSL
|
||||
static int prior_num = 0, prior_flags = 0, prior_result = 0;
|
||||
#endif
|
||||
|
||||
#ifdef SUPPORT_XXH3
|
||||
if (nni->num == CSUM_XXH3_64 || nni->num == CSUM_XXH3_128) {
|
||||
if (!xxh3_result) {
|
||||
char buf[32816];
|
||||
int j;
|
||||
for (j = 0; j < (int)sizeof buf; j++)
|
||||
buf[j] = ' ' + (j % 96);
|
||||
sum_init(nni, 0);
|
||||
sum_update(buf, 32816);
|
||||
sum_update(buf, 31152);
|
||||
sum_update(buf, 32474);
|
||||
sum_update(buf, 9322);
|
||||
xxh3_result = XXH3_64bits_digest(xxh3_state) != 0xadbcf16d4678d1de ? -1 : 1;
|
||||
}
|
||||
if (xxh3_result < 0)
|
||||
nni->num = CSUM_gone;
|
||||
if (protocol_version >= 30) {
|
||||
md5_update(&md, (uchar *)p, len);
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef USE_OPENSSL
|
||||
if (BITS_SETnUNSET(nni->flags, NNI_EVP, NNI_BUILTIN|NNI_EVP_OK)) {
|
||||
if (nni->num == prior_num && nni->flags == prior_flags) {
|
||||
nni->flags = prior_result;
|
||||
if (!(nni->flags & NNI_EVP))
|
||||
nni->num = CSUM_gone;
|
||||
} else {
|
||||
prior_num = nni->num;
|
||||
prior_flags = nni->flags;
|
||||
if (!csum_evp_md(nni))
|
||||
nni->num = CSUM_gone;
|
||||
prior_result = nni->flags;
|
||||
if (check_auth_list && (nni = get_nni_by_num(&valid_auth_checksums, prior_num)) != NULL)
|
||||
verify_digest(nni, False);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
|
||||
void init_checksum_choices()
|
||||
{
|
||||
#if defined SUPPORT_XXH3 || defined USE_OPENSSL
|
||||
struct name_num_item *nni;
|
||||
#endif
|
||||
|
||||
if (initialized_choices)
|
||||
if (len + sumresidue < CSUM_CHUNK) {
|
||||
memcpy(md.buffer + sumresidue, p, len);
|
||||
sumresidue += len;
|
||||
return;
|
||||
}
|
||||
|
||||
#if defined USE_OPENSSL && OPENSSL_VERSION_NUMBER < 0x10100000L
|
||||
OpenSSL_add_all_algorithms();
|
||||
#endif
|
||||
if (sumresidue) {
|
||||
int32 i = CSUM_CHUNK - sumresidue;
|
||||
memcpy(md.buffer + sumresidue, p, i);
|
||||
mdfour_update(&md, (uchar *)md.buffer, CSUM_CHUNK);
|
||||
len -= i;
|
||||
p += i;
|
||||
}
|
||||
|
||||
#if defined SUPPORT_XXH3 || defined USE_OPENSSL
|
||||
for (nni = valid_checksums.list; nni->name; nni++)
|
||||
verify_digest(nni, True);
|
||||
while (len >= CSUM_CHUNK) {
|
||||
mdfour_update(&md, (uchar *)p, CSUM_CHUNK);
|
||||
len -= CSUM_CHUNK;
|
||||
p += CSUM_CHUNK;
|
||||
}
|
||||
|
||||
for (nni = valid_auth_checksums.list; nni->name; nni++)
|
||||
verify_digest(nni, False);
|
||||
#endif
|
||||
|
||||
initialized_choices = 1;
|
||||
sumresidue = len;
|
||||
if (sumresidue)
|
||||
memcpy(md.buffer, p, sumresidue);
|
||||
}
|
||||
|
||||
int sum_end(char *sum)
|
||||
{
|
||||
if (protocol_version >= 30) {
|
||||
md5_result(&md, (uchar *)sum);
|
||||
return MD5_DIGEST_LEN;
|
||||
}
|
||||
|
||||
if (sumresidue || protocol_version >= 27)
|
||||
mdfour_update(&md, (uchar *)md.buffer, sumresidue);
|
||||
|
||||
mdfour_result(&md, (uchar *)sum);
|
||||
|
||||
return MD4_DIGEST_LEN;
|
||||
}
|
||||
|
||||
34
chmod.c
34
chmod.c
@@ -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-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,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++;
|
||||
}
|
||||
|
||||
155
cleanup.c
155
cleanup.c
@@ -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-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,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, src_file(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,60 +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)))) {
|
||||
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();
|
||||
|
||||
@@ -269,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;
|
||||
}
|
||||
|
||||
|
||||
427
clientname.c
427
clientname.c
@@ -3,7 +3,7 @@
|
||||
*
|
||||
* Copyright (C) 1992-2001 Andrew Tridgell <tridge@samba.org>
|
||||
* Copyright (C) 2001, 2002 Martin Pool <mbp@samba.org>
|
||||
* Copyright (C) 2002-2022 Wayne Davison
|
||||
* Copyright (C) 2002-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
|
||||
@@ -27,60 +27,50 @@
|
||||
*/
|
||||
|
||||
#include "rsync.h"
|
||||
#include "itypes.h"
|
||||
|
||||
extern int am_daemon;
|
||||
|
||||
static const char default_name[] = "UNKNOWN";
|
||||
static const char proxyv2sig[] = "\r\n\r\n\0\r\nQUIT\n";
|
||||
extern int am_server;
|
||||
|
||||
static char ipaddr_buf[100];
|
||||
|
||||
#define PROXY_V2_SIG_SIZE ((int)sizeof proxyv2sig - 1)
|
||||
#define PROXY_V2_HEADER_SIZE (PROXY_V2_SIG_SIZE + 1 + 1 + 2)
|
||||
|
||||
#define CMD_LOCAL 0
|
||||
#define CMD_PROXY 1
|
||||
|
||||
#define PROXY_FAM_TCPv4 0x11
|
||||
#define PROXY_FAM_TCPv6 0x21
|
||||
|
||||
#define GET_SOCKADDR_FAMILY(ss) ((struct sockaddr*)ss)->sa_family
|
||||
|
||||
static void client_sockaddr(int fd, struct sockaddr_storage *ss, socklen_t *ss_len);
|
||||
static int check_name(const char *ipaddr, const struct sockaddr_storage *ss, char *name_buf, size_t name_buf_size);
|
||||
static int valid_ipaddr(const char *s, int allow_scope);
|
||||
|
||||
/* Return the IP addr of the client as a string. */
|
||||
/**
|
||||
* Return the IP addr of the client as a string
|
||||
**/
|
||||
char *client_addr(int fd)
|
||||
{
|
||||
static char addr_buf[100];
|
||||
static int initialised;
|
||||
struct sockaddr_storage ss;
|
||||
socklen_t length = sizeof ss;
|
||||
char *ssh_info, *p;
|
||||
|
||||
if (*ipaddr_buf)
|
||||
return ipaddr_buf;
|
||||
if (initialised)
|
||||
return addr_buf;
|
||||
|
||||
if (am_daemon < 0) { /* daemon over --rsh mode */
|
||||
char *env_str;
|
||||
strlcpy(ipaddr_buf, "0.0.0.0", sizeof ipaddr_buf);
|
||||
if ((env_str = getenv("REMOTE_HOST")) != NULL
|
||||
|| (env_str = getenv("SSH_CONNECTION")) != NULL
|
||||
|| (env_str = getenv("SSH_CLIENT")) != NULL
|
||||
|| (env_str = getenv("SSH2_CLIENT")) != NULL) {
|
||||
char *p;
|
||||
strlcpy(ipaddr_buf, env_str, sizeof ipaddr_buf);
|
||||
initialised = 1;
|
||||
|
||||
if (am_server) { /* daemon over --rsh mode */
|
||||
strlcpy(addr_buf, "0.0.0.0", sizeof addr_buf);
|
||||
if ((ssh_info = getenv("SSH_CONNECTION")) != NULL
|
||||
|| (ssh_info = getenv("SSH_CLIENT")) != NULL
|
||||
|| (ssh_info = getenv("SSH2_CLIENT")) != NULL) {
|
||||
strlcpy(addr_buf, ssh_info, sizeof addr_buf);
|
||||
/* Truncate the value to just the IP address. */
|
||||
if ((p = strchr(ipaddr_buf, ' ')) != NULL)
|
||||
if ((p = strchr(addr_buf, ' ')) != NULL)
|
||||
*p = '\0';
|
||||
}
|
||||
if (valid_ipaddr(ipaddr_buf, True))
|
||||
return ipaddr_buf;
|
||||
} else {
|
||||
client_sockaddr(fd, &ss, &length);
|
||||
getnameinfo((struct sockaddr *)&ss, length,
|
||||
addr_buf, sizeof addr_buf, NULL, 0, NI_NUMERICHOST);
|
||||
}
|
||||
|
||||
client_sockaddr(fd, &ss, &length);
|
||||
getnameinfo((struct sockaddr *)&ss, length, ipaddr_buf, sizeof ipaddr_buf, NULL, 0, NI_NUMERICHOST);
|
||||
return addr_buf;
|
||||
}
|
||||
|
||||
return ipaddr_buf;
|
||||
|
||||
static int get_sockaddr_family(const struct sockaddr_storage *ss)
|
||||
{
|
||||
return ((struct sockaddr *) ss)->sa_family;
|
||||
}
|
||||
|
||||
|
||||
@@ -97,218 +87,68 @@ 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;
|
||||
|
||||
memset(&hint, 0, sizeof hint);
|
||||
|
||||
#ifdef AI_NUMERICHOST
|
||||
hint.ai_flags = AI_NUMERICHOST;
|
||||
hint.ai_flags = AI_NUMERICHOST;
|
||||
#endif
|
||||
hint.ai_socktype = SOCK_STREAM;
|
||||
hint.ai_socktype = SOCK_STREAM;
|
||||
|
||||
if ((err = getaddrinfo(ipaddr, NULL, &hint, &answer)) != 0) {
|
||||
rprintf(FLOG, "malformed address %s: %s\n", ipaddr, gai_strerror(err));
|
||||
return name_buf;
|
||||
}
|
||||
if ((err = getaddrinfo(addr, NULL, &hint, &answer)) != 0) {
|
||||
rprintf(FLOG, "malformed address %s: %s\n",
|
||||
addr, gai_strerror(err));
|
||||
return name_buf;
|
||||
}
|
||||
|
||||
switch (answer->ai_family) {
|
||||
case AF_INET:
|
||||
ss_len = sizeof (struct sockaddr_in);
|
||||
memcpy(&ss, answer->ai_addr, ss_len);
|
||||
break;
|
||||
switch (answer->ai_family) {
|
||||
case AF_INET:
|
||||
ss_len = sizeof (struct sockaddr_in);
|
||||
memcpy(&ss, answer->ai_addr, ss_len);
|
||||
break;
|
||||
#ifdef INET6
|
||||
case AF_INET6:
|
||||
ss_len = sizeof (struct sockaddr_in6);
|
||||
memcpy(&ss, answer->ai_addr, ss_len);
|
||||
break;
|
||||
case AF_INET6:
|
||||
ss_len = sizeof (struct sockaddr_in6);
|
||||
memcpy(&ss, answer->ai_addr, ss_len);
|
||||
break;
|
||||
#endif
|
||||
default:
|
||||
NOISY_DEATH("Unknown ai_family value");
|
||||
default:
|
||||
exit_cleanup(RERR_SOCKETIO);
|
||||
}
|
||||
freeaddrinfo(answer);
|
||||
} else {
|
||||
ss_len = sizeof ss;
|
||||
client_sockaddr(fd, &ss, &ss_len);
|
||||
}
|
||||
freeaddrinfo(answer);
|
||||
|
||||
/* reverse lookup */
|
||||
err = getnameinfo((struct sockaddr*)&ss, ss_len, name_buf, sizeof name_buf,
|
||||
port_buf, sizeof port_buf, NI_NAMEREQD | NI_NUMERICSERV);
|
||||
if (err) {
|
||||
strlcpy(name_buf, default_name, sizeof name_buf);
|
||||
rprintf(FLOG, "name lookup failed for %s: %s\n", ipaddr, gai_strerror(err));
|
||||
} else
|
||||
check_name(ipaddr, &ss, name_buf, sizeof name_buf);
|
||||
if (lookup_name(fd, &ss, ss_len, name_buf, sizeof name_buf,
|
||||
port_buf, sizeof port_buf) == 0)
|
||||
check_name(fd, &ss, name_buf, sizeof name_buf);
|
||||
|
||||
return name_buf;
|
||||
}
|
||||
|
||||
|
||||
/* Try to read a proxy protocol header (V1 or V2). Returns 1 on success or 0 on failure. */
|
||||
int read_proxy_protocol_header(int fd)
|
||||
{
|
||||
union {
|
||||
struct {
|
||||
char line[108];
|
||||
} v1;
|
||||
struct {
|
||||
char sig[PROXY_V2_SIG_SIZE];
|
||||
char ver_cmd;
|
||||
char fam;
|
||||
char len[2];
|
||||
union {
|
||||
struct {
|
||||
char src_addr[4];
|
||||
char dst_addr[4];
|
||||
char src_port[2];
|
||||
char dst_port[2];
|
||||
} ip4;
|
||||
struct {
|
||||
char src_addr[16];
|
||||
char dst_addr[16];
|
||||
char src_port[2];
|
||||
char dst_port[2];
|
||||
} ip6;
|
||||
struct {
|
||||
char src_addr[108];
|
||||
char dst_addr[108];
|
||||
} unx;
|
||||
} addr;
|
||||
} v2;
|
||||
} hdr;
|
||||
|
||||
read_buf(fd, (char*)&hdr, PROXY_V2_SIG_SIZE);
|
||||
|
||||
if (memcmp(hdr.v2.sig, proxyv2sig, PROXY_V2_SIG_SIZE) == 0) { /* Proxy V2 */
|
||||
int ver, cmd, size;
|
||||
|
||||
read_buf(fd, (char*)&hdr + PROXY_V2_SIG_SIZE, PROXY_V2_HEADER_SIZE - PROXY_V2_SIG_SIZE);
|
||||
|
||||
ver = (hdr.v2.ver_cmd & 0xf0) >> 4;
|
||||
cmd = (hdr.v2.ver_cmd & 0x0f);
|
||||
size = (hdr.v2.len[0] << 8) + hdr.v2.len[1];
|
||||
|
||||
if (ver != 2 || size + PROXY_V2_HEADER_SIZE > (int)sizeof hdr)
|
||||
return 0;
|
||||
|
||||
/* Grab all the remaining data in the binary request. */
|
||||
read_buf(fd, (char*)&hdr + PROXY_V2_HEADER_SIZE, size);
|
||||
|
||||
switch (cmd) {
|
||||
case CMD_PROXY:
|
||||
switch (hdr.v2.fam) {
|
||||
case PROXY_FAM_TCPv4:
|
||||
if (size != sizeof hdr.v2.addr.ip4)
|
||||
return 0;
|
||||
inet_ntop(AF_INET, hdr.v2.addr.ip4.src_addr, ipaddr_buf, sizeof ipaddr_buf);
|
||||
return valid_ipaddr(ipaddr_buf, False);
|
||||
#ifdef INET6
|
||||
case PROXY_FAM_TCPv6:
|
||||
if (size != sizeof hdr.v2.addr.ip6)
|
||||
return 0;
|
||||
inet_ntop(AF_INET6, hdr.v2.addr.ip6.src_addr, ipaddr_buf, sizeof ipaddr_buf);
|
||||
return valid_ipaddr(ipaddr_buf, False);
|
||||
#endif
|
||||
default:
|
||||
break;
|
||||
}
|
||||
/* For an unsupported protocol we'll ignore the proxy data (leaving ipaddr_buf unset)
|
||||
* and accept the connection, which will get handled as a normal socket addr. */
|
||||
return 1;
|
||||
case CMD_LOCAL:
|
||||
return 1;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (memcmp(hdr.v1.line, "PROXY", 5) == 0) { /* Proxy V1 */
|
||||
char *endc, *sp, *p = hdr.v1.line + PROXY_V2_SIG_SIZE;
|
||||
int port_chk;
|
||||
|
||||
*p = '\0';
|
||||
if (!strchr(hdr.v1.line, '\n')) {
|
||||
while (1) {
|
||||
read_buf(fd, p, 1);
|
||||
if (*p++ == '\n')
|
||||
break;
|
||||
if (p - hdr.v1.line >= (int)sizeof hdr.v1.line - 1)
|
||||
return 0;
|
||||
}
|
||||
*p = '\0';
|
||||
}
|
||||
|
||||
endc = strchr(hdr.v1.line, '\r');
|
||||
if (!endc || endc[1] != '\n' || endc[2])
|
||||
return 0;
|
||||
*endc = '\0';
|
||||
|
||||
p = hdr.v1.line + 5;
|
||||
|
||||
if (!isSpace(p++))
|
||||
return 0;
|
||||
if (strncmp(p, "TCP4", 4) == 0)
|
||||
p += 4;
|
||||
else if (strncmp(p, "TCP6", 4) == 0)
|
||||
p += 4;
|
||||
else if (strncmp(p, "UNKNOWN", 7) == 0)
|
||||
return 1;
|
||||
else
|
||||
return 0;
|
||||
|
||||
if (!isSpace(p++))
|
||||
return 0;
|
||||
|
||||
if ((sp = strchr(p, ' ')) == NULL)
|
||||
return 0;
|
||||
*sp = '\0';
|
||||
if (!valid_ipaddr(p, False))
|
||||
return 0;
|
||||
strlcpy(ipaddr_buf, p, sizeof ipaddr_buf); /* It will always fit when valid. */
|
||||
|
||||
p = sp + 1;
|
||||
if ((sp = strchr(p, ' ')) == NULL)
|
||||
return 0;
|
||||
*sp = '\0';
|
||||
if (!valid_ipaddr(p, False))
|
||||
return 0;
|
||||
/* Ignore destination address. */
|
||||
|
||||
p = sp + 1;
|
||||
if ((sp = strchr(p, ' ')) == NULL)
|
||||
return 0;
|
||||
*sp = '\0';
|
||||
port_chk = strtol(p, &endc, 10);
|
||||
if (*endc || port_chk == 0)
|
||||
return 0;
|
||||
/* Ignore source port. */
|
||||
|
||||
p = sp + 1;
|
||||
port_chk = strtol(p, &endc, 10);
|
||||
if (*endc || port_chk == 0)
|
||||
return 0;
|
||||
/* Ignore destination port. */
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Get the sockaddr for the client.
|
||||
@@ -316,7 +156,9 @@ int read_proxy_protocol_header(int fd)
|
||||
* If it comes in as an ipv4 address mapped into IPv6 format then we
|
||||
* convert it back to a regular IPv4.
|
||||
**/
|
||||
static void client_sockaddr(int fd, struct sockaddr_storage *ss, socklen_t *ss_len)
|
||||
void client_sockaddr(int fd,
|
||||
struct sockaddr_storage *ss,
|
||||
socklen_t *ss_len)
|
||||
{
|
||||
memset(ss, 0, sizeof *ss);
|
||||
|
||||
@@ -327,8 +169,8 @@ static void client_sockaddr(int fd, struct sockaddr_storage *ss, socklen_t *ss_l
|
||||
}
|
||||
|
||||
#ifdef INET6
|
||||
if (GET_SOCKADDR_FAMILY(ss) == AF_INET6
|
||||
&& IN6_IS_ADDR_V4MAPPED(&((struct sockaddr_in6 *)ss)->sin6_addr)) {
|
||||
if (get_sockaddr_family(ss) == AF_INET6 &&
|
||||
IN6_IS_ADDR_V4MAPPED(&((struct sockaddr_in6 *)ss)->sin6_addr)) {
|
||||
/* OK, so ss is in the IPv6 family, but it is really
|
||||
* an IPv4 address: something like
|
||||
* "::ffff:10.130.1.2". If we use it as-is, then the
|
||||
@@ -351,20 +193,51 @@ static void client_sockaddr(int fd, struct sockaddr_storage *ss, socklen_t *ss_l
|
||||
/* There is a macro to extract the mapped part
|
||||
* (IN6_V4MAPPED_TO_SINADDR ?), but it does not seem
|
||||
* to be present in the Linux headers. */
|
||||
memcpy(&sin->sin_addr, &sin6.sin6_addr.s6_addr[12], sizeof sin->sin_addr);
|
||||
memcpy(&sin->sin_addr, &sin6.sin6_addr.s6_addr[12],
|
||||
sizeof sin->sin_addr);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Look up a name from @p ss into @p name_buf.
|
||||
*
|
||||
* @param fd file descriptor for client socket.
|
||||
**/
|
||||
int lookup_name(int fd, const struct sockaddr_storage *ss,
|
||||
socklen_t ss_len,
|
||||
char *name_buf, size_t name_buf_size,
|
||||
char *port_buf, size_t port_buf_size)
|
||||
{
|
||||
int name_err;
|
||||
|
||||
/* reverse lookup */
|
||||
name_err = getnameinfo((struct sockaddr *) ss, ss_len,
|
||||
name_buf, name_buf_size,
|
||||
port_buf, port_buf_size,
|
||||
NI_NAMEREQD | NI_NUMERICSERV);
|
||||
if (name_err != 0) {
|
||||
strlcpy(name_buf, default_name, name_buf_size);
|
||||
rprintf(FLOG, "name lookup failed for %s: %s\n",
|
||||
client_addr(fd), gai_strerror(name_err));
|
||||
return name_err;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Compare an addrinfo from the resolver to a sockinfo.
|
||||
*
|
||||
* Like strcmp, returns 0 for identical.
|
||||
**/
|
||||
static int compare_addrinfo_sockaddr(const struct addrinfo *ai, const struct sockaddr_storage *ss)
|
||||
int compare_addrinfo_sockaddr(const struct addrinfo *ai,
|
||||
const struct sockaddr_storage *ss)
|
||||
{
|
||||
int ss_family = GET_SOCKADDR_FAMILY(ss);
|
||||
int ss_family = get_sockaddr_family(ss);
|
||||
const char fn[] = "compare_addrinfo_sockaddr";
|
||||
|
||||
if (ai->ai_family != ss_family) {
|
||||
@@ -380,7 +253,8 @@ static int compare_addrinfo_sockaddr(const struct addrinfo *ai, const struct soc
|
||||
sin1 = (const struct sockaddr_in *) ss;
|
||||
sin2 = (const struct sockaddr_in *) ai->ai_addr;
|
||||
|
||||
return memcmp(&sin1->sin_addr, &sin2->sin_addr, sizeof sin1->sin_addr);
|
||||
return memcmp(&sin1->sin_addr, &sin2->sin_addr,
|
||||
sizeof sin1->sin_addr);
|
||||
}
|
||||
|
||||
#ifdef INET6
|
||||
@@ -390,13 +264,14 @@ static int compare_addrinfo_sockaddr(const struct addrinfo *ai, const struct soc
|
||||
sin1 = (const struct sockaddr_in6 *) ss;
|
||||
sin2 = (const struct sockaddr_in6 *) ai->ai_addr;
|
||||
|
||||
if (ai->ai_addrlen < (int)sizeof (struct sockaddr_in6)) {
|
||||
if (ai->ai_addrlen < sizeof (struct sockaddr_in6)) {
|
||||
rprintf(FLOG, "%s: too short sockaddr_in6; length=%d\n",
|
||||
fn, (int)ai->ai_addrlen);
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (memcmp(&sin1->sin6_addr, &sin2->sin6_addr, sizeof sin1->sin6_addr))
|
||||
if (memcmp(&sin1->sin6_addr, &sin2->sin6_addr,
|
||||
sizeof sin1->sin6_addr))
|
||||
return 1;
|
||||
|
||||
#ifdef HAVE_SOCKADDR_IN6_SCOPE_ID
|
||||
@@ -422,11 +297,13 @@ static int compare_addrinfo_sockaddr(const struct addrinfo *ai, const struct soc
|
||||
* because it doesn't seem that it could be spoofed in any way, and
|
||||
* getaddrinfo on random service names seems to cause problems on AIX.
|
||||
**/
|
||||
static int check_name(const char *ipaddr, const struct sockaddr_storage *ss, char *name_buf, size_t name_buf_size)
|
||||
int check_name(int fd,
|
||||
const struct sockaddr_storage *ss,
|
||||
char *name_buf, size_t name_buf_size)
|
||||
{
|
||||
struct addrinfo hints, *res, *res0;
|
||||
int error;
|
||||
int ss_family = GET_SOCKADDR_FAMILY(ss);
|
||||
int ss_family = get_sockaddr_family(ss);
|
||||
|
||||
memset(&hints, 0, sizeof hints);
|
||||
hints.ai_family = ss_family;
|
||||
@@ -457,82 +334,10 @@ static int check_name(const char *ipaddr, const struct sockaddr_storage *ss, cha
|
||||
/* We hit the end of the list without finding an
|
||||
* address that was the same as ss. */
|
||||
rprintf(FLOG, "%s is not a known address for \"%s\": "
|
||||
"spoofed address?\n", ipaddr, name_buf);
|
||||
"spoofed address?\n", client_addr(fd), name_buf);
|
||||
strlcpy(name_buf, default_name, name_buf_size);
|
||||
}
|
||||
|
||||
freeaddrinfo(res0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Returns 1 for a valid IPv4 or IPv6 addr, or 0 for a bad one. */
|
||||
static int valid_ipaddr(const char *s, int allow_scope)
|
||||
{
|
||||
int i;
|
||||
|
||||
if (strchr(s, ':') != NULL) { /* Only IPv6 has a colon. */
|
||||
int count, saw_double_colon = 0;
|
||||
int ipv4_at_end = 0;
|
||||
|
||||
if (*s == ':') { /* A colon at the start must be a :: */
|
||||
if (*++s != ':')
|
||||
return 0;
|
||||
saw_double_colon = 1;
|
||||
s++;
|
||||
}
|
||||
|
||||
for (count = 0; count < 8; count++) {
|
||||
if (!*s)
|
||||
return saw_double_colon;
|
||||
if (allow_scope && *s == '%') {
|
||||
if (saw_double_colon)
|
||||
break;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (strchr(s, ':') == NULL && strchr(s, '.') != NULL) {
|
||||
if ((!saw_double_colon && count != 6) || (saw_double_colon && count > 6))
|
||||
return 0;
|
||||
ipv4_at_end = 1;
|
||||
break;
|
||||
}
|
||||
|
||||
if (!isHexDigit(s++)) /* Need 1-4 hex digits */
|
||||
return 0;
|
||||
if (isHexDigit(s) && isHexDigit(++s) && isHexDigit(++s) && isHexDigit(++s))
|
||||
return 0;
|
||||
|
||||
if (*s == ':') {
|
||||
if (!*++s)
|
||||
return 0;
|
||||
if (*s == ':') {
|
||||
if (saw_double_colon)
|
||||
return 0;
|
||||
saw_double_colon = 1;
|
||||
s++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!ipv4_at_end) {
|
||||
if (allow_scope && *s == '%')
|
||||
for (s++; isAlNum(s); s++) { }
|
||||
return !*s && s[-1] != '%';
|
||||
}
|
||||
}
|
||||
|
||||
/* IPv4 */
|
||||
for (i = 0; i < 4; i++) {
|
||||
long n;
|
||||
char *end;
|
||||
|
||||
if (i && *s++ != '.')
|
||||
return 0;
|
||||
n = strtol(s, &end, 10);
|
||||
if (n > 255 || n < 0 || end <= s || end > s+3)
|
||||
return 0;
|
||||
s = end;
|
||||
}
|
||||
|
||||
return !*s;
|
||||
}
|
||||
|
||||
1071
clientserver.c
1071
clientserver.c
File diff suppressed because it is too large
Load Diff
11
cmd-or-msg
11
cmd-or-msg
@@ -1,11 +0,0 @@
|
||||
#!/bin/sh
|
||||
|
||||
srcdir=`dirname $0`
|
||||
opt="$1"
|
||||
shift
|
||||
|
||||
echo "$*"
|
||||
if ! "${@}"; then
|
||||
echo "If you can't fix the issue, re-run $srcdir/configure with --$opt."
|
||||
exit 1
|
||||
fi
|
||||
679
compat.c
679
compat.c
@@ -3,7 +3,7 @@
|
||||
*
|
||||
* Copyright (C) Andrew Tridgell 1996
|
||||
* Copyright (C) Paul Mackerras 1996
|
||||
* Copyright (C) 2004-2022 Wayne Davison
|
||||
* Copyright (C) 2004-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
|
||||
@@ -20,9 +20,12 @@
|
||||
*/
|
||||
|
||||
#include "rsync.h"
|
||||
#include "itypes.h"
|
||||
#include "ifuncs.h"
|
||||
|
||||
int remote_protocol = 0;
|
||||
int file_extra_cnt = 0; /* count of file-list extras that everyone gets */
|
||||
int inc_recurse = 0;
|
||||
|
||||
extern int verbose;
|
||||
extern int am_server;
|
||||
extern int am_sender;
|
||||
extern int local_server;
|
||||
@@ -30,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;
|
||||
@@ -43,50 +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_crtimes;
|
||||
extern int preserve_acls;
|
||||
extern int preserve_xattrs;
|
||||
extern int xfer_flags_as_varint;
|
||||
extern int need_messages_from_generator;
|
||||
extern int delete_mode, delete_before, delete_during, delete_after;
|
||||
extern int do_compression;
|
||||
extern int do_compression_level;
|
||||
extern int saw_stderr_opt;
|
||||
extern int msgs2stderr;
|
||||
extern char *shell_cmd;
|
||||
extern char *partial_dir;
|
||||
extern char *dest_option;
|
||||
extern char *files_from;
|
||||
extern char *filesfrom_host;
|
||||
extern const char *checksum_choice;
|
||||
extern const char *compress_choice;
|
||||
extern char *daemon_auth_choices;
|
||||
extern filter_rule_list filter_list;
|
||||
extern struct filter_list_struct filter_list;
|
||||
extern int need_unsorted_flist;
|
||||
#ifdef ICONV_OPTION
|
||||
extern iconv_t ic_send, ic_recv;
|
||||
extern char *iconv_opt;
|
||||
#endif
|
||||
extern struct name_num_obj valid_checksums, valid_auth_checksums;
|
||||
|
||||
extern struct name_num_item *xfer_sum_nni;
|
||||
|
||||
int remote_protocol = 0;
|
||||
int file_extra_cnt = 0; /* count of file-list extras that everyone gets */
|
||||
int inc_recurse = 0;
|
||||
int compat_flags = 0;
|
||||
int use_safe_inc_flist = 0;
|
||||
int want_xattr_optim = 0;
|
||||
int proper_seed_order = 0;
|
||||
int inplace_partial = 0;
|
||||
int do_negotiated_strings = 0;
|
||||
int xmit_id0_names = 0;
|
||||
|
||||
struct name_num_item *xattr_sum_nni;
|
||||
int xattr_sum_len = 0;
|
||||
|
||||
/* These index values are for the file-list's extra-attribute array. */
|
||||
int pathname_ndx, depth_ndx, atimes_ndx, crtimes_ndx, uid_ndx, gid_ndx, acls_ndx, xattrs_ndx, unsort_ndx;
|
||||
int uid_ndx, gid_ndx, acls_ndx, xattrs_ndx, unsort_ndx;
|
||||
|
||||
int receiver_symlink_times = 0; /* receiver can set the time on a symlink */
|
||||
int sender_symlink_iconv = 0; /* sender should convert symlink content */
|
||||
@@ -95,34 +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_item valid_compressions_items[] = {
|
||||
#ifdef SUPPORT_ZSTD
|
||||
{ CPRES_ZSTD, 0, "zstd", NULL },
|
||||
#endif
|
||||
#ifdef SUPPORT_LZ4
|
||||
{ CPRES_LZ4, 0, "lz4", NULL },
|
||||
#endif
|
||||
{ CPRES_ZLIBX, 0, "zlibx", NULL },
|
||||
{ CPRES_ZLIB, 0, "zlib", NULL },
|
||||
{ CPRES_NONE, 0, "none", NULL },
|
||||
{ 0, 0, NULL, NULL }
|
||||
};
|
||||
|
||||
struct name_num_obj valid_compressions = {
|
||||
"compress", NULL, 0, 0, valid_compressions_items
|
||||
};
|
||||
|
||||
#define CF_INC_RECURSE (1<<0)
|
||||
#define CF_SYMLINK_TIMES (1<<1)
|
||||
#define CF_SYMLINK_ICONV (1<<2)
|
||||
#define CF_SAFE_FLIST (1<<3)
|
||||
#define CF_AVOID_XATTR_OPTIM (1<<4)
|
||||
#define CF_CHKSUM_SEED_FIX (1<<5)
|
||||
#define CF_INPLACE_PARTIAL_DIR (1<<6)
|
||||
#define CF_VARINT_FLIST_FLAGS (1<<7)
|
||||
#define CF_ID0_NAMES (1<<8)
|
||||
|
||||
static const char *client_info;
|
||||
|
||||
@@ -133,7 +83,11 @@ static void check_sub_protocol(void)
|
||||
{
|
||||
char *dot;
|
||||
int their_protocol, their_sub;
|
||||
int our_sub = get_subprotocol_version();
|
||||
#if SUBPROTOCOL_VERSION != 0
|
||||
int our_sub = protocol_version < PROTOCOL_VERSION ? 0 : SUBPROTOCOL_VERSION;
|
||||
#else
|
||||
int our_sub = 0;
|
||||
#endif
|
||||
|
||||
/* client_info starts with VER.SUB string if client is a pre-release. */
|
||||
if (!(their_protocol = atoi(client_info))
|
||||
@@ -160,13 +114,7 @@ static void check_sub_protocol(void)
|
||||
|
||||
void set_allow_inc_recurse(void)
|
||||
{
|
||||
if (!local_server)
|
||||
client_info = shell_cmd ? shell_cmd : "";
|
||||
else if (am_server) {
|
||||
char buf[64];
|
||||
maybe_add_e_option(buf, sizeof buf);
|
||||
client_info = *buf ? strdup(buf+1) : ""; /* The +1 skips the leading "e". */
|
||||
}
|
||||
client_info = shell_cmd ? shell_cmd : "";
|
||||
|
||||
if (!recurse || use_qsort)
|
||||
allow_inc_recurse = 0;
|
||||
@@ -174,416 +122,17 @@ void set_allow_inc_recurse(void)
|
||||
&& (delete_before || delete_after
|
||||
|| delay_updates || prune_empty_dirs))
|
||||
allow_inc_recurse = 0;
|
||||
else if (am_server && strchr(client_info, 'i') == NULL)
|
||||
else if (am_server && !local_server
|
||||
&& (strchr(client_info, 'i') == NULL))
|
||||
allow_inc_recurse = 0;
|
||||
}
|
||||
|
||||
void parse_compress_choice(int final_call)
|
||||
{
|
||||
if (valid_compressions.negotiated_nni)
|
||||
do_compression = valid_compressions.negotiated_nni->num;
|
||||
else if (compress_choice) {
|
||||
struct name_num_item *nni = get_nni_by_name(&valid_compressions, compress_choice, -1);
|
||||
if (!nni) {
|
||||
rprintf(FERROR, "unknown compress name: %s\n", compress_choice);
|
||||
exit_cleanup(RERR_UNSUPPORTED);
|
||||
}
|
||||
do_compression = nni->num;
|
||||
if (am_server)
|
||||
validate_choice_vs_env(NSTR_COMPRESS, do_compression, -1);
|
||||
} else if (do_compression)
|
||||
do_compression = CPRES_ZLIB;
|
||||
else
|
||||
do_compression = CPRES_NONE;
|
||||
|
||||
if (do_compression != CPRES_NONE && final_call)
|
||||
init_compression_level(); /* There's a chance this might turn compression off! */
|
||||
|
||||
if (do_compression == CPRES_NONE)
|
||||
compress_choice = NULL;
|
||||
|
||||
/* Snag the compression name for both write_batch's option output & the following debug output. */
|
||||
if (valid_compressions.negotiated_nni)
|
||||
compress_choice = valid_compressions.negotiated_nni->name;
|
||||
else if (compress_choice == NULL) {
|
||||
struct name_num_item *nni = get_nni_by_num(&valid_compressions, do_compression);
|
||||
compress_choice = nni ? nni->name : "UNKNOWN";
|
||||
}
|
||||
|
||||
if (final_call && DEBUG_GTE(NSTR, am_server ? 3 : 1)
|
||||
&& (do_compression != CPRES_NONE || do_compression_level != CLVL_NOT_SPECIFIED)) {
|
||||
rprintf(FINFO, "%s%s compress: %s (level %d)\n",
|
||||
am_server ? "Server" : "Client",
|
||||
valid_compressions.negotiated_nni ? " negotiated" : "",
|
||||
compress_choice, do_compression_level);
|
||||
}
|
||||
}
|
||||
|
||||
struct name_num_item *get_nni_by_name(struct name_num_obj *nno, const char *name, int len)
|
||||
{
|
||||
struct name_num_item *nni;
|
||||
|
||||
if (len < 0)
|
||||
len = strlen(name);
|
||||
|
||||
for (nni = nno->list; nni->name; nni++) {
|
||||
if (nni->num == CSUM_gone)
|
||||
continue;
|
||||
if (strncasecmp(name, nni->name, len) == 0 && nni->name[len] == '\0')
|
||||
return nni;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
struct name_num_item *get_nni_by_num(struct name_num_obj *nno, int num)
|
||||
{
|
||||
struct name_num_item *nni;
|
||||
|
||||
for (nni = nno->list; nni->name; nni++) {
|
||||
if (num == nni->num)
|
||||
return nni;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void init_nno_saw(struct name_num_obj *nno, int val)
|
||||
{
|
||||
struct name_num_item *nni;
|
||||
int cnt;
|
||||
|
||||
if (!nno->saw_len) {
|
||||
for (nni = nno->list; nni->name; nni++) {
|
||||
if (nni->num >= nno->saw_len)
|
||||
nno->saw_len = nni->num + 1;
|
||||
}
|
||||
}
|
||||
|
||||
if (!nno->saw) {
|
||||
nno->saw = new_array0(uchar, nno->saw_len);
|
||||
|
||||
/* We'll take this opportunity to set the main_nni values for duplicates. */
|
||||
for (cnt = 1, nni = nno->list; nni->name; nni++, cnt++) {
|
||||
if (nni->num == CSUM_gone)
|
||||
continue;
|
||||
if (nno->saw[nni->num])
|
||||
nni->main_nni = &nno->list[nno->saw[nni->num]-1];
|
||||
else
|
||||
nno->saw[nni->num] = cnt;
|
||||
}
|
||||
}
|
||||
|
||||
memset(nno->saw, val, nno->saw_len);
|
||||
}
|
||||
|
||||
/* Simplify the user-provided string so that it contains valid names without any duplicates.
|
||||
* It also sets the "saw" flags to a 1-relative count of which name was seen first. */
|
||||
static int parse_nni_str(struct name_num_obj *nno, const char *from, char *tobuf, int tobuf_len)
|
||||
{
|
||||
char *to = tobuf, *tok = NULL;
|
||||
int saw_tok = 0, cnt = 0;
|
||||
|
||||
while (1) {
|
||||
int at_space = isSpace(from);
|
||||
char ch = *from++;
|
||||
if (ch == '&')
|
||||
ch = '\0';
|
||||
if (!ch || at_space) {
|
||||
if (tok) {
|
||||
struct name_num_item *nni = get_nni_by_name(nno, tok, to - tok);
|
||||
if (nni && !nno->saw[nni->num]) {
|
||||
nno->saw[nni->num] = ++cnt;
|
||||
if (nni->main_nni) {
|
||||
to = tok + strlcpy(tok, nni->main_nni->name, tobuf_len - (tok - tobuf));
|
||||
if (to - tobuf >= tobuf_len) {
|
||||
to = tok - 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else
|
||||
to = tok - (tok != tobuf);
|
||||
saw_tok = 1;
|
||||
tok = NULL;
|
||||
}
|
||||
if (!ch)
|
||||
break;
|
||||
continue;
|
||||
}
|
||||
if (!tok) {
|
||||
if (to != tobuf)
|
||||
*to++ = ' ';
|
||||
tok = to;
|
||||
}
|
||||
if (to - tobuf >= tobuf_len - 1) {
|
||||
to = tok - (tok != tobuf);
|
||||
break;
|
||||
}
|
||||
*to++ = ch;
|
||||
}
|
||||
*to = '\0';
|
||||
|
||||
if (saw_tok && to == tobuf)
|
||||
return strlcpy(tobuf, "INVALID", MAX_NSTR_STRLEN);
|
||||
|
||||
return to - tobuf;
|
||||
}
|
||||
|
||||
static int parse_negotiate_str(struct name_num_obj *nno, char *tmpbuf)
|
||||
{
|
||||
struct name_num_item *nni, *ret = NULL;
|
||||
int best = nno->saw_len; /* We want best == 1 from the client list, so start with a big number. */
|
||||
char *space, *tok = tmpbuf;
|
||||
while (tok) {
|
||||
while (*tok == ' ') tok++; /* Should be unneeded... */
|
||||
if (!*tok)
|
||||
break;
|
||||
if ((space = strchr(tok, ' ')) != NULL)
|
||||
*space = '\0';
|
||||
nni = get_nni_by_name(nno, tok, -1);
|
||||
if (space) {
|
||||
*space = ' ';
|
||||
tok = space + 1;
|
||||
} else
|
||||
tok = NULL;
|
||||
if (!nni || !nno->saw[nni->num] || best <= nno->saw[nni->num])
|
||||
continue;
|
||||
ret = nni;
|
||||
best = nno->saw[nni->num];
|
||||
if (best == 1 || am_server) /* The server side stops at the first acceptable client choice */
|
||||
break;
|
||||
}
|
||||
if (ret) {
|
||||
free(nno->saw);
|
||||
nno->saw = NULL;
|
||||
nno->negotiated_nni = ret->main_nni ? ret->main_nni : ret;
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* This routine is always called with a tmpbuf of MAX_NSTR_STRLEN length, but the
|
||||
* buffer may be pre-populated with a "len" length string to use OR a len of -1
|
||||
* to tell us to read a string from the fd. */
|
||||
static void recv_negotiate_str(int f_in, struct name_num_obj *nno, char *tmpbuf, int len)
|
||||
{
|
||||
if (len < 0)
|
||||
len = read_vstring(f_in, tmpbuf, MAX_NSTR_STRLEN);
|
||||
|
||||
if (DEBUG_GTE(NSTR, am_server ? 3 : 2)) {
|
||||
if (am_server)
|
||||
rprintf(FINFO, "Client %s list (on server): %s\n", nno->type, tmpbuf);
|
||||
else
|
||||
rprintf(FINFO, "Server %s list (on client): %s\n", nno->type, tmpbuf);
|
||||
}
|
||||
|
||||
if (len > 0 && parse_negotiate_str(nno, tmpbuf))
|
||||
return;
|
||||
|
||||
if (!am_server || !do_negotiated_strings) {
|
||||
char *cp = tmpbuf;
|
||||
int j;
|
||||
rprintf(FERROR, "Failed to negotiate a %s choice.\n", nno->type);
|
||||
rprintf(FERROR, "%s list: %s\n", am_server ? "Client" : "Server", tmpbuf);
|
||||
/* Recreate our original list from the saw values. This can't overflow our huge
|
||||
* buffer because we don't have enough valid entries to get anywhere close. */
|
||||
for (j = 1, *cp = '\0'; j <= nno->saw_len; j++) {
|
||||
struct name_num_item *nni;
|
||||
for (nni = nno->list; nni->name; nni++) {
|
||||
if (nno->saw[nni->num] == j) {
|
||||
*cp++ = ' ';
|
||||
cp += strlcpy(cp, nni->name, MAX_NSTR_STRLEN - (cp - tmpbuf));
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!*tmpbuf)
|
||||
strlcpy(cp, " INVALID", MAX_NSTR_STRLEN);
|
||||
rprintf(FERROR, "%s list:%s\n", am_server ? "Server" : "Client", tmpbuf);
|
||||
}
|
||||
|
||||
exit_cleanup(RERR_UNSUPPORTED);
|
||||
}
|
||||
|
||||
static const char *getenv_nstr(int ntype)
|
||||
{
|
||||
const char *env_str = getenv(ntype == NSTR_COMPRESS ? "RSYNC_COMPRESS_LIST" : "RSYNC_CHECKSUM_LIST");
|
||||
|
||||
/* When writing a batch file, we always negotiate an old-style choice. */
|
||||
if (write_batch)
|
||||
env_str = ntype == NSTR_COMPRESS ? "zlib" : protocol_version >= 30 ? "md5" : "md4";
|
||||
|
||||
if (am_server && env_str) {
|
||||
char *cp = strchr(env_str, '&');
|
||||
if (cp)
|
||||
env_str = cp + 1;
|
||||
}
|
||||
|
||||
return env_str;
|
||||
}
|
||||
|
||||
void validate_choice_vs_env(int ntype, int num1, int num2)
|
||||
{
|
||||
struct name_num_obj *nno = ntype == NSTR_COMPRESS ? &valid_compressions : &valid_checksums;
|
||||
const char *list_str = getenv_nstr(ntype);
|
||||
char tmpbuf[MAX_NSTR_STRLEN];
|
||||
|
||||
if (!list_str)
|
||||
return;
|
||||
|
||||
while (isSpace(list_str)) list_str++;
|
||||
|
||||
if (!*list_str)
|
||||
return;
|
||||
|
||||
init_nno_saw(nno, 0);
|
||||
parse_nni_str(nno, list_str, tmpbuf, MAX_NSTR_STRLEN);
|
||||
|
||||
if (ntype == NSTR_CHECKSUM) /* If "md4" is in the env list, all the old MD4 choices are OK too. */
|
||||
nno->saw[CSUM_MD4_ARCHAIC] = nno->saw[CSUM_MD4_BUSTED] = nno->saw[CSUM_MD4_OLD] = nno->saw[CSUM_MD4];
|
||||
|
||||
if (!nno->saw[num1] || (num2 >= 0 && !nno->saw[num2])) {
|
||||
rprintf(FERROR, "Your --%s-choice value (%s) was refused by the server.\n",
|
||||
ntype == NSTR_COMPRESS ? "compress" : "checksum",
|
||||
ntype == NSTR_COMPRESS ? compress_choice : checksum_choice);
|
||||
exit_cleanup(RERR_UNSUPPORTED);
|
||||
}
|
||||
|
||||
free(nno->saw);
|
||||
nno->saw = NULL;
|
||||
}
|
||||
|
||||
/* The saw buffer is initialized and used to store ordinal values from 1 to N
|
||||
* for the order of the args in the array. If dup_markup == '\0', duplicates
|
||||
* are removed otherwise the char is prefixed to the duplicate term and, if it
|
||||
* is an opening paren/bracket/brace, the matching closing char is suffixed.
|
||||
* "none" is removed on the client side unless dup_markup != '\0'. */
|
||||
int get_default_nno_list(struct name_num_obj *nno, char *to_buf, int to_buf_len, char dup_markup)
|
||||
{
|
||||
struct name_num_item *nni;
|
||||
int len = 0, cnt = 0;
|
||||
char delim = '\0', post_delim;
|
||||
|
||||
switch (dup_markup) {
|
||||
case '(': post_delim = ')'; break;
|
||||
case '[': post_delim = ']'; break;
|
||||
case '{': post_delim = '}'; break;
|
||||
default: post_delim = '\0'; break;
|
||||
}
|
||||
|
||||
init_nno_saw(nno, 0);
|
||||
|
||||
for (nni = nno->list, len = 0; nni->name; nni++) {
|
||||
if (nni->num == CSUM_gone)
|
||||
continue;
|
||||
if (nni->main_nni) {
|
||||
if (!dup_markup || nni->main_nni->num == CSUM_gone)
|
||||
continue;
|
||||
delim = dup_markup;
|
||||
}
|
||||
if (nni->num == 0 && !am_server && !dup_markup)
|
||||
continue;
|
||||
if (len)
|
||||
to_buf[len++]= ' ';
|
||||
if (delim) {
|
||||
to_buf[len++]= delim;
|
||||
delim = post_delim;
|
||||
}
|
||||
len += strlcpy(to_buf+len, nni->name, to_buf_len - len);
|
||||
if (len >= to_buf_len - 3)
|
||||
exit_cleanup(RERR_UNSUPPORTED); /* IMPOSSIBLE... */
|
||||
if (delim) {
|
||||
to_buf[len++]= delim;
|
||||
delim = '\0';
|
||||
}
|
||||
nno->saw[nni->num] = ++cnt;
|
||||
}
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
static void send_negotiate_str(int f_out, struct name_num_obj *nno, int ntype)
|
||||
{
|
||||
char tmpbuf[MAX_NSTR_STRLEN];
|
||||
const char *list_str = getenv_nstr(ntype);
|
||||
int len;
|
||||
|
||||
if (list_str && *list_str) {
|
||||
init_nno_saw(nno, 0);
|
||||
len = parse_nni_str(nno, list_str, tmpbuf, MAX_NSTR_STRLEN);
|
||||
list_str = tmpbuf;
|
||||
} else
|
||||
list_str = NULL;
|
||||
|
||||
if (!list_str || !*list_str)
|
||||
len = get_default_nno_list(nno, tmpbuf, MAX_NSTR_STRLEN, '\0');
|
||||
|
||||
if (DEBUG_GTE(NSTR, am_server ? 3 : 2)) {
|
||||
if (am_server)
|
||||
rprintf(FINFO, "Server %s list (on server): %s\n", nno->type, tmpbuf);
|
||||
else
|
||||
rprintf(FINFO, "Client %s list (on client): %s\n", nno->type, tmpbuf);
|
||||
}
|
||||
|
||||
/* Each side sends their list of valid names to the other side and then both sides
|
||||
* pick the first name in the client's list that is also in the server's list. */
|
||||
if (do_negotiated_strings)
|
||||
write_vstring(f_out, tmpbuf, len);
|
||||
}
|
||||
|
||||
static void negotiate_the_strings(int f_in, int f_out)
|
||||
{
|
||||
/* We send all the negotiation strings before we start to read them to help avoid a slow startup. */
|
||||
|
||||
init_checksum_choices();
|
||||
|
||||
if (!checksum_choice)
|
||||
send_negotiate_str(f_out, &valid_checksums, NSTR_CHECKSUM);
|
||||
|
||||
if (do_compression && !compress_choice)
|
||||
send_negotiate_str(f_out, &valid_compressions, NSTR_COMPRESS);
|
||||
|
||||
if (valid_checksums.saw) {
|
||||
char tmpbuf[MAX_NSTR_STRLEN];
|
||||
int len;
|
||||
if (do_negotiated_strings)
|
||||
len = -1;
|
||||
else
|
||||
len = strlcpy(tmpbuf, protocol_version >= 30 ? "md5" : "md4", MAX_NSTR_STRLEN);
|
||||
recv_negotiate_str(f_in, &valid_checksums, tmpbuf, len);
|
||||
}
|
||||
|
||||
if (valid_compressions.saw) {
|
||||
char tmpbuf[MAX_NSTR_STRLEN];
|
||||
int len;
|
||||
if (do_negotiated_strings)
|
||||
len = -1;
|
||||
else
|
||||
len = strlcpy(tmpbuf, "zlib", MAX_NSTR_STRLEN);
|
||||
recv_negotiate_str(f_in, &valid_compressions, tmpbuf, len);
|
||||
}
|
||||
|
||||
/* If the other side is too old to negotiate, the above steps just made sure that
|
||||
* the env didn't disallow the old algorithm. Mark things as non-negotiated. */
|
||||
if (!do_negotiated_strings)
|
||||
valid_checksums.negotiated_nni = valid_compressions.negotiated_nni = NULL;
|
||||
}
|
||||
|
||||
void setup_protocol(int f_out,int f_in)
|
||||
{
|
||||
assert(file_extra_cnt == 0);
|
||||
assert(EXTRA64_CNT == 2 || EXTRA64_CNT == 1);
|
||||
|
||||
/* All int64 values must be set first so that they are guaranteed to be
|
||||
* aligned for direct int64-pointer memory access. */
|
||||
if (preserve_atimes)
|
||||
atimes_ndx = (file_extra_cnt += EXTRA64_CNT);
|
||||
if (preserve_crtimes)
|
||||
crtimes_ndx = (file_extra_cnt += EXTRA64_CNT);
|
||||
if (am_sender) /* This is most likely in the file_extras64 union as well. */
|
||||
pathname_ndx = (file_extra_cnt += PTR_EXTRA_CNT);
|
||||
if (am_sender)
|
||||
file_extra_cnt += PTR_EXTRA_CNT;
|
||||
else
|
||||
depth_ndx = ++file_extra_cnt;
|
||||
file_extra_cnt++;
|
||||
if (preserve_uid)
|
||||
uid_ndx = ++file_extra_cnt;
|
||||
if (preserve_gid)
|
||||
@@ -611,14 +160,14 @@ void setup_protocol(int f_out,int f_in)
|
||||
exit_cleanup(RERR_PROTOCOL);
|
||||
}
|
||||
|
||||
if (DEBUG_GTE(PROTO, 1)) {
|
||||
if (verbose > 3) {
|
||||
rprintf(FINFO, "(%s) Protocol versions: remote=%d, negotiated=%d\n",
|
||||
am_server? "Server" : "Client", remote_protocol, protocol_version);
|
||||
}
|
||||
if (remote_protocol < MIN_PROTOCOL_VERSION
|
||||
|| remote_protocol > MAX_PROTOCOL_VERSION) {
|
||||
rprintf(FERROR,"protocol version mismatch -- is your shell clean?\n");
|
||||
rprintf(FERROR,"(see the rsync manpage for an explanation)\n");
|
||||
rprintf(FERROR,"(see the rsync man page for an explanation)\n");
|
||||
exit_cleanup(RERR_PROTOCOL);
|
||||
}
|
||||
if (remote_protocol < OLD_PROTOCOL_VERSION) {
|
||||
@@ -638,32 +187,21 @@ void setup_protocol(int f_out,int f_in)
|
||||
if (read_batch)
|
||||
check_batch_flags();
|
||||
|
||||
if (!saw_stderr_opt && protocol_version <= 28 && am_server)
|
||||
msgs2stderr = 0; /* The client side may not have stderr setup for us. */
|
||||
|
||||
#ifndef SUPPORT_PREALLOCATION
|
||||
if (preallocate_files && !am_sender) {
|
||||
rprintf(FERROR, "preallocation is not supported on this %s\n",
|
||||
am_server ? "Server" : "Client");
|
||||
exit_cleanup(RERR_SYNTAX);
|
||||
}
|
||||
#endif
|
||||
|
||||
if (protocol_version < 30) {
|
||||
if (append_mode == 1)
|
||||
append_mode = 2;
|
||||
if (preserve_acls && !local_server) {
|
||||
rprintf(FERROR,
|
||||
"--acls requires protocol 30 or higher"
|
||||
" (negotiated %d).\n",
|
||||
protocol_version);
|
||||
"--acls requires protocol 30 or higher"
|
||||
" (negotiated %d).\n",
|
||||
protocol_version);
|
||||
exit_cleanup(RERR_PROTOCOL);
|
||||
}
|
||||
if (preserve_xattrs && !local_server) {
|
||||
rprintf(FERROR,
|
||||
"--xattrs requires protocol 30 or higher"
|
||||
" (negotiated %d).\n",
|
||||
protocol_version);
|
||||
"--xattrs requires protocol 30 or higher"
|
||||
" (negotiated %d).\n",
|
||||
protocol_version);
|
||||
exit_cleanup(RERR_PROTOCOL);
|
||||
}
|
||||
}
|
||||
@@ -678,85 +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 (strchr(client_info, 'f') != NULL)
|
||||
compat_flags |= CF_SAFE_FLIST;
|
||||
if (strchr(client_info, 'x') != NULL)
|
||||
compat_flags |= CF_AVOID_XATTR_OPTIM;
|
||||
if (strchr(client_info, 'C') != NULL)
|
||||
compat_flags |= CF_CHKSUM_SEED_FIX;
|
||||
if (strchr(client_info, 'I') != NULL)
|
||||
compat_flags |= CF_INPLACE_PARTIAL_DIR;
|
||||
if (strchr(client_info, 'u') != NULL)
|
||||
compat_flags |= CF_ID0_NAMES;
|
||||
if (strchr(client_info, 'v') != NULL) {
|
||||
do_negotiated_strings = 1;
|
||||
compat_flags |= CF_VARINT_FLIST_FLAGS;
|
||||
}
|
||||
if (strchr(client_info, 'V') != NULL) { /* Support a pre-release 'V' that got superseded */
|
||||
if (!write_batch)
|
||||
compat_flags |= CF_VARINT_FLIST_FLAGS;
|
||||
write_byte(f_out, compat_flags);
|
||||
} else
|
||||
write_varint(f_out, compat_flags);
|
||||
} else { /* read_varint() is compatible with the older write_byte() when the 0x80 bit isn't on. */
|
||||
compat_flags = read_varint(f_in);
|
||||
if (compat_flags & CF_VARINT_FLIST_FLAGS)
|
||||
do_negotiated_strings = 1;
|
||||
}
|
||||
write_byte(f_out, compat_flags);
|
||||
} else
|
||||
compat_flags = read_byte(f_in);
|
||||
/* The inc_recurse var MUST be set to 0 or 1. */
|
||||
inc_recurse = compat_flags & CF_INC_RECURSE ? 1 : 0;
|
||||
want_xattr_optim = protocol_version >= 31 && !(compat_flags & CF_AVOID_XATTR_OPTIM);
|
||||
proper_seed_order = compat_flags & CF_CHKSUM_SEED_FIX ? 1 : 0;
|
||||
xfer_flags_as_varint = compat_flags & CF_VARINT_FLIST_FLAGS ? 1 : 0;
|
||||
xmit_id0_names = compat_flags & CF_ID0_NAMES ? 1 : 0;
|
||||
if (!xfer_flags_as_varint && preserve_crtimes) {
|
||||
fprintf(stderr, "Both rsync versions must be at least 3.2.0 for --crtimes.\n");
|
||||
exit_cleanup(RERR_PROTOCOL);
|
||||
}
|
||||
if (am_sender) {
|
||||
receiver_symlink_times = am_server
|
||||
? strchr(client_info, 'L') != NULL
|
||||
: !!(compat_flags & CF_SYMLINK_TIMES);
|
||||
}
|
||||
#ifdef CAN_SET_SYMLINK_TIMES
|
||||
#if defined HAVE_LUTIMES && defined HAVE_UTIMES
|
||||
else
|
||||
receiver_symlink_times = 1;
|
||||
#endif
|
||||
@@ -768,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);
|
||||
}
|
||||
|
||||
|
||||
@@ -805,87 +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 file_sum_nni & xfer_sum_nni */
|
||||
parse_compress_choice(1); /* Sets do_compression */
|
||||
|
||||
/* TODO in the future allow this algorithm to be chosen somehow, but it can't get too
|
||||
* long or the size starts to cause a problem in the xattr abbrev/non-abbrev code. */
|
||||
xattr_sum_nni = parse_csum_name(NULL, 0);
|
||||
xattr_sum_len = csum_len_for_type(xattr_sum_nni->num, 0);
|
||||
|
||||
if (write_batch && !am_server)
|
||||
write_batch_shell_file();
|
||||
|
||||
init_flist();
|
||||
}
|
||||
|
||||
void output_daemon_greeting(int f_out, int am_client)
|
||||
{
|
||||
char tmpbuf[MAX_NSTR_STRLEN];
|
||||
int our_sub = get_subprotocol_version();
|
||||
|
||||
init_checksum_choices();
|
||||
|
||||
get_default_nno_list(&valid_auth_checksums, tmpbuf, MAX_NSTR_STRLEN, '\0');
|
||||
|
||||
io_printf(f_out, "@RSYNCD: %d.%d %s\n", protocol_version, our_sub, tmpbuf);
|
||||
|
||||
if (am_client && DEBUG_GTE(NSTR, 2))
|
||||
rprintf(FINFO, "Client %s list (on client): %s\n", valid_auth_checksums.type, tmpbuf);
|
||||
}
|
||||
|
||||
void negotiate_daemon_auth(int f_out, int am_client)
|
||||
{
|
||||
char tmpbuf[MAX_NSTR_STRLEN];
|
||||
int save_am_server = am_server;
|
||||
int md4_is_old = 0;
|
||||
|
||||
if (!am_client)
|
||||
am_server = 1;
|
||||
|
||||
if (daemon_auth_choices)
|
||||
strlcpy(tmpbuf, daemon_auth_choices, MAX_NSTR_STRLEN);
|
||||
else {
|
||||
strlcpy(tmpbuf, protocol_version >= 30 ? "md5" : "md4", MAX_NSTR_STRLEN);
|
||||
md4_is_old = 1;
|
||||
}
|
||||
|
||||
if (am_client) {
|
||||
recv_negotiate_str(-1, &valid_auth_checksums, tmpbuf, strlen(tmpbuf));
|
||||
if (DEBUG_GTE(NSTR, 1)) {
|
||||
rprintf(FINFO, "Client negotiated %s: %s\n", valid_auth_checksums.type,
|
||||
valid_auth_checksums.negotiated_nni->name);
|
||||
}
|
||||
} else {
|
||||
if (!parse_negotiate_str(&valid_auth_checksums, tmpbuf)) {
|
||||
get_default_nno_list(&valid_auth_checksums, tmpbuf, MAX_NSTR_STRLEN, '\0');
|
||||
io_printf(f_out, "@ERROR: your client does not support one of our daemon-auth checksums: %s\n",
|
||||
tmpbuf);
|
||||
exit_cleanup(RERR_UNSUPPORTED);
|
||||
}
|
||||
}
|
||||
am_server = save_am_server;
|
||||
if (md4_is_old && valid_auth_checksums.negotiated_nni->num == CSUM_MD4) {
|
||||
valid_auth_checksums.negotiated_nni->num = CSUM_MD4_OLD;
|
||||
valid_auth_checksums.negotiated_nni->flags = 0;
|
||||
}
|
||||
}
|
||||
|
||||
int get_subprotocol_version()
|
||||
{
|
||||
#if SUBPROTOCOL_VERSION != 0
|
||||
return protocol_version < PROTOCOL_VERSION ? 0 : SUBPROTOCOL_VERSION;
|
||||
#else
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
1950
config.guess
vendored
Normal file → Executable file
1950
config.guess
vendored
Normal file → Executable file
File diff suppressed because it is too large
Load Diff
2825
config.sub
vendored
Normal file → Executable file
2825
config.sub
vendored
Normal file → Executable file
File diff suppressed because it is too large
Load Diff
26
configure
vendored
26
configure
vendored
@@ -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" "${@}"
|
||||
|
||||
1445
configure.ac
1445
configure.ac
File diff suppressed because it is too large
Load Diff
983
configure.in
Normal file
983
configure.in
Normal file
@@ -0,0 +1,983 @@
|
||||
dnl Process this file with autoconf to produce a configure script.
|
||||
|
||||
AC_INIT()
|
||||
AC_CONFIG_SRCDIR([byteorder.h])
|
||||
AC_CONFIG_HEADER(config.h)
|
||||
AC_PREREQ(2.59)
|
||||
|
||||
RSYNC_VERSION=3.0.4
|
||||
AC_SUBST(RSYNC_VERSION)
|
||||
AC_MSG_NOTICE([Configuring rsync $RSYNC_VERSION])
|
||||
|
||||
AC_DEFINE_UNQUOTED(RSYNC_VERSION, ["$RSYNC_VERSION"], [rsync release version])
|
||||
|
||||
LDFLAGS=${LDFLAGS-""}
|
||||
|
||||
AC_CANONICAL_TARGET([])
|
||||
|
||||
dnl Checks for programs.
|
||||
AC_PROG_CC
|
||||
AC_PROG_CPP
|
||||
AC_PROG_EGREP
|
||||
AC_PROG_INSTALL
|
||||
AC_PROG_CC_STDC
|
||||
AC_SUBST(SHELL)
|
||||
|
||||
AC_DEFINE([_GNU_SOURCE], 1,
|
||||
[Define _GNU_SOURCE so that we get all necessary prototypes])
|
||||
|
||||
if test x"$ac_cv_prog_cc_stdc" = x"no"; then
|
||||
AC_MSG_WARN([rsync requires an ANSI C compiler and you don't seem to have one])
|
||||
fi
|
||||
|
||||
# We must decide this before testing the compiler.
|
||||
|
||||
# Please allow this to default to yes, so that your users have more
|
||||
# chance of getting a useful stack trace if problems occur.
|
||||
|
||||
AC_MSG_CHECKING([whether to include debugging symbols])
|
||||
AC_ARG_ENABLE(debug,
|
||||
AC_HELP_STRING([--disable-debug],
|
||||
[disable debugging symbols and features]))
|
||||
|
||||
if test x"$enable_debug" = x"no"; then
|
||||
AC_MSG_RESULT(no)
|
||||
CFLAGS=${CFLAGS-"-O"}
|
||||
else
|
||||
AC_MSG_RESULT([yes])
|
||||
# leave CFLAGS alone; AC_PROG_CC will try to include -g if it can
|
||||
dnl AC_DEFINE(DEBUG, 1, [Define to turn on debugging code that may slow normal operation])
|
||||
dnl CFLAGS=${CFLAGS-"-g"}
|
||||
fi
|
||||
|
||||
|
||||
AC_ARG_ENABLE(profile,
|
||||
AC_HELP_STRING([--enable-profile],
|
||||
[turn on CPU profiling]))
|
||||
if test x"$enable_profile" = x"yes"; then
|
||||
CFLAGS="$CFLAGS -pg"
|
||||
fi
|
||||
|
||||
|
||||
# Specifically, this turns on panic_action handling.
|
||||
AC_ARG_ENABLE(maintainer-mode,
|
||||
AC_HELP_STRING([--enable-maintainer-mode],
|
||||
[turn on extra debug features]))
|
||||
if test x"$enable_maintainer_mode" = x"yes"; then
|
||||
CFLAGS="$CFLAGS -DMAINTAINER_MODE"
|
||||
fi
|
||||
|
||||
|
||||
# This is needed for our included version of popt. Kind of silly, but
|
||||
# I don't want our version too far out of sync.
|
||||
CFLAGS="$CFLAGS -DHAVE_CONFIG_H"
|
||||
|
||||
# If GCC, turn on warnings.
|
||||
if test x"$GCC" = x"yes"; then
|
||||
CFLAGS="$CFLAGS -Wall -W"
|
||||
fi
|
||||
|
||||
AC_ARG_WITH(included-popt,
|
||||
AC_HELP_STRING([--with-included-popt], [use bundled popt library, not from system]))
|
||||
|
||||
AC_ARG_WITH(rsync-path,
|
||||
AC_HELP_STRING([--with-rsync-path=PATH], [set default --rsync-path to PATH (default: rsync)]),
|
||||
[ RSYNC_PATH="$with_rsync_path" ],
|
||||
[ RSYNC_PATH="rsync" ])
|
||||
|
||||
AC_DEFINE_UNQUOTED(RSYNC_PATH, "$RSYNC_PATH", [location of rsync on remote machine])
|
||||
|
||||
AC_ARG_WITH(rsyncd-conf,
|
||||
AC_HELP_STRING([--with-rsyncd-conf=PATH], [set configuration file for rsync server to PATH (default: /etc/rsyncd.conf)]),
|
||||
[ if test ! -z "$with_rsyncd_conf" ; then
|
||||
case $with_rsyncd_conf in
|
||||
yes|no)
|
||||
RSYNCD_SYSCONF="/etc/rsyncd.conf"
|
||||
;;
|
||||
/*)
|
||||
RSYNCD_SYSCONF="$with_rsyncd_conf"
|
||||
;;
|
||||
*)
|
||||
AC_MSG_ERROR(You must specify an absolute path to --with-rsyncd-conf=PATH)
|
||||
;;
|
||||
esac
|
||||
else
|
||||
RSYNCD_SYSCONF="/etc/rsyncd.conf"
|
||||
fi ],
|
||||
[ RSYNCD_SYSCONF="/etc/rsyncd.conf" ])
|
||||
|
||||
AC_DEFINE_UNQUOTED(RSYNCD_SYSCONF, "$RSYNCD_SYSCONF", [location of configuration file for rsync server])
|
||||
|
||||
AC_ARG_WITH(rsh,
|
||||
AC_HELP_STRING([--with-rsh=CMD], [set remote shell command to CMD (default: ssh)]))
|
||||
|
||||
AC_CHECK_PROG(HAVE_REMSH, remsh, 1, 0)
|
||||
if test x$HAVE_REMSH = x1; then
|
||||
AC_DEFINE(HAVE_REMSH, 1, [Define to 1 if remote shell is remsh, not rsh])
|
||||
fi
|
||||
|
||||
if test x"$with_rsh" != x; then
|
||||
RSYNC_RSH="$with_rsh"
|
||||
else
|
||||
RSYNC_RSH="ssh"
|
||||
fi
|
||||
AC_DEFINE_UNQUOTED(RSYNC_RSH, "$RSYNC_RSH", [default -e command])
|
||||
|
||||
AC_CHECK_PROG(HAVE_YODL2MAN, yodl2man, 1, 0)
|
||||
if test x$HAVE_YODL2MAN = x1; then
|
||||
MAKE_MAN=man
|
||||
fi
|
||||
|
||||
AC_ARG_WITH(nobody-group,
|
||||
AC_HELP_STRING([--with-nobody-group=GROUP],
|
||||
[set the default unprivileged group (default nobody or nogroup)]),
|
||||
[ NOBODY_GROUP="$with_nobody_group" ])
|
||||
|
||||
if test x"$with_nobody_group" = x; then
|
||||
AC_MSG_CHECKING([the group for user "nobody"])
|
||||
if grep '^nobody:' /etc/group >/dev/null 2>&1; then
|
||||
NOBODY_GROUP=nobody
|
||||
elif grep '^nogroup:' /etc/group >/dev/null 2>&1; then
|
||||
NOBODY_GROUP=nogroup
|
||||
else
|
||||
NOBODY_GROUP=nobody # test for others?
|
||||
fi
|
||||
AC_MSG_RESULT($NOBODY_GROUP)
|
||||
fi
|
||||
|
||||
AC_DEFINE_UNQUOTED(NOBODY_USER, "nobody", [unprivileged user--e.g. nobody])
|
||||
AC_DEFINE_UNQUOTED(NOBODY_GROUP, "$NOBODY_GROUP", [unprivileged group for unprivileged user])
|
||||
|
||||
# arrgh. libc in some old debian version screwed up the largefile
|
||||
# stuff, getting byte range locking wrong
|
||||
AC_CACHE_CHECK([for broken largefile support],rsync_cv_HAVE_BROKEN_LARGEFILE,[
|
||||
AC_TRY_RUN([
|
||||
#define _FILE_OFFSET_BITS 64
|
||||
#include <stdio.h>
|
||||
#include <fcntl.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/wait.h>
|
||||
|
||||
int main(void)
|
||||
{
|
||||
struct flock lock;
|
||||
int status;
|
||||
char tpl[32] = "/tmp/locktest.XXXXXX";
|
||||
int fd = mkstemp(tpl);
|
||||
if (fd < 0) {
|
||||
strcpy(tpl, "conftest.dat");
|
||||
fd = open(tpl, O_CREAT|O_RDWR, 0600);
|
||||
}
|
||||
|
||||
lock.l_type = F_WRLCK;
|
||||
lock.l_whence = SEEK_SET;
|
||||
lock.l_start = 0;
|
||||
lock.l_len = 1;
|
||||
lock.l_pid = 0;
|
||||
fcntl(fd,F_SETLK,&lock);
|
||||
if (fork() == 0) {
|
||||
lock.l_start = 1;
|
||||
_exit(fcntl(fd,F_SETLK,&lock) == 0);
|
||||
}
|
||||
wait(&status);
|
||||
unlink(tpl);
|
||||
exit(WEXITSTATUS(status));
|
||||
}
|
||||
],
|
||||
rsync_cv_HAVE_BROKEN_LARGEFILE=yes,rsync_cv_HAVE_BROKEN_LARGEFILE=no,rsync_cv_HAVE_BROKEN_LARGEFILE=cross)])
|
||||
if test x"$rsync_cv_HAVE_BROKEN_LARGEFILE" != x"yes"; then
|
||||
AC_SYS_LARGEFILE
|
||||
fi
|
||||
|
||||
ipv6type=unknown
|
||||
ipv6lib=none
|
||||
ipv6trylibc=yes
|
||||
|
||||
AC_ARG_ENABLE(ipv6,
|
||||
AC_HELP_STRING([--disable-ipv6],
|
||||
[don't even try to use IPv6]))
|
||||
if test x"$enable_ipv6" != x"no"; then
|
||||
AC_MSG_CHECKING([ipv6 stack type])
|
||||
for i in inria kame linux-glibc linux-inet6 toshiba v6d zeta; do
|
||||
case $i in
|
||||
inria)
|
||||
# http://www.kame.net/
|
||||
AC_EGREP_CPP(yes, [
|
||||
#include <netinet/in.h>
|
||||
#ifdef IPV6_INRIA_VERSION
|
||||
yes
|
||||
#endif],
|
||||
[ipv6type=$i;
|
||||
AC_DEFINE(INET6, 1, [true if you have IPv6])
|
||||
])
|
||||
;;
|
||||
kame)
|
||||
# http://www.kame.net/
|
||||
AC_EGREP_CPP(yes, [
|
||||
#include <netinet/in.h>
|
||||
#ifdef __KAME__
|
||||
yes
|
||||
#endif],
|
||||
[ipv6type=$i;
|
||||
AC_DEFINE(INET6, 1, [true if you have IPv6])])
|
||||
;;
|
||||
linux-glibc)
|
||||
# http://www.v6.linux.or.jp/
|
||||
AC_EGREP_CPP(yes, [
|
||||
#include <features.h>
|
||||
#if defined(__GLIBC__) && __GLIBC__ >= 2 && __GLIBC_MINOR__ >= 1
|
||||
yes
|
||||
#endif],
|
||||
[ipv6type=$i;
|
||||
AC_DEFINE(INET6, 1, [true if you have IPv6])])
|
||||
;;
|
||||
linux-inet6)
|
||||
# http://www.v6.linux.or.jp/
|
||||
if test -d /usr/inet6 -o -f /usr/inet6/lib/libinet6.a; then
|
||||
ipv6type=$i
|
||||
ipv6lib=inet6
|
||||
ipv6libdir=/usr/inet6/lib
|
||||
ipv6trylibc=yes;
|
||||
AC_DEFINE(INET6, 1, [true if you have IPv6])
|
||||
CFLAGS="-I/usr/inet6/include $CFLAGS"
|
||||
fi
|
||||
;;
|
||||
toshiba)
|
||||
AC_EGREP_CPP(yes, [
|
||||
#include <sys/param.h>
|
||||
#ifdef _TOSHIBA_INET6
|
||||
yes
|
||||
#endif],
|
||||
[ipv6type=$i;
|
||||
ipv6lib=inet6;
|
||||
ipv6libdir=/usr/local/v6/lib;
|
||||
AC_DEFINE(INET6, 1, [true if you have IPv6])])
|
||||
;;
|
||||
v6d)
|
||||
AC_EGREP_CPP(yes, [
|
||||
#include </usr/local/v6/include/sys/v6config.h>
|
||||
#ifdef __V6D__
|
||||
yes
|
||||
#endif],
|
||||
[ipv6type=$i;
|
||||
ipv6lib=v6;
|
||||
ipv6libdir=/usr/local/v6/lib;
|
||||
AC_DEFINE(INET6, 1, [true if you have IPv6])])
|
||||
;;
|
||||
zeta)
|
||||
AC_EGREP_CPP(yes, [
|
||||
#include <sys/param.h>
|
||||
#ifdef _ZETA_MINAMI_INET6
|
||||
yes
|
||||
#endif],
|
||||
[ipv6type=$i;
|
||||
ipv6lib=inet6;
|
||||
ipv6libdir=/usr/local/v6/lib;
|
||||
AC_DEFINE(INET6, 1, [true if you have IPv6])])
|
||||
;;
|
||||
esac
|
||||
if test "$ipv6type" != "unknown"; then
|
||||
break
|
||||
fi
|
||||
done
|
||||
AC_MSG_RESULT($ipv6type)
|
||||
|
||||
AC_SEARCH_LIBS(getaddrinfo, inet6)
|
||||
fi
|
||||
|
||||
dnl Do you want to disable use of locale functions
|
||||
AC_ARG_ENABLE([locale],
|
||||
AC_HELP_STRING([--disable-locale],
|
||||
[disable locale features]))
|
||||
AH_TEMPLATE([CONFIG_LOCALE],
|
||||
[Undefine if you don't want locale features. By default this is defined.])
|
||||
if test x"$enable_locale" != x"no"; then
|
||||
AC_DEFINE(CONFIG_LOCALE)
|
||||
fi
|
||||
|
||||
AC_MSG_CHECKING([whether to call shutdown on all sockets])
|
||||
case $host_os in
|
||||
*cygwin* ) AC_MSG_RESULT(yes)
|
||||
AC_DEFINE(SHUTDOWN_ALL_SOCKETS, 1,
|
||||
[Define to 1 if sockets need to be shutdown])
|
||||
;;
|
||||
* ) AC_MSG_RESULT(no);;
|
||||
esac
|
||||
|
||||
AC_C_BIGENDIAN
|
||||
AC_HEADER_DIRENT
|
||||
AC_HEADER_TIME
|
||||
AC_HEADER_SYS_WAIT
|
||||
AC_CHECK_HEADERS(sys/fcntl.h sys/select.h fcntl.h sys/time.h sys/unistd.h \
|
||||
unistd.h utime.h grp.h compat.h sys/param.h ctype.h sys/wait.h \
|
||||
sys/ioctl.h sys/filio.h string.h stdlib.h sys/socket.h sys/mode.h \
|
||||
sys/un.h sys/attr.h mcheck.h arpa/inet.h arpa/nameser.h locale.h \
|
||||
netdb.h malloc.h float.h limits.h iconv.h libcharset.h langinfo.h \
|
||||
sys/acl.h acl/libacl.h attr/xattr.h sys/xattr.h sys/extattr.h \
|
||||
popt.h popt/popt.h)
|
||||
AC_HEADER_MAJOR
|
||||
|
||||
AC_CACHE_CHECK([if makedev takes 3 args],rsync_cv_MAKEDEV_TAKES_3_ARGS,[
|
||||
AC_TRY_RUN([
|
||||
#include <sys/types.h>
|
||||
#ifdef MAJOR_IN_MKDEV
|
||||
#include <sys/mkdev.h>
|
||||
# if !defined makedev && (defined mkdev || defined _WIN32 || defined __WIN32__)
|
||||
# define makedev mkdev
|
||||
# endif
|
||||
#elif defined MAJOR_IN_SYSMACROS
|
||||
#include <sys/sysmacros.h>
|
||||
#endif
|
||||
|
||||
int main(void)
|
||||
{
|
||||
dev_t dev = makedev(0, 5, 7);
|
||||
if (major(dev) != 5 || minor(dev) != 7)
|
||||
exit(1);
|
||||
return 0;
|
||||
}
|
||||
],
|
||||
rsync_cv_MAKEDEV_TAKES_3_ARGS=yes,rsync_cv_MAKEDEV_TAKES_3_ARGS=no,rsync_cv_MAKEDEV_TAKES_3_ARGS=no)])
|
||||
if test x"$rsync_cv_MAKEDEV_TAKES_3_ARGS" = x"yes"; then
|
||||
AC_DEFINE(MAKEDEV_TAKES_3_ARGS, 1, [Define to 1 if makedev() takes 3 args])
|
||||
fi
|
||||
|
||||
AC_CHECK_SIZEOF(int)
|
||||
AC_CHECK_SIZEOF(long)
|
||||
AC_CHECK_SIZEOF(long long)
|
||||
AC_CHECK_SIZEOF(short)
|
||||
AC_CHECK_SIZEOF(int16_t)
|
||||
AC_CHECK_SIZEOF(uint16_t)
|
||||
AC_CHECK_SIZEOF(int32_t)
|
||||
AC_CHECK_SIZEOF(uint32_t)
|
||||
AC_CHECK_SIZEOF(int64_t)
|
||||
AC_CHECK_SIZEOF(off_t)
|
||||
AC_CHECK_SIZEOF(off64_t)
|
||||
AC_CHECK_SIZEOF(time_t)
|
||||
|
||||
AC_C_INLINE
|
||||
AC_C_LONG_DOUBLE
|
||||
|
||||
AC_TYPE_SIGNAL
|
||||
AC_TYPE_UID_T
|
||||
AC_CHECK_TYPES([mode_t,off_t,size_t,pid_t,id_t])
|
||||
AC_TYPE_GETGROUPS
|
||||
AC_CHECK_MEMBERS([struct stat.st_rdev])
|
||||
|
||||
TYPE_SOCKLEN_T
|
||||
|
||||
AC_CACHE_CHECK([for errno in errno.h],rsync_cv_errno, [
|
||||
AC_TRY_COMPILE([#include <errno.h>],[int i = errno],
|
||||
rsync_cv_errno=yes,rsync_cv_have_errno_decl=no)])
|
||||
if test x"$rsync_cv_errno" = x"yes"; then
|
||||
AC_DEFINE(HAVE_ERRNO_DECL, 1, [Define to 1 if errno is declared in errno.h])
|
||||
fi
|
||||
|
||||
# The following test taken from the cvs sources
|
||||
# If we can't find connect, try looking in -lsocket, -lnsl, and -linet.
|
||||
# These need checks to be before checks for any other functions that
|
||||
# might be in the same libraries.
|
||||
# The Irix 5 libc.so has connect and gethostbyname, but Irix 5 also has
|
||||
# libsocket.so which has a bad implementation of gethostbyname (it
|
||||
# only looks in /etc/hosts), so we only look for -lsocket if we need
|
||||
# it.
|
||||
AC_CHECK_FUNCS(connect)
|
||||
if test x"$ac_cv_func_connect" = x"no"; then
|
||||
case "$LIBS" in
|
||||
*-lnsl*) ;;
|
||||
*) AC_CHECK_LIB(nsl_s, printf) ;;
|
||||
esac
|
||||
case "$LIBS" in
|
||||
*-lnsl*) ;;
|
||||
*) AC_CHECK_LIB(nsl, printf) ;;
|
||||
esac
|
||||
case "$LIBS" in
|
||||
*-lsocket*) ;;
|
||||
*) AC_CHECK_LIB(socket, connect) ;;
|
||||
esac
|
||||
case "$LIBS" in
|
||||
*-linet*) ;;
|
||||
*) AC_CHECK_LIB(inet, connect) ;;
|
||||
esac
|
||||
dnl We can't just call AC_CHECK_FUNCS(connect) here, because the value
|
||||
dnl has been cached.
|
||||
if test x"$ac_cv_lib_socket_connect" = x"yes" ||
|
||||
test x"$ac_cv_lib_inet_connect" = x"yes"; then
|
||||
# ac_cv_func_connect=yes
|
||||
# don't! it would cause AC_CHECK_FUNC to succeed next time configure is run
|
||||
AC_DEFINE(HAVE_CONNECT, 1, [Define to 1 if you have the "connect" function])
|
||||
fi
|
||||
fi
|
||||
|
||||
AC_SEARCH_LIBS(inet_ntop, resolv)
|
||||
|
||||
# Solaris and HP-UX weirdness:
|
||||
# Search for libiconv_open (not iconv_open) to discover if -liconv is needed!
|
||||
AC_SEARCH_LIBS(libiconv_open, iconv)
|
||||
|
||||
AC_MSG_CHECKING([for iconv declaration])
|
||||
AC_CACHE_VAL(am_cv_proto_iconv, [
|
||||
AC_TRY_COMPILE([
|
||||
#include <stdlib.h>
|
||||
#include <iconv.h>
|
||||
extern
|
||||
#ifdef __cplusplus
|
||||
"C"
|
||||
#endif
|
||||
#if defined(__STDC__) || defined(__cplusplus)
|
||||
size_t iconv (iconv_t cd, char * *inbuf, size_t *inbytesleft, char * *outbuf, size_t *outbytesleft);
|
||||
#else
|
||||
size_t iconv();
|
||||
#endif
|
||||
], [], am_cv_proto_iconv_arg1="", am_cv_proto_iconv_arg1="const")
|
||||
am_cv_proto_iconv="extern size_t iconv (iconv_t cd, $am_cv_proto_iconv_arg1 char * *inbuf, size_t *inbytesleft, char * *outbuf, size_t *outbytesleft);"])
|
||||
am_cv_proto_iconv=`echo "[$]am_cv_proto_iconv" | tr -s ' ' | sed -e 's/( /(/'`
|
||||
AC_MSG_RESULT([$]{ac_t:-
|
||||
}[$]am_cv_proto_iconv)
|
||||
AC_DEFINE_UNQUOTED(ICONV_CONST, $am_cv_proto_iconv_arg1,
|
||||
[Define as const if the declaration of iconv() needs const.])
|
||||
|
||||
dnl AC_MSG_NOTICE([Looking in libraries: $LIBS])
|
||||
|
||||
AC_CHECK_FUNCS(inet_ntop, , [AC_LIBOBJ(lib/inet_ntop)])
|
||||
AC_CHECK_FUNCS(inet_pton, , [AC_LIBOBJ(lib/inet_pton)])
|
||||
|
||||
AC_HAVE_TYPE([struct addrinfo], [#include <netdb.h>])
|
||||
AC_HAVE_TYPE([struct sockaddr_storage], [#include <sys/types.h>
|
||||
#include <sys/socket.h>])
|
||||
|
||||
# Irix 6.5 has getaddrinfo but not the corresponding defines, so use
|
||||
# builtin getaddrinfo if one of the defines don't exist
|
||||
AC_CACHE_CHECK([whether defines needed by getaddrinfo exist],
|
||||
rsync_cv_HAVE_GETADDR_DEFINES,[
|
||||
AC_EGREP_CPP(yes, [
|
||||
#include <sys/types.h>
|
||||
#include <sys/socket.h>
|
||||
#include <netdb.h>
|
||||
#ifdef AI_PASSIVE
|
||||
yes
|
||||
#endif],
|
||||
rsync_cv_HAVE_GETADDR_DEFINES=yes,
|
||||
rsync_cv_HAVE_GETADDR_DEFINES=no)])
|
||||
if test x"$rsync_cv_HAVE_GETADDR_DEFINES" = x"yes" -a x"$ac_cv_type_struct_addrinfo" = x"yes"; then
|
||||
# Tru64 UNIX has getaddrinfo() but has it renamed in libc as
|
||||
# something else so we must include <netdb.h> to get the
|
||||
# redefinition.
|
||||
AC_CHECK_FUNCS(getaddrinfo, ,
|
||||
[AC_MSG_CHECKING([for getaddrinfo by including <netdb.h>])
|
||||
AC_TRY_LINK([#include <sys/types.h>
|
||||
#include <sys/socket.h>
|
||||
#include <netdb.h>],[getaddrinfo(NULL, NULL, NULL, NULL);],
|
||||
[AC_MSG_RESULT([yes])
|
||||
AC_DEFINE(HAVE_GETADDRINFO, 1,
|
||||
[Define to 1 if you have the "getaddrinfo" function and required types.])],
|
||||
[AC_MSG_RESULT([no])
|
||||
AC_LIBOBJ(lib/getaddrinfo)])])
|
||||
else
|
||||
AC_LIBOBJ(lib/getaddrinfo)
|
||||
fi
|
||||
|
||||
AC_CHECK_MEMBER([struct sockaddr.sa_len],
|
||||
[ AC_DEFINE(HAVE_SOCKADDR_LEN, 1, [Do we have sockaddr.sa_len?]) ],
|
||||
[],
|
||||
[
|
||||
#include <sys/types.h>
|
||||
#include <sys/socket.h>
|
||||
])
|
||||
|
||||
AC_CHECK_MEMBER([struct sockaddr_in.sin_len],
|
||||
[ AC_DEFINE(HAVE_SOCKADDR_IN_LEN, 1, [Do we have sockaddr_in.sin_len?]) ],
|
||||
[],
|
||||
[
|
||||
#include <sys/types.h>
|
||||
#include <sys/socket.h>
|
||||
#include <netinet/in.h>
|
||||
])
|
||||
|
||||
AC_CHECK_MEMBER([struct sockaddr_un.sun_len],
|
||||
[ AC_DEFINE(HAVE_SOCKADDR_UN_LEN, 1, [Do we have sockaddr_un.sun_len?]) ],
|
||||
[],
|
||||
[
|
||||
#include <sys/types.h>
|
||||
#include <sys/socket.h>
|
||||
#include <netinet/in.h>
|
||||
])
|
||||
|
||||
AC_CHECK_MEMBER([struct sockaddr_in6.sin6_scope_id],
|
||||
[ AC_DEFINE(HAVE_SOCKADDR_IN6_SCOPE_ID, 1, [Do we have sockaddr_in6.sin6_scope_id?]) ],
|
||||
[],
|
||||
[
|
||||
#include <sys/types.h>
|
||||
#include <sys/socket.h>
|
||||
#include <netinet/in.h>
|
||||
])
|
||||
|
||||
AC_HAVE_TYPE([struct stat64], [#include <stdio.h>
|
||||
#if HAVE_SYS_TYPES_H
|
||||
# include <sys/types.h>
|
||||
#endif
|
||||
#if HAVE_SYS_STAT_H
|
||||
# include <sys/stat.h>
|
||||
#endif
|
||||
#if STDC_HEADERS
|
||||
# include <stdlib.h>
|
||||
# include <stddef.h>
|
||||
#else
|
||||
# if HAVE_STDLIB_H
|
||||
# include <stdlib.h>
|
||||
# endif
|
||||
#endif
|
||||
])
|
||||
|
||||
# if we can't find strcasecmp, look in -lresolv (for Unixware at least)
|
||||
#
|
||||
AC_CHECK_FUNCS(strcasecmp)
|
||||
if test x"$ac_cv_func_strcasecmp" = x"no"; then
|
||||
AC_CHECK_LIB(resolv, strcasecmp)
|
||||
fi
|
||||
|
||||
AC_CHECK_FUNCS(aclsort)
|
||||
if test x"$ac_cv_func_aclsort" = x"no"; then
|
||||
AC_CHECK_LIB(sec, aclsort)
|
||||
fi
|
||||
|
||||
dnl At the moment we don't test for a broken memcmp(), because all we
|
||||
dnl need to do is test for equality, not comparison, and it seems that
|
||||
dnl every platform has a memcmp that can do at least that.
|
||||
dnl AC_FUNC_MEMCMP
|
||||
|
||||
AC_FUNC_UTIME_NULL
|
||||
AC_FUNC_ALLOCA
|
||||
AC_CHECK_FUNCS(waitpid wait4 getcwd strdup chown chmod lchmod mknod mkfifo \
|
||||
fchmod fstat ftruncate strchr readlink link utime utimes lutimes strftime \
|
||||
memmove lchown vsnprintf snprintf vasprintf asprintf setsid strpbrk \
|
||||
strlcat strlcpy strtol mallinfo getgroups setgroups geteuid getegid \
|
||||
setlocale setmode open64 lseek64 mkstemp64 mtrace va_copy __va_copy \
|
||||
strerror putenv iconv_open locale_charset nl_langinfo getxattr \
|
||||
extattr_get_link sigaction sigprocmask setattrlist)
|
||||
|
||||
dnl cygwin iconv.h defines iconv_open as libiconv_open
|
||||
if test x"$ac_cv_func_iconv_open" != x"yes"; then
|
||||
AC_CHECK_FUNC(libiconv_open, [ac_cv_func_iconv_open=yes; AC_DEFINE(HAVE_ICONV_OPEN, 1)])
|
||||
fi
|
||||
|
||||
AC_CHECK_FUNCS(getpgrp tcgetpgrp)
|
||||
if test $ac_cv_func_getpgrp = yes; then
|
||||
AC_FUNC_GETPGRP
|
||||
fi
|
||||
|
||||
AC_ARG_ENABLE(iconv,
|
||||
AC_HELP_STRING([--disable-iconv],
|
||||
[disable rsync's --iconv option]),
|
||||
[], [enable_iconv=$ac_cv_func_iconv_open])
|
||||
AH_TEMPLATE([ICONV_OPTION],
|
||||
[Define if you want the --iconv option. Specifing a value will set the
|
||||
default iconv setting (a NULL means no --iconv processing by default).])
|
||||
if test x"$enable_iconv" != x"no"; then
|
||||
if test x"$enable_iconv" = x"yes"; then
|
||||
AC_DEFINE(ICONV_OPTION, NULL)
|
||||
else
|
||||
AC_DEFINE_UNQUOTED(ICONV_OPTION, "$enable_iconv")
|
||||
fi
|
||||
AC_DEFINE(UTF8_CHARSET, "UTF-8", [String to pass to iconv() for the UTF-8 charset.])
|
||||
fi
|
||||
|
||||
AC_CACHE_CHECK([whether chown() modifies symlinks],rsync_cv_chown_modifies_symlink,[
|
||||
AC_TRY_RUN([
|
||||
#if HAVE_UNISTD_H
|
||||
# include <unistd.h>
|
||||
#endif
|
||||
#include <stdlib.h>
|
||||
#include <errno.h>
|
||||
main() {
|
||||
char const *dangling_symlink = "conftest.dangle";
|
||||
unlink(dangling_symlink);
|
||||
if (symlink("conftest.no-such", dangling_symlink) < 0) abort();
|
||||
if (chown(dangling_symlink, getuid(), getgid()) < 0 && errno == ENOENT) exit(1);
|
||||
exit(0);
|
||||
}],
|
||||
rsync_cv_chown_modifies_symlink=yes,rsync_cv_chown_modifies_symlink=no,rsync_cv_chown_modifies_symlink=no)])
|
||||
if test $rsync_cv_chown_modifies_symlink = yes; then
|
||||
AC_DEFINE(CHOWN_MODIFIES_SYMLINK, 1, [Define to 1 if chown modifies symlinks.])
|
||||
fi
|
||||
|
||||
AC_CACHE_CHECK([whether link() can hard-link symlinks],rsync_cv_can_hardlink_symlink,[
|
||||
AC_TRY_RUN([
|
||||
#if HAVE_UNISTD_H
|
||||
# include <unistd.h>
|
||||
#endif
|
||||
#include <stdlib.h>
|
||||
#include <errno.h>
|
||||
#define FILENAME "conftest.dangle"
|
||||
main() {
|
||||
unlink(FILENAME);
|
||||
if (symlink("conftest.no-such", FILENAME) < 0) abort();
|
||||
if (link(FILENAME, FILENAME "2") < 0) exit(1);
|
||||
exit(0);
|
||||
}],
|
||||
rsync_cv_can_hardlink_symlink=yes,rsync_cv_can_hardlink_symlink=no,rsync_cv_can_hardlink_symlink=no)])
|
||||
if test $rsync_cv_can_hardlink_symlink = yes; then
|
||||
AC_DEFINE(CAN_HARDLINK_SYMLINK, 1, [Define to 1 if link() can hard-link symlinks.])
|
||||
fi
|
||||
|
||||
AC_CACHE_CHECK([whether link() can hard-link special files],rsync_cv_can_hardlink_special,[
|
||||
AC_TRY_RUN([
|
||||
#if HAVE_UNISTD_H
|
||||
# include <unistd.h>
|
||||
#endif
|
||||
#include <stdlib.h>
|
||||
#include <errno.h>
|
||||
#define FILENAME "conftest.fifi"
|
||||
main() {
|
||||
unlink(FILENAME);
|
||||
if (mkfifo(FILENAME, 0777) < 0) abort();
|
||||
if (link(FILENAME, FILENAME "2") < 0) exit(1);
|
||||
exit(0);
|
||||
}],
|
||||
rsync_cv_can_hardlink_special=yes,rsync_cv_can_hardlink_special=no,rsync_cv_can_hardlink_special=no)])
|
||||
if test $rsync_cv_can_hardlink_special = yes; then
|
||||
AC_DEFINE(CAN_HARDLINK_SPECIAL, 1, [Define to 1 if link() can hard-link special files.])
|
||||
fi
|
||||
|
||||
AC_CACHE_CHECK([for working socketpair],rsync_cv_HAVE_SOCKETPAIR,[
|
||||
AC_TRY_RUN([
|
||||
#include <sys/types.h>
|
||||
#include <sys/socket.h>
|
||||
|
||||
main() {
|
||||
int fd[2];
|
||||
exit((socketpair(AF_UNIX, SOCK_STREAM, 0, fd) != -1) ? 0 : 1);
|
||||
}],
|
||||
rsync_cv_HAVE_SOCKETPAIR=yes,rsync_cv_HAVE_SOCKETPAIR=no,rsync_cv_HAVE_SOCKETPAIR=cross)])
|
||||
if test x"$rsync_cv_HAVE_SOCKETPAIR" = x"yes"; then
|
||||
AC_DEFINE(HAVE_SOCKETPAIR, 1, [Define to 1 if you have the "socketpair" function])
|
||||
fi
|
||||
|
||||
if test x"$with_included_popt" != x"yes"; then
|
||||
AC_CHECK_LIB(popt, poptGetContext, , [with_included_popt=yes])
|
||||
fi
|
||||
if test x"$ac_cv_header_popt_popt_h" = x"yes"; then
|
||||
# If the system has /usr/include/popt/popt.h, we enable the
|
||||
# included popt because an attempt to "#include <popt/popt.h>"
|
||||
# would use our included header file anyway (due to -I.), and
|
||||
# might conflict with the system popt.
|
||||
with_included_popt=yes
|
||||
elif test x"$ac_cv_header_popt_h" != x"yes"; then
|
||||
with_included_popt=yes
|
||||
fi
|
||||
|
||||
AC_MSG_CHECKING([whether to use included libpopt])
|
||||
if test x"$with_included_popt" = x"yes"; then
|
||||
AC_MSG_RESULT($srcdir/popt)
|
||||
BUILD_POPT='$(popt_OBJS)'
|
||||
CFLAGS="$CFLAGS -I$srcdir/popt"
|
||||
if test x"$ALLOCA" != x
|
||||
then
|
||||
# this can be removed when/if we add an included alloca.c;
|
||||
# see autoconf documentation on AC_FUNC_ALLOCA
|
||||
AC_MSG_WARN([included libpopt will use malloc, not alloca (which wastes a small amount of memory)])
|
||||
fi
|
||||
else
|
||||
AC_MSG_RESULT(no)
|
||||
fi
|
||||
|
||||
AC_CACHE_CHECK([for unsigned char],rsync_cv_SIGNED_CHAR_OK,[
|
||||
AC_TRY_COMPILE([],[signed char *s = ""],
|
||||
rsync_cv_SIGNED_CHAR_OK=yes,rsync_cv_SIGNED_CHAR_OK=no)])
|
||||
if test x"$rsync_cv_SIGNED_CHAR_OK" = x"yes"; then
|
||||
AC_DEFINE(SIGNED_CHAR_OK, 1, [Define to 1 if "signed char" is a valid type])
|
||||
fi
|
||||
|
||||
AC_CACHE_CHECK([for broken readdir],rsync_cv_HAVE_BROKEN_READDIR,[
|
||||
AC_TRY_RUN([#include <sys/types.h>
|
||||
#include <dirent.h>
|
||||
main() { struct dirent *di; DIR *d = opendir("."); di = readdir(d);
|
||||
if (di && di->d_name[-2] == '.' && di->d_name[-1] == 0 &&
|
||||
di->d_name[0] == 0) exit(0); exit(1);} ],
|
||||
rsync_cv_HAVE_BROKEN_READDIR=yes,rsync_cv_HAVE_BROKEN_READDIR=no,rsync_cv_HAVE_BROKEN_READDIR=cross)])
|
||||
if test x"$rsync_cv_HAVE_BROKEN_READDIR" = x"yes"; then
|
||||
AC_DEFINE(HAVE_BROKEN_READDIR, 1, [Define to 1 if readdir() is broken])
|
||||
fi
|
||||
|
||||
AC_CACHE_CHECK([for utimbuf],rsync_cv_HAVE_STRUCT_UTIMBUF,[
|
||||
AC_TRY_COMPILE([#include <sys/types.h>
|
||||
#include <utime.h>],
|
||||
[struct utimbuf tbuf; tbuf.actime = 0; tbuf.modtime = 1; exit(utime("foo.c",&tbuf));],
|
||||
rsync_cv_HAVE_STRUCT_UTIMBUF=yes,rsync_cv_HAVE_STRUCT_UTIMBUF=no)])
|
||||
if test x"$rsync_cv_HAVE_STRUCT_UTIMBUF" = x"yes"; then
|
||||
AC_DEFINE(HAVE_STRUCT_UTIMBUF, 1, [Define to 1 if you have the "struct utimbuf" type])
|
||||
fi
|
||||
|
||||
AC_CACHE_CHECK([if gettimeofday takes tz argument],rsync_cv_HAVE_GETTIMEOFDAY_TZ,[
|
||||
AC_TRY_COMPILE([#include <sys/time.h>
|
||||
#include <unistd.h>],
|
||||
[struct timeval tv; exit(gettimeofday(&tv, NULL));],
|
||||
rsync_cv_HAVE_GETTIMEOFDAY_TZ=yes,rsync_cv_HAVE_GETTIMEOFDAY_TZ=no)])
|
||||
if test x"$rsync_cv_HAVE_GETTIMEOFDAY_TZ" != x"no"; then
|
||||
AC_DEFINE(HAVE_GETTIMEOFDAY_TZ, 1, [Define to 1 if gettimeofday() takes a time-zone arg])
|
||||
fi
|
||||
|
||||
AC_CACHE_CHECK([for C99 vsnprintf],rsync_cv_HAVE_C99_VSNPRINTF,[
|
||||
AC_TRY_RUN([
|
||||
#include <sys/types.h>
|
||||
#include <stdarg.h>
|
||||
void foo(const char *format, ...) {
|
||||
va_list ap;
|
||||
int len;
|
||||
char buf[5];
|
||||
|
||||
va_start(ap, format);
|
||||
len = vsnprintf(0, 0, format, ap);
|
||||
va_end(ap);
|
||||
if (len != 5) exit(1);
|
||||
|
||||
if (snprintf(buf, 3, "hello") != 5 || strcmp(buf, "he") != 0) exit(1);
|
||||
|
||||
exit(0);
|
||||
}
|
||||
main() { foo("hello"); }
|
||||
],
|
||||
rsync_cv_HAVE_C99_VSNPRINTF=yes,rsync_cv_HAVE_C99_VSNPRINTF=no,rsync_cv_HAVE_C99_VSNPRINTF=cross)])
|
||||
if test x"$rsync_cv_HAVE_C99_VSNPRINTF" = x"yes"; then
|
||||
AC_DEFINE(HAVE_C99_VSNPRINTF, 1, [Define to 1 if vsprintf has a C99-compatible return value])
|
||||
fi
|
||||
|
||||
|
||||
AC_CACHE_CHECK([for secure mkstemp],rsync_cv_HAVE_SECURE_MKSTEMP,[
|
||||
AC_TRY_RUN([#include <stdlib.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <unistd.h>
|
||||
main() {
|
||||
struct stat st;
|
||||
char tpl[20]="/tmp/test.XXXXXX";
|
||||
int fd = mkstemp(tpl);
|
||||
if (fd == -1) exit(1);
|
||||
unlink(tpl);
|
||||
if (fstat(fd, &st) != 0) exit(1);
|
||||
if ((st.st_mode & 0777) != 0600) exit(1);
|
||||
exit(0);
|
||||
}],
|
||||
rsync_cv_HAVE_SECURE_MKSTEMP=yes,
|
||||
rsync_cv_HAVE_SECURE_MKSTEMP=no,
|
||||
rsync_cv_HAVE_SECURE_MKSTEMP=cross)])
|
||||
if test x"$rsync_cv_HAVE_SECURE_MKSTEMP" = x"yes"; then
|
||||
case $target_os in
|
||||
hpux*)
|
||||
dnl HP-UX has a broken mkstemp() implementation they refuse to fix,
|
||||
dnl so we noisily skip using it. See HP change request JAGaf34426
|
||||
dnl for details. (sbonds)
|
||||
AC_MSG_WARN(Skipping broken HP-UX mkstemp() -- using mktemp() instead)
|
||||
;;
|
||||
*)
|
||||
AC_DEFINE(HAVE_SECURE_MKSTEMP, 1, [Define to 1 if mkstemp() is available and works right])
|
||||
;;
|
||||
esac
|
||||
fi
|
||||
|
||||
|
||||
AC_CACHE_CHECK([if mknod creates FIFOs],rsync_cv_MKNOD_CREATES_FIFOS,[
|
||||
AC_TRY_RUN([
|
||||
#include <stdio.h>
|
||||
#include <sys/stat.h>
|
||||
#include <errno.h>
|
||||
main() { int rc, ec; char *fn = "fifo-test";
|
||||
unlink(fn); rc = mknod(fn,S_IFIFO,0600); ec = errno; unlink(fn);
|
||||
if (rc) {printf("(%d %d) ",rc,ec); return ec;}
|
||||
return 0;}],
|
||||
rsync_cv_MKNOD_CREATES_FIFOS=yes,rsync_cv_MKNOD_CREATES_FIFOS=no,rsync_cv_MKNOD_CREATES_FIFOS=cross)])
|
||||
if test x"$rsync_cv_MKNOD_CREATES_FIFOS" = x"yes"; then
|
||||
AC_DEFINE(MKNOD_CREATES_FIFOS, 1, [Define to 1 if mknod() can create FIFOs.])
|
||||
fi
|
||||
|
||||
AC_CACHE_CHECK([if mknod creates sockets],rsync_cv_MKNOD_CREATES_SOCKETS,[
|
||||
AC_TRY_RUN([
|
||||
#include <stdio.h>
|
||||
#include <sys/stat.h>
|
||||
#include <errno.h>
|
||||
main() { int rc, ec; char *fn = "sock-test";
|
||||
unlink(fn); rc = mknod(fn,S_IFSOCK,0600); ec = errno; unlink(fn);
|
||||
if (rc) {printf("(%d %d) ",rc,ec); return ec;}
|
||||
return 0;}],
|
||||
rsync_cv_MKNOD_CREATES_SOCKETS=yes,rsync_cv_MKNOD_CREATES_SOCKETS=no,rsync_cv_MKNOD_CREATES_SOCKETS=cross)])
|
||||
if test x"$rsync_cv_MKNOD_CREATES_SOCKETS" = x"yes"; then
|
||||
AC_DEFINE(MKNOD_CREATES_SOCKETS, 1, [Define to 1 if mknod() can create sockets.])
|
||||
fi
|
||||
|
||||
#
|
||||
# The following test was mostly taken from the tcl/tk plus patches
|
||||
#
|
||||
AC_CACHE_CHECK([whether -c -o works],rsync_cv_DASHC_WORKS_WITH_DASHO,[
|
||||
rm -rf conftest*
|
||||
cat > conftest.$ac_ext <<EOF
|
||||
int main() { return 0; }
|
||||
EOF
|
||||
${CC-cc} -c -o conftest..o conftest.$ac_ext
|
||||
if test -f conftest..o; then
|
||||
rsync_cv_DASHC_WORKS_WITH_DASHO=yes
|
||||
else
|
||||
rsync_cv_DASHC_WORKS_WITH_DASHO=no
|
||||
fi
|
||||
rm -rf conftest*
|
||||
])
|
||||
if test x"$rsync_cv_DASHC_WORKS_WITH_DASHO" = x"yes"; then
|
||||
OBJ_SAVE="#"
|
||||
OBJ_RESTORE="#"
|
||||
CC_SHOBJ_FLAG='-o $@'
|
||||
else
|
||||
OBJ_SAVE=' @b=`basename $@ .o`;rm -f $$b.o.sav;if test -f $$b.o; then mv $$b.o $$b.o.sav;fi;'
|
||||
OBJ_RESTORE=' @b=`basename $@ .o`;if test "$$b.o" != "$@"; then mv $$b.o $@; if test -f $$b.o.sav; then mv $$b.o.sav $$b.o; fi; fi'
|
||||
CC_SHOBJ_FLAG=""
|
||||
fi
|
||||
|
||||
AC_SUBST(OBJ_SAVE)
|
||||
AC_SUBST(OBJ_RESTORE)
|
||||
AC_SUBST(CC_SHOBJ_FLAG)
|
||||
AC_SUBST(BUILD_POPT)
|
||||
AC_SUBST(MAKE_MAN)
|
||||
|
||||
AC_CHECK_FUNCS(_acl __acl _facl __facl)
|
||||
#################################################
|
||||
# check for ACL support
|
||||
|
||||
AC_MSG_CHECKING([whether to support ACLs])
|
||||
AC_ARG_ENABLE(acl-support,
|
||||
AC_HELP_STRING([--disable-acl-support],
|
||||
[disable ACL support]))
|
||||
|
||||
if test x"$enable_acl_support" = x"no"; then
|
||||
AC_MSG_RESULT(no)
|
||||
else
|
||||
case "$host_os" in
|
||||
*sysv5*)
|
||||
AC_MSG_RESULT(Using UnixWare ACLs)
|
||||
AC_DEFINE(HAVE_UNIXWARE_ACLS, 1, [true if you have UnixWare ACLs])
|
||||
AC_DEFINE(SUPPORT_ACLS, 1, [Define to 1 to add support for ACLs])
|
||||
;;
|
||||
*solaris*|*cygwin*)
|
||||
AC_MSG_RESULT(Using solaris ACLs)
|
||||
AC_DEFINE(HAVE_SOLARIS_ACLS, 1, [true if you have solaris ACLs])
|
||||
AC_DEFINE(SUPPORT_ACLS, 1)
|
||||
;;
|
||||
*hpux*)
|
||||
AC_MSG_RESULT(Using HPUX ACLs)
|
||||
AC_DEFINE(HAVE_HPUX_ACLS, 1, [true if you have HPUX ACLs])
|
||||
AC_DEFINE(SUPPORT_ACLS, 1)
|
||||
;;
|
||||
*irix*)
|
||||
AC_MSG_RESULT(Using IRIX ACLs)
|
||||
AC_DEFINE(HAVE_IRIX_ACLS, 1, [true if you have IRIX ACLs])
|
||||
AC_DEFINE(SUPPORT_ACLS, 1)
|
||||
;;
|
||||
*aix*)
|
||||
AC_MSG_RESULT(Using AIX ACLs)
|
||||
AC_DEFINE(HAVE_AIX_ACLS, 1, [true if you have AIX ACLs])
|
||||
AC_DEFINE(SUPPORT_ACLS, 1)
|
||||
;;
|
||||
*osf*)
|
||||
AC_MSG_RESULT(Using Tru64 ACLs)
|
||||
AC_DEFINE(HAVE_TRU64_ACLS, 1, [true if you have Tru64 ACLs])
|
||||
AC_DEFINE(SUPPORT_ACLS, 1)
|
||||
LIBS="$LIBS -lpacl"
|
||||
;;
|
||||
darwin*)
|
||||
AC_MSG_RESULT(Using OS X ACLs)
|
||||
AC_DEFINE(HAVE_OSX_ACLS, 1, [true if you have Mac OS X ACLs])
|
||||
AC_DEFINE(SUPPORT_ACLS, 1)
|
||||
;;
|
||||
*)
|
||||
AC_MSG_RESULT(running tests:)
|
||||
AC_CHECK_LIB(acl,acl_get_file)
|
||||
AC_CACHE_CHECK([for ACL support],samba_cv_HAVE_POSIX_ACLS,[
|
||||
AC_TRY_LINK([#include <sys/types.h>
|
||||
#include <sys/acl.h>],
|
||||
[ acl_t acl; int entry_id; acl_entry_t *entry_p; return acl_get_entry( acl, entry_id, entry_p);],
|
||||
samba_cv_HAVE_POSIX_ACLS=yes,samba_cv_HAVE_POSIX_ACLS=no)])
|
||||
AC_MSG_CHECKING(ACL test results)
|
||||
if test x"$samba_cv_HAVE_POSIX_ACLS" = x"yes"; then
|
||||
AC_MSG_RESULT(Using posix ACLs)
|
||||
AC_DEFINE(HAVE_POSIX_ACLS, 1, [true if you have posix ACLs])
|
||||
AC_DEFINE(SUPPORT_ACLS, 1)
|
||||
AC_CACHE_CHECK([for acl_get_perm_np],samba_cv_HAVE_ACL_GET_PERM_NP,[
|
||||
AC_TRY_LINK([#include <sys/types.h>
|
||||
#include <sys/acl.h>],
|
||||
[ acl_permset_t permset_d; acl_perm_t perm; return acl_get_perm_np( permset_d, perm);],
|
||||
samba_cv_HAVE_ACL_GET_PERM_NP=yes,samba_cv_HAVE_ACL_GET_PERM_NP=no)])
|
||||
if test x"$samba_cv_HAVE_ACL_GET_PERM_NP" = x"yes"; then
|
||||
AC_DEFINE(HAVE_ACL_GET_PERM_NP, 1, [true if you have acl_get_perm_np])
|
||||
fi
|
||||
else
|
||||
if test x"$enable_acl_support" = x"yes"; then
|
||||
AC_MSG_ERROR(Failed to find ACL support)
|
||||
else
|
||||
AC_MSG_RESULT(No ACL support found)
|
||||
fi
|
||||
fi
|
||||
;;
|
||||
esac
|
||||
fi
|
||||
|
||||
#################################################
|
||||
# check for extended attribute support
|
||||
AC_MSG_CHECKING(whether to support extended attributes)
|
||||
AC_ARG_ENABLE(xattr-support,
|
||||
AC_HELP_STRING([--disable-xattr-support],
|
||||
[disable extended attributes]),
|
||||
[], [case "$ac_cv_func_getxattr$ac_cv_func_extattr_get_link" in
|
||||
*yes*) enable_xattr_support=maybe ;;
|
||||
*) enable_xattr_support=no ;;
|
||||
esac])
|
||||
AH_TEMPLATE([SUPPORT_XATTRS],
|
||||
[Define to 1 to add support for extended attributes])
|
||||
if test x"$enable_xattr_support" = x"no"; then
|
||||
AC_MSG_RESULT(no)
|
||||
else
|
||||
case "$host_os" in
|
||||
*linux*)
|
||||
AC_MSG_RESULT(Using Linux xattrs)
|
||||
AC_DEFINE(HAVE_LINUX_XATTRS, 1, [True if you have Linux xattrs])
|
||||
AC_DEFINE(SUPPORT_XATTRS, 1)
|
||||
;;
|
||||
darwin*)
|
||||
AC_MSG_RESULT(Using OS X xattrs)
|
||||
AC_DEFINE(HAVE_OSX_XATTRS, 1, [True if you have Mac OS X xattrs])
|
||||
AC_DEFINE(SUPPORT_XATTRS, 1)
|
||||
;;
|
||||
freebsd*)
|
||||
AC_MSG_RESULT(Using FreeBSD extattrs)
|
||||
AC_DEFINE(HAVE_FREEBSD_XATTRS, 1, [True if you have FreeBSD xattrs])
|
||||
AC_DEFINE(SUPPORT_XATTRS, 1)
|
||||
;;
|
||||
*)
|
||||
if test x"$enable_xattr_support" = x"yes"; then
|
||||
AC_MSG_ERROR(Failed to find extended attribute support)
|
||||
else
|
||||
AC_MSG_RESULT(No extended attribute support found)
|
||||
fi
|
||||
;;
|
||||
esac
|
||||
fi
|
||||
|
||||
if test x"$enable_acl_support" = x"no" -o x"$enable_xattr_support" = x"no" -o x"$enable_iconv" = x"no"; then
|
||||
AC_MSG_CHECKING([whether $CC supports -Wno-unused-parameter])
|
||||
OLD_CFLAGS="$CFLAGS"
|
||||
CFLAGS="$CFLAGS -Wno-unused-parameter"
|
||||
AC_COMPILE_IFELSE([ ], [rsync_warn_flag=yes], [rsync_warn_flag=no])
|
||||
AC_MSG_RESULT([$rsync_warn_flag])
|
||||
if test x"$rsync_warn_flag" = x"no"; then
|
||||
CFLAGS="$OLD_CFLAGS"
|
||||
fi
|
||||
fi
|
||||
|
||||
case "$CC" in
|
||||
' checker'*|checker*)
|
||||
AC_DEFINE(FORCE_FD_ZERO_MEMSET, 1, [Used to make "checker" understand that FD_ZERO() clears memory.])
|
||||
;;
|
||||
esac
|
||||
|
||||
AC_CONFIG_FILES([Makefile lib/dummy zlib/dummy popt/dummy shconfig])
|
||||
AC_OUTPUT
|
||||
|
||||
AC_MSG_RESULT()
|
||||
AC_MSG_RESULT([ rsync ${RSYNC_VERSION} configuration successful])
|
||||
AC_MSG_RESULT()
|
||||
@@ -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
|
||||
|
||||
@@ -7,54 +7,39 @@ basically a summary of clientserver.c and authenticate.c.
|
||||
This is the protocol used for rsync --daemon; i.e. connections to port
|
||||
873 rather than invocations over a remote shell.
|
||||
|
||||
When the server accepts a connection, it prints a newline-terminated
|
||||
greeting line:
|
||||
When the server accepts a connection, it prints a greeting
|
||||
|
||||
@RSYNCD: <version>.<subprotocol> <digest1> <digestN>
|
||||
@RSYNCD: <version>.<subprotocol>
|
||||
|
||||
The <version> is the numeric version (see PROTOCOL_VERSION in rsync.h)
|
||||
The <subprotocol> is the numeric subprotocol version (which is 0 for a
|
||||
final protocol version, as the SUBPROTOCOL_VERSION define discusses).
|
||||
The <digestN> names are the authentication digest algorithms that the
|
||||
daemon supports, listed in order of preference.
|
||||
|
||||
An rsync prior to 3.2.7 omits the digest names. An rsync prior to 3.0.0
|
||||
also omits the period and the <subprotocol> value. Since a final
|
||||
protocol has a subprotocol value of 0, a missing subprotocol value is
|
||||
assumed to be 0 for any protocol prior to 30. It is considered a fatal
|
||||
error for protocol 30 and above to omit it. It is considered a fatal
|
||||
error for protocol 32 and above to omit the digest name list (currently
|
||||
31 is the newest protocol).
|
||||
|
||||
The daemon expects to see a similar greeting line back from the client.
|
||||
Once received, the daemon follows the opening line with a free-format
|
||||
text message-of-the-day (if any is defined).
|
||||
where <version> is the numeric version (see PROTOCOL_VERSION in rsync.h)
|
||||
'.' is a literal period, and <subprotocol> is the numeric subprotocol
|
||||
version (see SUBPROTOCOL_VERSION -- it will be 0 for final releases).
|
||||
Protocols prior to 30 only output <version> alone. The daemon expects
|
||||
to see a similar greeting back from the client. For protocols prior to
|
||||
30, an absent ".<subprotocol>" value is assumed to be 0. For protocol
|
||||
30, an absent value is a fatal error. The daemon then follows this line
|
||||
with a free-format text message-of-the-day (if any is defined).
|
||||
|
||||
The server is now in the connected state. The client can either send
|
||||
the command:
|
||||
the command
|
||||
|
||||
#list
|
||||
|
||||
(to get a listing of modules) or the name of a module. After this, the
|
||||
to get a listing of modules, or the name of a module. After this, the
|
||||
connection is now bound to a particular module. Access per host for
|
||||
this module is now checked, as is per-module connection limits.
|
||||
|
||||
If authentication is required to use this module, the server will say:
|
||||
If authentication is required to use this module, the server will say
|
||||
|
||||
@RSYNCD: AUTHREQD <challenge>
|
||||
|
||||
where <challenge> is a random string of base64 characters. The client
|
||||
must respond with:
|
||||
must respond with
|
||||
|
||||
<user> <response>
|
||||
|
||||
The <user> is the username they claim to be. The <response> is the
|
||||
base64 form of the digest hash of the challenge+password string. The
|
||||
chosen digest method is the most preferred client method that is also in
|
||||
the server's list. If no digest list was explicitly provided, the side
|
||||
expecting a list assumes the other side provided either the single name
|
||||
"md5" (for a negotiated protocol 30 or 31), or the single name "md4"
|
||||
(for an older protocol).
|
||||
where <user> is the username they claim to be, and <response> is the
|
||||
base64 form of the MD4 hash of challenge+password.
|
||||
|
||||
At this point the server applies all remaining constraints before
|
||||
handing control to the client, including switching uid/gid, setting up
|
||||
@@ -91,13 +76,6 @@ stay tuned (or write it yourself!).
|
||||
------------
|
||||
Protocol version changes
|
||||
|
||||
31 (2013-09-28, 3.1.0)
|
||||
|
||||
Initial release of protocol 31 had no changes. Rsync 3.2.7
|
||||
introduced the suffixed list of digest names on the greeting
|
||||
line. The presence of the list is allowed even if the greeting
|
||||
indicates an older protocol version number.
|
||||
|
||||
30 (2007-10-04, 3.0.0pre1)
|
||||
|
||||
The use of a ".<subprotocol>" number was added to
|
||||
|
||||
114
daemon-parm.awk
114
daemon-parm.awk
@@ -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
|
||||
}
|
||||
}
|
||||
@@ -1,68 +0,0 @@
|
||||
Globals: ================================================================
|
||||
|
||||
STRING bind_address|address NULL
|
||||
STRING daemon_chroot NULL
|
||||
STRING daemon_gid NULL
|
||||
STRING daemon_uid NULL
|
||||
STRING motd_file NULL
|
||||
STRING pid_file NULL
|
||||
STRING socket_options NULL
|
||||
|
||||
INTEGER listen_backlog 5
|
||||
INTEGER rsync_port|port 0
|
||||
|
||||
BOOL proxy_protocol False
|
||||
|
||||
Locals: =================================================================
|
||||
|
||||
STRING auth_users NULL
|
||||
STRING charset NULL
|
||||
STRING comment NULL
|
||||
STRING dont_compress DEFAULT_DONT_COMPRESS
|
||||
STRING early_exec NULL
|
||||
STRING exclude NULL
|
||||
STRING exclude_from NULL
|
||||
STRING filter NULL
|
||||
STRING gid NULL
|
||||
STRING hosts_allow NULL
|
||||
STRING hosts_deny NULL
|
||||
STRING include NULL
|
||||
STRING include_from NULL
|
||||
STRING incoming_chmod NULL
|
||||
STRING lock_file DEFAULT_LOCK_FILE
|
||||
STRING log_file NULL
|
||||
STRING log_format "%o %h [%a] %m (%u) %f %l"
|
||||
STRING name NULL
|
||||
STRING name_converter NULL
|
||||
STRING outgoing_chmod NULL
|
||||
STRING post-xfer_exec NULL
|
||||
STRING pre-xfer_exec NULL
|
||||
STRING refuse_options NULL
|
||||
STRING secrets_file NULL
|
||||
STRING syslog_tag "rsyncd"
|
||||
STRING uid NULL
|
||||
|
||||
PATH path NULL
|
||||
PATH temp_dir NULL
|
||||
|
||||
INTEGER max_connections 0
|
||||
INTEGER max_verbosity 1
|
||||
INTEGER timeout 0
|
||||
|
||||
ENUM syslog_facility LOG_DAEMON
|
||||
|
||||
BOOL fake_super False
|
||||
BOOL forward_lookup True
|
||||
BOOL ignore_errors False
|
||||
BOOL ignore_nonreadable False
|
||||
BOOL list True
|
||||
BOOL read_only True
|
||||
BOOL reverse_lookup True
|
||||
BOOL strict_modes True
|
||||
BOOL transfer_logging False
|
||||
BOOL write_only False
|
||||
|
||||
BOOL3 munge_symlinks Unset
|
||||
BOOL3 numeric_ids Unset
|
||||
BOOL3 open_noatime Unset
|
||||
BOOL3 use_chroot Unset
|
||||
@@ -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
240
delete.c
@@ -1,240 +0,0 @@
|
||||
/*
|
||||
* Deletion routines used in rsync.
|
||||
*
|
||||
* Copyright (C) 1996-2000 Andrew Tridgell
|
||||
* Copyright (C) 1996 Paul Mackerras
|
||||
* Copyright (C) 2002 Martin Pool <mbp@samba.org>
|
||||
* Copyright (C) 2003-2024 Wayne Davison
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, visit the http://fsf.org website.
|
||||
*/
|
||||
|
||||
#include "rsync.h"
|
||||
|
||||
extern int am_root;
|
||||
extern int make_backups;
|
||||
extern int max_delete;
|
||||
extern char *backup_dir;
|
||||
extern char *backup_suffix;
|
||||
extern int backup_suffix_len;
|
||||
extern struct stats stats;
|
||||
|
||||
int ignore_perishable = 0;
|
||||
int non_perishable_cnt = 0;
|
||||
int skipped_deletes = 0;
|
||||
|
||||
static inline int is_backup_file(char *fn)
|
||||
{
|
||||
int k = strlen(fn) - backup_suffix_len;
|
||||
return k > 0 && strcmp(fn+k, backup_suffix) == 0;
|
||||
}
|
||||
|
||||
/* The directory is about to be deleted: if DEL_RECURSE is given, delete all
|
||||
* its contents, otherwise just checks for content. Returns DR_SUCCESS or
|
||||
* DR_NOT_EMPTY. Note that fname must point to a MAXPATHLEN buffer! (The
|
||||
* buffer is used for recursion, but returned unchanged.)
|
||||
*/
|
||||
static enum delret delete_dir_contents(char *fname, uint16 flags)
|
||||
{
|
||||
struct file_list *dirlist;
|
||||
enum delret ret;
|
||||
unsigned remainder;
|
||||
void *save_filters;
|
||||
int j, dlen;
|
||||
char *p;
|
||||
|
||||
if (DEBUG_GTE(DEL, 3)) {
|
||||
rprintf(FINFO, "delete_dir_contents(%s) flags=%d\n",
|
||||
fname, flags);
|
||||
}
|
||||
|
||||
dlen = strlen(fname);
|
||||
save_filters = push_local_filters(fname, dlen);
|
||||
|
||||
non_perishable_cnt = 0;
|
||||
dirlist = get_dirlist(fname, dlen, 0);
|
||||
ret = non_perishable_cnt ? DR_NOT_EMPTY : DR_SUCCESS;
|
||||
|
||||
if (!dirlist->used)
|
||||
goto done;
|
||||
|
||||
if (!(flags & DEL_RECURSE)) {
|
||||
ret = DR_NOT_EMPTY;
|
||||
goto done;
|
||||
}
|
||||
|
||||
p = fname + dlen;
|
||||
if (dlen != 1 || *fname != '/')
|
||||
*p++ = '/';
|
||||
remainder = MAXPATHLEN - (p - fname);
|
||||
|
||||
/* We do our own recursion, so make delete_item() non-recursive. */
|
||||
flags = (flags & ~(DEL_RECURSE|DEL_MAKE_ROOM|DEL_NO_UID_WRITE))
|
||||
| DEL_DIR_IS_EMPTY;
|
||||
|
||||
for (j = dirlist->used; j--; ) {
|
||||
struct file_struct *fp = dirlist->files[j];
|
||||
|
||||
if (fp->flags & FLAG_MOUNT_DIR && S_ISDIR(fp->mode)) {
|
||||
if (DEBUG_GTE(DEL, 1)) {
|
||||
rprintf(FINFO,
|
||||
"mount point, %s, pins parent directory\n",
|
||||
f_name(fp, NULL));
|
||||
}
|
||||
ret = DR_NOT_EMPTY;
|
||||
continue;
|
||||
}
|
||||
|
||||
strlcpy(p, fp->basename, remainder);
|
||||
if (!(fp->mode & S_IWUSR) && !am_root && fp->flags & FLAG_OWNED_BY_US)
|
||||
do_chmod(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_devices++;
|
||||
else
|
||||
stats.deleted_specials++;
|
||||
}
|
||||
ret = DR_SUCCESS;
|
||||
} else {
|
||||
if (S_ISDIR(mode) && errno == ENOTEMPTY) {
|
||||
rprintf(FINFO, "cannot delete non-empty directory: %s\n",
|
||||
fbuf);
|
||||
ret = DR_NOT_EMPTY;
|
||||
} else if (errno != ENOENT) {
|
||||
rsyserr(FERROR_XFER, errno, "delete_file: %s(%s) failed",
|
||||
what, fbuf);
|
||||
ret = DR_FAILURE;
|
||||
} else
|
||||
ret = DR_SUCCESS;
|
||||
}
|
||||
|
||||
check_ret:
|
||||
if (ret != DR_SUCCESS && flags & DEL_MAKE_ROOM) {
|
||||
const char *desc;
|
||||
switch (flags & DEL_MAKE_ROOM) {
|
||||
case DEL_FOR_FILE: desc = "regular file"; break;
|
||||
case DEL_FOR_DIR: desc = "directory"; break;
|
||||
case DEL_FOR_SYMLINK: desc = "symlink"; break;
|
||||
case DEL_FOR_DEVICE: desc = "device file"; break;
|
||||
case DEL_FOR_SPECIAL: desc = "special file"; break;
|
||||
default: exit_cleanup(RERR_UNSUPPORTED); /* IMPOSSIBLE */
|
||||
}
|
||||
rprintf(FERROR_XFER, "could not make way for %s %s: %s\n",
|
||||
flags & DEL_FOR_BACKUP ? "backup" : "new",
|
||||
desc, fbuf);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
uint16 get_del_for_flag(uint16 mode)
|
||||
{
|
||||
if (S_ISREG(mode))
|
||||
return DEL_FOR_FILE;
|
||||
if (S_ISDIR(mode))
|
||||
return DEL_FOR_DIR;
|
||||
if (S_ISLNK(mode))
|
||||
return DEL_FOR_SYMLINK;
|
||||
if (IS_DEVICE(mode))
|
||||
return DEL_FOR_DEVICE;
|
||||
if (IS_SPECIAL(mode))
|
||||
return DEL_FOR_SPECIAL;
|
||||
exit_cleanup(RERR_UNSUPPORTED); /* IMPOSSIBLE */
|
||||
}
|
||||
@@ -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>
|
||||
@@ -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
|
||||
|
||||
170
fileio.c
170
fileio.c
@@ -3,7 +3,7 @@
|
||||
*
|
||||
* Copyright (C) 1998 Andrew Tridgell
|
||||
* Copyright (C) 2002 Martin Pool
|
||||
* Copyright (C) 2004-2023 Wayne Davison
|
||||
* Copyright (C) 2004-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
|
||||
@@ -20,108 +20,68 @@
|
||||
*/
|
||||
|
||||
#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 size_t sparse_seek = 0;
|
||||
|
||||
static OFF_T sparse_seek = 0;
|
||||
static OFF_T sparse_past_write = 0;
|
||||
|
||||
int sparse_end(int f, OFF_T size, int updating_basis_or_equiv)
|
||||
int sparse_end(int f)
|
||||
{
|
||||
int ret = 0;
|
||||
int ret;
|
||||
|
||||
if (updating_basis_or_equiv) {
|
||||
if (sparse_seek && do_punch_hole(f, sparse_past_write, sparse_seek) < 0)
|
||||
ret = -1;
|
||||
#ifdef HAVE_FTRUNCATE /* A compilation formality -- in-place requires ftruncate() */
|
||||
else /* Just in case the original file was longer */
|
||||
ret = do_ftruncate(f, size);
|
||||
#endif
|
||||
} else if (sparse_seek) {
|
||||
#ifdef HAVE_FTRUNCATE
|
||||
ret = do_ftruncate(f, size);
|
||||
#else
|
||||
if (do_lseek(f, sparse_seek-1, SEEK_CUR) != size-1)
|
||||
ret = -1;
|
||||
else {
|
||||
do {
|
||||
ret = write(f, "", 1);
|
||||
} while (ret < 0 && errno == EINTR);
|
||||
if (!sparse_seek)
|
||||
return 0;
|
||||
|
||||
ret = ret <= 0 ? -1 : 0;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
do_lseek(f, sparse_seek-1, SEEK_CUR);
|
||||
sparse_seek = 0;
|
||||
|
||||
sparse_past_write = sparse_seek = 0;
|
||||
do {
|
||||
ret = write(f, "", 1);
|
||||
} while (ret < 0 && errno == EINTR);
|
||||
|
||||
return ret;
|
||||
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, size_t len)
|
||||
{
|
||||
int l1 = 0, l2 = 0;
|
||||
size_t l1 = 0, l2 = 0;
|
||||
int ret;
|
||||
|
||||
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;
|
||||
@@ -143,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,size_t len)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
@@ -154,15 +116,16 @@ 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);
|
||||
r1 = MIN(len, wf_writeBufSize - wf_writeBufCnt);
|
||||
if (r1) {
|
||||
memcpy(wf_writeBuf + wf_writeBufCnt, buf, r1);
|
||||
wf_writeBufCnt += r1;
|
||||
@@ -186,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;
|
||||
}
|
||||
@@ -235,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;
|
||||
@@ -251,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;
|
||||
@@ -287,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;
|
||||
@@ -297,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;
|
||||
@@ -311,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;
|
||||
@@ -323,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;
|
||||
|
||||
1497
generator.c
1497
generator.c
File diff suppressed because it is too large
Load Diff
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
548
hashtable.c
548
hashtable.c
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* Routines to provide a memory-efficient hashtable.
|
||||
*
|
||||
* Copyright (C) 2007-2022 Wayne Davison
|
||||
* Copyright (C) 2007-2008 Wayne Davison
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
@@ -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,485 +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.
|
||||
-------------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
#define NON_ZERO_32(x) ((x) ? (x) : (uint32_t)1)
|
||||
#define NON_ZERO_64(x, y) ((x) || (y) ? (y) | (int64)(x) << 32 | (y) : (int64)1)
|
||||
|
||||
uint32_t hashlittle(const void *key, size_t length)
|
||||
{
|
||||
uint32_t a,b,c; /* internal state */
|
||||
union { const void *ptr; size_t i; } u; /* needed for Mac Powerbook G4 */
|
||||
|
||||
/* Set up the internal state */
|
||||
a = b = c = 0xdeadbeef + ((uint32_t)length);
|
||||
|
||||
u.ptr = key;
|
||||
if (HASH_LITTLE_ENDIAN && ((u.i & 0x3) == 0)) {
|
||||
const uint32_t *k = (const uint32_t *)key; /* read 32-bit chunks */
|
||||
const uint8_t *k8;
|
||||
|
||||
/*------ all but last block: aligned reads and affect 32 bits of (a,b,c) */
|
||||
while (length > 12)
|
||||
{
|
||||
a += k[0];
|
||||
b += k[1];
|
||||
c += k[2];
|
||||
mix(a,b,c);
|
||||
length -= 12;
|
||||
k += 3;
|
||||
}
|
||||
|
||||
/*----------------------------- handle the last (probably partial) block */
|
||||
k8 = (const uint8_t *)k;
|
||||
switch(length)
|
||||
{
|
||||
case 12: c+=k[2]; b+=k[1]; a+=k[0]; break;
|
||||
case 11: c+=((uint32_t)k8[10])<<16; /* fall through */
|
||||
case 10: c+=((uint32_t)k8[9])<<8; /* fall through */
|
||||
case 9 : c+=k8[8]; /* fall through */
|
||||
case 8 : b+=k[1]; a+=k[0]; break;
|
||||
case 7 : b+=((uint32_t)k8[6])<<16; /* fall through */
|
||||
case 6 : b+=((uint32_t)k8[5])<<8; /* fall through */
|
||||
case 5 : b+=k8[4]; /* fall through */
|
||||
case 4 : a+=k[0]; break;
|
||||
case 3 : a+=((uint32_t)k8[2])<<16; /* fall through */
|
||||
case 2 : a+=((uint32_t)k8[1])<<8; /* fall through */
|
||||
case 1 : a+=k8[0]; break;
|
||||
case 0 : return NON_ZERO_32(c);
|
||||
}
|
||||
} else if (HASH_LITTLE_ENDIAN && ((u.i & 0x1) == 0)) {
|
||||
const uint16_t *k = (const uint16_t *)key; /* read 16-bit chunks */
|
||||
const uint8_t *k8;
|
||||
|
||||
/*--------------- all but last block: aligned reads and different mixing */
|
||||
while (length > 12)
|
||||
{
|
||||
a += k[0] + (((uint32_t)k[1])<<16);
|
||||
b += k[2] + (((uint32_t)k[3])<<16);
|
||||
c += k[4] + (((uint32_t)k[5])<<16);
|
||||
mix(a,b,c);
|
||||
length -= 12;
|
||||
k += 6;
|
||||
}
|
||||
|
||||
/*----------------------------- handle the last (probably partial) block */
|
||||
k8 = (const uint8_t *)k;
|
||||
switch(length)
|
||||
{
|
||||
case 12: c+=k[4]+(((uint32_t)k[5])<<16);
|
||||
b+=k[2]+(((uint32_t)k[3])<<16);
|
||||
a+=k[0]+(((uint32_t)k[1])<<16);
|
||||
break;
|
||||
case 11: c+=((uint32_t)k8[10])<<16; /* fall through */
|
||||
case 10: c+=k[4];
|
||||
b+=k[2]+(((uint32_t)k[3])<<16);
|
||||
a+=k[0]+(((uint32_t)k[1])<<16);
|
||||
break;
|
||||
case 9 : c+=k8[8]; /* fall through */
|
||||
case 8 : b+=k[2]+(((uint32_t)k[3])<<16);
|
||||
a+=k[0]+(((uint32_t)k[1])<<16);
|
||||
break;
|
||||
case 7 : b+=((uint32_t)k8[6])<<16; /* fall through */
|
||||
case 6 : b+=k[2];
|
||||
a+=k[0]+(((uint32_t)k[1])<<16);
|
||||
break;
|
||||
case 5 : b+=k8[4]; /* fall through */
|
||||
case 4 : a+=k[0]+(((uint32_t)k[1])<<16);
|
||||
break;
|
||||
case 3 : a+=((uint32_t)k8[2])<<16; /* fall through */
|
||||
case 2 : a+=k[0];
|
||||
break;
|
||||
case 1 : a+=k8[0];
|
||||
break;
|
||||
case 0 : return NON_ZERO_32(c); /* zero length requires no mixing */
|
||||
}
|
||||
|
||||
} else { /* need to read the key one byte at a time */
|
||||
const uint8_t *k = (const uint8_t *)key;
|
||||
|
||||
/*--------------- all but the last block: affect some 32 bits of (a,b,c) */
|
||||
while (length > 12)
|
||||
{
|
||||
a += k[0];
|
||||
a += ((uint32_t)k[1])<<8;
|
||||
a += ((uint32_t)k[2])<<16;
|
||||
a += ((uint32_t)k[3])<<24;
|
||||
b += k[4];
|
||||
b += ((uint32_t)k[5])<<8;
|
||||
b += ((uint32_t)k[6])<<16;
|
||||
b += ((uint32_t)k[7])<<24;
|
||||
c += k[8];
|
||||
c += ((uint32_t)k[9])<<8;
|
||||
c += ((uint32_t)k[10])<<16;
|
||||
c += ((uint32_t)k[11])<<24;
|
||||
mix(a,b,c);
|
||||
length -= 12;
|
||||
k += 12;
|
||||
}
|
||||
|
||||
/*-------------------------------- last block: affect all 32 bits of (c) */
|
||||
switch(length) /* all the case statements fall through */
|
||||
{
|
||||
case 12: c+=((uint32_t)k[11])<<24;
|
||||
/* FALLTHROUGH */
|
||||
case 11: c+=((uint32_t)k[10])<<16;
|
||||
/* FALLTHROUGH */
|
||||
case 10: c+=((uint32_t)k[9])<<8;
|
||||
/* FALLTHROUGH */
|
||||
case 9 : c+=k[8];
|
||||
/* FALLTHROUGH */
|
||||
case 8 : b+=((uint32_t)k[7])<<24;
|
||||
/* FALLTHROUGH */
|
||||
case 7 : b+=((uint32_t)k[6])<<16;
|
||||
/* FALLTHROUGH */
|
||||
case 6 : b+=((uint32_t)k[5])<<8;
|
||||
/* FALLTHROUGH */
|
||||
case 5 : b+=k[4];
|
||||
/* FALLTHROUGH */
|
||||
case 4 : a+=((uint32_t)k[3])<<24;
|
||||
/* FALLTHROUGH */
|
||||
case 3 : a+=((uint32_t)k[2])<<16;
|
||||
/* FALLTHROUGH */
|
||||
case 2 : a+=((uint32_t)k[1])<<8;
|
||||
/* FALLTHROUGH */
|
||||
case 1 : a+=k[0];
|
||||
break;
|
||||
case 0 : return NON_ZERO_32(c);
|
||||
}
|
||||
}
|
||||
|
||||
final(a,b,c);
|
||||
return NON_ZERO_32(c);
|
||||
}
|
||||
|
||||
#if SIZEOF_INT64 >= 8
|
||||
/*
|
||||
* hashlittle2: return 2 32-bit hash values joined into an int64.
|
||||
*
|
||||
* This is identical to hashlittle(), except it returns two 32-bit hash
|
||||
* values instead of just one. This is good enough for hash table
|
||||
* lookup with 2^^64 buckets, or if you want a second hash if you're not
|
||||
* happy with the first, or if you want a probably-unique 64-bit ID for
|
||||
* the key. *pc is better mixed than *pb, so use *pc first. If you want
|
||||
* a 64-bit value do something like "*pc + (((uint64_t)*pb)<<32)".
|
||||
*/
|
||||
int64 hashlittle2(const void *key, size_t length)
|
||||
{
|
||||
uint32_t a,b,c; /* internal state */
|
||||
union { const void *ptr; size_t i; } u; /* needed for Mac Powerbook G4 */
|
||||
|
||||
/* Set up the internal state */
|
||||
a = b = c = 0xdeadbeef + ((uint32_t)length);
|
||||
|
||||
u.ptr = key;
|
||||
if (HASH_LITTLE_ENDIAN && ((u.i & 0x3) == 0)) {
|
||||
const uint32_t *k = (const uint32_t *)key; /* read 32-bit chunks */
|
||||
const uint8_t *k8;
|
||||
|
||||
/*------ all but last block: aligned reads and affect 32 bits of (a,b,c) */
|
||||
while (length > 12)
|
||||
{
|
||||
a += k[0];
|
||||
b += k[1];
|
||||
c += k[2];
|
||||
mix(a,b,c);
|
||||
length -= 12;
|
||||
k += 3;
|
||||
}
|
||||
|
||||
/*----------------------------- handle the last (probably partial) block */
|
||||
k8 = (const uint8_t *)k;
|
||||
switch(length)
|
||||
{
|
||||
case 12: c+=k[2]; b+=k[1]; a+=k[0]; break;
|
||||
case 11: c+=((uint32_t)k8[10])<<16; /* fall through */
|
||||
case 10: c+=((uint32_t)k8[9])<<8; /* fall through */
|
||||
case 9 : c+=k8[8]; /* fall through */
|
||||
case 8 : b+=k[1]; a+=k[0]; break;
|
||||
case 7 : b+=((uint32_t)k8[6])<<16; /* fall through */
|
||||
case 6 : b+=((uint32_t)k8[5])<<8; /* fall through */
|
||||
case 5 : b+=k8[4]; /* fall through */
|
||||
case 4 : a+=k[0]; break;
|
||||
case 3 : a+=((uint32_t)k8[2])<<16; /* fall through */
|
||||
case 2 : a+=((uint32_t)k8[1])<<8; /* fall through */
|
||||
case 1 : a+=k8[0]; break;
|
||||
case 0 : return NON_ZERO_64(b, c);
|
||||
}
|
||||
} else if (HASH_LITTLE_ENDIAN && ((u.i & 0x1) == 0)) {
|
||||
const uint16_t *k = (const uint16_t *)key; /* read 16-bit chunks */
|
||||
const uint8_t *k8;
|
||||
|
||||
/*--------------- all but last block: aligned reads and different mixing */
|
||||
while (length > 12)
|
||||
{
|
||||
a += k[0] + (((uint32_t)k[1])<<16);
|
||||
b += k[2] + (((uint32_t)k[3])<<16);
|
||||
c += k[4] + (((uint32_t)k[5])<<16);
|
||||
mix(a,b,c);
|
||||
length -= 12;
|
||||
k += 6;
|
||||
}
|
||||
|
||||
/*----------------------------- handle the last (probably partial) block */
|
||||
k8 = (const uint8_t *)k;
|
||||
switch(length)
|
||||
{
|
||||
case 12: c+=k[4]+(((uint32_t)k[5])<<16);
|
||||
b+=k[2]+(((uint32_t)k[3])<<16);
|
||||
a+=k[0]+(((uint32_t)k[1])<<16);
|
||||
break;
|
||||
case 11: c+=((uint32_t)k8[10])<<16; /* fall through */
|
||||
case 10: c+=k[4];
|
||||
b+=k[2]+(((uint32_t)k[3])<<16);
|
||||
a+=k[0]+(((uint32_t)k[1])<<16);
|
||||
break;
|
||||
case 9 : c+=k8[8]; /* fall through */
|
||||
case 8 : b+=k[2]+(((uint32_t)k[3])<<16);
|
||||
a+=k[0]+(((uint32_t)k[1])<<16);
|
||||
break;
|
||||
case 7 : b+=((uint32_t)k8[6])<<16; /* fall through */
|
||||
case 6 : b+=k[2];
|
||||
a+=k[0]+(((uint32_t)k[1])<<16);
|
||||
break;
|
||||
case 5 : b+=k8[4]; /* fall through */
|
||||
case 4 : a+=k[0]+(((uint32_t)k[1])<<16);
|
||||
break;
|
||||
case 3 : a+=((uint32_t)k8[2])<<16; /* fall through */
|
||||
case 2 : a+=k[0];
|
||||
break;
|
||||
case 1 : a+=k8[0];
|
||||
break;
|
||||
case 0 : return NON_ZERO_64(b, c); /* zero length strings require no mixing */
|
||||
}
|
||||
|
||||
} else { /* need to read the key one byte at a time */
|
||||
const uint8_t *k = (const uint8_t *)key;
|
||||
|
||||
/*--------------- all but the last block: affect some 32 bits of (a,b,c) */
|
||||
while (length > 12)
|
||||
{
|
||||
a += k[0];
|
||||
a += ((uint32_t)k[1])<<8;
|
||||
a += ((uint32_t)k[2])<<16;
|
||||
a += ((uint32_t)k[3])<<24;
|
||||
b += k[4];
|
||||
b += ((uint32_t)k[5])<<8;
|
||||
b += ((uint32_t)k[6])<<16;
|
||||
b += ((uint32_t)k[7])<<24;
|
||||
c += k[8];
|
||||
c += ((uint32_t)k[9])<<8;
|
||||
c += ((uint32_t)k[10])<<16;
|
||||
c += ((uint32_t)k[11])<<24;
|
||||
mix(a,b,c);
|
||||
length -= 12;
|
||||
k += 12;
|
||||
}
|
||||
|
||||
/*-------------------------------- last block: affect all 32 bits of (c) */
|
||||
switch(length) /* all the case statements fall through */
|
||||
{
|
||||
case 12: c+=((uint32_t)k[11])<<24;
|
||||
/* FALLTHROUGH */
|
||||
case 11: c+=((uint32_t)k[10])<<16;
|
||||
/* FALLTHROUGH */
|
||||
case 10: c+=((uint32_t)k[9])<<8;
|
||||
/* FALLTHROUGH */
|
||||
case 9 : c+=k[8];
|
||||
/* FALLTHROUGH */
|
||||
case 8 : b+=((uint32_t)k[7])<<24;
|
||||
/* FALLTHROUGH */
|
||||
case 7 : b+=((uint32_t)k[6])<<16;
|
||||
/* FALLTHROUGH */
|
||||
case 6 : b+=((uint32_t)k[5])<<8;
|
||||
/* FALLTHROUGH */
|
||||
case 5 : b+=k[4];
|
||||
/* FALLTHROUGH */
|
||||
case 4 : a+=((uint32_t)k[3])<<24;
|
||||
/* FALLTHROUGH */
|
||||
case 3 : a+=((uint32_t)k[2])<<16;
|
||||
/* FALLTHROUGH */
|
||||
case 2 : a+=((uint32_t)k[1])<<8;
|
||||
/* FALLTHROUGH */
|
||||
case 1 : a+=k[0];
|
||||
break;
|
||||
case 0 : return NON_ZERO_64(b, c);
|
||||
}
|
||||
}
|
||||
|
||||
final(a,b,c);
|
||||
return NON_ZERO_64(b, c);
|
||||
}
|
||||
#else
|
||||
#define hashlittle2(key, len) hashlittle(key, len)
|
||||
#endif
|
||||
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
173
hlink.c
173
hlink.c
@@ -4,7 +4,7 @@
|
||||
* Copyright (C) 1996 Andrew Tridgell
|
||||
* Copyright (C) 1996 Paul Mackerras
|
||||
* Copyright (C) 2002 Martin Pool <mbp@samba.org>
|
||||
* Copyright (C) 2004-2022 Wayne Davison
|
||||
* Copyright (C) 2004-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
|
||||
@@ -21,23 +21,22 @@
|
||||
*/
|
||||
|
||||
#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 +47,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 +56,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 +110,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 +184,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 +204,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 +216,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 +268,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 +286,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 +305,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 +321,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 +330,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 +338,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 +354,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,26 +365,28 @@ 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
|
||||
do {
|
||||
pathjoin(cmpbuf, MAXPATHLEN, basis_dir[j], fname);
|
||||
if (link_stat(cmpbuf, &alt_sx.st, 0) < 0)
|
||||
continue;
|
||||
if (alt_dest_type == LINK_DEST) {
|
||||
if (link_dest) {
|
||||
if (prev_st.st_dev != alt_sx.st.st_dev
|
||||
|| prev_st.st_ino != alt_sx.st.st_ino)
|
||||
continue;
|
||||
statret = 1;
|
||||
if (stdout_format_has_i == 0
|
||||
|| (!INFO_GTE(NAME, 2) && stdout_format_has_i < 2)) {
|
||||
|| (verbose < 2 && stdout_format_has_i < 2)) {
|
||||
itemizing = 0;
|
||||
code = FNONE;
|
||||
if (INFO_GTE(NAME, 2) && maybe_ATTRS_REPORT)
|
||||
if (verbose > 1 && maybe_ATTRS_REPORT)
|
||||
rprintf(FCLIENT, "%s is uptodate\n", fname);
|
||||
}
|
||||
break;
|
||||
}
|
||||
if (!quick_check_ok(FT_REG, cmpbuf, file, &alt_sx.st))
|
||||
if (!unchanged_file(cmpbuf, file, &alt_sx.st))
|
||||
continue;
|
||||
statret = 1;
|
||||
if (unchanged_attrs(cmpbuf, file, &alt_sx))
|
||||
@@ -416,29 +396,19 @@ int hard_link_check(struct file_struct *file, int ndx, char *fname,
|
||||
sxp->st = alt_sx.st;
|
||||
#ifdef SUPPORT_ACLS
|
||||
if (preserve_acls && !S_ISLNK(file->mode)) {
|
||||
free_acl(sxp);
|
||||
if (!ACL_READY(alt_sx))
|
||||
if (!ACL_READY(*sxp))
|
||||
get_acl(cmpbuf, sxp);
|
||||
else {
|
||||
sxp->acc_acl = alt_sx.acc_acl;
|
||||
sxp->def_acl = alt_sx.def_acl;
|
||||
alt_sx.acc_acl = alt_sx.def_acl = NULL;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
#ifdef SUPPORT_XATTRS
|
||||
if (preserve_xattrs) {
|
||||
free_xattr(sxp);
|
||||
if (!XATTR_READY(alt_sx))
|
||||
get_xattr(cmpbuf, sxp);
|
||||
else {
|
||||
sxp->xattr = alt_sx.xattr;
|
||||
alt_sx.xattr = NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
#ifdef SUPPORT_ACLS
|
||||
else if (preserve_acls)
|
||||
free_acl(&alt_sx);
|
||||
#endif
|
||||
} else
|
||||
free_stat_x(&alt_sx);
|
||||
}
|
||||
|
||||
if (maybe_hard_link(file, ndx, fname, statret, sxp, prev_name, &prev_st,
|
||||
@@ -446,7 +416,7 @@ int hard_link_check(struct file_struct *file, int ndx, char *fname,
|
||||
return -1;
|
||||
|
||||
if (remove_source_files == 1 && do_xfers)
|
||||
send_msg_success(fname, ndx);
|
||||
send_msg_int(MSG_SUCCESS, ndx);
|
||||
|
||||
return 1;
|
||||
}
|
||||
@@ -457,7 +427,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 +454,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 +472,9 @@ 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
|
||||
|
||||
while ((ndx = prev_ndx) >= 0) {
|
||||
int val;
|
||||
@@ -515,31 +487,24 @@ 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
|
||||
if (val < 0)
|
||||
continue;
|
||||
if (remove_source_files == 1 && do_xfers)
|
||||
send_msg_success(fname, ndx);
|
||||
send_msg_int(MSG_SUCCESS, ndx);
|
||||
}
|
||||
|
||||
if (inc_recurse) {
|
||||
int gnum = F_HL_GNUM(file);
|
||||
struct ht_int32_node *node = hashtable_find(prior_hlinks, gnum, NULL);
|
||||
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");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
78
ifuncs.h
78
ifuncs.h
@@ -1,6 +1,6 @@
|
||||
/* Inline functions for rsync.
|
||||
*
|
||||
* Copyright (C) 2007-2022 Wayne Davison
|
||||
* Copyright (C) 2007-2008 Wayne Davison
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
@@ -19,7 +19,8 @@
|
||||
static inline void
|
||||
alloc_xbuf(xbuf *xb, size_t sz)
|
||||
{
|
||||
xb->buf = new_array(char, sz);
|
||||
if (!(xb->buf = new_array(char, sz)))
|
||||
out_of_memory("alloc_xbuf");
|
||||
xb->size = sz;
|
||||
xb->len = xb->pos = 0;
|
||||
}
|
||||
@@ -28,18 +29,12 @@ static inline void
|
||||
realloc_xbuf(xbuf *xb, size_t sz)
|
||||
{
|
||||
char *bf = realloc_array(xb->buf, char, sz);
|
||||
if (!bf)
|
||||
out_of_memory("realloc_xbuf");
|
||||
xb->buf = bf;
|
||||
xb->size = sz;
|
||||
}
|
||||
|
||||
static inline void
|
||||
free_xbuf(xbuf *xb)
|
||||
{
|
||||
if (xb->buf)
|
||||
free(xb->buf);
|
||||
memset(xb, 0, sizeof (xbuf));
|
||||
}
|
||||
|
||||
static inline int
|
||||
to_wire_mode(mode_t mode)
|
||||
{
|
||||
@@ -72,41 +67,44 @@ d_name(struct dirent *di)
|
||||
#endif
|
||||
}
|
||||
|
||||
static inline void
|
||||
init_stat_x(stat_x *sx_p)
|
||||
static inline int
|
||||
isDigit(const char *ptr)
|
||||
{
|
||||
sx_p->crtime = 0;
|
||||
#ifdef SUPPORT_ACLS
|
||||
sx_p->acc_acl = sx_p->def_acl = NULL;
|
||||
#endif
|
||||
#ifdef SUPPORT_XATTRS
|
||||
sx_p->xattr = NULL;
|
||||
#endif
|
||||
return isdigit(*(unsigned char *)ptr);
|
||||
}
|
||||
|
||||
static inline void
|
||||
free_stat_x(stat_x *sx_p)
|
||||
static inline int
|
||||
isPrint(const char *ptr)
|
||||
{
|
||||
#ifdef SUPPORT_ACLS
|
||||
{
|
||||
extern int preserve_acls;
|
||||
if (preserve_acls)
|
||||
free_acl(sx_p);
|
||||
}
|
||||
#endif
|
||||
#ifdef SUPPORT_XATTRS
|
||||
{
|
||||
extern int preserve_xattrs;
|
||||
if (preserve_xattrs)
|
||||
free_xattr(sx_p);
|
||||
}
|
||||
#endif
|
||||
return isprint(*(unsigned char *)ptr);
|
||||
}
|
||||
|
||||
static inline char *my_strdup(const char *str, const char *file, int line)
|
||||
static inline int
|
||||
isSpace(const char *ptr)
|
||||
{
|
||||
int len = strlen(str)+1;
|
||||
char *buf = my_alloc(NULL, len, 1, file, line);
|
||||
memcpy(buf, str, len);
|
||||
return buf;
|
||||
return isspace(*(unsigned char *)ptr);
|
||||
}
|
||||
|
||||
static inline int
|
||||
isLower(const char *ptr)
|
||||
{
|
||||
return islower(*(unsigned char *)ptr);
|
||||
}
|
||||
|
||||
static inline int
|
||||
isUpper(const char *ptr)
|
||||
{
|
||||
return isupper(*(unsigned char *)ptr);
|
||||
}
|
||||
|
||||
static inline int
|
||||
toLower(const char *ptr)
|
||||
{
|
||||
return tolower(*(unsigned char *)ptr);
|
||||
}
|
||||
|
||||
static inline int
|
||||
toUpper(const char *ptr)
|
||||
{
|
||||
return toupper(*(unsigned char *)ptr);
|
||||
}
|
||||
|
||||
@@ -115,7 +115,7 @@ else
|
||||
# might cause directories to be created, which would be especially bad
|
||||
# if $src (and thus $dsttmp) contains '*'.
|
||||
|
||||
if [ -f $src ] || [ -d $src ]
|
||||
if [ -f $src -o -d $src ]
|
||||
then
|
||||
true
|
||||
else
|
||||
|
||||
57
inums.h
57
inums.h
@@ -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);
|
||||
}
|
||||
2
io.h
2
io.h
@@ -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
|
||||
|
||||
71
itypes.h
71
itypes.h
@@ -1,71 +0,0 @@
|
||||
/* Inline functions for rsync.
|
||||
*
|
||||
* Copyright (C) 2007-2022 Wayne Davison
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, visit the http://fsf.org website.
|
||||
*/
|
||||
|
||||
static inline int
|
||||
isDigit(const char *ptr)
|
||||
{
|
||||
return isdigit(*(unsigned char *)ptr);
|
||||
}
|
||||
|
||||
static inline int
|
||||
isHexDigit(const char *ptr)
|
||||
{
|
||||
return isxdigit(*(unsigned char *)ptr);
|
||||
}
|
||||
|
||||
static inline int
|
||||
isPrint(const char *ptr)
|
||||
{
|
||||
return isprint(*(unsigned char *)ptr);
|
||||
}
|
||||
|
||||
static inline int
|
||||
isSpace(const char *ptr)
|
||||
{
|
||||
return isspace(*(unsigned char *)ptr);
|
||||
}
|
||||
|
||||
static inline int
|
||||
isAlNum(const char *ptr)
|
||||
{
|
||||
return isalnum(*(unsigned char *)ptr);
|
||||
}
|
||||
|
||||
static inline int
|
||||
isLower(const char *ptr)
|
||||
{
|
||||
return islower(*(unsigned char *)ptr);
|
||||
}
|
||||
|
||||
static inline int
|
||||
isUpper(const char *ptr)
|
||||
{
|
||||
return isupper(*(unsigned char *)ptr);
|
||||
}
|
||||
|
||||
static inline int
|
||||
toLower(const char *ptr)
|
||||
{
|
||||
return tolower(*(unsigned char *)ptr);
|
||||
}
|
||||
|
||||
static inline int
|
||||
toUpper(const char *ptr)
|
||||
{
|
||||
return toupper(*(unsigned char *)ptr);
|
||||
}
|
||||
@@ -1 +0,0 @@
|
||||
#define LATEST_YEAR "2024"
|
||||
139
lib/compat.c
139
lib/compat.c
@@ -3,7 +3,7 @@
|
||||
*
|
||||
* Copyright (C) 1998 Andrew Tridgell
|
||||
* Copyright (C) 2002 Martin Pool
|
||||
* Copyright (C) 2004-2020 Wayne Davison
|
||||
* Copyright (C) 2004, 2005, 2006 Wayne Davison
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
@@ -20,28 +20,17 @@
|
||||
*/
|
||||
|
||||
#include "rsync.h"
|
||||
#include "itypes.h"
|
||||
|
||||
static char number_separator;
|
||||
|
||||
char get_number_separator(void)
|
||||
#ifndef HAVE_STRDUP
|
||||
char *strdup(char *s)
|
||||
{
|
||||
if (!number_separator) {
|
||||
char buf[32];
|
||||
snprintf(buf, sizeof buf, "%f", 3.14);
|
||||
if (strchr(buf, '.') != NULL)
|
||||
number_separator = ',';
|
||||
else
|
||||
number_separator = '.';
|
||||
}
|
||||
|
||||
return number_separator;
|
||||
}
|
||||
|
||||
char get_decimal_point(void)
|
||||
{
|
||||
return get_number_separator() == ',' ? '.' : ',';
|
||||
int len = strlen(s) + 1;
|
||||
char *ret = (char *)malloc(len);
|
||||
if (ret)
|
||||
memcpy(ret, s, len);
|
||||
return ret;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifndef HAVE_GETCWD
|
||||
char *getcwd(char *buf, int size)
|
||||
@@ -87,7 +76,7 @@ char get_decimal_point(void)
|
||||
|
||||
#ifndef HAVE_STRPBRK
|
||||
/**
|
||||
* Find the first occurrence in @p s of any character in @p accept.
|
||||
* Find the first ocurrence in @p s of any character in @p accept.
|
||||
*
|
||||
* Derived from glibc
|
||||
**/
|
||||
@@ -162,111 +151,3 @@ int sys_gettimeofday(struct timeval *tv)
|
||||
return gettimeofday(tv);
|
||||
#endif
|
||||
}
|
||||
|
||||
/* Return the int64 number as a string. If the human_flag arg is non-zero,
|
||||
* we may output the number in K, M, G, or T units. If we don't add a unit
|
||||
* suffix, we will append the fract string, if it is non-NULL. We can
|
||||
* return up to 4 buffers at a time. */
|
||||
char *do_big_num(int64 num, int human_flag, const char *fract)
|
||||
{
|
||||
static char bufs[4][128]; /* more than enough room */
|
||||
static unsigned int n;
|
||||
char *s;
|
||||
int len, negated;
|
||||
|
||||
if (human_flag && !number_separator)
|
||||
(void)get_number_separator();
|
||||
|
||||
n = (n + 1) % (sizeof bufs / sizeof bufs[0]);
|
||||
|
||||
if (human_flag > 1) {
|
||||
int mult = human_flag == 2 ? 1000 : 1024;
|
||||
if (num >= mult || num <= -mult) {
|
||||
double dnum = (double)num / mult;
|
||||
char units;
|
||||
if (num < 0)
|
||||
dnum = -dnum;
|
||||
if (dnum < mult)
|
||||
units = 'K';
|
||||
else if ((dnum /= mult) < mult)
|
||||
units = 'M';
|
||||
else if ((dnum /= mult) < mult)
|
||||
units = 'G';
|
||||
else if ((dnum /= mult) < mult)
|
||||
units = 'T';
|
||||
else {
|
||||
dnum /= mult;
|
||||
units = 'P';
|
||||
}
|
||||
if (num < 0)
|
||||
dnum = -dnum;
|
||||
snprintf(bufs[n], sizeof bufs[0], "%.2f%c", dnum, units);
|
||||
return bufs[n];
|
||||
}
|
||||
}
|
||||
|
||||
s = bufs[n] + sizeof bufs[0] - 1;
|
||||
if (fract) {
|
||||
len = strlen(fract);
|
||||
s -= len;
|
||||
strlcpy(s, fract, len + 1);
|
||||
} else
|
||||
*s = '\0';
|
||||
|
||||
len = 0;
|
||||
|
||||
if (!num)
|
||||
*--s = '0';
|
||||
if (num < 0) {
|
||||
/* A maximum-size negated number can't fit as a positive,
|
||||
* so do one digit in negated form to start us off. */
|
||||
*--s = (char)(-(num % 10)) + '0';
|
||||
num = -(num / 10);
|
||||
len++;
|
||||
negated = 1;
|
||||
} else
|
||||
negated = 0;
|
||||
|
||||
while (num) {
|
||||
if (human_flag) {
|
||||
if (len == 3) {
|
||||
*--s = number_separator;
|
||||
len = 1;
|
||||
} else
|
||||
len++;
|
||||
}
|
||||
*--s = (char)(num % 10) + '0';
|
||||
num /= 10;
|
||||
}
|
||||
|
||||
if (negated)
|
||||
*--s = '-';
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
/* Return the double number as a string. If the human_flag option is > 1,
|
||||
* we may output the number in K, M, G, or T units. The buffer we use for
|
||||
* our result is either a single static buffer defined here, or a buffer
|
||||
* we get from do_big_num(). */
|
||||
char *do_big_dnum(double dnum, int human_flag, int decimal_digits)
|
||||
{
|
||||
static char tmp_buf[128];
|
||||
#if SIZEOF_INT64 >= 8
|
||||
char *fract;
|
||||
|
||||
snprintf(tmp_buf, sizeof tmp_buf, "%.*f", decimal_digits, dnum);
|
||||
|
||||
if (!human_flag || (dnum < 1000.0 && dnum > -1000.0))
|
||||
return tmp_buf;
|
||||
|
||||
for (fract = tmp_buf+1; isDigit(fract); fract++) {}
|
||||
|
||||
return do_big_num((int64)dnum, human_flag, fract);
|
||||
#else
|
||||
/* A big number might lose digits converting to a too-short int64,
|
||||
* so let's just return the raw double conversion. */
|
||||
snprintf(tmp_buf, sizeof tmp_buf, "%.*f", decimal_digits, dnum);
|
||||
return tmp_buf;
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -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,
|
||||
@@ -491,10 +492,13 @@ int getnameinfo(const struct sockaddr *sa, socklen_t salen,
|
||||
return EAI_FAIL;
|
||||
}
|
||||
|
||||
/* We don't support those. */
|
||||
if ((node && !(flags & NI_NUMERICHOST))
|
||||
|| (service && !(flags & NI_NUMERICSERV)))
|
||||
return EAI_FAIL;
|
||||
|
||||
if (node) {
|
||||
int ret = gethostnameinfo(sa, node, nodelen, flags);
|
||||
if (ret)
|
||||
return ret;
|
||||
return gethostnameinfo(sa, node, nodelen, flags);
|
||||
}
|
||||
|
||||
if (service) {
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
@@ -1,37 +0,0 @@
|
||||
/* Keep this simple so both C and ASM can use it */
|
||||
|
||||
/* These allow something like CFLAGS=-DDISABLE_SHA512_DIGEST */
|
||||
#ifdef DISABLE_SHA256_DIGEST
|
||||
#undef SHA256_DIGEST_LENGTH
|
||||
#endif
|
||||
#ifdef DISABLE_SHA512_DIGEST
|
||||
#undef SHA512_DIGEST_LENGTH
|
||||
#endif
|
||||
|
||||
#define MD4_DIGEST_LEN 16
|
||||
#define MD5_DIGEST_LEN 16
|
||||
#if defined SHA512_DIGEST_LENGTH
|
||||
#define MAX_DIGEST_LEN SHA512_DIGEST_LENGTH
|
||||
#elif defined SHA256_DIGEST_LENGTH
|
||||
#define MAX_DIGEST_LEN SHA256_DIGEST_LENGTH
|
||||
#elif defined SHA_DIGEST_LENGTH
|
||||
#define MAX_DIGEST_LEN SHA_DIGEST_LENGTH
|
||||
#else
|
||||
#define MAX_DIGEST_LEN MD5_DIGEST_LEN
|
||||
#endif
|
||||
|
||||
#define CSUM_CHUNK 64
|
||||
|
||||
#define CSUM_gone -1
|
||||
#define CSUM_NONE 0
|
||||
#define CSUM_MD4_ARCHAIC 1
|
||||
#define CSUM_MD4_BUSTED 2
|
||||
#define CSUM_MD4_OLD 3
|
||||
#define CSUM_MD4 4
|
||||
#define CSUM_MD5 5
|
||||
#define CSUM_XXH64 6
|
||||
#define CSUM_XXH3_64 7
|
||||
#define CSUM_XXH3_128 8
|
||||
#define CSUM_SHA1 9
|
||||
#define CSUM_SHA256 10
|
||||
#define CSUM_SHA512 11
|
||||
@@ -1,701 +0,0 @@
|
||||
/*
|
||||
* x86-64 optimized assembler MD5 implementation
|
||||
*
|
||||
* Author: Marc Bevand, 2004
|
||||
*
|
||||
* This code was placed in the public domain by the author. The original
|
||||
* publication can be found at:
|
||||
*
|
||||
* https://www.zorinaq.com/papers/md5-amd64.html
|
||||
*/
|
||||
/*
|
||||
* No modifications were made aside from changing the function and file names.
|
||||
* The MD5_CTX structure as expected here (from OpenSSL) is binary compatible
|
||||
* with the md_context used by rsync, for the fields accessed.
|
||||
*
|
||||
* Benchmarks (in MB/s) C ASM
|
||||
* - Intel Atom D2700 302 334
|
||||
* - Intel i7-7700hq 351 376
|
||||
* - AMD ThreadRipper 2950x 728 784
|
||||
*
|
||||
* The original code was also incorporated into OpenSSL. It has since been
|
||||
* modified there. Those changes have not been made here due to licensing
|
||||
* incompatibilities. Benchmarks of those changes on the above CPUs did not
|
||||
* show any significant difference in performance, though.
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
#include "md-defines.h"
|
||||
|
||||
#ifdef USE_MD5_ASM /* { */
|
||||
|
||||
#ifdef __APPLE__
|
||||
#define md5_process_asm _md5_process_asm
|
||||
#endif
|
||||
|
||||
.text
|
||||
.align 16
|
||||
|
||||
.globl md5_process_asm
|
||||
md5_process_asm:
|
||||
push %rbp
|
||||
push %rbx
|
||||
push %r12
|
||||
push %r13 # not really useful (r13 is unused)
|
||||
push %r14
|
||||
push %r15
|
||||
|
||||
# rdi = arg #1 (ctx, MD5_CTX pointer)
|
||||
# rsi = arg #2 (ptr, data pointer)
|
||||
# rdx = arg #3 (nbr, number of 16-word blocks to process)
|
||||
mov %rdi, %rbp # rbp = ctx
|
||||
shl $6, %rdx # rdx = nbr in bytes
|
||||
lea (%rsi,%rdx), %rdi # rdi = end
|
||||
mov 0*4(%rbp), %eax # eax = ctx->A
|
||||
mov 1*4(%rbp), %ebx # ebx = ctx->B
|
||||
mov 2*4(%rbp), %ecx # ecx = ctx->C
|
||||
mov 3*4(%rbp), %edx # edx = ctx->D
|
||||
# end is 'rdi'
|
||||
# ptr is 'rsi'
|
||||
# A is 'eax'
|
||||
# B is 'ebx'
|
||||
# C is 'ecx'
|
||||
# D is 'edx'
|
||||
|
||||
cmp %rdi, %rsi # cmp end with ptr
|
||||
je 1f # jmp if ptr == end
|
||||
|
||||
# BEGIN of loop over 16-word blocks
|
||||
2: # save old values of A, B, C, D
|
||||
mov %eax, %r8d
|
||||
mov %ebx, %r9d
|
||||
mov %ecx, %r14d
|
||||
mov %edx, %r15d
|
||||
mov 0*4(%rsi), %r10d /* (NEXT STEP) X[0] */
|
||||
mov %edx, %r11d /* (NEXT STEP) z' = %edx */
|
||||
xor %ecx, %r11d /* y ^ ... */
|
||||
lea -680876936(%eax,%r10d),%eax /* Const + dst + ... */
|
||||
and %ebx, %r11d /* x & ... */
|
||||
xor %edx, %r11d /* z ^ ... */
|
||||
mov 1*4(%rsi),%r10d /* (NEXT STEP) X[1] */
|
||||
add %r11d, %eax /* dst += ... */
|
||||
rol $7, %eax /* dst <<< s */
|
||||
mov %ecx, %r11d /* (NEXT STEP) z' = %ecx */
|
||||
add %ebx, %eax /* dst += x */
|
||||
xor %ebx, %r11d /* y ^ ... */
|
||||
lea -389564586(%edx,%r10d),%edx /* Const + dst + ... */
|
||||
and %eax, %r11d /* x & ... */
|
||||
xor %ecx, %r11d /* z ^ ... */
|
||||
mov 2*4(%rsi),%r10d /* (NEXT STEP) X[2] */
|
||||
add %r11d, %edx /* dst += ... */
|
||||
rol $12, %edx /* dst <<< s */
|
||||
mov %ebx, %r11d /* (NEXT STEP) z' = %ebx */
|
||||
add %eax, %edx /* dst += x */
|
||||
xor %eax, %r11d /* y ^ ... */
|
||||
lea 606105819(%ecx,%r10d),%ecx /* Const + dst + ... */
|
||||
and %edx, %r11d /* x & ... */
|
||||
xor %ebx, %r11d /* z ^ ... */
|
||||
mov 3*4(%rsi),%r10d /* (NEXT STEP) X[3] */
|
||||
add %r11d, %ecx /* dst += ... */
|
||||
rol $17, %ecx /* dst <<< s */
|
||||
mov %eax, %r11d /* (NEXT STEP) z' = %eax */
|
||||
add %edx, %ecx /* dst += x */
|
||||
xor %edx, %r11d /* y ^ ... */
|
||||
lea -1044525330(%ebx,%r10d),%ebx /* Const + dst + ... */
|
||||
and %ecx, %r11d /* x & ... */
|
||||
xor %eax, %r11d /* z ^ ... */
|
||||
mov 4*4(%rsi),%r10d /* (NEXT STEP) X[4] */
|
||||
add %r11d, %ebx /* dst += ... */
|
||||
rol $22, %ebx /* dst <<< s */
|
||||
mov %edx, %r11d /* (NEXT STEP) z' = %edx */
|
||||
add %ecx, %ebx /* dst += x */
|
||||
xor %ecx, %r11d /* y ^ ... */
|
||||
lea -176418897(%eax,%r10d),%eax /* Const + dst + ... */
|
||||
and %ebx, %r11d /* x & ... */
|
||||
xor %edx, %r11d /* z ^ ... */
|
||||
mov 5*4(%rsi),%r10d /* (NEXT STEP) X[5] */
|
||||
add %r11d, %eax /* dst += ... */
|
||||
rol $7, %eax /* dst <<< s */
|
||||
mov %ecx, %r11d /* (NEXT STEP) z' = %ecx */
|
||||
add %ebx, %eax /* dst += x */
|
||||
xor %ebx, %r11d /* y ^ ... */
|
||||
lea 1200080426(%edx,%r10d),%edx /* Const + dst + ... */
|
||||
and %eax, %r11d /* x & ... */
|
||||
xor %ecx, %r11d /* z ^ ... */
|
||||
mov 6*4(%rsi),%r10d /* (NEXT STEP) X[6] */
|
||||
add %r11d, %edx /* dst += ... */
|
||||
rol $12, %edx /* dst <<< s */
|
||||
mov %ebx, %r11d /* (NEXT STEP) z' = %ebx */
|
||||
add %eax, %edx /* dst += x */
|
||||
xor %eax, %r11d /* y ^ ... */
|
||||
lea -1473231341(%ecx,%r10d),%ecx /* Const + dst + ... */
|
||||
and %edx, %r11d /* x & ... */
|
||||
xor %ebx, %r11d /* z ^ ... */
|
||||
mov 7*4(%rsi),%r10d /* (NEXT STEP) X[7] */
|
||||
add %r11d, %ecx /* dst += ... */
|
||||
rol $17, %ecx /* dst <<< s */
|
||||
mov %eax, %r11d /* (NEXT STEP) z' = %eax */
|
||||
add %edx, %ecx /* dst += x */
|
||||
xor %edx, %r11d /* y ^ ... */
|
||||
lea -45705983(%ebx,%r10d),%ebx /* Const + dst + ... */
|
||||
and %ecx, %r11d /* x & ... */
|
||||
xor %eax, %r11d /* z ^ ... */
|
||||
mov 8*4(%rsi),%r10d /* (NEXT STEP) X[8] */
|
||||
add %r11d, %ebx /* dst += ... */
|
||||
rol $22, %ebx /* dst <<< s */
|
||||
mov %edx, %r11d /* (NEXT STEP) z' = %edx */
|
||||
add %ecx, %ebx /* dst += x */
|
||||
xor %ecx, %r11d /* y ^ ... */
|
||||
lea 1770035416(%eax,%r10d),%eax /* Const + dst + ... */
|
||||
and %ebx, %r11d /* x & ... */
|
||||
xor %edx, %r11d /* z ^ ... */
|
||||
mov 9*4(%rsi),%r10d /* (NEXT STEP) X[9] */
|
||||
add %r11d, %eax /* dst += ... */
|
||||
rol $7, %eax /* dst <<< s */
|
||||
mov %ecx, %r11d /* (NEXT STEP) z' = %ecx */
|
||||
add %ebx, %eax /* dst += x */
|
||||
xor %ebx, %r11d /* y ^ ... */
|
||||
lea -1958414417(%edx,%r10d),%edx /* Const + dst + ... */
|
||||
and %eax, %r11d /* x & ... */
|
||||
xor %ecx, %r11d /* z ^ ... */
|
||||
mov 10*4(%rsi),%r10d /* (NEXT STEP) X[10] */
|
||||
add %r11d, %edx /* dst += ... */
|
||||
rol $12, %edx /* dst <<< s */
|
||||
mov %ebx, %r11d /* (NEXT STEP) z' = %ebx */
|
||||
add %eax, %edx /* dst += x */
|
||||
xor %eax, %r11d /* y ^ ... */
|
||||
lea -42063(%ecx,%r10d),%ecx /* Const + dst + ... */
|
||||
and %edx, %r11d /* x & ... */
|
||||
xor %ebx, %r11d /* z ^ ... */
|
||||
mov 11*4(%rsi),%r10d /* (NEXT STEP) X[11] */
|
||||
add %r11d, %ecx /* dst += ... */
|
||||
rol $17, %ecx /* dst <<< s */
|
||||
mov %eax, %r11d /* (NEXT STEP) z' = %eax */
|
||||
add %edx, %ecx /* dst += x */
|
||||
xor %edx, %r11d /* y ^ ... */
|
||||
lea -1990404162(%ebx,%r10d),%ebx /* Const + dst + ... */
|
||||
and %ecx, %r11d /* x & ... */
|
||||
xor %eax, %r11d /* z ^ ... */
|
||||
mov 12*4(%rsi),%r10d /* (NEXT STEP) X[12] */
|
||||
add %r11d, %ebx /* dst += ... */
|
||||
rol $22, %ebx /* dst <<< s */
|
||||
mov %edx, %r11d /* (NEXT STEP) z' = %edx */
|
||||
add %ecx, %ebx /* dst += x */
|
||||
xor %ecx, %r11d /* y ^ ... */
|
||||
lea 1804603682(%eax,%r10d),%eax /* Const + dst + ... */
|
||||
and %ebx, %r11d /* x & ... */
|
||||
xor %edx, %r11d /* z ^ ... */
|
||||
mov 13*4(%rsi),%r10d /* (NEXT STEP) X[13] */
|
||||
add %r11d, %eax /* dst += ... */
|
||||
rol $7, %eax /* dst <<< s */
|
||||
mov %ecx, %r11d /* (NEXT STEP) z' = %ecx */
|
||||
add %ebx, %eax /* dst += x */
|
||||
xor %ebx, %r11d /* y ^ ... */
|
||||
lea -40341101(%edx,%r10d),%edx /* Const + dst + ... */
|
||||
and %eax, %r11d /* x & ... */
|
||||
xor %ecx, %r11d /* z ^ ... */
|
||||
mov 14*4(%rsi),%r10d /* (NEXT STEP) X[14] */
|
||||
add %r11d, %edx /* dst += ... */
|
||||
rol $12, %edx /* dst <<< s */
|
||||
mov %ebx, %r11d /* (NEXT STEP) z' = %ebx */
|
||||
add %eax, %edx /* dst += x */
|
||||
xor %eax, %r11d /* y ^ ... */
|
||||
lea -1502002290(%ecx,%r10d),%ecx /* Const + dst + ... */
|
||||
and %edx, %r11d /* x & ... */
|
||||
xor %ebx, %r11d /* z ^ ... */
|
||||
mov 15*4(%rsi),%r10d /* (NEXT STEP) X[15] */
|
||||
add %r11d, %ecx /* dst += ... */
|
||||
rol $17, %ecx /* dst <<< s */
|
||||
mov %eax, %r11d /* (NEXT STEP) z' = %eax */
|
||||
add %edx, %ecx /* dst += x */
|
||||
xor %edx, %r11d /* y ^ ... */
|
||||
lea 1236535329(%ebx,%r10d),%ebx /* Const + dst + ... */
|
||||
and %ecx, %r11d /* x & ... */
|
||||
xor %eax, %r11d /* z ^ ... */
|
||||
mov 0*4(%rsi),%r10d /* (NEXT STEP) X[0] */
|
||||
add %r11d, %ebx /* dst += ... */
|
||||
rol $22, %ebx /* dst <<< s */
|
||||
mov %edx, %r11d /* (NEXT STEP) z' = %edx */
|
||||
add %ecx, %ebx /* dst += x */
|
||||
mov 1*4(%rsi), %r10d /* (NEXT STEP) X[1] */
|
||||
mov %edx, %r11d /* (NEXT STEP) z' = %edx */
|
||||
mov %edx, %r12d /* (NEXT STEP) z' = %edx */
|
||||
not %r11d /* not z */
|
||||
lea -165796510(%eax,%r10d),%eax /* Const + dst + ... */
|
||||
and %ebx, %r12d /* x & z */
|
||||
and %ecx, %r11d /* y & (not z) */
|
||||
mov 6*4(%rsi),%r10d /* (NEXT STEP) X[6] */
|
||||
or %r11d, %r12d /* (y & (not z)) | (x & z) */
|
||||
mov %ecx, %r11d /* (NEXT STEP) z' = %ecx */
|
||||
add %r12d, %eax /* dst += ... */
|
||||
mov %ecx, %r12d /* (NEXT STEP) z' = %ecx */
|
||||
rol $5, %eax /* dst <<< s */
|
||||
add %ebx, %eax /* dst += x */
|
||||
not %r11d /* not z */
|
||||
lea -1069501632(%edx,%r10d),%edx /* Const + dst + ... */
|
||||
and %eax, %r12d /* x & z */
|
||||
and %ebx, %r11d /* y & (not z) */
|
||||
mov 11*4(%rsi),%r10d /* (NEXT STEP) X[11] */
|
||||
or %r11d, %r12d /* (y & (not z)) | (x & z) */
|
||||
mov %ebx, %r11d /* (NEXT STEP) z' = %ebx */
|
||||
add %r12d, %edx /* dst += ... */
|
||||
mov %ebx, %r12d /* (NEXT STEP) z' = %ebx */
|
||||
rol $9, %edx /* dst <<< s */
|
||||
add %eax, %edx /* dst += x */
|
||||
not %r11d /* not z */
|
||||
lea 643717713(%ecx,%r10d),%ecx /* Const + dst + ... */
|
||||
and %edx, %r12d /* x & z */
|
||||
and %eax, %r11d /* y & (not z) */
|
||||
mov 0*4(%rsi),%r10d /* (NEXT STEP) X[0] */
|
||||
or %r11d, %r12d /* (y & (not z)) | (x & z) */
|
||||
mov %eax, %r11d /* (NEXT STEP) z' = %eax */
|
||||
add %r12d, %ecx /* dst += ... */
|
||||
mov %eax, %r12d /* (NEXT STEP) z' = %eax */
|
||||
rol $14, %ecx /* dst <<< s */
|
||||
add %edx, %ecx /* dst += x */
|
||||
not %r11d /* not z */
|
||||
lea -373897302(%ebx,%r10d),%ebx /* Const + dst + ... */
|
||||
and %ecx, %r12d /* x & z */
|
||||
and %edx, %r11d /* y & (not z) */
|
||||
mov 5*4(%rsi),%r10d /* (NEXT STEP) X[5] */
|
||||
or %r11d, %r12d /* (y & (not z)) | (x & z) */
|
||||
mov %edx, %r11d /* (NEXT STEP) z' = %edx */
|
||||
add %r12d, %ebx /* dst += ... */
|
||||
mov %edx, %r12d /* (NEXT STEP) z' = %edx */
|
||||
rol $20, %ebx /* dst <<< s */
|
||||
add %ecx, %ebx /* dst += x */
|
||||
not %r11d /* not z */
|
||||
lea -701558691(%eax,%r10d),%eax /* Const + dst + ... */
|
||||
and %ebx, %r12d /* x & z */
|
||||
and %ecx, %r11d /* y & (not z) */
|
||||
mov 10*4(%rsi),%r10d /* (NEXT STEP) X[10] */
|
||||
or %r11d, %r12d /* (y & (not z)) | (x & z) */
|
||||
mov %ecx, %r11d /* (NEXT STEP) z' = %ecx */
|
||||
add %r12d, %eax /* dst += ... */
|
||||
mov %ecx, %r12d /* (NEXT STEP) z' = %ecx */
|
||||
rol $5, %eax /* dst <<< s */
|
||||
add %ebx, %eax /* dst += x */
|
||||
not %r11d /* not z */
|
||||
lea 38016083(%edx,%r10d),%edx /* Const + dst + ... */
|
||||
and %eax, %r12d /* x & z */
|
||||
and %ebx, %r11d /* y & (not z) */
|
||||
mov 15*4(%rsi),%r10d /* (NEXT STEP) X[15] */
|
||||
or %r11d, %r12d /* (y & (not z)) | (x & z) */
|
||||
mov %ebx, %r11d /* (NEXT STEP) z' = %ebx */
|
||||
add %r12d, %edx /* dst += ... */
|
||||
mov %ebx, %r12d /* (NEXT STEP) z' = %ebx */
|
||||
rol $9, %edx /* dst <<< s */
|
||||
add %eax, %edx /* dst += x */
|
||||
not %r11d /* not z */
|
||||
lea -660478335(%ecx,%r10d),%ecx /* Const + dst + ... */
|
||||
and %edx, %r12d /* x & z */
|
||||
and %eax, %r11d /* y & (not z) */
|
||||
mov 4*4(%rsi),%r10d /* (NEXT STEP) X[4] */
|
||||
or %r11d, %r12d /* (y & (not z)) | (x & z) */
|
||||
mov %eax, %r11d /* (NEXT STEP) z' = %eax */
|
||||
add %r12d, %ecx /* dst += ... */
|
||||
mov %eax, %r12d /* (NEXT STEP) z' = %eax */
|
||||
rol $14, %ecx /* dst <<< s */
|
||||
add %edx, %ecx /* dst += x */
|
||||
not %r11d /* not z */
|
||||
lea -405537848(%ebx,%r10d),%ebx /* Const + dst + ... */
|
||||
and %ecx, %r12d /* x & z */
|
||||
and %edx, %r11d /* y & (not z) */
|
||||
mov 9*4(%rsi),%r10d /* (NEXT STEP) X[9] */
|
||||
or %r11d, %r12d /* (y & (not z)) | (x & z) */
|
||||
mov %edx, %r11d /* (NEXT STEP) z' = %edx */
|
||||
add %r12d, %ebx /* dst += ... */
|
||||
mov %edx, %r12d /* (NEXT STEP) z' = %edx */
|
||||
rol $20, %ebx /* dst <<< s */
|
||||
add %ecx, %ebx /* dst += x */
|
||||
not %r11d /* not z */
|
||||
lea 568446438(%eax,%r10d),%eax /* Const + dst + ... */
|
||||
and %ebx, %r12d /* x & z */
|
||||
and %ecx, %r11d /* y & (not z) */
|
||||
mov 14*4(%rsi),%r10d /* (NEXT STEP) X[14] */
|
||||
or %r11d, %r12d /* (y & (not z)) | (x & z) */
|
||||
mov %ecx, %r11d /* (NEXT STEP) z' = %ecx */
|
||||
add %r12d, %eax /* dst += ... */
|
||||
mov %ecx, %r12d /* (NEXT STEP) z' = %ecx */
|
||||
rol $5, %eax /* dst <<< s */
|
||||
add %ebx, %eax /* dst += x */
|
||||
not %r11d /* not z */
|
||||
lea -1019803690(%edx,%r10d),%edx /* Const + dst + ... */
|
||||
and %eax, %r12d /* x & z */
|
||||
and %ebx, %r11d /* y & (not z) */
|
||||
mov 3*4(%rsi),%r10d /* (NEXT STEP) X[3] */
|
||||
or %r11d, %r12d /* (y & (not z)) | (x & z) */
|
||||
mov %ebx, %r11d /* (NEXT STEP) z' = %ebx */
|
||||
add %r12d, %edx /* dst += ... */
|
||||
mov %ebx, %r12d /* (NEXT STEP) z' = %ebx */
|
||||
rol $9, %edx /* dst <<< s */
|
||||
add %eax, %edx /* dst += x */
|
||||
not %r11d /* not z */
|
||||
lea -187363961(%ecx,%r10d),%ecx /* Const + dst + ... */
|
||||
and %edx, %r12d /* x & z */
|
||||
and %eax, %r11d /* y & (not z) */
|
||||
mov 8*4(%rsi),%r10d /* (NEXT STEP) X[8] */
|
||||
or %r11d, %r12d /* (y & (not z)) | (x & z) */
|
||||
mov %eax, %r11d /* (NEXT STEP) z' = %eax */
|
||||
add %r12d, %ecx /* dst += ... */
|
||||
mov %eax, %r12d /* (NEXT STEP) z' = %eax */
|
||||
rol $14, %ecx /* dst <<< s */
|
||||
add %edx, %ecx /* dst += x */
|
||||
not %r11d /* not z */
|
||||
lea 1163531501(%ebx,%r10d),%ebx /* Const + dst + ... */
|
||||
and %ecx, %r12d /* x & z */
|
||||
and %edx, %r11d /* y & (not z) */
|
||||
mov 13*4(%rsi),%r10d /* (NEXT STEP) X[13] */
|
||||
or %r11d, %r12d /* (y & (not z)) | (x & z) */
|
||||
mov %edx, %r11d /* (NEXT STEP) z' = %edx */
|
||||
add %r12d, %ebx /* dst += ... */
|
||||
mov %edx, %r12d /* (NEXT STEP) z' = %edx */
|
||||
rol $20, %ebx /* dst <<< s */
|
||||
add %ecx, %ebx /* dst += x */
|
||||
not %r11d /* not z */
|
||||
lea -1444681467(%eax,%r10d),%eax /* Const + dst + ... */
|
||||
and %ebx, %r12d /* x & z */
|
||||
and %ecx, %r11d /* y & (not z) */
|
||||
mov 2*4(%rsi),%r10d /* (NEXT STEP) X[2] */
|
||||
or %r11d, %r12d /* (y & (not z)) | (x & z) */
|
||||
mov %ecx, %r11d /* (NEXT STEP) z' = %ecx */
|
||||
add %r12d, %eax /* dst += ... */
|
||||
mov %ecx, %r12d /* (NEXT STEP) z' = %ecx */
|
||||
rol $5, %eax /* dst <<< s */
|
||||
add %ebx, %eax /* dst += x */
|
||||
not %r11d /* not z */
|
||||
lea -51403784(%edx,%r10d),%edx /* Const + dst + ... */
|
||||
and %eax, %r12d /* x & z */
|
||||
and %ebx, %r11d /* y & (not z) */
|
||||
mov 7*4(%rsi),%r10d /* (NEXT STEP) X[7] */
|
||||
or %r11d, %r12d /* (y & (not z)) | (x & z) */
|
||||
mov %ebx, %r11d /* (NEXT STEP) z' = %ebx */
|
||||
add %r12d, %edx /* dst += ... */
|
||||
mov %ebx, %r12d /* (NEXT STEP) z' = %ebx */
|
||||
rol $9, %edx /* dst <<< s */
|
||||
add %eax, %edx /* dst += x */
|
||||
not %r11d /* not z */
|
||||
lea 1735328473(%ecx,%r10d),%ecx /* Const + dst + ... */
|
||||
and %edx, %r12d /* x & z */
|
||||
and %eax, %r11d /* y & (not z) */
|
||||
mov 12*4(%rsi),%r10d /* (NEXT STEP) X[12] */
|
||||
or %r11d, %r12d /* (y & (not z)) | (x & z) */
|
||||
mov %eax, %r11d /* (NEXT STEP) z' = %eax */
|
||||
add %r12d, %ecx /* dst += ... */
|
||||
mov %eax, %r12d /* (NEXT STEP) z' = %eax */
|
||||
rol $14, %ecx /* dst <<< s */
|
||||
add %edx, %ecx /* dst += x */
|
||||
not %r11d /* not z */
|
||||
lea -1926607734(%ebx,%r10d),%ebx /* Const + dst + ... */
|
||||
and %ecx, %r12d /* x & z */
|
||||
and %edx, %r11d /* y & (not z) */
|
||||
mov 0*4(%rsi),%r10d /* (NEXT STEP) X[0] */
|
||||
or %r11d, %r12d /* (y & (not z)) | (x & z) */
|
||||
mov %edx, %r11d /* (NEXT STEP) z' = %edx */
|
||||
add %r12d, %ebx /* dst += ... */
|
||||
mov %edx, %r12d /* (NEXT STEP) z' = %edx */
|
||||
rol $20, %ebx /* dst <<< s */
|
||||
add %ecx, %ebx /* dst += x */
|
||||
mov 5*4(%rsi), %r10d /* (NEXT STEP) X[5] */
|
||||
mov %ecx, %r11d /* (NEXT STEP) y' = %ecx */
|
||||
lea -378558(%eax,%r10d),%eax /* Const + dst + ... */
|
||||
mov 8*4(%rsi),%r10d /* (NEXT STEP) X[8] */
|
||||
xor %edx, %r11d /* z ^ ... */
|
||||
xor %ebx, %r11d /* x ^ ... */
|
||||
add %r11d, %eax /* dst += ... */
|
||||
rol $4, %eax /* dst <<< s */
|
||||
mov %ebx, %r11d /* (NEXT STEP) y' = %ebx */
|
||||
add %ebx, %eax /* dst += x */
|
||||
lea -2022574463(%edx,%r10d),%edx /* Const + dst + ... */
|
||||
mov 11*4(%rsi),%r10d /* (NEXT STEP) X[11] */
|
||||
xor %ecx, %r11d /* z ^ ... */
|
||||
xor %eax, %r11d /* x ^ ... */
|
||||
add %r11d, %edx /* dst += ... */
|
||||
rol $11, %edx /* dst <<< s */
|
||||
mov %eax, %r11d /* (NEXT STEP) y' = %eax */
|
||||
add %eax, %edx /* dst += x */
|
||||
lea 1839030562(%ecx,%r10d),%ecx /* Const + dst + ... */
|
||||
mov 14*4(%rsi),%r10d /* (NEXT STEP) X[14] */
|
||||
xor %ebx, %r11d /* z ^ ... */
|
||||
xor %edx, %r11d /* x ^ ... */
|
||||
add %r11d, %ecx /* dst += ... */
|
||||
rol $16, %ecx /* dst <<< s */
|
||||
mov %edx, %r11d /* (NEXT STEP) y' = %edx */
|
||||
add %edx, %ecx /* dst += x */
|
||||
lea -35309556(%ebx,%r10d),%ebx /* Const + dst + ... */
|
||||
mov 1*4(%rsi),%r10d /* (NEXT STEP) X[1] */
|
||||
xor %eax, %r11d /* z ^ ... */
|
||||
xor %ecx, %r11d /* x ^ ... */
|
||||
add %r11d, %ebx /* dst += ... */
|
||||
rol $23, %ebx /* dst <<< s */
|
||||
mov %ecx, %r11d /* (NEXT STEP) y' = %ecx */
|
||||
add %ecx, %ebx /* dst += x */
|
||||
lea -1530992060(%eax,%r10d),%eax /* Const + dst + ... */
|
||||
mov 4*4(%rsi),%r10d /* (NEXT STEP) X[4] */
|
||||
xor %edx, %r11d /* z ^ ... */
|
||||
xor %ebx, %r11d /* x ^ ... */
|
||||
add %r11d, %eax /* dst += ... */
|
||||
rol $4, %eax /* dst <<< s */
|
||||
mov %ebx, %r11d /* (NEXT STEP) y' = %ebx */
|
||||
add %ebx, %eax /* dst += x */
|
||||
lea 1272893353(%edx,%r10d),%edx /* Const + dst + ... */
|
||||
mov 7*4(%rsi),%r10d /* (NEXT STEP) X[7] */
|
||||
xor %ecx, %r11d /* z ^ ... */
|
||||
xor %eax, %r11d /* x ^ ... */
|
||||
add %r11d, %edx /* dst += ... */
|
||||
rol $11, %edx /* dst <<< s */
|
||||
mov %eax, %r11d /* (NEXT STEP) y' = %eax */
|
||||
add %eax, %edx /* dst += x */
|
||||
lea -155497632(%ecx,%r10d),%ecx /* Const + dst + ... */
|
||||
mov 10*4(%rsi),%r10d /* (NEXT STEP) X[10] */
|
||||
xor %ebx, %r11d /* z ^ ... */
|
||||
xor %edx, %r11d /* x ^ ... */
|
||||
add %r11d, %ecx /* dst += ... */
|
||||
rol $16, %ecx /* dst <<< s */
|
||||
mov %edx, %r11d /* (NEXT STEP) y' = %edx */
|
||||
add %edx, %ecx /* dst += x */
|
||||
lea -1094730640(%ebx,%r10d),%ebx /* Const + dst + ... */
|
||||
mov 13*4(%rsi),%r10d /* (NEXT STEP) X[13] */
|
||||
xor %eax, %r11d /* z ^ ... */
|
||||
xor %ecx, %r11d /* x ^ ... */
|
||||
add %r11d, %ebx /* dst += ... */
|
||||
rol $23, %ebx /* dst <<< s */
|
||||
mov %ecx, %r11d /* (NEXT STEP) y' = %ecx */
|
||||
add %ecx, %ebx /* dst += x */
|
||||
lea 681279174(%eax,%r10d),%eax /* Const + dst + ... */
|
||||
mov 0*4(%rsi),%r10d /* (NEXT STEP) X[0] */
|
||||
xor %edx, %r11d /* z ^ ... */
|
||||
xor %ebx, %r11d /* x ^ ... */
|
||||
add %r11d, %eax /* dst += ... */
|
||||
rol $4, %eax /* dst <<< s */
|
||||
mov %ebx, %r11d /* (NEXT STEP) y' = %ebx */
|
||||
add %ebx, %eax /* dst += x */
|
||||
lea -358537222(%edx,%r10d),%edx /* Const + dst + ... */
|
||||
mov 3*4(%rsi),%r10d /* (NEXT STEP) X[3] */
|
||||
xor %ecx, %r11d /* z ^ ... */
|
||||
xor %eax, %r11d /* x ^ ... */
|
||||
add %r11d, %edx /* dst += ... */
|
||||
rol $11, %edx /* dst <<< s */
|
||||
mov %eax, %r11d /* (NEXT STEP) y' = %eax */
|
||||
add %eax, %edx /* dst += x */
|
||||
lea -722521979(%ecx,%r10d),%ecx /* Const + dst + ... */
|
||||
mov 6*4(%rsi),%r10d /* (NEXT STEP) X[6] */
|
||||
xor %ebx, %r11d /* z ^ ... */
|
||||
xor %edx, %r11d /* x ^ ... */
|
||||
add %r11d, %ecx /* dst += ... */
|
||||
rol $16, %ecx /* dst <<< s */
|
||||
mov %edx, %r11d /* (NEXT STEP) y' = %edx */
|
||||
add %edx, %ecx /* dst += x */
|
||||
lea 76029189(%ebx,%r10d),%ebx /* Const + dst + ... */
|
||||
mov 9*4(%rsi),%r10d /* (NEXT STEP) X[9] */
|
||||
xor %eax, %r11d /* z ^ ... */
|
||||
xor %ecx, %r11d /* x ^ ... */
|
||||
add %r11d, %ebx /* dst += ... */
|
||||
rol $23, %ebx /* dst <<< s */
|
||||
mov %ecx, %r11d /* (NEXT STEP) y' = %ecx */
|
||||
add %ecx, %ebx /* dst += x */
|
||||
lea -640364487(%eax,%r10d),%eax /* Const + dst + ... */
|
||||
mov 12*4(%rsi),%r10d /* (NEXT STEP) X[12] */
|
||||
xor %edx, %r11d /* z ^ ... */
|
||||
xor %ebx, %r11d /* x ^ ... */
|
||||
add %r11d, %eax /* dst += ... */
|
||||
rol $4, %eax /* dst <<< s */
|
||||
mov %ebx, %r11d /* (NEXT STEP) y' = %ebx */
|
||||
add %ebx, %eax /* dst += x */
|
||||
lea -421815835(%edx,%r10d),%edx /* Const + dst + ... */
|
||||
mov 15*4(%rsi),%r10d /* (NEXT STEP) X[15] */
|
||||
xor %ecx, %r11d /* z ^ ... */
|
||||
xor %eax, %r11d /* x ^ ... */
|
||||
add %r11d, %edx /* dst += ... */
|
||||
rol $11, %edx /* dst <<< s */
|
||||
mov %eax, %r11d /* (NEXT STEP) y' = %eax */
|
||||
add %eax, %edx /* dst += x */
|
||||
lea 530742520(%ecx,%r10d),%ecx /* Const + dst + ... */
|
||||
mov 2*4(%rsi),%r10d /* (NEXT STEP) X[2] */
|
||||
xor %ebx, %r11d /* z ^ ... */
|
||||
xor %edx, %r11d /* x ^ ... */
|
||||
add %r11d, %ecx /* dst += ... */
|
||||
rol $16, %ecx /* dst <<< s */
|
||||
mov %edx, %r11d /* (NEXT STEP) y' = %edx */
|
||||
add %edx, %ecx /* dst += x */
|
||||
lea -995338651(%ebx,%r10d),%ebx /* Const + dst + ... */
|
||||
mov 0*4(%rsi),%r10d /* (NEXT STEP) X[0] */
|
||||
xor %eax, %r11d /* z ^ ... */
|
||||
xor %ecx, %r11d /* x ^ ... */
|
||||
add %r11d, %ebx /* dst += ... */
|
||||
rol $23, %ebx /* dst <<< s */
|
||||
mov %ecx, %r11d /* (NEXT STEP) y' = %ecx */
|
||||
add %ecx, %ebx /* dst += x */
|
||||
mov 0*4(%rsi), %r10d /* (NEXT STEP) X[0] */
|
||||
mov $0xffffffff, %r11d
|
||||
xor %edx, %r11d /* (NEXT STEP) not z' = not %edx*/
|
||||
lea -198630844(%eax,%r10d),%eax /* Const + dst + ... */
|
||||
or %ebx, %r11d /* x | ... */
|
||||
xor %ecx, %r11d /* y ^ ... */
|
||||
add %r11d, %eax /* dst += ... */
|
||||
mov 7*4(%rsi),%r10d /* (NEXT STEP) X[7] */
|
||||
mov $0xffffffff, %r11d
|
||||
rol $6, %eax /* dst <<< s */
|
||||
xor %ecx, %r11d /* (NEXT STEP) not z' = not %ecx */
|
||||
add %ebx, %eax /* dst += x */
|
||||
lea 1126891415(%edx,%r10d),%edx /* Const + dst + ... */
|
||||
or %eax, %r11d /* x | ... */
|
||||
xor %ebx, %r11d /* y ^ ... */
|
||||
add %r11d, %edx /* dst += ... */
|
||||
mov 14*4(%rsi),%r10d /* (NEXT STEP) X[14] */
|
||||
mov $0xffffffff, %r11d
|
||||
rol $10, %edx /* dst <<< s */
|
||||
xor %ebx, %r11d /* (NEXT STEP) not z' = not %ebx */
|
||||
add %eax, %edx /* dst += x */
|
||||
lea -1416354905(%ecx,%r10d),%ecx /* Const + dst + ... */
|
||||
or %edx, %r11d /* x | ... */
|
||||
xor %eax, %r11d /* y ^ ... */
|
||||
add %r11d, %ecx /* dst += ... */
|
||||
mov 5*4(%rsi),%r10d /* (NEXT STEP) X[5] */
|
||||
mov $0xffffffff, %r11d
|
||||
rol $15, %ecx /* dst <<< s */
|
||||
xor %eax, %r11d /* (NEXT STEP) not z' = not %eax */
|
||||
add %edx, %ecx /* dst += x */
|
||||
lea -57434055(%ebx,%r10d),%ebx /* Const + dst + ... */
|
||||
or %ecx, %r11d /* x | ... */
|
||||
xor %edx, %r11d /* y ^ ... */
|
||||
add %r11d, %ebx /* dst += ... */
|
||||
mov 12*4(%rsi),%r10d /* (NEXT STEP) X[12] */
|
||||
mov $0xffffffff, %r11d
|
||||
rol $21, %ebx /* dst <<< s */
|
||||
xor %edx, %r11d /* (NEXT STEP) not z' = not %edx */
|
||||
add %ecx, %ebx /* dst += x */
|
||||
lea 1700485571(%eax,%r10d),%eax /* Const + dst + ... */
|
||||
or %ebx, %r11d /* x | ... */
|
||||
xor %ecx, %r11d /* y ^ ... */
|
||||
add %r11d, %eax /* dst += ... */
|
||||
mov 3*4(%rsi),%r10d /* (NEXT STEP) X[3] */
|
||||
mov $0xffffffff, %r11d
|
||||
rol $6, %eax /* dst <<< s */
|
||||
xor %ecx, %r11d /* (NEXT STEP) not z' = not %ecx */
|
||||
add %ebx, %eax /* dst += x */
|
||||
lea -1894986606(%edx,%r10d),%edx /* Const + dst + ... */
|
||||
or %eax, %r11d /* x | ... */
|
||||
xor %ebx, %r11d /* y ^ ... */
|
||||
add %r11d, %edx /* dst += ... */
|
||||
mov 10*4(%rsi),%r10d /* (NEXT STEP) X[10] */
|
||||
mov $0xffffffff, %r11d
|
||||
rol $10, %edx /* dst <<< s */
|
||||
xor %ebx, %r11d /* (NEXT STEP) not z' = not %ebx */
|
||||
add %eax, %edx /* dst += x */
|
||||
lea -1051523(%ecx,%r10d),%ecx /* Const + dst + ... */
|
||||
or %edx, %r11d /* x | ... */
|
||||
xor %eax, %r11d /* y ^ ... */
|
||||
add %r11d, %ecx /* dst += ... */
|
||||
mov 1*4(%rsi),%r10d /* (NEXT STEP) X[1] */
|
||||
mov $0xffffffff, %r11d
|
||||
rol $15, %ecx /* dst <<< s */
|
||||
xor %eax, %r11d /* (NEXT STEP) not z' = not %eax */
|
||||
add %edx, %ecx /* dst += x */
|
||||
lea -2054922799(%ebx,%r10d),%ebx /* Const + dst + ... */
|
||||
or %ecx, %r11d /* x | ... */
|
||||
xor %edx, %r11d /* y ^ ... */
|
||||
add %r11d, %ebx /* dst += ... */
|
||||
mov 8*4(%rsi),%r10d /* (NEXT STEP) X[8] */
|
||||
mov $0xffffffff, %r11d
|
||||
rol $21, %ebx /* dst <<< s */
|
||||
xor %edx, %r11d /* (NEXT STEP) not z' = not %edx */
|
||||
add %ecx, %ebx /* dst += x */
|
||||
lea 1873313359(%eax,%r10d),%eax /* Const + dst + ... */
|
||||
or %ebx, %r11d /* x | ... */
|
||||
xor %ecx, %r11d /* y ^ ... */
|
||||
add %r11d, %eax /* dst += ... */
|
||||
mov 15*4(%rsi),%r10d /* (NEXT STEP) X[15] */
|
||||
mov $0xffffffff, %r11d
|
||||
rol $6, %eax /* dst <<< s */
|
||||
xor %ecx, %r11d /* (NEXT STEP) not z' = not %ecx */
|
||||
add %ebx, %eax /* dst += x */
|
||||
lea -30611744(%edx,%r10d),%edx /* Const + dst + ... */
|
||||
or %eax, %r11d /* x | ... */
|
||||
xor %ebx, %r11d /* y ^ ... */
|
||||
add %r11d, %edx /* dst += ... */
|
||||
mov 6*4(%rsi),%r10d /* (NEXT STEP) X[6] */
|
||||
mov $0xffffffff, %r11d
|
||||
rol $10, %edx /* dst <<< s */
|
||||
xor %ebx, %r11d /* (NEXT STEP) not z' = not %ebx */
|
||||
add %eax, %edx /* dst += x */
|
||||
lea -1560198380(%ecx,%r10d),%ecx /* Const + dst + ... */
|
||||
or %edx, %r11d /* x | ... */
|
||||
xor %eax, %r11d /* y ^ ... */
|
||||
add %r11d, %ecx /* dst += ... */
|
||||
mov 13*4(%rsi),%r10d /* (NEXT STEP) X[13] */
|
||||
mov $0xffffffff, %r11d
|
||||
rol $15, %ecx /* dst <<< s */
|
||||
xor %eax, %r11d /* (NEXT STEP) not z' = not %eax */
|
||||
add %edx, %ecx /* dst += x */
|
||||
lea 1309151649(%ebx,%r10d),%ebx /* Const + dst + ... */
|
||||
or %ecx, %r11d /* x | ... */
|
||||
xor %edx, %r11d /* y ^ ... */
|
||||
add %r11d, %ebx /* dst += ... */
|
||||
mov 4*4(%rsi),%r10d /* (NEXT STEP) X[4] */
|
||||
mov $0xffffffff, %r11d
|
||||
rol $21, %ebx /* dst <<< s */
|
||||
xor %edx, %r11d /* (NEXT STEP) not z' = not %edx */
|
||||
add %ecx, %ebx /* dst += x */
|
||||
lea -145523070(%eax,%r10d),%eax /* Const + dst + ... */
|
||||
or %ebx, %r11d /* x | ... */
|
||||
xor %ecx, %r11d /* y ^ ... */
|
||||
add %r11d, %eax /* dst += ... */
|
||||
mov 11*4(%rsi),%r10d /* (NEXT STEP) X[11] */
|
||||
mov $0xffffffff, %r11d
|
||||
rol $6, %eax /* dst <<< s */
|
||||
xor %ecx, %r11d /* (NEXT STEP) not z' = not %ecx */
|
||||
add %ebx, %eax /* dst += x */
|
||||
lea -1120210379(%edx,%r10d),%edx /* Const + dst + ... */
|
||||
or %eax, %r11d /* x | ... */
|
||||
xor %ebx, %r11d /* y ^ ... */
|
||||
add %r11d, %edx /* dst += ... */
|
||||
mov 2*4(%rsi),%r10d /* (NEXT STEP) X[2] */
|
||||
mov $0xffffffff, %r11d
|
||||
rol $10, %edx /* dst <<< s */
|
||||
xor %ebx, %r11d /* (NEXT STEP) not z' = not %ebx */
|
||||
add %eax, %edx /* dst += x */
|
||||
lea 718787259(%ecx,%r10d),%ecx /* Const + dst + ... */
|
||||
or %edx, %r11d /* x | ... */
|
||||
xor %eax, %r11d /* y ^ ... */
|
||||
add %r11d, %ecx /* dst += ... */
|
||||
mov 9*4(%rsi),%r10d /* (NEXT STEP) X[9] */
|
||||
mov $0xffffffff, %r11d
|
||||
rol $15, %ecx /* dst <<< s */
|
||||
xor %eax, %r11d /* (NEXT STEP) not z' = not %eax */
|
||||
add %edx, %ecx /* dst += x */
|
||||
lea -343485551(%ebx,%r10d),%ebx /* Const + dst + ... */
|
||||
or %ecx, %r11d /* x | ... */
|
||||
xor %edx, %r11d /* y ^ ... */
|
||||
add %r11d, %ebx /* dst += ... */
|
||||
mov 0*4(%rsi),%r10d /* (NEXT STEP) X[0] */
|
||||
mov $0xffffffff, %r11d
|
||||
rol $21, %ebx /* dst <<< s */
|
||||
xor %edx, %r11d /* (NEXT STEP) not z' = not %edx */
|
||||
add %ecx, %ebx /* dst += x */
|
||||
# add old values of A, B, C, D
|
||||
add %r8d, %eax
|
||||
add %r9d, %ebx
|
||||
add %r14d, %ecx
|
||||
add %r15d, %edx
|
||||
|
||||
# loop control
|
||||
add $64, %rsi # ptr += 64
|
||||
cmp %rdi, %rsi # cmp end with ptr
|
||||
jb 2b # jmp if ptr < end
|
||||
# END of loop over 16-word blocks
|
||||
1:
|
||||
mov %eax, 0*4(%rbp) # ctx->A = A
|
||||
mov %ebx, 1*4(%rbp) # ctx->B = B
|
||||
mov %ecx, 2*4(%rbp) # ctx->C = C
|
||||
mov %edx, 3*4(%rbp) # ctx->D = D
|
||||
|
||||
pop %r15
|
||||
pop %r14
|
||||
pop %r13 # not really useful (r13 is unused)
|
||||
pop %r12
|
||||
pop %rbx
|
||||
pop %rbp
|
||||
ret
|
||||
|
||||
#endif /* } USE_MD5_ASM */
|
||||
67
lib/md5.c
67
lib/md5.c
@@ -2,7 +2,6 @@
|
||||
* RFC 1321 compliant MD5 implementation
|
||||
*
|
||||
* Copyright (C) 2001-2003 Christophe Devine
|
||||
* Copyright (C) 2007-2022 Wayne Davison
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
@@ -39,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)))
|
||||
|
||||
@@ -147,13 +146,6 @@ static void md5_process(md_context *ctx, const uchar data[CSUM_CHUNK])
|
||||
ctx->D += D;
|
||||
}
|
||||
|
||||
#ifdef USE_MD5_ASM
|
||||
#if CSUM_CHUNK != 64
|
||||
#error The MD5 ASM code does not support CSUM_CHUNK != 64
|
||||
#endif
|
||||
extern void md5_process_asm(md_context *ctx, const void *data, size_t num);
|
||||
#endif
|
||||
|
||||
void md5_update(md_context *ctx, const uchar *input, uint32 length)
|
||||
{
|
||||
uint32 left, fill;
|
||||
@@ -178,20 +170,11 @@ void md5_update(md_context *ctx, const uchar *input, uint32 length)
|
||||
left = 0;
|
||||
}
|
||||
|
||||
#ifdef USE_MD5_ASM /* { */
|
||||
if (length >= CSUM_CHUNK) {
|
||||
uint32 chunks = length / CSUM_CHUNK;
|
||||
md5_process_asm(ctx, input, chunks);
|
||||
length -= chunks * CSUM_CHUNK;
|
||||
input += chunks * CSUM_CHUNK;
|
||||
}
|
||||
#else /* } { */
|
||||
while (length >= CSUM_CHUNK) {
|
||||
md5_process(ctx, input);
|
||||
length -= CSUM_CHUNK;
|
||||
input += CSUM_CHUNK;
|
||||
}
|
||||
#endif /* } */
|
||||
|
||||
if (length)
|
||||
memcpy(ctx->buffer + left, input, length);
|
||||
@@ -209,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;
|
||||
@@ -218,14 +201,12 @@ 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);
|
||||
}
|
||||
|
||||
#ifdef TEST_MD5 /* { */
|
||||
|
||||
void get_md5(uchar *out, const uchar *input, int n)
|
||||
{
|
||||
md_context ctx;
|
||||
@@ -234,6 +215,8 @@ void get_md5(uchar *out, const uchar *input, int n)
|
||||
md5_result(&ctx, out);
|
||||
}
|
||||
|
||||
#ifdef TEST_MD5
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
|
||||
@@ -318,4 +301,4 @@ int main(int argc, char *argv[])
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif /* } */
|
||||
#endif
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
/* The include file for both the MD4 and MD5 routines. */
|
||||
|
||||
#ifdef USE_OPENSSL
|
||||
#include <openssl/sha.h>
|
||||
#include <openssl/evp.h>
|
||||
#endif
|
||||
#include "md-defines.h"
|
||||
#define MD4_DIGEST_LEN 16
|
||||
#define MD5_DIGEST_LEN 16
|
||||
#define MAX_DIGEST_LEN MD5_DIGEST_LEN
|
||||
|
||||
#define CSUM_CHUNK 64
|
||||
|
||||
typedef struct {
|
||||
uint32 A, B, C, D;
|
||||
@@ -17,6 +17,10 @@ void mdfour_begin(md_context *md);
|
||||
void mdfour_update(md_context *md, const uchar *in, uint32 length);
|
||||
void mdfour_result(md_context *md, uchar digest[MD4_DIGEST_LEN]);
|
||||
|
||||
void get_mdfour(uchar digest[MD4_DIGEST_LEN], const uchar *in, int length);
|
||||
|
||||
void md5_begin(md_context *ctx);
|
||||
void md5_update(md_context *ctx, const uchar *input, uint32 length);
|
||||
void md5_result(md_context *ctx, uchar digest[MD5_DIGEST_LEN]);
|
||||
|
||||
void get_md5(uchar digest[MD5_DIGEST_LEN], const uchar *input, int n);
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -33,7 +33,7 @@ pool_alloc, pool_free, pool_free_old, pool_talloc, pool_tfree, pool_create, pool
|
||||
.SH SYNOPSIS
|
||||
.B #include "pool_alloc.h"
|
||||
|
||||
\fBstruct alloc_pool *pool_create(size_t \fIsize\fB, size_t \fIquantum\fB, void (*\fIbomb\fB)(char*,char*,int), int \fIflags\fB);
|
||||
\fBstruct alloc_pool *pool_create(size_t \fIsize\fB, size_t \fIquantum\fB, void (*\fIbomb\fB)(char *), int \fIflags\fB);
|
||||
|
||||
\fBvoid pool_destroy(struct alloc_pool *\fIpool\fB);
|
||||
|
||||
@@ -95,39 +95,25 @@ for
|
||||
.I quantum
|
||||
will produce a quantum that should meet maximal alignment
|
||||
on most platforms.
|
||||
Unless
|
||||
.B POOL_NO_QALIGN
|
||||
If
|
||||
.B POOL_QALIGN
|
||||
is set in the
|
||||
.IR flags ,
|
||||
allocations will be aligned to addresses that are a
|
||||
multiple of
|
||||
.IR quantum .
|
||||
A
|
||||
.B NULL
|
||||
may be specified for the
|
||||
.I bomb
|
||||
function pointer if it is not needed. (See the
|
||||
.B pool_alloc()
|
||||
function for how it is used.)
|
||||
If
|
||||
.B POOL_CLEAR
|
||||
is set in the
|
||||
.IR flags ,
|
||||
all allocations from the pool will be initialized to zeros.
|
||||
If either
|
||||
.B POOL_PREPEND
|
||||
or
|
||||
.B POOL_INTERN
|
||||
is specified in the
|
||||
.IR flags ,
|
||||
each extent's data structure will be allocated at the start of the
|
||||
.IR size -length
|
||||
buffer (rather than as a separate, non-pool allocation), with the
|
||||
former extending the
|
||||
.I size
|
||||
to hold the structure, and the latter subtracting the structure's
|
||||
length from the indicated
|
||||
.IR size .
|
||||
You may specify a
|
||||
.B NULL
|
||||
for the
|
||||
.I bomb
|
||||
function pointer if you don't wish to use it. (See the
|
||||
.B pool_alloc()
|
||||
function for how it is used.)
|
||||
.P
|
||||
.B pool_destroy()
|
||||
destroys an allocation
|
||||
@@ -145,8 +131,8 @@ is
|
||||
.BR 0 ,
|
||||
.I quantum
|
||||
bytes will be allocated.
|
||||
If the pool has been created without
|
||||
.BR POOL_NO_QALIGN ,
|
||||
If the pool has been created with
|
||||
.BR POOL_QALIGN ,
|
||||
every chunk of memory that is returned will be suitably aligned.
|
||||
You can use this with the default
|
||||
.I quantum
|
||||
@@ -183,7 +169,7 @@ an extent), its memory will be completely freed back to the system.
|
||||
If
|
||||
.I addr
|
||||
is
|
||||
.BR NULL ,
|
||||
.BR 0 ,
|
||||
no memory will be freed, but subsequent allocations will come
|
||||
from a new extent.
|
||||
.P
|
||||
|
||||
193
lib/pool_alloc.c
193
lib/pool_alloc.c
@@ -2,19 +2,18 @@
|
||||
|
||||
#define POOL_DEF_EXTENT (32 * 1024)
|
||||
|
||||
#define POOL_QALIGN_P2 (1<<16) /* power-of-2 qalign */
|
||||
|
||||
struct alloc_pool
|
||||
{
|
||||
size_t size; /* extent size */
|
||||
size_t quantum; /* allocation quantum */
|
||||
struct pool_extent *extents; /* top extent is "live" */
|
||||
void (*bomb)(); /* called if malloc fails */
|
||||
void (*bomb)(); /* function to call if
|
||||
* malloc fails */
|
||||
int flags;
|
||||
|
||||
/* statistical data */
|
||||
unsigned long e_created; /* extents created */
|
||||
unsigned long e_freed; /* extents destroyed */
|
||||
unsigned long e_freed; /* extents detroyed */
|
||||
int64 n_allocated; /* calls to alloc */
|
||||
int64 n_freed; /* calls to free */
|
||||
int64 b_allocated; /* cum. bytes allocated */
|
||||
@@ -23,18 +22,16 @@ struct alloc_pool
|
||||
|
||||
struct pool_extent
|
||||
{
|
||||
struct pool_extent *next;
|
||||
void *start; /* starting address */
|
||||
size_t free; /* free bytecount */
|
||||
size_t bound; /* trapped free bytes */
|
||||
size_t bound; /* bytes bound by padding,
|
||||
* overhead and freed */
|
||||
struct pool_extent *next;
|
||||
};
|
||||
|
||||
struct align_test {
|
||||
uchar foo;
|
||||
union {
|
||||
int64 i;
|
||||
void *p;
|
||||
} bar;
|
||||
void *foo;
|
||||
int64 bar;
|
||||
};
|
||||
|
||||
#define MINALIGN offsetof(struct align_test, bar)
|
||||
@@ -44,44 +41,22 @@ struct align_test {
|
||||
#define PTR_ADD(b,o) ( (void*) ((char*)(b) + (o)) )
|
||||
|
||||
alloc_pool_t
|
||||
pool_create(size_t size, size_t quantum, void (*bomb)(const char*, const char*, int), int flags)
|
||||
pool_create(size_t size, size_t quantum, void (*bomb)(const char *), int flags)
|
||||
{
|
||||
struct alloc_pool *pool;
|
||||
struct alloc_pool *pool;
|
||||
|
||||
if ((MINALIGN & (MINALIGN - 1)) != (0)) {
|
||||
if (bomb)
|
||||
(*bomb)("Compiler error: MINALIGN is not a power of 2", __FILE__, __LINE__);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (!(pool = new0(struct alloc_pool)))
|
||||
return NULL;
|
||||
|
||||
if (!size)
|
||||
size = POOL_DEF_EXTENT;
|
||||
if (!quantum)
|
||||
quantum = MINALIGN;
|
||||
if (!(pool = new(struct alloc_pool)))
|
||||
return pool;
|
||||
memset(pool, 0, sizeof (struct alloc_pool));
|
||||
|
||||
pool->size = size /* round extent size to min alignment reqs */
|
||||
? (size + MINALIGN - 1) & ~(MINALIGN - 1)
|
||||
: POOL_DEF_EXTENT;
|
||||
if (flags & POOL_INTERN) {
|
||||
if (size <= sizeof (struct pool_extent))
|
||||
size = quantum;
|
||||
else
|
||||
size -= sizeof (struct pool_extent);
|
||||
flags |= POOL_PREPEND;
|
||||
pool->size -= sizeof (struct pool_extent);
|
||||
flags |= POOL_APPEND;
|
||||
}
|
||||
|
||||
if (quantum <= 1)
|
||||
flags = (flags | POOL_NO_QALIGN) & ~POOL_QALIGN_P2;
|
||||
else if (!(flags & POOL_NO_QALIGN)) {
|
||||
if (size % quantum)
|
||||
size += quantum - size % quantum;
|
||||
/* If quantum is a power of 2, we'll avoid using modulus. */
|
||||
if (!(quantum & (quantum - 1)))
|
||||
flags |= POOL_QALIGN_P2;
|
||||
}
|
||||
|
||||
pool->size = size;
|
||||
pool->quantum = quantum;
|
||||
pool->quantum = quantum ? quantum : MINALIGN;
|
||||
pool->bomb = bomb;
|
||||
pool->flags = flags;
|
||||
|
||||
@@ -92,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);
|
||||
}
|
||||
|
||||
@@ -119,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;
|
||||
|
||||
@@ -168,7 +144,7 @@ pool_alloc(alloc_pool_t p, size_t len, const char *bomb_msg)
|
||||
|
||||
bomb_out:
|
||||
if (pool->bomb)
|
||||
(*pool->bomb)(bomb_msg, __FILE__, __LINE__);
|
||||
(*pool->bomb)(bomb_msg);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@@ -184,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;
|
||||
@@ -217,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);
|
||||
@@ -234,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. */
|
||||
@@ -276,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;
|
||||
}
|
||||
@@ -291,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++;
|
||||
}
|
||||
}
|
||||
@@ -325,30 +295,24 @@ pool_boundary(alloc_pool_t p, size_t len)
|
||||
}
|
||||
|
||||
#define FDPRINT(label, value) \
|
||||
do { \
|
||||
int len = snprintf(buf, sizeof buf, label, value); \
|
||||
if (write(fd, buf, len) != len) \
|
||||
ret = -1; \
|
||||
} while (0)
|
||||
snprintf(buf, sizeof buf, label, value), \
|
||||
write(fd, buf, strlen(buf))
|
||||
|
||||
#define FDEXTSTAT(ext) \
|
||||
do { \
|
||||
int len = snprintf(buf, sizeof buf, " %12ld %5ld\n", \
|
||||
(long)ext->free, (long)ext->bound); \
|
||||
if (write(fd, buf, len) != len) \
|
||||
ret = -1; \
|
||||
} while (0)
|
||||
snprintf(buf, sizeof buf, " %12ld %5ld\n", \
|
||||
(long) ext->free, \
|
||||
(long) ext->bound), \
|
||||
write(fd, buf, strlen(buf))
|
||||
|
||||
int
|
||||
void
|
||||
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;
|
||||
|
||||
if (!pool)
|
||||
return ret;
|
||||
return;
|
||||
|
||||
FDPRINT(" Extent size: %12ld\n", (long) pool->size);
|
||||
FDPRINT(" Alloc quantum: %12ld\n", (long) pool->quantum);
|
||||
@@ -360,16 +324,13 @@ pool_stats(alloc_pool_t p, int fd, int summarize)
|
||||
FDPRINT(" Bytes freed: %12.0f\n", (double) pool->b_freed);
|
||||
|
||||
if (summarize)
|
||||
return ret;
|
||||
return;
|
||||
|
||||
if (!pool->extents)
|
||||
return ret;
|
||||
return;
|
||||
|
||||
if (write(fd, "\n", 1) != 1)
|
||||
ret = -1;
|
||||
write(fd, "\n", 1);
|
||||
|
||||
for (cur = pool->extents; cur; cur = cur->next)
|
||||
FDEXTSTAT(cur);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
#include <stddef.h>
|
||||
|
||||
#define POOL_CLEAR (1<<0) /* zero fill allocations */
|
||||
#define POOL_NO_QALIGN (1<<1) /* don't align data to quanta */
|
||||
#define POOL_QALIGN (1<<1) /* align data to quanta */
|
||||
#define POOL_INTERN (1<<2) /* Allocate extent structures */
|
||||
#define POOL_PREPEND (1<<3) /* or prepend to extent data */
|
||||
#define POOL_APPEND (1<<3) /* or appended to extent data */
|
||||
|
||||
typedef void *alloc_pool_t;
|
||||
|
||||
alloc_pool_t pool_create(size_t size, size_t quantum, void (*bomb)(const char*, const char*, int), int flags);
|
||||
alloc_pool_t pool_create(size_t size, size_t quantum, void (*bomb)(const char *), int flags);
|
||||
void pool_destroy(alloc_pool_t pool);
|
||||
void *pool_alloc(alloc_pool_t pool, size_t size, const char *bomb_msg);
|
||||
void pool_free(alloc_pool_t pool, size_t size, void *addr);
|
||||
|
||||
927
lib/snprintf.c
927
lib/snprintf.c
File diff suppressed because it is too large
Load Diff
815
lib/sysacls.c
815
lib/sysacls.c
File diff suppressed because it is too large
Load Diff
@@ -3,7 +3,7 @@
|
||||
* Version 2.2.x
|
||||
* Portable SMB ACL interface
|
||||
* Copyright (C) Jeremy Allison 2000
|
||||
* Copyright (C) 2007-2022 Wayne Davison
|
||||
* Copyright (C) 2007-2008 Wayne Davison
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
@@ -139,9 +139,7 @@ typedef struct acl *SMB_ACL_ENTRY_T;
|
||||
|
||||
/* Based on the Solaris & UnixWare code. */
|
||||
|
||||
#ifndef __TANDEM
|
||||
#undef GROUP
|
||||
#endif
|
||||
#include <sys/aclv.h>
|
||||
|
||||
/* SVR4.2 ES/MP ACLs */
|
||||
@@ -232,7 +230,7 @@ struct new_acl_entry{
|
||||
|
||||
#define SMB_ACL_ENTRY_T struct new_acl_entry*
|
||||
#define SMB_ACL_T struct acl_entry_link*
|
||||
|
||||
|
||||
#define SMB_ACL_TAG_T unsigned short
|
||||
#define SMB_ACL_TYPE_T int
|
||||
|
||||
|
||||
170
lib/sysxattrs.c
170
lib/sysxattrs.c
@@ -2,7 +2,7 @@
|
||||
* Extended attribute support for rsync.
|
||||
*
|
||||
* Copyright (C) 2004 Red Hat, Inc.
|
||||
* Copyright (C) 2003-2022 Wayne Davison
|
||||
* Copyright (C) 2003-2008 Wayne Davison
|
||||
* Written by Jay Fenlason.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
@@ -24,10 +24,6 @@
|
||||
|
||||
#ifdef SUPPORT_XATTRS
|
||||
|
||||
#ifdef HAVE_OSX_XATTRS
|
||||
#define GETXATTR_FETCH_LIMIT (64*1024*1024)
|
||||
#endif
|
||||
|
||||
#if defined HAVE_LINUX_XATTRS
|
||||
|
||||
ssize_t sys_lgetxattr(const char *path, const char *name, void *value, size_t size)
|
||||
@@ -59,24 +55,7 @@ ssize_t sys_llistxattr(const char *path, char *list, size_t size)
|
||||
|
||||
ssize_t sys_lgetxattr(const char *path, const char *name, void *value, size_t size)
|
||||
{
|
||||
ssize_t len = getxattr(path, name, value, size, 0, XATTR_NOFOLLOW);
|
||||
|
||||
/* If we're retrieving data, handle resource forks > 64MB specially */
|
||||
if (value != NULL && len == GETXATTR_FETCH_LIMIT && (size_t)len < size) {
|
||||
/* getxattr will only return 64MB of data at a time, need to call again with a new offset */
|
||||
u_int32_t offset = len;
|
||||
size_t data_retrieved = len;
|
||||
while (data_retrieved < size) {
|
||||
len = getxattr(path, name, (char*)value + offset, size - data_retrieved, offset, XATTR_NOFOLLOW);
|
||||
if (len <= 0)
|
||||
break;
|
||||
data_retrieved += len;
|
||||
offset += (u_int32_t)len;
|
||||
}
|
||||
len = data_retrieved;
|
||||
}
|
||||
|
||||
return len;
|
||||
return getxattr(path, name, value, size, 0, XATTR_NOFOLLOW);
|
||||
}
|
||||
|
||||
ssize_t sys_fgetxattr(int filedes, const char *name, void *value, size_t size)
|
||||
@@ -147,151 +126,6 @@ ssize_t sys_llistxattr(const char *path, char *list, size_t size)
|
||||
return len;
|
||||
}
|
||||
|
||||
#elif HAVE_SOLARIS_XATTRS
|
||||
|
||||
static ssize_t read_xattr(int attrfd, void *buf, size_t buflen)
|
||||
{
|
||||
STRUCT_STAT sb;
|
||||
ssize_t ret;
|
||||
|
||||
if (fstat(attrfd, &sb) < 0)
|
||||
ret = -1;
|
||||
else if (sb.st_size > SSIZE_MAX) {
|
||||
errno = ERANGE;
|
||||
ret = -1;
|
||||
} else if (buflen == 0)
|
||||
ret = sb.st_size;
|
||||
else if (sb.st_size > buflen) {
|
||||
errno = ERANGE;
|
||||
ret = -1;
|
||||
} else {
|
||||
size_t bufpos;
|
||||
for (bufpos = 0; bufpos < sb.st_size; ) {
|
||||
ssize_t cnt = read(attrfd, (char*)buf + bufpos, sb.st_size - bufpos);
|
||||
if (cnt <= 0) {
|
||||
if (cnt < 0 && errno == EINTR)
|
||||
continue;
|
||||
bufpos = -1;
|
||||
break;
|
||||
}
|
||||
bufpos += cnt;
|
||||
}
|
||||
ret = bufpos;
|
||||
}
|
||||
|
||||
close(attrfd);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
ssize_t sys_lgetxattr(const char *path, const char *name, void *value, size_t size)
|
||||
{
|
||||
int attrfd;
|
||||
|
||||
if ((attrfd = attropen(path, name, O_RDONLY)) < 0) {
|
||||
errno = ENOATTR;
|
||||
return -1;
|
||||
}
|
||||
|
||||
return read_xattr(attrfd, value, size);
|
||||
}
|
||||
|
||||
ssize_t sys_fgetxattr(int filedes, const char *name, void *value, size_t size)
|
||||
{
|
||||
int attrfd;
|
||||
|
||||
if ((attrfd = openat(filedes, name, O_RDONLY|O_XATTR, 0)) < 0) {
|
||||
errno = ENOATTR;
|
||||
return -1;
|
||||
}
|
||||
|
||||
return read_xattr(attrfd, value, size);
|
||||
}
|
||||
|
||||
int sys_lsetxattr(const char *path, const char *name, const void *value, size_t size)
|
||||
{
|
||||
int attrfd;
|
||||
size_t bufpos;
|
||||
mode_t mode = S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP;
|
||||
|
||||
if ((attrfd = attropen(path, name, O_CREAT|O_TRUNC|O_WRONLY, mode)) < 0)
|
||||
return -1;
|
||||
|
||||
for (bufpos = 0; bufpos < size; ) {
|
||||
ssize_t cnt = write(attrfd, (char*)value + bufpos, size);
|
||||
if (cnt <= 0) {
|
||||
if (cnt < 0 && errno == EINTR)
|
||||
continue;
|
||||
bufpos = -1;
|
||||
break;
|
||||
}
|
||||
bufpos += cnt;
|
||||
}
|
||||
|
||||
close(attrfd);
|
||||
|
||||
return bufpos > 0 ? 0 : -1;
|
||||
}
|
||||
|
||||
int sys_lremovexattr(const char *path, const char *name)
|
||||
{
|
||||
int attrdirfd;
|
||||
int ret;
|
||||
|
||||
if ((attrdirfd = attropen(path, ".", O_RDONLY)) < 0)
|
||||
return -1;
|
||||
|
||||
ret = unlinkat(attrdirfd, name, 0);
|
||||
|
||||
close(attrdirfd);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
ssize_t sys_llistxattr(const char *path, char *list, size_t size)
|
||||
{
|
||||
int attrdirfd;
|
||||
DIR *dirp;
|
||||
struct dirent *dp;
|
||||
ssize_t ret = 0;
|
||||
|
||||
if ((attrdirfd = attropen(path, ".", O_RDONLY)) < 0) {
|
||||
errno = ENOTSUP;
|
||||
return -1;
|
||||
}
|
||||
|
||||
if ((dirp = fdopendir(attrdirfd)) == NULL) {
|
||||
close(attrdirfd);
|
||||
return -1;
|
||||
}
|
||||
|
||||
while ((dp = readdir(dirp))) {
|
||||
int len = strlen(dp->d_name);
|
||||
|
||||
if (dp->d_name[0] == '.' && (len == 1 || (len == 2 && dp->d_name[1] == '.')))
|
||||
continue;
|
||||
if (len == 11 && dp->d_name[0] == 'S' && strncmp(dp->d_name, "SUNWattr_r", 10) == 0
|
||||
&& (dp->d_name[10] == 'o' || dp->d_name[10] == 'w'))
|
||||
continue;
|
||||
|
||||
ret += len + 1;
|
||||
if ((size_t)ret > size) {
|
||||
if (size == 0)
|
||||
continue;
|
||||
ret = -1;
|
||||
errno = ERANGE;
|
||||
break;
|
||||
}
|
||||
memcpy(list, dp->d_name, len+1);
|
||||
list += len+1;
|
||||
}
|
||||
|
||||
closedir(dirp);
|
||||
close(attrdirfd);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
#error You need to create xattr compatibility functions.
|
||||
|
||||
@@ -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
|
||||
|
||||
1084
loadparm.c
1084
loadparm.c
File diff suppressed because it is too large
Load Diff
370
log.c
370
log.c
@@ -3,7 +3,7 @@
|
||||
*
|
||||
* Copyright (C) 1998-2001 Andrew Tridgell <tridge@samba.org>
|
||||
* Copyright (C) 2000-2001 Martin Pool <mbp@samba.org>
|
||||
* Copyright (C) 2003-2022 Wayne Davison
|
||||
* Copyright (C) 2003-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
|
||||
@@ -20,9 +20,9 @@
|
||||
*/
|
||||
|
||||
#include "rsync.h"
|
||||
#include "itypes.h"
|
||||
#include "inums.h"
|
||||
#include "ifuncs.h"
|
||||
|
||||
extern int verbose;
|
||||
extern int dry_run;
|
||||
extern int am_daemon;
|
||||
extern int am_server;
|
||||
@@ -31,18 +31,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_mtimes;
|
||||
extern int msgs2stderr;
|
||||
extern int preserve_times;
|
||||
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;
|
||||
@@ -52,15 +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 *full_module_path;
|
||||
extern char curr_dir[];
|
||||
extern char *module_dir;
|
||||
extern unsigned int module_dirlen;
|
||||
extern char sender_file_sum[MAX_DIGEST_LEN];
|
||||
extern const char undetermined_hostname[];
|
||||
|
||||
extern struct name_num_item *xfer_sum_nni, *file_sum_nni;
|
||||
|
||||
static int log_initialised;
|
||||
static int logfile_was_closed;
|
||||
@@ -68,15 +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 == 1 ? stderr : stdout;
|
||||
int trailing_CR_or_NL;
|
||||
FILE *f = NULL;
|
||||
#ifdef ICONV_OPTION
|
||||
iconv_t ic = is_utf8 && ic_recv != (iconv_t)-1 ? ic_recv : ic_chck;
|
||||
#else
|
||||
@@ -263,15 +255,7 @@ void rwrite(enum logcode code, const char *buf, int len, int is_utf8)
|
||||
if (len < 0)
|
||||
exit_cleanup(RERR_MESSAGEIO);
|
||||
|
||||
if (msgs2stderr == 1) {
|
||||
/* A normal daemon can get msgs2stderr set if the socket is busted, so we
|
||||
* change the message destination into an FLOG message in order to try to
|
||||
* get some info about an abnormal-exit into the log file. An rsh daemon
|
||||
* can have this set via user request, so we'll leave the code alone so
|
||||
* that the msg gets logged and then sent to stderr after that. */
|
||||
if (am_daemon > 0 && code != FCLIENT)
|
||||
code = FLOG;
|
||||
} else if (send_msgs_to_gen) {
|
||||
if (am_server && msg_fd_out >= 0) {
|
||||
assert(!is_utf8);
|
||||
/* Pass the message to our sibling in native charset. */
|
||||
send_msg((enum msgcode)code, buf, len, 0);
|
||||
@@ -306,28 +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 != 1 && (msgs2stderr != 2 || f != stderr)) {
|
||||
if (am_server) {
|
||||
enum msgcode msg = (enum msgcode)code;
|
||||
if (protocol_version < 30) {
|
||||
if (msg == MSG_ERROR)
|
||||
@@ -338,25 +304,34 @@ void rwrite(enum logcode code, const char *buf, int len, int is_utf8)
|
||||
/* Pass the message to the non-server side. */
|
||||
if (send_msg(msg, buf, len, !is_utf8))
|
||||
return;
|
||||
if (am_daemon > 0) {
|
||||
if (am_daemon) {
|
||||
/* TODO: can we send the error to the user somehow? */
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
switch (code) {
|
||||
case FERROR_XFER:
|
||||
got_xfer_error = 1;
|
||||
/* FALL THROUGH */
|
||||
case FERROR:
|
||||
case FWARNING:
|
||||
f = stderr;
|
||||
break;
|
||||
case FINFO:
|
||||
f = am_server ? stderr : stdout;
|
||||
break;
|
||||
default:
|
||||
exit_cleanup(RERR_MESSAGEIO);
|
||||
}
|
||||
|
||||
if (output_needs_newline) {
|
||||
if (progress_is_active && !am_server) {
|
||||
fputc('\n', f);
|
||||
output_needs_newline = 0;
|
||||
progress_is_active = 0;
|
||||
}
|
||||
|
||||
trailing_CR_or_NL = len && (buf[len-1] == '\n' || buf[len-1] == '\r') ? buf[--len] : '\0';
|
||||
|
||||
if (len && buf[0] == '\r') {
|
||||
fputc('\r', f);
|
||||
buf++;
|
||||
len--;
|
||||
}
|
||||
trailing_CR_or_NL = len && (buf[len-1] == '\n' || buf[len-1] == '\r')
|
||||
? buf[--len] : 0;
|
||||
|
||||
#ifdef ICONV_CONST
|
||||
if (ic != (iconv_t)-1) {
|
||||
@@ -365,39 +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) {
|
||||
char trailing = inbuf.len ? '\0' : trailing_CR_or_NL;
|
||||
filtered_fwrite(f, convbuf, outbuf.len, 0, trailing);
|
||||
if (trailing) {
|
||||
trailing_CR_or_NL = '\0';
|
||||
fflush(f);
|
||||
}
|
||||
filtered_fwrite(f, convbuf, outbuf.len, 0);
|
||||
outbuf.len = 0;
|
||||
}
|
||||
/* Log one byte of illegal/incomplete sequence and continue with
|
||||
* the next character. Check that the buffer is non-empty for the
|
||||
* sake of robustness. */
|
||||
if ((ierrno == EILSEQ || ierrno == EINVAL) && inbuf.len) {
|
||||
fprintf(f, "\\#%03o", CVAL(inbuf.buf, inbuf.pos++));
|
||||
inbuf.len--;
|
||||
}
|
||||
}
|
||||
|
||||
if (trailing_CR_or_NL) {
|
||||
fputc(trailing_CR_or_NL, f);
|
||||
fflush(f);
|
||||
if (!ierrno || ierrno == E2BIG)
|
||||
continue;
|
||||
fprintf(f, "\\#%03o", CVAL(inbuf.buf, inbuf.pos++));
|
||||
inbuf.len--;
|
||||
}
|
||||
} else
|
||||
#endif
|
||||
{
|
||||
filtered_fwrite(f, buf, len, !allow_8bit_chars, trailing_CR_or_NL);
|
||||
if (trailing_CR_or_NL)
|
||||
fflush(f);
|
||||
filtered_fwrite(f, buf, len, !allow_8bit_chars);
|
||||
|
||||
if (trailing_CR_or_NL) {
|
||||
fputc(trailing_CR_or_NL, f);
|
||||
fflush(f);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -456,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);
|
||||
@@ -474,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;
|
||||
@@ -487,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];
|
||||
@@ -518,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':
|
||||
@@ -576,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':
|
||||
@@ -658,39 +603,34 @@ static void log_formatted(enum logcode code, const char *format, const char *op,
|
||||
n = timestring(time(NULL));
|
||||
break;
|
||||
case 'P':
|
||||
n = full_module_path;
|
||||
n = module_dir;
|
||||
break;
|
||||
case 'u':
|
||||
n = auth_user;
|
||||
break;
|
||||
case 'b':
|
||||
case 'c':
|
||||
if (!(iflags & ITEM_TRANSFER))
|
||||
b = 0;
|
||||
else if ((!!am_sender) ^ (*p == 'c'))
|
||||
b = total_data_written - initial_data_written;
|
||||
else
|
||||
b = total_data_read - initial_data_read;
|
||||
strlcat(fmt, "s", sizeof fmt);
|
||||
snprintf(buf2, sizeof buf2, fmt,
|
||||
do_big_num(b, humanize, NULL));
|
||||
if (am_sender) {
|
||||
b = stats.total_written -
|
||||
initial_stats->total_written;
|
||||
} else {
|
||||
b = stats.total_read -
|
||||
initial_stats->total_read;
|
||||
}
|
||||
strlcat(fmt, ".0f", sizeof fmt);
|
||||
snprintf(buf2, sizeof buf2, fmt, (double)b);
|
||||
n = buf2;
|
||||
break;
|
||||
case 'C':
|
||||
n = NULL;
|
||||
if (S_ISREG(file->mode)) {
|
||||
if (always_checksum)
|
||||
n = sum_as_hex(file_sum_nni->num, F_SUM(file), 1);
|
||||
else if (iflags & ITEM_TRANSFER)
|
||||
n = sum_as_hex(xfer_sum_nni->num, sender_file_sum, 0);
|
||||
}
|
||||
if (!n) {
|
||||
int sum_len = csum_len_for_type(always_checksum ? file_sum_nni->num : xfer_sum_nni->num,
|
||||
always_checksum);
|
||||
memset(buf2, ' ', sum_len*2);
|
||||
buf2[sum_len*2] = '\0';
|
||||
n = buf2;
|
||||
case 'c':
|
||||
if (!am_sender) {
|
||||
b = stats.total_written -
|
||||
initial_stats->total_written;
|
||||
} else {
|
||||
b = stats.total_read -
|
||||
initial_stats->total_read;
|
||||
}
|
||||
strlcat(fmt, ".0f", sizeof fmt);
|
||||
snprintf(buf2, sizeof buf2, fmt, (double)b);
|
||||
n = buf2;
|
||||
break;
|
||||
case 'i':
|
||||
if (iflags & ITEM_DELETED) {
|
||||
@@ -699,14 +639,14 @@ static void log_formatted(enum logcode code, const char *format, const char *op,
|
||||
}
|
||||
n = c = buf2 + MAXPATHLEN - 32;
|
||||
c[0] = iflags & ITEM_LOCAL_CHANGE
|
||||
? iflags & ITEM_XNAME_FOLLOWS ? 'h' : 'c'
|
||||
? iflags & ITEM_XNAME_FOLLOWS ? 'h' : 'c'
|
||||
: !(iflags & ITEM_TRANSFER) ? '.'
|
||||
: !local_server && *op == 's' ? '<' : '>';
|
||||
if (S_ISLNK(file->mode)) {
|
||||
c[1] = 'L';
|
||||
c[3] = '.';
|
||||
c[4] = !(iflags & ITEM_REPORT_TIME) ? '.'
|
||||
: !preserve_mtimes || !receiver_symlink_times
|
||||
: !preserve_times || !receiver_symlink_times
|
||||
|| (iflags & ITEM_REPORT_TIMEFAIL) ? 'T' : 't';
|
||||
} else {
|
||||
c[1] = S_ISDIR(file->mode) ? 'd'
|
||||
@@ -714,15 +654,13 @@ static void log_formatted(enum logcode code, const char *format, const char *op,
|
||||
: IS_DEVICE(file->mode) ? 'D' : 'f';
|
||||
c[3] = !(iflags & ITEM_REPORT_SIZE) ? '.' : 's';
|
||||
c[4] = !(iflags & ITEM_REPORT_TIME) ? '.'
|
||||
: !preserve_mtimes ? 'T' : 't';
|
||||
: !preserve_times ? 'T' : 't';
|
||||
}
|
||||
c[2] = !(iflags & ITEM_REPORT_CHANGE) ? '.' : 'c';
|
||||
c[5] = !(iflags & ITEM_REPORT_PERMS) ? '.' : 'p';
|
||||
c[6] = !(iflags & ITEM_REPORT_OWNER) ? '.' : 'o';
|
||||
c[7] = !(iflags & ITEM_REPORT_GROUP) ? '.' : 'g';
|
||||
c[8] = !(iflags & (ITEM_REPORT_ATIME|ITEM_REPORT_CRTIME)) ? '.'
|
||||
: BITS_SET(iflags, ITEM_REPORT_ATIME|ITEM_REPORT_CRTIME) ? 'b'
|
||||
: iflags & ITEM_REPORT_ATIME ? 'u' : 'n';
|
||||
c[8] = !(iflags & ITEM_REPORT_ATIME) ? '.' : 'u';
|
||||
c[9] = !(iflags & ITEM_REPORT_ACL) ? '.' : 'a';
|
||||
c[10] = !(iflags & ITEM_REPORT_XATTR) ? '.' : 'x';
|
||||
c[11] = '\0';
|
||||
@@ -792,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)
|
||||
@@ -809,70 +745,67 @@ int log_format_has(const char *format, char esc)
|
||||
/* Log the transfer of a file. If the code is FCLIENT, the output just goes
|
||||
* to stdout. If it is FLOG, it just goes to the log file. Otherwise we
|
||||
* output to both. */
|
||||
void log_item(enum logcode code, struct file_struct *file, int iflags, const char *hlink)
|
||||
void log_item(enum logcode code, struct file_struct *file,
|
||||
struct stats *initial_stats, int iflags, const char *hlink)
|
||||
{
|
||||
const char *s_or_r = am_sender ? "send" : "recv";
|
||||
|
||||
if (code != FLOG && stdout_format && !am_server)
|
||||
log_formatted(FCLIENT, stdout_format, s_or_r, file, NULL, iflags, hlink);
|
||||
if (code != FCLIENT && logfile_format && *logfile_format)
|
||||
log_formatted(FLOG, logfile_format, s_or_r, file, NULL, iflags, hlink);
|
||||
if (code != FLOG && stdout_format && !am_server) {
|
||||
log_formatted(FCLIENT, stdout_format, s_or_r,
|
||||
file, NULL, initial_stats, iflags, hlink);
|
||||
}
|
||||
if (code != FCLIENT && logfile_format && *logfile_format) {
|
||||
log_formatted(FLOG, logfile_format, s_or_r,
|
||||
file, NULL, initial_stats, iflags, hlink);
|
||||
}
|
||||
}
|
||||
|
||||
void maybe_log_item(struct file_struct *file, int iflags, int itemizing, const char *buf)
|
||||
void maybe_log_item(struct file_struct *file, int iflags, int itemizing,
|
||||
const char *buf)
|
||||
{
|
||||
int significant_flags = iflags & SIGNIFICANT_ITEM_FLAGS;
|
||||
int see_item = itemizing && (significant_flags || *buf
|
||||
|| stdout_format_has_i > 1 || (INFO_GTE(NAME, 2) && stdout_format_has_i));
|
||||
|| stdout_format_has_i > 1 || (verbose > 1 && stdout_format_has_i));
|
||||
int local_change = iflags & ITEM_LOCAL_CHANGE && significant_flags;
|
||||
if (am_server) {
|
||||
if (logfile_name && !dry_run && see_item
|
||||
&& (significant_flags || logfile_format_has_i))
|
||||
log_item(FLOG, file, iflags, buf);
|
||||
log_item(FLOG, file, &stats, iflags, buf);
|
||||
} else if (see_item || local_change || *buf
|
||||
|| (S_ISDIR(file->mode) && significant_flags)) {
|
||||
enum logcode code = significant_flags || logfile_format_has_i ? FINFO : FCLIENT;
|
||||
log_item(code, file, iflags, buf);
|
||||
log_item(code, file, &stats, iflags, buf);
|
||||
}
|
||||
}
|
||||
|
||||
void log_delete(const char *fname, int mode)
|
||||
{
|
||||
static struct file_struct *file = NULL;
|
||||
static struct {
|
||||
union file_extras ex[4]; /* just in case... */
|
||||
struct file_struct file;
|
||||
} x;
|
||||
int len = strlen(fname);
|
||||
const char *fmt;
|
||||
|
||||
if (!file) {
|
||||
int extra_len = (file_extra_cnt + 2) * EXTRA_LEN;
|
||||
char *bp;
|
||||
#if EXTRA_ROUNDING > 0
|
||||
if (extra_len & (EXTRA_ROUNDING * EXTRA_LEN))
|
||||
extra_len = (extra_len | (EXTRA_ROUNDING * EXTRA_LEN)) + EXTRA_LEN;
|
||||
#endif
|
||||
x.file.mode = mode;
|
||||
|
||||
bp = new_array0(char, FILE_STRUCT_LEN + extra_len + 1);
|
||||
bp += extra_len;
|
||||
file = (struct file_struct *)bp;
|
||||
}
|
||||
|
||||
file->mode = mode;
|
||||
|
||||
if (am_server && protocol_version >= 29 && len < MAXPATHLEN) {
|
||||
if (!verbose && !stdout_format)
|
||||
;
|
||||
else if (am_server && protocol_version >= 29 && len < MAXPATHLEN) {
|
||||
if (S_ISDIR(mode))
|
||||
len++; /* directories include trailing null */
|
||||
send_msg(MSG_DELETED, fname, len, am_generator);
|
||||
} else if (!INFO_GTE(DEL, 1) && !stdout_format)
|
||||
;
|
||||
else {
|
||||
} else {
|
||||
fmt = stdout_format_has_o_or_i ? stdout_format : "deleting %n";
|
||||
log_formatted(FCLIENT, fmt, "del.", file, fname, ITEM_DELETED, NULL);
|
||||
log_formatted(FCLIENT, fmt, "del.", &x.file, fname, &stats,
|
||||
ITEM_DELETED, NULL);
|
||||
}
|
||||
|
||||
if (!logfile_name || dry_run || !logfile_format)
|
||||
return;
|
||||
|
||||
fmt = logfile_format_has_o_or_i ? logfile_format : "deleting %n";
|
||||
log_formatted(FLOG, fmt, "del.", file, fname, ITEM_DELETED, NULL);
|
||||
log_formatted(FLOG, fmt, "del.", &x.file, fname, &stats, ITEM_DELETED, NULL);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -883,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);
|
||||
@@ -901,10 +831,10 @@ void log_exit(int code, const char *file, int line)
|
||||
/* VANISHED is not an error, only a warning */
|
||||
if (code == RERR_VANISHED) {
|
||||
rprintf(FWARNING, "rsync warning: %s (code %d) at %s(%d) [%s=%s]\n",
|
||||
name, code, src_file(file), line, who_am_i(), rsync_version());
|
||||
name, code, file, line, who_am_i(), RSYNC_VERSION);
|
||||
} else {
|
||||
rprintf(FERROR, "rsync error: %s (code %d) at %s(%d) [%s=%s]\n",
|
||||
name, code, src_file(file), line, who_am_i(), rsync_version());
|
||||
name, code, file, line, who_am_i(), RSYNC_VERSION);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,21 +0,0 @@
|
||||
dnl AC_HAVE_TYPE(TYPE,INCLUDES)
|
||||
AC_DEFUN([AC_HAVE_TYPE], [
|
||||
cv=`echo "$1" | sed 'y%./+- %__p__%'`
|
||||
AC_MSG_CHECKING(for $1)
|
||||
AC_CACHE_VAL([ac_cv_type_$cv],
|
||||
AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[
|
||||
AC_INCLUDES_DEFAULT
|
||||
$2]],
|
||||
[[$1 foo;]])],
|
||||
[eval "ac_cv_type_$cv=yes"],
|
||||
[eval "ac_cv_type_$cv=no"]))dnl
|
||||
ac_foo=`eval echo \\$ac_cv_type_$cv`
|
||||
AC_MSG_RESULT($ac_foo)
|
||||
if test "$ac_foo" = yes; then
|
||||
ac_tr_hdr=HAVE_`echo $1 | sed 'y%abcdefghijklmnopqrstuvwxyz./- %ABCDEFGHIJKLMNOPQRSTUVWXYZ____%'`
|
||||
if false; then
|
||||
AC_CHECK_TYPES($1)
|
||||
fi
|
||||
AC_DEFINE_UNQUOTED($ac_tr_hdr, 1, [Define if you have type `$1'])
|
||||
fi
|
||||
])
|
||||
@@ -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
|
||||
])
|
||||
@@ -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>])
|
||||
])
|
||||
@@ -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"
|
||||
])
|
||||
199
match.c
199
match.c
@@ -3,7 +3,7 @@
|
||||
*
|
||||
* Copyright (C) 1996 Andrew Tridgell
|
||||
* Copyright (C) 1996 Paul Mackerras
|
||||
* Copyright (C) 2003-2023 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
|
||||
@@ -20,16 +20,13 @@
|
||||
*/
|
||||
|
||||
#include "rsync.h"
|
||||
#include "inums.h"
|
||||
|
||||
extern int verbose;
|
||||
extern int do_progress;
|
||||
extern int checksum_seed;
|
||||
extern int append_mode;
|
||||
|
||||
extern struct name_num_item *xfer_sum_nni;
|
||||
extern int xfer_sum_len;
|
||||
|
||||
int updating_basis_file;
|
||||
char sender_file_sum[MAX_DIGEST_LEN];
|
||||
|
||||
static int false_alarms;
|
||||
static int hash_hits;
|
||||
@@ -67,6 +64,8 @@ static void build_hash_table(struct sum_struct *s)
|
||||
if (hash_table)
|
||||
free(hash_table);
|
||||
hash_table = new_array(int32, tablesize);
|
||||
if (!hash_table)
|
||||
out_of_memory("build_hash_table");
|
||||
alloc_size = tablesize;
|
||||
}
|
||||
|
||||
@@ -91,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,
|
||||
@@ -99,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);
|
||||
}
|
||||
|
||||
@@ -132,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);
|
||||
}
|
||||
|
||||
@@ -140,9 +141,9 @@ 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;
|
||||
char sum2[MAX_DIGEST_LEN];
|
||||
OFF_T offset, end;
|
||||
int32 k, want_i, backup;
|
||||
char sum2[SUM_LENGTH];
|
||||
uint32 s1, s2, sum;
|
||||
int more;
|
||||
schar *map;
|
||||
@@ -151,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);
|
||||
@@ -163,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;
|
||||
|
||||
@@ -220,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) {
|
||||
@@ -239,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);
|
||||
@@ -316,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);
|
||||
|
||||
@@ -358,19 +329,22 @@ static void hash_search(int f,struct sum_struct *s,
|
||||
**/
|
||||
void match_sums(int f, struct sum_struct *s, struct map_struct *buf, OFF_T len)
|
||||
{
|
||||
char file_sum[MAX_DIGEST_LEN];
|
||||
int sum_len;
|
||||
|
||||
last_match = 0;
|
||||
false_alarms = 0;
|
||||
hash_hits = 0;
|
||||
matches = 0;
|
||||
data_transfer = 0;
|
||||
|
||||
sum_init(xfer_sum_nni, checksum_seed);
|
||||
sum_init(checksum_seed);
|
||||
|
||||
if (append_mode > 0) {
|
||||
if (append_mode == 2) {
|
||||
OFF_T j = 0;
|
||||
for (j = CHUNK_SIZE; j < s->flength; j += CHUNK_SIZE) {
|
||||
if (buf && INFO_GTE(PROGRESS, 1))
|
||||
if (buf && do_progress)
|
||||
show_progress(last_match, buf->file_size);
|
||||
sum_update(map_ptr(buf, last_match, CHUNK_SIZE),
|
||||
CHUNK_SIZE);
|
||||
@@ -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_end(sender_file_sum);
|
||||
sum_len = sum_end(file_sum);
|
||||
/* If we had a read error, send a bad checksum. */
|
||||
if (buf && buf->status != 0)
|
||||
file_sum[0]++;
|
||||
|
||||
/* If we had a read error, send a bad checksum. We use all bits
|
||||
* off as long as the checksum doesn't happen to be that, in
|
||||
* which case we turn the last 0 bit into a 1. */
|
||||
if (buf && buf->status != 0) {
|
||||
int i;
|
||||
for (i = 0; i < xfer_sum_len && sender_file_sum[i] == 0; i++) {}
|
||||
memset(sender_file_sum, 0, xfer_sum_len);
|
||||
if (i == xfer_sum_len)
|
||||
sender_file_sum[i-1]++;
|
||||
}
|
||||
|
||||
if (DEBUG_GTE(DELTASUM, 2))
|
||||
if (verbose > 2)
|
||||
rprintf(FINFO,"sending file_sum\n");
|
||||
write_buf(f, sender_file_sum, xfer_sum_len);
|
||||
write_buf(f, file_sum, sum_len);
|
||||
|
||||
if (DEBUG_GTE(DELTASUM, 2)) {
|
||||
if (verbose > 2)
|
||||
rprintf(FINFO, "false_alarms=%d hash_hits=%d matches=%d\n",
|
||||
false_alarms, hash_hits, matches);
|
||||
}
|
||||
|
||||
total_hash_hits += hash_hits;
|
||||
total_false_alarms += false_alarms;
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -1,42 +0,0 @@
|
||||
#!/bin/sh
|
||||
|
||||
if [ $# != 1 ]; then
|
||||
echo "Usage: $0 NAME.NUM.md" 1>&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
inname="$1"
|
||||
srcdir=`dirname "$0"`
|
||||
flagfile="$srcdir/.md2man-works"
|
||||
force_flagfile="$srcdir/.md2man-force"
|
||||
|
||||
if [ ! -f "$flagfile" ]; then
|
||||
# We test our smallest manpage just to see if the python setup works.
|
||||
if "$srcdir/md-convert" --test "$srcdir/rsync-ssl.1.md" >/dev/null 2>&1; then
|
||||
touch $flagfile
|
||||
else
|
||||
outname=`echo "$inname" | sed 's/\.md$//'`
|
||||
if [ -f "$outname" ]; then
|
||||
exit 0
|
||||
elif [ -f "$srcdir/$outname" ]; then
|
||||
echo "Copying $srcdir/$outname"
|
||||
cp -p "$srcdir/$outname" .
|
||||
exit 0
|
||||
else
|
||||
echo "ERROR: $outname cannot be created."
|
||||
if [ -f "$HOME/build_farm/build_test.fns" ]; then
|
||||
exit 0 # No exit errorno to avoid a build failure in the samba build farm
|
||||
else
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
|
||||
if [ -f "$force_flagfile" ]; then
|
||||
opt='--force-link-text'
|
||||
else
|
||||
opt=''
|
||||
fi
|
||||
|
||||
"$srcdir/md-convert" $opt "$srcdir/$inname"
|
||||
662
md-convert
662
md-convert
@@ -1,662 +0,0 @@
|
||||
#!/usr/bin/env python3
|
||||
|
||||
# This script transforms markdown files into html and (optionally) nroff. The
|
||||
# output files are written into the current directory named for the input file
|
||||
# without the .md suffix and either the .html suffix or no suffix.
|
||||
#
|
||||
# If the input .md file has a section number at the end of the name (e.g.,
|
||||
# rsync.1.md) a nroff file is also output (PROJ.NUM.md -> PROJ.NUM).
|
||||
#
|
||||
# The markdown input format has one extra extension: if a numbered list starts
|
||||
# at 0, it is turned into a description list. The dl's dt tag is taken from the
|
||||
# contents of the first tag inside the li, which is usually a p, code, or
|
||||
# strong tag.
|
||||
#
|
||||
# The cmarkgfm or commonmark lib is used to transforms the input file into
|
||||
# html. Then, the html.parser is used as a state machine that lets us tweak
|
||||
# the html and (optionally) output nroff data based on the html tags.
|
||||
#
|
||||
# If the string @USE_GFM_PARSER@ exists in the file, the string is removed and
|
||||
# a github-flavored-markup parser is used to parse the file.
|
||||
#
|
||||
# The man-page .md files also get the vars @VERSION@, @BINDIR@, and @LIBDIR@
|
||||
# substituted. Some of these values depend on the Makefile $(prefix) (see the
|
||||
# generated Makefile). If the maintainer wants to build files for /usr/local
|
||||
# while creating release-ready man-page files for /usr, use the environment to
|
||||
# set RSYNC_OVERRIDE_PREFIX=/usr.
|
||||
|
||||
# Copyright (C) 2020 - 2021 Wayne Davison
|
||||
#
|
||||
# This program is freely redistributable.
|
||||
|
||||
import os, sys, re, argparse, subprocess, time
|
||||
from html.parser import HTMLParser
|
||||
|
||||
VALID_PAGES = 'README INSTALL COPYING rsync.1 rrsync.1 rsync-ssl.1 rsyncd.conf.5'.split()
|
||||
|
||||
CONSUMES_TXT = set('h1 h2 h3 p li pre'.split())
|
||||
|
||||
HTML_START = """\
|
||||
<html><head>
|
||||
<title>%TITLE%</title>
|
||||
<meta charset="UTF-8"/>
|
||||
<link href="https://fonts.googleapis.com/css2?family=Roboto&family=Roboto+Mono&display=swap" rel="stylesheet">
|
||||
<style>
|
||||
body {
|
||||
max-width: 50em;
|
||||
margin: auto;
|
||||
}
|
||||
body, b, strong, u {
|
||||
font-family: 'Roboto', sans-serif;
|
||||
}
|
||||
a.tgt { font-face: symbol; font-weight: 400; font-size: 70%; visibility: hidden; text-decoration: none; color: #ddd; padding: 0 4px; border: 0; }
|
||||
a.tgt:after { content: '🔗'; }
|
||||
a.tgt:hover { color: #444; background-color: #eaeaea; }
|
||||
h1:hover > a.tgt, h2:hover > a.tgt, h3:hover > a.tgt, dt:hover > a.tgt { visibility: visible; }
|
||||
code {
|
||||
font-family: 'Roboto Mono', monospace;
|
||||
font-weight: bold;
|
||||
white-space: pre;
|
||||
}
|
||||
pre code {
|
||||
display: block;
|
||||
font-weight: normal;
|
||||
}
|
||||
blockquote pre code {
|
||||
background: #f1f1f1;
|
||||
}
|
||||
dd p:first-of-type {
|
||||
margin-block-start: 0em;
|
||||
}
|
||||
</style>
|
||||
</head><body>
|
||||
"""
|
||||
|
||||
TABLE_STYLE = """\
|
||||
table {
|
||||
border-color: grey;
|
||||
border-spacing: 0;
|
||||
}
|
||||
tr {
|
||||
border-top: 1px solid grey;
|
||||
}
|
||||
tr:nth-child(2n) {
|
||||
background-color: #f6f8fa;
|
||||
}
|
||||
th, td {
|
||||
border: 1px solid #dfe2e5;
|
||||
text-align: center;
|
||||
padding-left: 1em;
|
||||
padding-right: 1em;
|
||||
}
|
||||
"""
|
||||
|
||||
MAN_HTML_END = """\
|
||||
<div style="float: right"><p><i>%s</i></p></div>
|
||||
"""
|
||||
|
||||
HTML_END = """\
|
||||
</body></html>
|
||||
"""
|
||||
|
||||
MAN_START = r"""
|
||||
.TH "%s" "%s" "%s" "%s" "User Commands"
|
||||
.\" prefix=%s
|
||||
""".lstrip()
|
||||
|
||||
MAN_END = """\
|
||||
"""
|
||||
|
||||
NORM_FONT = ('\1', r"\fP")
|
||||
BOLD_FONT = ('\2', r"\fB")
|
||||
UNDR_FONT = ('\3', r"\fI")
|
||||
NBR_DASH = ('\4', r"\-")
|
||||
NBR_SPACE = ('\xa0', r"\ ")
|
||||
|
||||
FILENAME_RE = re.compile(r'^(?P<fn>(?P<srcdir>.+/)?(?P<name>(?P<prog>[^/]+?)(\.(?P<sect>\d+))?)\.md)$')
|
||||
ASSIGNMENT_RE = re.compile(r'^(\w+)=(.+)')
|
||||
VER_RE = re.compile(r'^#define\s+RSYNC_VERSION\s+"(\d.+?)"', re.M)
|
||||
TZ_RE = re.compile(r'^#define\s+MAINTAINER_TZ_OFFSET\s+(-?\d+(\.\d+)?)', re.M)
|
||||
VAR_REF_RE = re.compile(r'\$\{(\w+)\}')
|
||||
VERSION_RE = re.compile(r' (\d[.\d]+)[, ]')
|
||||
BIN_CHARS_RE = re.compile(r'[\1-\7]+')
|
||||
SPACE_DOUBLE_DASH_RE = re.compile(r'\s--(\s)')
|
||||
NON_SPACE_SINGLE_DASH_RE = re.compile(r'(^|\W)-')
|
||||
WHITESPACE_RE = re.compile(r'\s')
|
||||
CODE_BLOCK_RE = re.compile(r'[%s]([^=%s]+)[=%s]' % (BOLD_FONT[0], NORM_FONT[0], NORM_FONT[0]))
|
||||
NBR_DASH_RE = re.compile(r'[%s]' % NBR_DASH[0])
|
||||
INVALID_TARGET_CHARS_RE = re.compile(r'[^-A-Za-z0-9._]')
|
||||
INVALID_START_CHAR_RE = re.compile(r'^([^A-Za-z0-9])')
|
||||
MANIFY_LINESTART_RE = re.compile(r"^(['.])", flags=re.M)
|
||||
|
||||
md_parser = None
|
||||
env_subs = { }
|
||||
|
||||
warning_count = 0
|
||||
|
||||
def main():
|
||||
for mdfn in args.mdfiles:
|
||||
parse_md_file(mdfn)
|
||||
|
||||
if args.test:
|
||||
print("The test was successful.")
|
||||
|
||||
|
||||
def parse_md_file(mdfn):
|
||||
fi = FILENAME_RE.match(mdfn)
|
||||
if not fi:
|
||||
die('Failed to parse a md input file name:', mdfn)
|
||||
fi = argparse.Namespace(**fi.groupdict())
|
||||
fi.want_manpage = not not fi.sect
|
||||
if fi.want_manpage:
|
||||
fi.title = fi.prog + '(' + fi.sect + ') manpage'
|
||||
else:
|
||||
fi.title = fi.prog + ' for rsync'
|
||||
|
||||
if fi.want_manpage:
|
||||
if not env_subs:
|
||||
find_man_substitutions()
|
||||
prog_ver = 'rsync ' + env_subs['VERSION']
|
||||
if fi.prog != 'rsync':
|
||||
prog_ver = fi.prog + ' from ' + prog_ver
|
||||
fi.man_headings = (fi.prog, fi.sect, env_subs['date'], prog_ver, env_subs['prefix'])
|
||||
|
||||
with open(mdfn, 'r', encoding='utf-8') as fh:
|
||||
txt = fh.read()
|
||||
|
||||
use_gfm_parser = '@USE_GFM_PARSER@' in txt
|
||||
if use_gfm_parser:
|
||||
txt = txt.replace('@USE_GFM_PARSER@', '')
|
||||
|
||||
if fi.want_manpage:
|
||||
txt = (txt.replace('@VERSION@', env_subs['VERSION'])
|
||||
.replace('@BINDIR@', env_subs['bindir'])
|
||||
.replace('@LIBDIR@', env_subs['libdir']))
|
||||
|
||||
if use_gfm_parser:
|
||||
if not gfm_parser:
|
||||
die('Input file requires cmarkgfm parser:', mdfn)
|
||||
fi.html_in = gfm_parser(txt)
|
||||
else:
|
||||
fi.html_in = md_parser(txt)
|
||||
txt = None
|
||||
|
||||
TransformHtml(fi)
|
||||
|
||||
if args.test:
|
||||
return
|
||||
|
||||
output_list = [ (fi.name + '.html', fi.html_out) ]
|
||||
if fi.want_manpage:
|
||||
output_list += [ (fi.name, fi.man_out) ]
|
||||
for fn, txt in output_list:
|
||||
if args.dest and args.dest != '.':
|
||||
fn = os.path.join(args.dest, fn)
|
||||
if os.path.lexists(fn):
|
||||
os.unlink(fn)
|
||||
print("Wrote:", fn)
|
||||
with open(fn, 'w', encoding='utf-8') as fh:
|
||||
fh.write(txt)
|
||||
|
||||
|
||||
def find_man_substitutions():
|
||||
srcdir = os.path.dirname(sys.argv[0]) + '/'
|
||||
mtime = 0
|
||||
|
||||
git_dir = srcdir + '.git'
|
||||
if os.path.lexists(git_dir):
|
||||
mtime = int(subprocess.check_output(['git', '--git-dir', git_dir, 'log', '-1', '--format=%at']))
|
||||
|
||||
# Allow "prefix" to be overridden via the environment:
|
||||
env_subs['prefix'] = os.environ.get('RSYNC_OVERRIDE_PREFIX', None)
|
||||
|
||||
if args.test:
|
||||
env_subs['VERSION'] = '1.0.0'
|
||||
env_subs['bindir'] = '/usr/bin'
|
||||
env_subs['libdir'] = '/usr/lib/rsync'
|
||||
tz_offset = 0
|
||||
else:
|
||||
for fn in (srcdir + 'version.h', 'Makefile'):
|
||||
try:
|
||||
st = os.lstat(fn)
|
||||
except OSError:
|
||||
die('Failed to find', srcdir + fn)
|
||||
if not mtime:
|
||||
mtime = st.st_mtime
|
||||
|
||||
with open(srcdir + 'version.h', 'r', encoding='utf-8') as fh:
|
||||
txt = fh.read()
|
||||
m = VER_RE.search(txt)
|
||||
env_subs['VERSION'] = m.group(1)
|
||||
m = TZ_RE.search(txt) # the tzdata lib may not be installed, so we use a simple hour offset
|
||||
tz_offset = float(m.group(1)) * 60 * 60
|
||||
|
||||
with open('Makefile', 'r', encoding='utf-8') as fh:
|
||||
for line in fh:
|
||||
m = ASSIGNMENT_RE.match(line)
|
||||
if not m:
|
||||
continue
|
||||
var, val = (m.group(1), m.group(2))
|
||||
if var == 'prefix' and env_subs[var] is not None:
|
||||
continue
|
||||
while VAR_REF_RE.search(val):
|
||||
val = VAR_REF_RE.sub(lambda m: env_subs[m.group(1)], val)
|
||||
env_subs[var] = val
|
||||
if var == 'srcdir':
|
||||
break
|
||||
|
||||
env_subs['date'] = time.strftime('%d %b %Y', time.gmtime(mtime + tz_offset)).lstrip('0')
|
||||
|
||||
|
||||
def html_via_commonmark(txt):
|
||||
return commonmark.HtmlRenderer().render(commonmark.Parser().parse(txt))
|
||||
|
||||
|
||||
class TransformHtml(HTMLParser):
|
||||
def __init__(self, fi):
|
||||
HTMLParser.__init__(self, convert_charrefs=True)
|
||||
|
||||
self.fn = fi.fn
|
||||
|
||||
st = self.state = argparse.Namespace(
|
||||
list_state = [ ],
|
||||
p_macro = ".P\n",
|
||||
at_first_tag_in_li = False,
|
||||
at_first_tag_in_dd = False,
|
||||
dt_from = None,
|
||||
in_pre = False,
|
||||
in_code = False,
|
||||
html_out = [ HTML_START.replace('%TITLE%', fi.title) ],
|
||||
man_out = [ ],
|
||||
txt = '',
|
||||
want_manpage = fi.want_manpage,
|
||||
created_hashtags = set(),
|
||||
derived_hashtags = set(),
|
||||
referenced_hashtags = set(),
|
||||
bad_hashtags = set(),
|
||||
latest_targets = [ ],
|
||||
opt_prefix = 'opt',
|
||||
a_href = None,
|
||||
a_href_external = False,
|
||||
a_txt_start = None,
|
||||
after_a_tag = False,
|
||||
target_suf = '',
|
||||
)
|
||||
|
||||
if st.want_manpage:
|
||||
st.man_out.append(MAN_START % fi.man_headings)
|
||||
|
||||
if '</table>' in fi.html_in:
|
||||
st.html_out[0] = st.html_out[0].replace('</style>', TABLE_STYLE + '</style>')
|
||||
|
||||
self.feed(fi.html_in)
|
||||
fi.html_in = None
|
||||
|
||||
if st.want_manpage:
|
||||
st.html_out.append(MAN_HTML_END % env_subs['date'])
|
||||
st.html_out.append(HTML_END)
|
||||
st.man_out.append(MAN_END)
|
||||
|
||||
fi.html_out = ''.join(st.html_out)
|
||||
st.html_out = None
|
||||
|
||||
fi.man_out = ''.join(st.man_out)
|
||||
st.man_out = None
|
||||
|
||||
for tgt, txt in st.derived_hashtags:
|
||||
derived = txt2target(txt, tgt)
|
||||
if derived not in st.created_hashtags:
|
||||
txt = BIN_CHARS_RE.sub('', txt.replace(NBR_DASH[0], '-').replace(NBR_SPACE[0], ' '))
|
||||
warn('Unknown derived hashtag link in', self.fn, 'based on:', (tgt, txt))
|
||||
|
||||
for bad in st.bad_hashtags:
|
||||
if bad in st.created_hashtags:
|
||||
warn('Missing "#" in hashtag link in', self.fn + ':', bad)
|
||||
else:
|
||||
warn('Unknown non-hashtag link in', self.fn + ':', bad)
|
||||
|
||||
for bad in st.referenced_hashtags - st.created_hashtags:
|
||||
warn('Unknown hashtag link in', self.fn + ':', '#' + bad)
|
||||
|
||||
def handle_UE(self):
|
||||
st = self.state
|
||||
if st.txt.startswith(('.', ',', '!', '?', ';', ':')):
|
||||
st.man_out[-1] = ".UE " + st.txt[0] + "\n"
|
||||
st.txt = st.txt[1:]
|
||||
st.after_a_tag = False
|
||||
|
||||
def handle_starttag(self, tag, attrs_list):
|
||||
st = self.state
|
||||
if args.debug:
|
||||
self.output_debug('START', (tag, attrs_list))
|
||||
if st.at_first_tag_in_li:
|
||||
if st.list_state[-1] == 'dl':
|
||||
st.dt_from = tag
|
||||
if tag == 'p':
|
||||
tag = 'dt'
|
||||
else:
|
||||
st.html_out.append('<dt>')
|
||||
elif tag == 'p':
|
||||
st.at_first_tag_in_dd = True # Kluge to suppress a .P at the start of an li.
|
||||
st.at_first_tag_in_li = False
|
||||
if tag == 'p':
|
||||
if not st.at_first_tag_in_dd:
|
||||
st.man_out.append(st.p_macro)
|
||||
elif tag == 'li':
|
||||
st.at_first_tag_in_li = True
|
||||
lstate = st.list_state[-1]
|
||||
if lstate == 'dl':
|
||||
return
|
||||
if lstate == 'o':
|
||||
st.man_out.append(".IP o\n")
|
||||
else:
|
||||
st.man_out.append(".IP " + str(lstate) + ".\n")
|
||||
st.list_state[-1] += 1
|
||||
elif tag == 'blockquote':
|
||||
st.man_out.append(".RS 4\n")
|
||||
elif tag == 'pre':
|
||||
st.in_pre = True
|
||||
st.man_out.append(st.p_macro + ".nf\n")
|
||||
elif tag == 'code' and not st.in_pre:
|
||||
st.in_code = True
|
||||
st.txt += BOLD_FONT[0]
|
||||
elif tag == 'strong' or tag == 'b':
|
||||
st.txt += BOLD_FONT[0]
|
||||
elif tag == 'em' or tag == 'i':
|
||||
if st.want_manpage:
|
||||
tag = 'u' # Change it into underline to be more like the manpage
|
||||
st.txt += UNDR_FONT[0]
|
||||
elif tag == 'ol':
|
||||
start = 1
|
||||
for var, val in attrs_list:
|
||||
if var == 'start':
|
||||
start = int(val) # We only support integers.
|
||||
break
|
||||
if st.list_state:
|
||||
st.man_out.append(".RS\n")
|
||||
if start == 0:
|
||||
tag = 'dl'
|
||||
attrs_list = [ ]
|
||||
st.list_state.append('dl')
|
||||
else:
|
||||
st.list_state.append(start)
|
||||
st.man_out.append(st.p_macro)
|
||||
st.p_macro = ".IP\n"
|
||||
elif tag == 'ul':
|
||||
st.man_out.append(st.p_macro)
|
||||
if st.list_state:
|
||||
st.man_out.append(".RS\n")
|
||||
st.p_macro = ".IP\n"
|
||||
st.list_state.append('o')
|
||||
elif tag == 'hr':
|
||||
st.man_out.append(".l\n")
|
||||
st.html_out.append("<hr />")
|
||||
return
|
||||
elif tag == 'a':
|
||||
st.a_href = None
|
||||
for var, val in attrs_list:
|
||||
if var == 'href':
|
||||
if val.startswith(('https://', 'http://', 'mailto:', 'ftp:')):
|
||||
if st.after_a_tag:
|
||||
self.handle_UE()
|
||||
st.man_out.append(manify(st.txt.strip()) + "\n")
|
||||
st.man_out.append(".UR " + val + "\n")
|
||||
st.txt = ''
|
||||
st.a_href = val
|
||||
st.a_href_external = True
|
||||
elif '#' in val:
|
||||
pg, tgt = val.split('#', 1)
|
||||
if pg and pg not in VALID_PAGES or '#' in tgt:
|
||||
st.bad_hashtags.add(val)
|
||||
elif tgt in ('', 'opt', 'dopt'):
|
||||
st.a_href = val
|
||||
st.a_href_external = False
|
||||
elif pg == '':
|
||||
st.referenced_hashtags.add(tgt)
|
||||
if tgt in st.latest_targets:
|
||||
warn('Found link to the current section in', self.fn + ':', val)
|
||||
elif val not in VALID_PAGES:
|
||||
st.bad_hashtags.add(val)
|
||||
st.a_txt_start = len(st.txt)
|
||||
st.html_out.append('<' + tag + ''.join(' ' + var + '="' + htmlify(val) + '"' for var, val in attrs_list) + '>')
|
||||
st.at_first_tag_in_dd = False
|
||||
|
||||
|
||||
def handle_endtag(self, tag):
|
||||
st = self.state
|
||||
if args.debug:
|
||||
self.output_debug('END', (tag,))
|
||||
if st.after_a_tag:
|
||||
self.handle_UE()
|
||||
if tag in CONSUMES_TXT or st.dt_from == tag:
|
||||
txt = st.txt.strip()
|
||||
st.txt = ''
|
||||
else:
|
||||
txt = None
|
||||
add_to_txt = None
|
||||
if tag == 'h1':
|
||||
tgt = txt
|
||||
target_suf = ''
|
||||
if tgt.startswith('NEWS for '):
|
||||
m = VERSION_RE.search(tgt)
|
||||
if m:
|
||||
tgt = m.group(1)
|
||||
st.target_suf = '-' + tgt
|
||||
self.add_targets(tag, tgt)
|
||||
elif tag == 'h2':
|
||||
st.man_out.append(st.p_macro + '.SH "' + manify(txt) + '"\n')
|
||||
self.add_targets(tag, txt, st.target_suf)
|
||||
st.opt_prefix = 'dopt' if txt == 'DAEMON OPTIONS' else 'opt'
|
||||
elif tag == 'h3':
|
||||
st.man_out.append(st.p_macro + '.SS "' + manify(txt) + '"\n')
|
||||
self.add_targets(tag, txt, st.target_suf)
|
||||
elif tag == 'p':
|
||||
if st.dt_from == 'p':
|
||||
tag = 'dt'
|
||||
st.man_out.append('.IP "' + manify(txt) + '"\n')
|
||||
if txt.startswith(BOLD_FONT[0]):
|
||||
self.add_targets(tag, txt)
|
||||
st.dt_from = None
|
||||
elif txt != '':
|
||||
st.man_out.append(manify(txt) + "\n")
|
||||
elif tag == 'li':
|
||||
if st.list_state[-1] == 'dl':
|
||||
if st.at_first_tag_in_li:
|
||||
die("Invalid 0. -> td translation")
|
||||
tag = 'dd'
|
||||
if txt != '':
|
||||
st.man_out.append(manify(txt) + "\n")
|
||||
st.at_first_tag_in_li = False
|
||||
elif tag == 'blockquote':
|
||||
st.man_out.append(".RE\n")
|
||||
elif tag == 'pre':
|
||||
st.in_pre = False
|
||||
st.man_out.append(manify(txt) + "\n.fi\n")
|
||||
elif (tag == 'code' and not st.in_pre):
|
||||
st.in_code = False
|
||||
add_to_txt = NORM_FONT[0]
|
||||
elif tag == 'strong' or tag == 'b':
|
||||
add_to_txt = NORM_FONT[0]
|
||||
elif tag == 'em' or tag == 'i':
|
||||
if st.want_manpage:
|
||||
tag = 'u' # Change it into underline to be more like the manpage
|
||||
add_to_txt = NORM_FONT[0]
|
||||
elif tag == 'ol' or tag == 'ul':
|
||||
if st.list_state.pop() == 'dl':
|
||||
tag = 'dl'
|
||||
if st.list_state:
|
||||
st.man_out.append(".RE\n")
|
||||
else:
|
||||
st.p_macro = ".P\n"
|
||||
st.at_first_tag_in_dd = False
|
||||
elif tag == 'hr':
|
||||
return
|
||||
elif tag == 'a':
|
||||
if st.a_href_external:
|
||||
st.txt = st.txt.strip()
|
||||
if args.force_link_text or st.a_href != st.txt:
|
||||
st.man_out.append(manify(st.txt) + "\n")
|
||||
st.man_out.append(".UE\n") # This might get replaced with a punctuation version in handle_UE()
|
||||
st.after_a_tag = True
|
||||
st.a_href_external = False
|
||||
st.txt = ''
|
||||
elif st.a_href:
|
||||
atxt = st.txt[st.a_txt_start:]
|
||||
find = 'href="' + st.a_href + '"'
|
||||
for j in range(len(st.html_out)-1, 0, -1):
|
||||
if find in st.html_out[j]:
|
||||
pg, tgt = st.a_href.split('#', 1)
|
||||
derived = txt2target(atxt, tgt)
|
||||
if pg == '':
|
||||
if derived in st.latest_targets:
|
||||
warn('Found link to the current section in', self.fn + ':', st.a_href)
|
||||
st.derived_hashtags.add((tgt, atxt))
|
||||
st.html_out[j] = st.html_out[j].replace(find, 'href="' + pg + '#' + derived + '"')
|
||||
break
|
||||
else:
|
||||
die('INTERNAL ERROR: failed to find href in html data:', find)
|
||||
st.html_out.append('</' + tag + '>')
|
||||
if add_to_txt:
|
||||
if txt is None:
|
||||
st.txt += add_to_txt
|
||||
else:
|
||||
txt += add_to_txt
|
||||
if st.dt_from == tag:
|
||||
st.man_out.append('.IP "' + manify(txt) + '"\n')
|
||||
st.html_out.append('</dt><dd>')
|
||||
st.at_first_tag_in_dd = True
|
||||
st.dt_from = None
|
||||
elif tag == 'dt':
|
||||
st.html_out.append('<dd>')
|
||||
st.at_first_tag_in_dd = True
|
||||
|
||||
|
||||
def handle_data(self, txt):
|
||||
st = self.state
|
||||
if '](' in txt:
|
||||
warn('Malformed link in', self.fn + ':', txt)
|
||||
if args.debug:
|
||||
self.output_debug('DATA', (txt,))
|
||||
if st.in_pre:
|
||||
html = htmlify(txt)
|
||||
else:
|
||||
txt = SPACE_DOUBLE_DASH_RE.sub(NBR_SPACE[0] + r'--\1', txt).replace('--', NBR_DASH[0]*2)
|
||||
txt = NON_SPACE_SINGLE_DASH_RE.sub(r'\1' + NBR_DASH[0], txt)
|
||||
html = htmlify(txt)
|
||||
if st.in_code:
|
||||
txt = WHITESPACE_RE.sub(NBR_SPACE[0], txt)
|
||||
html = html.replace(NBR_DASH[0], '-').replace(NBR_SPACE[0], ' ') # <code> is non-breaking in CSS
|
||||
st.html_out.append(html.replace(NBR_SPACE[0], ' ').replace(NBR_DASH[0], '-⁠'))
|
||||
st.txt += txt
|
||||
|
||||
|
||||
def add_targets(self, tag, txt, suf=None):
|
||||
st = self.state
|
||||
tag = '<' + tag + '>'
|
||||
targets = CODE_BLOCK_RE.findall(txt)
|
||||
if not targets:
|
||||
targets = [ txt ]
|
||||
tag_pos = 0
|
||||
for txt in targets:
|
||||
txt = txt2target(txt, st.opt_prefix)
|
||||
if not txt:
|
||||
continue
|
||||
if suf:
|
||||
txt += suf
|
||||
if txt in st.created_hashtags:
|
||||
for j in range(2, 1000):
|
||||
chk = txt + '-' + str(j)
|
||||
if chk not in st.created_hashtags:
|
||||
print('Made link target unique:', chk)
|
||||
txt = chk
|
||||
break
|
||||
if tag_pos == 0:
|
||||
tag_pos -= 1
|
||||
while st.html_out[tag_pos] != tag:
|
||||
tag_pos -= 1
|
||||
st.html_out[tag_pos] = tag[:-1] + ' id="' + txt + '">'
|
||||
st.html_out.append('<a href="#' + txt + '" class="tgt"></a>')
|
||||
tag_pos -= 1 # take into account the append
|
||||
else:
|
||||
st.html_out[tag_pos] = '<span id="' + txt + '"></span>' + st.html_out[tag_pos]
|
||||
st.created_hashtags.add(txt)
|
||||
st.latest_targets = targets
|
||||
|
||||
|
||||
def output_debug(self, event, extra):
|
||||
import pprint
|
||||
st = self.state
|
||||
if args.debug < 2:
|
||||
st = argparse.Namespace(**vars(st))
|
||||
if len(st.html_out) > 2:
|
||||
st.html_out = ['...'] + st.html_out[-2:]
|
||||
if len(st.man_out) > 2:
|
||||
st.man_out = ['...'] + st.man_out[-2:]
|
||||
print(event, extra)
|
||||
pprint.PrettyPrinter(indent=2).pprint(vars(st))
|
||||
|
||||
|
||||
def txt2target(txt, opt_prefix):
|
||||
txt = txt.strip().rstrip(':')
|
||||
m = CODE_BLOCK_RE.search(txt)
|
||||
if m:
|
||||
txt = m.group(1)
|
||||
txt = NBR_DASH_RE.sub('-', txt)
|
||||
txt = BIN_CHARS_RE.sub('', txt)
|
||||
txt = INVALID_TARGET_CHARS_RE.sub('_', txt)
|
||||
if opt_prefix and txt.startswith('-'):
|
||||
txt = opt_prefix + txt
|
||||
else:
|
||||
txt = INVALID_START_CHAR_RE.sub(r't\1', txt)
|
||||
return txt
|
||||
|
||||
|
||||
def manify(txt):
|
||||
return MANIFY_LINESTART_RE.sub(r'\&\1', txt.replace('\\', '\\\\')
|
||||
.replace(NBR_SPACE[0], NBR_SPACE[1])
|
||||
.replace(NBR_DASH[0], NBR_DASH[1])
|
||||
.replace(NORM_FONT[0], NORM_FONT[1])
|
||||
.replace(BOLD_FONT[0], BOLD_FONT[1])
|
||||
.replace(UNDR_FONT[0], UNDR_FONT[1]))
|
||||
|
||||
|
||||
def htmlify(txt):
|
||||
return txt.replace('&', '&').replace('<', '<').replace('>', '>').replace('"', '"')
|
||||
|
||||
|
||||
def warn(*msg):
|
||||
print(*msg, file=sys.stderr)
|
||||
global warning_count
|
||||
warning_count += 1
|
||||
|
||||
|
||||
def die(*msg):
|
||||
warn(*msg)
|
||||
sys.exit(1)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
parser = argparse.ArgumentParser(description="Convert markdown into html and (optionally) nroff. Each input filename must have a .md suffix, which is changed to .html for the output filename. If the input filename ends with .num.md (e.g. foo.1.md) then a nroff file is also output with the input filename's .md suffix removed (e.g. foo.1).", add_help=False)
|
||||
parser.add_argument('--test', action='store_true', help="Just test the parsing without outputting any files.")
|
||||
parser.add_argument('--dest', metavar='DIR', help="Create files in DIR instead of the current directory.")
|
||||
parser.add_argument('--force-link-text', action='store_true', help="Don't remove the link text if it matches the link href. Useful when nroff doesn't understand .UR and .UE.")
|
||||
parser.add_argument('--debug', '-D', action='count', default=0, help='Output copious info on the html parsing. Repeat for even more.')
|
||||
parser.add_argument("--help", "-h", action="help", help="Output this help message and exit.")
|
||||
parser.add_argument("mdfiles", metavar='FILE.md', nargs='+', help="One or more .md files to convert.")
|
||||
args = parser.parse_args()
|
||||
|
||||
try:
|
||||
import cmarkgfm
|
||||
md_parser = cmarkgfm.markdown_to_html
|
||||
gfm_parser = cmarkgfm.github_flavored_markdown_to_html
|
||||
except:
|
||||
try:
|
||||
import commonmark
|
||||
md_parser = html_via_commonmark
|
||||
except:
|
||||
die("Failed to find cmarkgfm or commonmark for python3.")
|
||||
gfm_parser = None
|
||||
|
||||
main()
|
||||
if warning_count:
|
||||
sys.exit(1)
|
||||
22
mkgitver
22
mkgitver
@@ -1,22 +0,0 @@
|
||||
#!/bin/sh
|
||||
|
||||
srcdir=`dirname $0`
|
||||
|
||||
if [ ! -f git-version.h ]; then
|
||||
touch git-version.h
|
||||
fi
|
||||
|
||||
if test -d "$srcdir/.git" || test -f "$srcdir/.git"; then
|
||||
gitver=`git describe --abbrev=8 2>/dev/null`
|
||||
# NOTE: I'm avoiding "|" in sed since I'm not sure if sed -r is portable and "\|" fails on some OSes.
|
||||
verchk=`echo "$gitver-" | sed -n '/^v3\.[0-9][0-9]*\.[0-9][0-9]*\(pre[0-9]*\)*-/p'`
|
||||
if [ -n "$verchk" ]; then
|
||||
echo "#define RSYNC_GITVER \"$gitver\"" >git-version.h.new
|
||||
if ! diff git-version.h.new git-version.h >/dev/null; then
|
||||
echo "Updating git-version.h"
|
||||
mv git-version.h.new git-version.h
|
||||
else
|
||||
rm git-version.h.new
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
40
mkproto.awk
40
mkproto.awk
@@ -1,40 +0,0 @@
|
||||
#!/usr/bin/awk -f
|
||||
|
||||
BEGIN {
|
||||
while ((getline i < "proto.h") > 0) old_protos = old_protos ? old_protos "\n" i : i
|
||||
close("proto.h")
|
||||
protos = "/* This file is automatically generated with \"make proto\". DO NOT EDIT */\n"
|
||||
}
|
||||
|
||||
inheader {
|
||||
protos = protos "\n" ((inheader = /\)[ \t]*$/ ? 0 : 1) ? $0 : $0 ";")
|
||||
next
|
||||
}
|
||||
|
||||
/^FN_(LOCAL|GLOBAL)_[^(]+\([^,()]+/ {
|
||||
local = /^FN_LOCAL/
|
||||
gsub(/^FN_(LOC|GLOB)AL_|,.*$/, "")
|
||||
sub(/^BOOL\(/, "BOOL ")
|
||||
sub(/^CHAR\(/, "char ")
|
||||
sub(/^INTEGER\(/, "int ")
|
||||
sub(/^STRING\(/, "char *")
|
||||
protos = protos "\n" $0 (local ? "(int module_id);" : "(void);")
|
||||
next
|
||||
}
|
||||
|
||||
/^static|^extern|;/||!/^[A-Za-z][A-Za-z0-9_]* / { next }
|
||||
|
||||
/\(.*\)[ \t]*$/ {
|
||||
protos = protos "\n" $0 ";"
|
||||
next
|
||||
}
|
||||
|
||||
/\(/ {
|
||||
inheader = 1
|
||||
protos = protos "\n" $0
|
||||
}
|
||||
|
||||
END {
|
||||
if (old_protos != protos) print protos > "proto.h"
|
||||
system("touch proto.h-tstamp")
|
||||
}
|
||||
48
mkproto.pl
Normal file
48
mkproto.pl
Normal 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;
|
||||
@@ -1,12 +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 finddead rrsync
|
||||
|
||||
.PHONY: $(TARGETS) auto-prep
|
||||
|
||||
$(TARGETS): auto-prep
|
||||
make -C build $@
|
||||
|
||||
auto-prep:
|
||||
@if test x`packaging/prep-auto-dir` = x; then echo "auto-build-save is not setup"; exit 1; fi
|
||||
@echo 'Build branch: '`readlink build/.branch | tr % /`
|
||||
6
packaging/bin/gpg
Executable file
6
packaging/bin/gpg
Executable 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 "${@}"
|
||||
@@ -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
|
||||
@@ -1,148 +0,0 @@
|
||||
#!/usr/bin/env python3
|
||||
# This script outputs either perl or python code that parses all possible options
|
||||
# that the code in options.c might send to the server. The resulting code is then
|
||||
# included in the rrsync script.
|
||||
|
||||
import re, argparse
|
||||
|
||||
short_no_arg = { }
|
||||
short_with_num = { '@': 1 }
|
||||
long_opts = { # These include some extra long-args that BackupPC uses:
|
||||
'block-size': 1,
|
||||
'daemon': -1,
|
||||
'debug': 1,
|
||||
'fake-super': 0,
|
||||
'fuzzy': 0,
|
||||
'group': 0,
|
||||
'hard-links': 0,
|
||||
'ignore-times': 0,
|
||||
'info': 1,
|
||||
'links': 0,
|
||||
'log-file': 3,
|
||||
'munge-links': 0,
|
||||
'no-munge-links': -1,
|
||||
'one-file-system': 0,
|
||||
'owner': 0,
|
||||
'perms': 0,
|
||||
'recursive': 0,
|
||||
'stderr': 1,
|
||||
'times': 0,
|
||||
'copy-devices': -1,
|
||||
'write-devices': -1,
|
||||
}
|
||||
|
||||
def main():
|
||||
last_long_opt = None
|
||||
|
||||
with open('../options.c') as fh:
|
||||
for line in fh:
|
||||
m = re.search(r"argstr\[x\+\+\] = '([^.ie])'", line)
|
||||
if m:
|
||||
short_no_arg[m.group(1)] = 1
|
||||
last_long_opt = None
|
||||
continue
|
||||
|
||||
m = re.search(r'asprintf\([^,]+, "-([a-zA-Z0-9])\%l?[ud]"', line)
|
||||
if m:
|
||||
short_with_num[m.group(1)] = 1
|
||||
last_long_opt = None
|
||||
continue
|
||||
|
||||
m = re.search(r'args\[ac\+\+\] = "--([^"=]+)"', line)
|
||||
if m:
|
||||
last_long_opt = m.group(1)
|
||||
if last_long_opt not in long_opts:
|
||||
long_opts[last_long_opt] = 0
|
||||
else:
|
||||
last_long_opt = None
|
||||
continue
|
||||
|
||||
if last_long_opt:
|
||||
m = re.search(r'args\[ac\+\+\] = safe_arg\("", ([^[("\s]+)\);', line)
|
||||
if m:
|
||||
long_opts[last_long_opt] = 2
|
||||
last_long_opt = None
|
||||
continue
|
||||
if 'args[ac++] = ' in line:
|
||||
last_long_opt = None
|
||||
|
||||
m = re.search(r'return "--([^"]+-dest)";', line)
|
||||
if m:
|
||||
long_opts[m.group(1)] = 2
|
||||
last_long_opt = None
|
||||
continue
|
||||
|
||||
m = re.search(r'asprintf\([^,]+, "--([^"=]+)=', line)
|
||||
if not m:
|
||||
m = re.search(r'args\[ac\+\+\] = "--([^"=]+)=', line)
|
||||
if not m:
|
||||
m = re.search(r'args\[ac\+\+\] = safe_arg\("--([^"=]+)"', line)
|
||||
if not m:
|
||||
m = re.search(r'fmt = .*: "--([^"=]+)=', line)
|
||||
if m:
|
||||
long_opts[m.group(1)] = 1
|
||||
last_long_opt = None
|
||||
|
||||
long_opts['files-from'] = 3
|
||||
|
||||
txt = """\
|
||||
### START of options data produced by the cull-options script. ###
|
||||
|
||||
# To disable a short-named option, add its letter to this string:
|
||||
"""
|
||||
|
||||
txt += str_assign('short_disabled', 's') + "\n"
|
||||
txt += '# These are also disabled when the restricted dir is not "/":\n'
|
||||
txt += str_assign('short_disabled_subdir', 'KLk') + "\n"
|
||||
txt += '# These are all possible short options that we will accept (when not disabled above):\n'
|
||||
txt += str_assign('short_no_arg', ''.join(sorted(short_no_arg)), 'DO NOT REMOVE ANY')
|
||||
txt += str_assign('short_with_num', ''.join(sorted(short_with_num)), 'DO NOT REMOVE ANY')
|
||||
|
||||
txt += """
|
||||
# To disable a long-named option, change its value to a -1. The values mean:
|
||||
# 0 = the option has no arg; 1 = the arg doesn't need any checking; 2 = only
|
||||
# check the arg when receiving; and 3 = always check the arg.
|
||||
"""
|
||||
|
||||
print(txt, end='')
|
||||
|
||||
if args.python:
|
||||
print("long_opts = {")
|
||||
sep = ':'
|
||||
else:
|
||||
print("our %long_opt = (")
|
||||
sep = ' =>'
|
||||
|
||||
for opt in sorted(long_opts):
|
||||
if opt.startswith(('min-', 'max-')):
|
||||
val = 1
|
||||
else:
|
||||
val = long_opts[opt]
|
||||
print(' ', repr(opt) + sep, str(val) + ',')
|
||||
|
||||
if args.python:
|
||||
print("}")
|
||||
else:
|
||||
print(");")
|
||||
print("\n### END of options data produced by the cull-options script. ###")
|
||||
|
||||
|
||||
def str_assign(name, val, comment=None):
|
||||
comment = ' # ' + comment if comment else ''
|
||||
if args.python:
|
||||
return name + ' = ' + repr(val) + comment + "\n"
|
||||
return 'our $' + name + ' = ' + repr(val) + ';' + comment + "\n"
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
parser = argparse.ArgumentParser(description="Output culled rsync options for rrsync.", add_help=False)
|
||||
out_group = parser.add_mutually_exclusive_group()
|
||||
out_group.add_argument('--perl', action='store_true', help="Output perl code.")
|
||||
out_group.add_argument('--python', action='store_true', help="Output python code (the default).")
|
||||
parser.add_argument('--help', '-h', action='help', help="Output this help message and exit.")
|
||||
args = parser.parse_args()
|
||||
if not args.perl:
|
||||
args.python = True
|
||||
main()
|
||||
|
||||
# vim: sw=4 et
|
||||
70
packaging/cull_options
Executable file
70
packaging/cull_options
Executable file
@@ -0,0 +1,70 @@
|
||||
#!/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;
|
||||
our %long_opt = (
|
||||
'no-i-r' => 0,
|
||||
'fake-super' => 0,
|
||||
'log-file' => 3,
|
||||
);
|
||||
our $last_long_opt;
|
||||
|
||||
open(IN, '../options.c') or die "Unable to open ../options.c: $!\n";
|
||||
|
||||
while (<IN>) {
|
||||
if (/\Qargstr[x++]\E = '([^.ie])'/) {
|
||||
$short_no_arg{$1} = 1;
|
||||
undef $last_long_opt;
|
||||
} elsif (/\Qasprintf(\E[^,]+, "-([a-zA-Z0-9])\%l?[ud]"/) {
|
||||
$short_with_num{$1} = 1;
|
||||
undef $last_long_opt;
|
||||
} elsif (/\Qargs[ac++]\E = "--([^"=]+)"/) {
|
||||
$last_long_opt = $1;
|
||||
$long_opt{$1} = 0;
|
||||
} elsif (defined($last_long_opt)
|
||||
&& /\Qargs[ac++]\E = ([^["\s]+);/ && $1 ne 'dest_option') {
|
||||
$long_opt{$last_long_opt} = 2;
|
||||
undef $last_long_opt;
|
||||
} elsif (/dest_option = "--([^"]+)"/) {
|
||||
$long_opt{$1} = 2;
|
||||
undef $last_long_opt;
|
||||
} elsif (/\Qasprintf(\E[^,]+, "--([^"=]+)=/ || /\Qargs[ac++]\E = "--([^"=]+)=/) {
|
||||
$long_opt{$1} = 1;
|
||||
undef $last_long_opt;
|
||||
}
|
||||
}
|
||||
close IN;
|
||||
|
||||
my $short_no_arg = join('', sort keys %short_no_arg);
|
||||
my $short_with_num = join('', sort keys %short_with_num);
|
||||
|
||||
print <<EOT;
|
||||
|
||||
# These options are the only options that rsync might send to the server,
|
||||
# and only in the option format that the stock rsync produces.
|
||||
|
||||
# To disable a short-named option, add its letter to this string:
|
||||
our \$short_disabled = 's';
|
||||
|
||||
our \$short_no_arg = '$short_no_arg'; # DO NOT REMOVE ANY
|
||||
our \$short_with_num = '$short_with_num'; # DO NOT REMOVE ANY
|
||||
|
||||
# To disable a long-named option, change its value to a -1. The values mean:
|
||||
# 0 = the option has no arg; 1 = the arg doesn't need any checking; 2 = only
|
||||
# check the arg when receiving; and 3 = always check the arg.
|
||||
our \%long_opt = (
|
||||
EOT
|
||||
|
||||
foreach my $opt (sort keys %long_opt) {
|
||||
my $val = $long_opt{$opt};
|
||||
$val = 1 if $opt =~ /^(max-|min-)/;
|
||||
$val = 3 if $opt eq 'files-from';
|
||||
$val = '$ro ? -1 : ' . $val if $opt =~ /^remove-/;
|
||||
print " '$opt' => $val,\n";
|
||||
}
|
||||
|
||||
print ");\n\n";
|
||||
18
packaging/extern-squish
Executable file
18
packaging/extern-squish
Executable 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;
|
||||
}
|
||||
}
|
||||
@@ -1,22 +1,17 @@
|
||||
Summary: A fast, versatile, remote (and local) file-copying tool
|
||||
Name: rsync
|
||||
Version: 3.3.0
|
||||
Version: 3.0.4
|
||||
%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 Apr 06 2024 Wayne Davison <wayne@opencoder.net>
|
||||
Released 3.3.0.
|
||||
* Sat Sep 06 2008 Wayne Davison <wayned@samba.org>
|
||||
Released 3.0.4.
|
||||
|
||||
* 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.
|
||||
|
||||
121
packaging/nightly-rsync
Executable file
121
packaging/nightly-rsync
Executable 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
|
||||
}
|
||||
@@ -1,18 +0,0 @@
|
||||
# This config file can be used with rsync to enable legacy digests
|
||||
# (such as MD4) by using the OPENSSL_CONF environment variable.
|
||||
# See rsync's configure --with-openssl-conf=/path/name option.
|
||||
|
||||
openssl_conf = openssl_init
|
||||
|
||||
[openssl_init]
|
||||
providers = provider_sect
|
||||
|
||||
[provider_sect]
|
||||
default = default_sect
|
||||
legacy = legacy_sect
|
||||
|
||||
[default_sect]
|
||||
activate = 1
|
||||
|
||||
[legacy_sect]
|
||||
activate = 1
|
||||
@@ -1,244 +1,220 @@
|
||||
#!/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.$$";
|
||||
|
||||
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 "./config.status Makefile && make gen && 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']).out == '':
|
||||
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
|
||||
skip_shell = False
|
||||
if not ok or args.cmd or args.make 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 not args.make and not args.cmd:
|
||||
skip_shell = True
|
||||
if args.make:
|
||||
if cmd_run(['packaging/smart-make']).returncode != 0:
|
||||
if not run_a_shell(parent, patch):
|
||||
return 0
|
||||
if not args.cmd:
|
||||
skip_shell = True
|
||||
if args.cmd:
|
||||
if cmd_run(args.cmd).returncode != 0:
|
||||
if not run_a_shell(parent, patch):
|
||||
return 0
|
||||
skip_shell = True
|
||||
if args.shell and not skip_shell:
|
||||
if not run_a_shell(parent, patch):
|
||||
return 0
|
||||
if ($incl_generated_files) {
|
||||
system "./config.status Makefile && make gen && 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('--make', '-m', action='store_true', help="Run the smart-make script in every patch branch.")
|
||||
parser.add_argument('--cmd', '-c', help="Run a command in every patch branch.")
|
||||
parser.add_argument('--shell', '-s', action='store_true', help="Launch a shell for every patch/BASE/* branch updated, not just when a conflict occurs.")
|
||||
parser.add_argument('--gen', metavar='DIR', nargs='?', const='', help='Include generated files. Optional DIR value overrides the default of using the "patches" dir.')
|
||||
parser.add_argument('--patches-dir', '-p', metavar='DIR', default='patches', help="Override the location of the rsync-patches dir. Default: patches.")
|
||||
parser.add_argument('patch_files', metavar='patches/DIFF_FILE', nargs='*', help="Specify what patch diff files to process. Default: all of them.")
|
||||
parser.add_argument("--help", "-h", action="help", help="Output this help message and exit.")
|
||||
args = parser.parse_args()
|
||||
if args.gen == '':
|
||||
args.gen = args.patches_dir
|
||||
elif args.gen is not None:
|
||||
args.patches_dir = args.gen
|
||||
main()
|
||||
|
||||
# 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
|
||||
}
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user