mirror of
https://github.com/RsyncProject/rsync.git
synced 2026-05-25 07:15:35 -04:00
Compare commits
223 Commits
v3.2.4pre2
...
v3.3.0
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
6c8ca91c73 | ||
|
|
079e74a30f | ||
|
|
abc3c74652 | ||
|
|
99ab59464b | ||
|
|
a47ae6fad9 | ||
|
|
2f9b963aba | ||
|
|
3476caea3e | ||
|
|
6f3c5eccee | ||
|
|
79fda35342 | ||
|
|
cd76993461 | ||
|
|
05a683900f | ||
|
|
86f41650fb | ||
|
|
9a06b2edb0 | ||
|
|
273dced284 | ||
|
|
b6e2321973 | ||
|
|
fe95a9369a | ||
|
|
6ae7f4085a | ||
|
|
0f599d3641 | ||
|
|
c3d3b49d72 | ||
|
|
c69dc7a5ab | ||
|
|
2c82006b1f | ||
|
|
0698ea9aeb | ||
|
|
90df93e446 | ||
|
|
5c93dedf45 | ||
|
|
f1e3434b59 | ||
|
|
48252c3c2b | ||
|
|
5b67ff2a86 | ||
|
|
8990ad96de | ||
|
|
0f44e864d4 | ||
|
|
ab0d5021ed | ||
|
|
7402896523 | ||
|
|
5374994089 | ||
|
|
526366129a | ||
|
|
556a2c5bc2 | ||
|
|
27feda0436 | ||
|
|
bf96cd314c | ||
|
|
1b2688807d | ||
|
|
08ec80ac65 | ||
|
|
6b5ae825db | ||
|
|
3b719d1d6e | ||
|
|
ebe1af749c | ||
|
|
de6848ed97 | ||
|
|
42f8386823 | ||
|
|
ad6245f394 | ||
|
|
ca980b5863 | ||
|
|
677aa0dc91 | ||
|
|
025596757c | ||
|
|
449d9bf950 | ||
|
|
35ecec972a | ||
|
|
d76cabe54f | ||
|
|
b5544a95b1 | ||
|
|
11bd2a4fd6 | ||
|
|
6ba434de5c | ||
|
|
3296351442 | ||
|
|
0088a85aeb | ||
|
|
4923c4dc0c | ||
|
|
76c4fa8b54 | ||
|
|
25efa10802 | ||
|
|
fdf5e577f5 | ||
|
|
19bd0dd340 | ||
|
|
ed4b3448be | ||
|
|
4d44bf122d | ||
|
|
6af27a538e | ||
|
|
f9e29dfb09 | ||
|
|
591de7ce5c | ||
|
|
c8c627756a | ||
|
|
46884e4ff6 | ||
|
|
97e02bf21a | ||
|
|
77d762ced8 | ||
|
|
5b27d2e6f3 | ||
|
|
7e634f5355 | ||
|
|
8fe8cfd60a | ||
|
|
7a2dbf7177 | ||
|
|
8449539a0f | ||
|
|
71c2b5d0e3 | ||
|
|
f3f5d8420f | ||
|
|
8b1b81e054 | ||
|
|
e8161304f7 | ||
|
|
b012cde1ed | ||
|
|
464555ea92 | ||
|
|
df904f590e | ||
|
|
208d6ad1cd | ||
|
|
51dae12c92 | ||
|
|
950730313d | ||
|
|
81c5c81381 | ||
|
|
a6a0d2f77c | ||
|
|
418e38a878 | ||
|
|
b2dcabdbb9 | ||
|
|
ad53a9b5a0 | ||
|
|
1750288660 | ||
|
|
087fffaa2b | ||
|
|
5c1fa2a21d | ||
|
|
0efa63f2e6 | ||
|
|
ae16850dc5 | ||
|
|
7e2711bb2b | ||
|
|
b8c2fde3a5 | ||
|
|
1f12b196fd | ||
|
|
bafe73dd5c | ||
|
|
db5bfe67a5 | ||
|
|
5447d038c6 | ||
|
|
711773631b | ||
|
|
bf3e49b453 | ||
|
|
034d5e8770 | ||
|
|
ad8917437a | ||
|
|
1b664d30e4 | ||
|
|
ea38f34d02 | ||
|
|
44d4727664 | ||
|
|
1f2f413167 | ||
|
|
0a09df2c5e | ||
|
|
cc861cf8c0 | ||
|
|
5183c0d6f0 | ||
|
|
706bff9176 | ||
|
|
2c1204032b | ||
|
|
8adc2240e0 | ||
|
|
84ad83525b | ||
|
|
9a3449a398 | ||
|
|
3258534e99 | ||
|
|
b94bba4036 | ||
|
|
a182507bef | ||
|
|
2895b65f53 | ||
|
|
def595c559 | ||
|
|
68b1ce1dc3 | ||
|
|
5a4116e553 | ||
|
|
024bf1d831 | ||
|
|
db4f919ebe | ||
|
|
6ac2c7b682 | ||
|
|
0e10163a9d | ||
|
|
5fcf20ee9d | ||
|
|
fc72d2b771 | ||
|
|
b7ea3fcd19 | ||
|
|
9cb7529ba6 | ||
|
|
55ad8757ec | ||
|
|
3e4b01173a | ||
|
|
2f1d1d5cac | ||
|
|
4c0a4067df | ||
|
|
8550142804 | ||
|
|
97f40754ba | ||
|
|
cff8f04477 | ||
|
|
db8034f12e | ||
|
|
c86763dc38 | ||
|
|
5ce575b157 | ||
|
|
fabef23bea | ||
|
|
685bf58046 | ||
|
|
9e2921fce8 | ||
|
|
80d8f7c7cb | ||
|
|
38e1b075b4 | ||
|
|
d659610afc | ||
|
|
6cafc1f8bf | ||
|
|
788f11ea6a | ||
|
|
b7fdc9ef0e | ||
|
|
0d8cc26044 | ||
|
|
2955888468 | ||
|
|
0773cecc1f | ||
|
|
8e33586359 | ||
|
|
da5c72da4b | ||
|
|
2f7c583143 | ||
|
|
51fd4993ba | ||
|
|
e37bfdb445 | ||
|
|
3d7015afa2 | ||
|
|
7e5424b806 | ||
|
|
43f70b961e | ||
|
|
b7231c7d02 | ||
|
|
15c34f0a8c | ||
|
|
d1e42ffa16 | ||
|
|
36f489c211 | ||
|
|
defe2287aa | ||
|
|
112bef11ad | ||
|
|
b38780f3fd | ||
|
|
5f33238f06 | ||
|
|
3592ac3c02 | ||
|
|
c897b16f32 | ||
|
|
4f741addbd | ||
|
|
355b81d8bc | ||
|
|
6f35553372 | ||
|
|
71090b7e2c | ||
|
|
2ab2ee166e | ||
|
|
1e858e39e6 | ||
|
|
664639e349 | ||
|
|
517b9d91fc | ||
|
|
0ac7ebceef | ||
|
|
85c56b2603 | ||
|
|
10aeb75cea | ||
|
|
d41bb98c09 | ||
|
|
2fda51692b | ||
|
|
1de71e8a78 | ||
|
|
60dd42be60 | ||
|
|
d821e4cbfb | ||
|
|
8aa465117f | ||
|
|
8977815f5d | ||
|
|
a48c20c97c | ||
|
|
601f47436f | ||
|
|
ef76d6cfa5 | ||
|
|
96ed4b47b9 | ||
|
|
13c4019e94 | ||
|
|
b7b387b1f7 | ||
|
|
7569edfaef | ||
|
|
55b2a06812 | ||
|
|
b81a509556 | ||
|
|
26f4dbe12c | ||
|
|
b3f1970f18 | ||
|
|
c51da9174f | ||
|
|
81f71f6f29 | ||
|
|
48e7005554 | ||
|
|
2b3e68814b | ||
|
|
cc83294316 | ||
|
|
08c8375acb | ||
|
|
824a057935 | ||
|
|
d91ddb97d1 | ||
|
|
5bb637ca04 | ||
|
|
142aba00d5 | ||
|
|
8687e44d10 | ||
|
|
0bd8e85185 | ||
|
|
00a5ab2364 | ||
|
|
f44e76b65c | ||
|
|
1174d97072 | ||
|
|
d9eaffe564 | ||
|
|
6197385d1f | ||
|
|
d07272d631 | ||
|
|
e2a011d9d0 | ||
|
|
76dc7d0a76 | ||
|
|
7e94e52144 | ||
|
|
5ef7e3c9c5 | ||
|
|
d2cc1149b3 |
@@ -1,7 +1,7 @@
|
||||
freebsd_task:
|
||||
name: FreeBSD
|
||||
freebsd_instance:
|
||||
image_family: freebsd-12-2
|
||||
image_family: freebsd-13-1
|
||||
env:
|
||||
PATH: /usr/local/bin:$PATH
|
||||
prep_script:
|
||||
|
||||
21
.github/workflows/build.yml
vendored
21
.github/workflows/build.yml
vendored
@@ -15,7 +15,7 @@ jobs:
|
||||
ubuntu-build:
|
||||
runs-on: ubuntu-20.04
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- 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
|
||||
@@ -38,7 +38,7 @@ jobs:
|
||||
- name: ssl file list
|
||||
run: rsync-ssl --no-motd download.samba.org::rsyncftp/ || true
|
||||
- name: save artifact
|
||||
uses: actions/upload-artifact@v2
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: ubuntu-bin
|
||||
path: |
|
||||
@@ -53,7 +53,7 @@ jobs:
|
||||
macos-build:
|
||||
runs-on: macos-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: actions/checkout@v3
|
||||
- name: prep
|
||||
run: |
|
||||
brew install automake openssl xxhash zstd lz4 wget
|
||||
@@ -73,7 +73,7 @@ jobs:
|
||||
- name: ssl file list
|
||||
run: rsync-ssl --no-motd download.samba.org::rsyncftp/ || true
|
||||
- name: save artifact
|
||||
uses: actions/upload-artifact@v2
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: macos-bin
|
||||
path: |
|
||||
@@ -86,16 +86,15 @@ jobs:
|
||||
rrsync
|
||||
|
||||
cygwin-build:
|
||||
runs-on: windows-latest
|
||||
runs-on: windows-2022
|
||||
if: (github.event_name == 'schedule' || contains(github.event.head_commit.message, '[buildall]'))
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: crazy-max/ghaction-chocolatey@v1.2.2
|
||||
with:
|
||||
args: install -y --no-progress cygwin cyg-get
|
||||
- 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 python38 python38-pip libzstd-devel liblz4-devel libssl-devel libxxhash0 libxxhash-devel
|
||||
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
|
||||
@@ -113,7 +112,7 @@ jobs:
|
||||
- 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@v2
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: cygwin-bin
|
||||
path: |
|
||||
|
||||
1
.gitignore
vendored
1
.gitignore
vendored
@@ -16,6 +16,7 @@ aclocal.m4
|
||||
/proto.h
|
||||
/proto.h-tstamp
|
||||
/rsync*.[15]
|
||||
/rrsync
|
||||
/rrsync*.1
|
||||
/rsync*.html
|
||||
/rrsync*.html
|
||||
|
||||
@@ -13,11 +13,11 @@ 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 & man pages
|
||||
## 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 man pages).
|
||||
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):
|
||||
@@ -26,9 +26,9 @@ build user (after installing python3's pip package):
|
||||
|
||||
You can test if you've got it fixed by running (from the rsync checkout):
|
||||
|
||||
> ./md2man --test rsync-ssl.1.md
|
||||
> ./md-convert --test rsync-ssl.1.md
|
||||
|
||||
Alternately, you can avoid generating the man pages by fetching the very latest
|
||||
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:
|
||||
|
||||
|
||||
26
Makefile.in
26
Makefile.in
@@ -30,11 +30,13 @@ SHELL=/bin/sh
|
||||
.SUFFIXES:
|
||||
.SUFFIXES: .c .o
|
||||
|
||||
SIMD_x86_64=simd-checksum-x86_64.o simd-checksum-avx2.o
|
||||
ASM_x86_64=lib/md5-asm-x86_64.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
|
||||
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
|
||||
LIBOBJ=lib/wildmatch.o lib/compat.o lib/snprintf.o lib/mdfour.o lib/md5.o \
|
||||
@@ -45,7 +47,7 @@ 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
|
||||
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 @ASM@ @SIMD@
|
||||
OBJS3=progress.o pipe.o @MD5_ASM@ @ROLL_SIMD@ @ROLL_ASM@
|
||||
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
|
||||
@@ -68,6 +70,8 @@ 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
|
||||
|
||||
@@ -146,13 +150,13 @@ git-version.h: ALWAYS_RUN
|
||||
ALWAYS_RUN:
|
||||
|
||||
simd-checksum-x86_64.o: simd-checksum-x86_64.cpp
|
||||
@$(srcdir)/cmd-or-msg disable-simd $(CXX) -I. $(CXXFLAGS) $(CPPFLAGS) -c -o $@ $(srcdir)/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-asm $(CC) $(CFLAGS) --include=$(srcdir)/rsync.h -DAVX2_ASM -I. @NOEXECSTACK@ -c -o $@ $(srcdir)/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 config.h lib/md-defines.h
|
||||
@$(srcdir)/cmd-or-msg disable-asm $(CC) -I. @NOEXECSTACK@ -c -o $@ $(srcdir)/lib/md5-asm-x86_64.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)
|
||||
@@ -271,9 +275,9 @@ rrsync.1: support/rrsync.1.md md-convert Makefile
|
||||
|
||||
.PHONY: clean
|
||||
clean: cleantests
|
||||
rm -f *~ $(OBJS) $(CHECK_PROGS) $(CHECK_OBJS) $(CHECK_SYMLINKS) \
|
||||
git-version.h rounding rounding.h *.old rsync*.1 rsync*.5 rsync*.html \
|
||||
daemon-parm.h help-*.h default-*.h proto.h proto.h-tstamp
|
||||
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
|
||||
|
||||
.PHONY: cleantests
|
||||
cleantests:
|
||||
|
||||
@@ -65,8 +65,8 @@ RSYNC DAEMONS
|
||||
-------------
|
||||
|
||||
Rsync can also talk to "rsync daemons" which can provide anonymous or
|
||||
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
|
||||
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
|
||||
connect to an rsync daemon.
|
||||
|
||||
|
||||
|
||||
1
acls.c
1
acls.c
@@ -519,6 +519,7 @@ 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)) {
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
* Support rsync daemon authentication.
|
||||
*
|
||||
* Copyright (C) 1998-2000 Andrew Tridgell
|
||||
* Copyright (C) 2002-2020 Wayne Davison
|
||||
* Copyright (C) 2002-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
|
||||
@@ -24,6 +24,7 @@
|
||||
|
||||
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
|
||||
@@ -72,9 +73,9 @@ static void gen_challenge(const char *addr, char *challenge)
|
||||
SIVAL(input, 20, tv.tv_usec);
|
||||
SIVAL(input, 24, getpid());
|
||||
|
||||
sum_init(-1, 0);
|
||||
len = sum_init(valid_auth_checksums.negotiated_nni, 0);
|
||||
sum_update(input, sizeof input);
|
||||
len = sum_end(digest);
|
||||
sum_end(digest);
|
||||
|
||||
base64_encode(digest, len, challenge, 0);
|
||||
}
|
||||
@@ -86,10 +87,10 @@ static void generate_hash(const char *in, const char *challenge, char *out)
|
||||
char buf[MAX_DIGEST_LEN];
|
||||
int len;
|
||||
|
||||
sum_init(-1, 0);
|
||||
len = sum_init(valid_auth_checksums.negotiated_nni, 0);
|
||||
sum_update(in, strlen(in));
|
||||
sum_update(challenge, strlen(challenge));
|
||||
len = sum_end(buf);
|
||||
sum_end(buf);
|
||||
|
||||
base64_encode(buf, len, out, 0);
|
||||
}
|
||||
@@ -238,6 +239,7 @@ char *auth_server(int f_in, int f_out, int module, const char *host,
|
||||
if (!users || !*users)
|
||||
return "";
|
||||
|
||||
negotiate_daemon_auth(f_out, 0);
|
||||
gen_challenge(addr, challenge);
|
||||
|
||||
io_printf(f_out, "%s%s\n", leader, challenge);
|
||||
@@ -350,6 +352,7 @@ 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"))) {
|
||||
|
||||
4
batch.c
4
batch.c
@@ -3,7 +3,7 @@
|
||||
*
|
||||
* Copyright (C) 1999 Weiss
|
||||
* Copyright (C) 2004 Chris Shoemaker
|
||||
* Copyright (C) 2004-2020 Wayne Davison
|
||||
* Copyright (C) 2004-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
|
||||
@@ -194,7 +194,7 @@ 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;
|
||||
err = write(batch_sh_fd, opt, len) != len ? 1 : 0;
|
||||
if (arg) {
|
||||
err |= write(batch_sh_fd, "=", 1) != 1;
|
||||
err |= write_arg(arg);
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
* Simple byteorder handling.
|
||||
*
|
||||
* Copyright (C) 1992-1995 Andrew Tridgell
|
||||
* Copyright (C) 2007-2020 Wayne Davison
|
||||
* 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
|
||||
@@ -129,4 +129,3 @@ SIVAL(char *buf, int pos, uint32 val)
|
||||
{
|
||||
SIVALu((uchar*)buf, pos, val);
|
||||
}
|
||||
|
||||
|
||||
473
checksum.c
473
checksum.c
@@ -3,7 +3,7 @@
|
||||
*
|
||||
* Copyright (C) 1996 Andrew Tridgell
|
||||
* Copyright (C) 1996 Paul Mackerras
|
||||
* Copyright (C) 2004-2020 Wayne Davison
|
||||
* Copyright (C) 2004-2023 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
|
||||
@@ -42,41 +42,94 @@ extern int protocol_version;
|
||||
extern int proper_seed_order;
|
||||
extern const char *checksum_choice;
|
||||
|
||||
struct name_num_obj valid_checksums = {
|
||||
"checksum", NULL, NULL, 0, 0, {
|
||||
#define NNI_BUILTIN (1<<0)
|
||||
#define NNI_EVP (1<<1)
|
||||
#define NNI_EVP_OK (1<<2)
|
||||
|
||||
struct name_num_item valid_checksums_items[] = {
|
||||
#ifdef SUPPORT_XXH3
|
||||
{ CSUM_XXH3_128, "xxh128", NULL },
|
||||
{ CSUM_XXH3_64, "xxh3", NULL },
|
||||
{ CSUM_XXH3_128, 0, "xxh128", NULL },
|
||||
{ CSUM_XXH3_64, 0, "xxh3", NULL },
|
||||
#endif
|
||||
#ifdef SUPPORT_XXHASH
|
||||
{ CSUM_XXH64, "xxh64", NULL },
|
||||
{ CSUM_XXH64, "xxhash", NULL },
|
||||
{ CSUM_XXH64, 0, "xxh64", NULL },
|
||||
{ CSUM_XXH64, 0, "xxhash", NULL },
|
||||
#endif
|
||||
{ CSUM_MD5, "md5", NULL },
|
||||
{ CSUM_MD4, "md4", NULL },
|
||||
{ CSUM_NONE, "none", NULL },
|
||||
{ 0, NULL, NULL }
|
||||
}
|
||||
{ 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 }
|
||||
};
|
||||
|
||||
int xfersum_type = 0; /* used for the file transfer checksums */
|
||||
int checksum_type = 0; /* used for the pre-transfer (--checksum) checksums */
|
||||
struct name_num_obj valid_checksums = {
|
||||
"checksum", NULL, 0, 0, valid_checksums_items
|
||||
};
|
||||
|
||||
int parse_csum_name(const char *name, int len)
|
||||
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)
|
||||
return CSUM_MD5;
|
||||
if (protocol_version >= 27)
|
||||
return CSUM_MD4_OLD;
|
||||
if (protocol_version >= 21)
|
||||
return CSUM_MD4_BUSTED;
|
||||
return CSUM_MD4_ARCHAIC;
|
||||
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);
|
||||
@@ -86,44 +139,74 @@ int parse_csum_name(const char *name, int len)
|
||||
exit_cleanup(RERR_UNSUPPORTED);
|
||||
}
|
||||
|
||||
return nni->num;
|
||||
return nni;
|
||||
}
|
||||
|
||||
static const char *checksum_name(int num)
|
||||
#ifdef USE_OPENSSL
|
||||
static const EVP_MD *csum_evp_md(struct name_num_item *nni)
|
||||
{
|
||||
struct name_num_item *nni = get_nni_by_num(&valid_checksums, num);
|
||||
const EVP_MD *emd;
|
||||
if (!(nni->flags & NNI_EVP))
|
||||
return NULL;
|
||||
|
||||
return nni ? nni->name : num < CSUM_MD4 ? "md4" : "UNKNOWN";
|
||||
#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_name)
|
||||
xfersum_type = checksum_type = valid_checksums.negotiated_num;
|
||||
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) {
|
||||
xfersum_type = parse_csum_name(checksum_choice, cp - checksum_choice);
|
||||
checksum_type = parse_csum_name(cp+1, -1);
|
||||
xfer_sum_nni = parse_csum_name(checksum_choice, cp - checksum_choice);
|
||||
file_sum_nni = parse_csum_name(cp+1, -1);
|
||||
} else
|
||||
xfersum_type = checksum_type = parse_csum_name(checksum_choice, -1);
|
||||
xfer_sum_nni = file_sum_nni = parse_csum_name(checksum_choice, -1);
|
||||
if (am_server && checksum_choice)
|
||||
validate_choice_vs_env(NSTR_CHECKSUM, xfersum_type, checksum_type);
|
||||
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
|
||||
|
||||
if (xfersum_type == CSUM_NONE)
|
||||
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_name)
|
||||
checksum_choice = valid_checksums.negotiated_name;
|
||||
if (valid_checksums.negotiated_nni)
|
||||
checksum_choice = valid_checksums.negotiated_nni->name;
|
||||
else if (checksum_choice == NULL)
|
||||
checksum_choice = checksum_name(xfersum_type);
|
||||
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_name ? " negotiated" : "",
|
||||
valid_checksums.negotiated_nni ? " negotiated" : "",
|
||||
checksum_choice);
|
||||
}
|
||||
}
|
||||
@@ -143,6 +226,18 @@ int csum_len_for_type(int cst, BOOL flist_csum)
|
||||
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;
|
||||
@@ -168,6 +263,9 @@ int canonical_checksum(int csum_type)
|
||||
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:
|
||||
@@ -179,7 +277,7 @@ int canonical_checksum(int csum_type)
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifndef HAVE_SIMD /* See simd-checksum-*.cpp. */
|
||||
#ifndef USE_ROLL_SIMD /* See simd-checksum-*.cpp. */
|
||||
/*
|
||||
a simple 32 bit checksum that can be updated from either end
|
||||
(inspired by Mark Adler's Adler-32 checksum)
|
||||
@@ -202,9 +300,25 @@ uint32 get_checksum1(char *buf1, int32 len)
|
||||
}
|
||||
#endif
|
||||
|
||||
/* The "sum" buffer must be at least MAX_DIGEST_LEN bytes! */
|
||||
void get_checksum2(char *buf, int32 len, char *sum)
|
||||
{
|
||||
switch (xfersum_type) {
|
||||
#ifdef USE_OPENSSL
|
||||
if (xfer_sum_evp_md) {
|
||||
static EVP_MD_CTX *evp = NULL;
|
||||
uchar seedbuf[4];
|
||||
if (!evp && !(evp = EVP_MD_CTX_create()))
|
||||
out_of_memory("get_checksum2");
|
||||
EVP_DigestInit_ex(evp, xfer_sum_evp_md, NULL);
|
||||
if (checksum_seed) {
|
||||
SIVALu(seedbuf, 0, checksum_seed);
|
||||
EVP_DigestUpdate(evp, 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));
|
||||
@@ -222,40 +336,26 @@ void get_checksum2(char *buf, int32 len, char *sum)
|
||||
}
|
||||
#endif
|
||||
case CSUM_MD5: {
|
||||
MD5_CTX m5;
|
||||
md_context m5;
|
||||
uchar seedbuf[4];
|
||||
MD5_Init(&m5);
|
||||
md5_begin(&m5);
|
||||
if (proper_seed_order) {
|
||||
if (checksum_seed) {
|
||||
SIVALu(seedbuf, 0, checksum_seed);
|
||||
MD5_Update(&m5, seedbuf, 4);
|
||||
md5_update(&m5, seedbuf, 4);
|
||||
}
|
||||
MD5_Update(&m5, (uchar *)buf, len);
|
||||
md5_update(&m5, (uchar *)buf, len);
|
||||
} else {
|
||||
MD5_Update(&m5, (uchar *)buf, len);
|
||||
md5_update(&m5, (uchar *)buf, len);
|
||||
if (checksum_seed) {
|
||||
SIVALu(seedbuf, 0, checksum_seed);
|
||||
MD5_Update(&m5, seedbuf, 4);
|
||||
md5_update(&m5, seedbuf, 4);
|
||||
}
|
||||
}
|
||||
MD5_Final((uchar *)sum, &m5);
|
||||
md5_result(&m5, (uchar *)sum);
|
||||
break;
|
||||
}
|
||||
case CSUM_MD4:
|
||||
#ifdef USE_OPENSSL
|
||||
{
|
||||
MD4_CTX m4;
|
||||
MD4_Init(&m4);
|
||||
MD4_Update(&m4, (uchar *)buf, len);
|
||||
if (checksum_seed) {
|
||||
uchar seedbuf[4];
|
||||
SIVALu(seedbuf, 0, checksum_seed);
|
||||
MD4_Update(&m4, seedbuf, 4);
|
||||
}
|
||||
MD4_Final((uchar *)sum, &m4);
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
case CSUM_MD4_OLD:
|
||||
case CSUM_MD4_BUSTED:
|
||||
case CSUM_MD4_ARCHAIC: {
|
||||
@@ -288,7 +388,7 @@ void get_checksum2(char *buf, int32 len, char *sum)
|
||||
* are multiples of 64. This is fixed by calling mdfour_update()
|
||||
* even when there are no more bytes.
|
||||
*/
|
||||
if (len - i > 0 || xfersum_type > CSUM_MD4_BUSTED)
|
||||
if (len - i > 0 || xfer_sum_nni->num > CSUM_MD4_BUSTED)
|
||||
mdfour_update(&m, (uchar *)(buf1+i), len-i);
|
||||
|
||||
mdfour_result(&m, (uchar *)sum);
|
||||
@@ -306,15 +406,33 @@ void file_checksum(const char *fname, const STRUCT_STAT *st_p, char *sum)
|
||||
int32 remainder;
|
||||
int fd;
|
||||
|
||||
memset(sum, 0, MAX_DIGEST_LEN);
|
||||
|
||||
fd = do_open(fname, O_RDONLY, 0);
|
||||
if (fd == -1)
|
||||
if (fd == -1) {
|
||||
memset(sum, 0, file_sum_len);
|
||||
return;
|
||||
}
|
||||
|
||||
buf = map_file(fd, len, MAX_MAP_SIZE, CHUNK_SIZE);
|
||||
|
||||
switch (checksum_type) {
|
||||
#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");
|
||||
|
||||
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);
|
||||
|
||||
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;
|
||||
@@ -374,38 +492,21 @@ void file_checksum(const char *fname, const STRUCT_STAT *st_p, char *sum)
|
||||
}
|
||||
#endif
|
||||
case CSUM_MD5: {
|
||||
MD5_CTX m5;
|
||||
md_context m5;
|
||||
|
||||
MD5_Init(&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);
|
||||
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_update(&m5, (uchar *)map_ptr(buf, i, remainder), remainder);
|
||||
|
||||
MD5_Final((uchar *)sum, &m5);
|
||||
md5_result(&m5, (uchar *)sum);
|
||||
break;
|
||||
}
|
||||
case CSUM_MD4:
|
||||
#ifdef USE_OPENSSL
|
||||
{
|
||||
MD4_CTX m4;
|
||||
|
||||
MD4_Init(&m4);
|
||||
|
||||
for (i = 0; i + CHUNK_SIZE <= len; i += CHUNK_SIZE)
|
||||
MD4_Update(&m4, (uchar *)map_ptr(buf, i, CHUNK_SIZE), CHUNK_SIZE);
|
||||
|
||||
remainder = (int32)(len - i);
|
||||
if (remainder > 0)
|
||||
MD4_Update(&m4, (uchar *)map_ptr(buf, i, remainder), remainder);
|
||||
|
||||
MD4_Final((uchar *)sum, &m4);
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
case CSUM_MD4_OLD:
|
||||
case CSUM_MD4_BUSTED:
|
||||
case CSUM_MD4_ARCHAIC: {
|
||||
@@ -413,15 +514,15 @@ void file_checksum(const char *fname, const STRUCT_STAT *st_p, char *sum)
|
||||
|
||||
mdfour_begin(&m);
|
||||
|
||||
for (i = 0; i + CHUNK_SIZE <= len; i += CHUNK_SIZE)
|
||||
mdfour_update(&m, (uchar *)map_ptr(buf, i, CHUNK_SIZE), CHUNK_SIZE);
|
||||
for (i = 0; i + CSUM_CHUNK <= len; i += CSUM_CHUNK)
|
||||
mdfour_update(&m, (uchar *)map_ptr(buf, i, CSUM_CHUNK), CSUM_CHUNK);
|
||||
|
||||
/* Prior to version 27 an incorrect MD4 checksum was computed
|
||||
* by failing to call mdfour_tail() for block sizes that
|
||||
* are multiples of 64. This is fixed by calling mdfour_update()
|
||||
* even when there are no more bytes. */
|
||||
remainder = (int32)(len - i);
|
||||
if (remainder > 0 || checksum_type > CSUM_MD4_BUSTED)
|
||||
if (remainder > 0 || file_sum_nni->num > CSUM_MD4_BUSTED)
|
||||
mdfour_update(&m, (uchar *)map_ptr(buf, i, remainder), remainder);
|
||||
|
||||
mdfour_result(&m, (uchar *)sum);
|
||||
@@ -429,7 +530,7 @@ void file_checksum(const char *fname, const STRUCT_STAT *st_p, char *sum)
|
||||
}
|
||||
default:
|
||||
rprintf(FERROR, "Invalid checksum-choice for --checksum: %s (%d)\n",
|
||||
checksum_name(checksum_type), checksum_type);
|
||||
file_sum_nni->name, file_sum_nni->num);
|
||||
exit_cleanup(RERR_UNSUPPORTED);
|
||||
}
|
||||
|
||||
@@ -438,30 +539,43 @@ void file_checksum(const char *fname, const STRUCT_STAT *st_p, char *sum)
|
||||
}
|
||||
|
||||
static int32 sumresidue;
|
||||
static union {
|
||||
md_context md;
|
||||
#ifdef USE_OPENSSL
|
||||
MD4_CTX m4;
|
||||
#endif
|
||||
MD5_CTX m5;
|
||||
} ctx;
|
||||
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 int cursum_type;
|
||||
static struct name_num_item *cur_sum_nni;
|
||||
int cur_sum_len;
|
||||
|
||||
void sum_init(int csum_type, int seed)
|
||||
#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)
|
||||
{
|
||||
char s[4];
|
||||
|
||||
if (csum_type < 0)
|
||||
csum_type = parse_csum_name(NULL, 0);
|
||||
cursum_type = csum_type;
|
||||
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
|
||||
|
||||
switch (csum_type) {
|
||||
#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()))
|
||||
@@ -482,20 +596,16 @@ void sum_init(int csum_type, int seed)
|
||||
break;
|
||||
#endif
|
||||
case CSUM_MD5:
|
||||
MD5_Init(&ctx.m5);
|
||||
md5_begin(&ctx_md);
|
||||
break;
|
||||
case CSUM_MD4:
|
||||
#ifdef USE_OPENSSL
|
||||
MD4_Init(&ctx.m4);
|
||||
#else
|
||||
mdfour_begin(&ctx.md);
|
||||
mdfour_begin(&ctx_md);
|
||||
sumresidue = 0;
|
||||
#endif
|
||||
break;
|
||||
case CSUM_MD4_OLD:
|
||||
case CSUM_MD4_BUSTED:
|
||||
case CSUM_MD4_ARCHAIC:
|
||||
mdfour_begin(&ctx.md);
|
||||
mdfour_begin(&ctx_md);
|
||||
sumresidue = 0;
|
||||
SIVAL(s, 0, seed);
|
||||
sum_update(s, 4);
|
||||
@@ -505,19 +615,19 @@ void sum_init(int csum_type, int seed)
|
||||
default: /* paranoia to prevent missing case values */
|
||||
exit_cleanup(RERR_UNSUPPORTED);
|
||||
}
|
||||
|
||||
return cur_sum_len;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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.
|
||||
**/
|
||||
/* Feed data into a hash digest accumulator. */
|
||||
void sum_update(const char *p, int32 len)
|
||||
{
|
||||
switch (cursum_type) {
|
||||
#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);
|
||||
@@ -532,39 +642,35 @@ void sum_update(const char *p, int32 len)
|
||||
break;
|
||||
#endif
|
||||
case CSUM_MD5:
|
||||
MD5_Update(&ctx.m5, (uchar *)p, len);
|
||||
md5_update(&ctx_md, (uchar *)p, len);
|
||||
break;
|
||||
case CSUM_MD4:
|
||||
#ifdef USE_OPENSSL
|
||||
MD4_Update(&ctx.m4, (uchar *)p, len);
|
||||
break;
|
||||
#endif
|
||||
case CSUM_MD4_OLD:
|
||||
case CSUM_MD4_BUSTED:
|
||||
case CSUM_MD4_ARCHAIC:
|
||||
if (len + sumresidue < CSUM_CHUNK) {
|
||||
memcpy(ctx.md.buffer + sumresidue, p, len);
|
||||
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);
|
||||
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);
|
||||
mdfour_update(&ctx_md, (uchar *)p, CSUM_CHUNK);
|
||||
len -= CSUM_CHUNK;
|
||||
p += CSUM_CHUNK;
|
||||
}
|
||||
|
||||
sumresidue = len;
|
||||
if (sumresidue)
|
||||
memcpy(ctx.md.buffer, p, sumresidue);
|
||||
memcpy(ctx_md.buffer, p, sumresidue);
|
||||
break;
|
||||
case CSUM_NONE:
|
||||
break;
|
||||
@@ -573,13 +679,18 @@ void sum_update(const char *p, int32 len)
|
||||
}
|
||||
}
|
||||
|
||||
/* NOTE: all the callers of sum_end() pass in a pointer to a buffer that is
|
||||
* MAX_DIGEST_LEN in size, so even if the csum-len is shorter that that (i.e.
|
||||
* CSUM_MD4_ARCHAIC), we don't have to worry about limiting the data we write
|
||||
* into the "sum" buffer. */
|
||||
int sum_end(char *sum)
|
||||
/* 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)
|
||||
{
|
||||
switch (cursum_type) {
|
||||
#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));
|
||||
@@ -597,22 +708,18 @@ int sum_end(char *sum)
|
||||
}
|
||||
#endif
|
||||
case CSUM_MD5:
|
||||
MD5_Final((uchar *)sum, &ctx.m5);
|
||||
md5_result(&ctx_md, (uchar *)sum);
|
||||
break;
|
||||
case CSUM_MD4:
|
||||
#ifdef USE_OPENSSL
|
||||
MD4_Final((uchar *)sum, &ctx.m4);
|
||||
break;
|
||||
#endif
|
||||
case CSUM_MD4_OLD:
|
||||
mdfour_update(&ctx.md, (uchar *)ctx.md.buffer, sumresidue);
|
||||
mdfour_result(&ctx.md, (uchar *)sum);
|
||||
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);
|
||||
mdfour_update(&ctx_md, (uchar *)ctx_md.buffer, sumresidue);
|
||||
mdfour_result(&ctx_md, (uchar *)sum);
|
||||
break;
|
||||
case CSUM_NONE:
|
||||
*sum = '\0';
|
||||
@@ -620,6 +727,78 @@ int sum_end(char *sum)
|
||||
default: /* paranoia to prevent missing case values */
|
||||
exit_cleanup(RERR_UNSUPPORTED);
|
||||
}
|
||||
|
||||
return csum_len_for_type(cursum_type, 0);
|
||||
}
|
||||
|
||||
#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;
|
||||
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)
|
||||
return;
|
||||
|
||||
#if defined USE_OPENSSL && OPENSSL_VERSION_NUMBER < 0x10100000L
|
||||
OpenSSL_add_all_algorithms();
|
||||
#endif
|
||||
|
||||
#if defined SUPPORT_XXH3 || defined USE_OPENSSL
|
||||
for (nni = valid_checksums.list; nni->name; nni++)
|
||||
verify_digest(nni, True);
|
||||
|
||||
for (nni = valid_auth_checksums.list; nni->name; nni++)
|
||||
verify_digest(nni, False);
|
||||
#endif
|
||||
|
||||
initialized_choices = 1;
|
||||
}
|
||||
|
||||
113
clientserver.c
113
clientserver.c
@@ -47,6 +47,7 @@ extern int protocol_version;
|
||||
extern int io_timeout;
|
||||
extern int no_detach;
|
||||
extern int write_batch;
|
||||
extern int old_style_args;
|
||||
extern int default_af_hint;
|
||||
extern int logfile_format_has_i;
|
||||
extern int logfile_format_has_o_or_i;
|
||||
@@ -66,6 +67,7 @@ extern uid_t our_uid;
|
||||
extern gid_t our_gid;
|
||||
|
||||
char *auth_user;
|
||||
char *daemon_auth_choices;
|
||||
int read_only = 0;
|
||||
int module_id = -1;
|
||||
int pid_file_fd = -1;
|
||||
@@ -148,13 +150,9 @@ int start_socket_client(char *host, int remote_argc, char *remote_argv[],
|
||||
static int exchange_protocols(int f_in, int f_out, char *buf, size_t bufsiz, int am_client)
|
||||
{
|
||||
int remote_sub = -1;
|
||||
#if SUBPROTOCOL_VERSION != 0
|
||||
int our_sub = protocol_version < PROTOCOL_VERSION ? 0 : SUBPROTOCOL_VERSION;
|
||||
#else
|
||||
int our_sub = 0;
|
||||
#endif
|
||||
int our_sub = get_subprotocol_version();
|
||||
|
||||
io_printf(f_out, "@RSYNCD: %d.%d\n", protocol_version, our_sub);
|
||||
output_daemon_greeting(f_out, am_client);
|
||||
if (!am_client) {
|
||||
char *motd = lp_motd_file();
|
||||
if (motd && *motd) {
|
||||
@@ -186,16 +184,30 @@ static int exchange_protocols(int f_in, int f_out, char *buf, size_t bufsiz, int
|
||||
}
|
||||
|
||||
if (remote_sub < 0) {
|
||||
if (remote_protocol == 30) {
|
||||
if (remote_protocol >= 30) {
|
||||
if (am_client)
|
||||
rprintf(FERROR, "rsync: server is speaking an incompatible beta of protocol 30\n");
|
||||
rprintf(FERROR, "rsync: the server omitted the subprotocol value: %s\n", buf);
|
||||
else
|
||||
io_printf(f_out, "@ERROR: your client is speaking an incompatible beta of protocol 30\n");
|
||||
io_printf(f_out, "@ERROR: your client omitted the subprotocol value: %s\n", buf);
|
||||
return -1;
|
||||
}
|
||||
remote_sub = 0;
|
||||
}
|
||||
|
||||
daemon_auth_choices = strchr(buf + 9, ' ');
|
||||
if (daemon_auth_choices) {
|
||||
char *cp;
|
||||
daemon_auth_choices = strdup(daemon_auth_choices + 1);
|
||||
if ((cp = strchr(daemon_auth_choices, '\n')) != NULL)
|
||||
*cp = '\0';
|
||||
} else if (remote_protocol > 31) {
|
||||
if (am_client)
|
||||
rprintf(FERROR, "rsync: the server omitted the digest name list: %s\n", buf);
|
||||
else
|
||||
io_printf(f_out, "@ERROR: your client omitted the digest name list: %s\n", buf);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (protocol_version > remote_protocol) {
|
||||
protocol_version = remote_protocol;
|
||||
if (remote_sub)
|
||||
@@ -288,20 +300,45 @@ int start_inband_exchange(int f_in, int f_out, const char *user, int argc, char
|
||||
|
||||
sargs[sargc++] = ".";
|
||||
|
||||
if (!old_style_args)
|
||||
snprintf(line, sizeof line, " %.*s/", modlen, modname);
|
||||
|
||||
while (argc > 0) {
|
||||
if (sargc >= MAX_ARGS - 1) {
|
||||
arg_overflow:
|
||||
rprintf(FERROR, "internal: args[] overflowed in do_cmd()\n");
|
||||
exit_cleanup(RERR_SYNTAX);
|
||||
}
|
||||
if (strncmp(*argv, modname, modlen) == 0
|
||||
&& argv[0][modlen] == '\0')
|
||||
if (strncmp(*argv, modname, modlen) == 0 && argv[0][modlen] == '\0')
|
||||
sargs[sargc++] = modname; /* we send "modname/" */
|
||||
else if (**argv == '-') {
|
||||
if (asprintf(sargs + sargc++, "./%s", *argv) < 0)
|
||||
out_of_memory("start_inband_exchange");
|
||||
} else
|
||||
sargs[sargc++] = *argv;
|
||||
else {
|
||||
char *arg = *argv;
|
||||
int extra_chars = *arg == '-' ? 2 : 0; /* a leading dash needs a "./" prefix. */
|
||||
/* If --old-args was not specified, make sure that the arg won't split at a mod name! */
|
||||
if (!old_style_args && (p = strstr(arg, line)) != NULL) {
|
||||
do {
|
||||
extra_chars += 2;
|
||||
} while ((p = strstr(p+1, line)) != NULL);
|
||||
}
|
||||
if (extra_chars) {
|
||||
char *f = arg;
|
||||
char *t = arg = new_array(char, strlen(arg) + extra_chars + 1);
|
||||
if (*f == '-') {
|
||||
*t++ = '.';
|
||||
*t++ = '/';
|
||||
}
|
||||
while (*f) {
|
||||
if (*f == ' ' && strncmp(f, line, modlen+2) == 0) {
|
||||
*t++ = '[';
|
||||
*t++ = *f++;
|
||||
*t++ = ']';
|
||||
} else
|
||||
*t++ = *f++;
|
||||
}
|
||||
*t = '\0';
|
||||
}
|
||||
sargs[sargc++] = arg;
|
||||
}
|
||||
argv++;
|
||||
argc--;
|
||||
}
|
||||
@@ -355,7 +392,7 @@ int start_inband_exchange(int f_in, int f_out, const char *user, int argc, char
|
||||
|
||||
if (rl_nulls) {
|
||||
for (i = 0; i < sargc; i++) {
|
||||
if (!sargs[i]) /* stop at --protect-args NULL */
|
||||
if (!sargs[i]) /* stop at --secluded-args NULL */
|
||||
break;
|
||||
write_sbuf(f_out, sargs[i]);
|
||||
write_byte(f_out, 0);
|
||||
@@ -403,7 +440,7 @@ static int read_arg_from_pipe(int fd, char *buf, int limit)
|
||||
}
|
||||
#endif
|
||||
|
||||
static void set_env_str(const char *var, const char *str)
|
||||
void set_env_str(const char *var, const char *str)
|
||||
{
|
||||
#ifdef HAVE_SETENV
|
||||
if (setenv(var, str, 1) < 0)
|
||||
@@ -664,7 +701,7 @@ static int rsync_module(int f_in, int f_out, int i, const char *addr, const char
|
||||
int set_uid;
|
||||
char *p, *err_msg = NULL;
|
||||
char *name = lp_name(i);
|
||||
int use_chroot = lp_use_chroot(i);
|
||||
int use_chroot = lp_use_chroot(i); /* might be 1 (yes), 0 (no), or -1 (unset) */
|
||||
int ret, pre_exec_arg_fd = -1, pre_exec_error_fd = -1;
|
||||
int save_munge_symlinks;
|
||||
pid_t pre_exec_pid = 0;
|
||||
@@ -789,6 +826,20 @@ static int rsync_module(int f_in, int f_out, int i, const char *addr, const char
|
||||
io_printf(f_out, "@ERROR: no path setting.\n");
|
||||
return -1;
|
||||
}
|
||||
if (use_chroot < 0) {
|
||||
if (strstr(module_dir, "/./") != NULL)
|
||||
use_chroot = 1; /* The module is expecting a chroot inner & outer path. */
|
||||
else if (chroot("/") < 0) {
|
||||
rprintf(FLOG, "chroot test failed: %s. "
|
||||
"Switching 'use chroot' from unset to false.\n",
|
||||
strerror(errno));
|
||||
use_chroot = 0;
|
||||
} else {
|
||||
if (chdir("/") < 0)
|
||||
rsyserr(FLOG, errno, "chdir(\"/\") failed");
|
||||
use_chroot = 1;
|
||||
}
|
||||
}
|
||||
if (use_chroot) {
|
||||
if ((p = strstr(module_dir, "/./")) != NULL) {
|
||||
*p = '\0'; /* Temporary... */
|
||||
@@ -925,20 +976,8 @@ static int rsync_module(int f_in, int f_out, int i, const char *addr, const char
|
||||
}
|
||||
|
||||
if (use_chroot) {
|
||||
/*
|
||||
* XXX: The 'use chroot' flag is a fairly reliable
|
||||
* source of confusion, because it fails under two
|
||||
* important circumstances: running as non-root,
|
||||
* running on Win32 (or possibly others). On the
|
||||
* other hand, if you are running as root, then it
|
||||
* might be better to always use chroot.
|
||||
*
|
||||
* So, perhaps if we can't chroot we should just issue
|
||||
* a warning, unless a "require chroot" flag is set,
|
||||
* in which case we fail.
|
||||
*/
|
||||
if (chroot(module_chdir)) {
|
||||
rsyserr(FLOG, errno, "chroot %s failed", module_chdir);
|
||||
rsyserr(FLOG, errno, "chroot(\"%s\") failed", module_chdir);
|
||||
io_printf(f_out, "@ERROR: chroot failed\n");
|
||||
return -1;
|
||||
}
|
||||
@@ -947,7 +986,7 @@ static int rsync_module(int f_in, int f_out, int i, const char *addr, const char
|
||||
|
||||
if (!change_dir(module_chdir, CD_NORMAL))
|
||||
return path_failure(f_out, module_chdir, True);
|
||||
if (module_dirlen || (!use_chroot && !*lp_daemon_chroot()))
|
||||
if (module_dirlen)
|
||||
sanitize_paths = 1;
|
||||
|
||||
if ((munge_symlinks = lp_munge_symlinks(module_id)) < 0)
|
||||
@@ -1262,8 +1301,12 @@ int start_daemon(int f_in, int f_out)
|
||||
p = lp_daemon_chroot();
|
||||
if (*p) {
|
||||
log_init(0); /* Make use we've initialized syslog before chrooting. */
|
||||
if (chroot(p) < 0 || chdir("/") < 0) {
|
||||
rsyserr(FLOG, errno, "daemon chroot %s failed", p);
|
||||
if (chroot(p) < 0) {
|
||||
rsyserr(FLOG, errno, "daemon chroot(\"%s\") failed", p);
|
||||
return -1;
|
||||
}
|
||||
if (chdir("/") < 0) {
|
||||
rsyserr(FLOG, errno, "daemon chdir(\"/\") failed");
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
208
compat.c
208
compat.c
@@ -60,13 +60,16 @@ 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 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;
|
||||
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 */
|
||||
@@ -79,6 +82,9 @@ 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;
|
||||
|
||||
@@ -91,19 +97,21 @@ int filesfrom_convert = 0;
|
||||
|
||||
#define MAX_NSTR_STRLEN 256
|
||||
|
||||
struct name_num_obj valid_compressions = {
|
||||
"compress", NULL, NULL, 0, 0, {
|
||||
struct name_num_item valid_compressions_items[] = {
|
||||
#ifdef SUPPORT_ZSTD
|
||||
{ CPRES_ZSTD, "zstd", NULL },
|
||||
{ CPRES_ZSTD, 0, "zstd", NULL },
|
||||
#endif
|
||||
#ifdef SUPPORT_LZ4
|
||||
{ CPRES_LZ4, "lz4", NULL },
|
||||
{ CPRES_LZ4, 0, "lz4", NULL },
|
||||
#endif
|
||||
{ CPRES_ZLIBX, "zlibx", NULL },
|
||||
{ CPRES_ZLIB, "zlib", NULL },
|
||||
{ CPRES_NONE, "none", NULL },
|
||||
{ 0, NULL, NULL }
|
||||
}
|
||||
{ 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)
|
||||
@@ -125,11 +133,7 @@ static void check_sub_protocol(void)
|
||||
{
|
||||
char *dot;
|
||||
int their_protocol, their_sub;
|
||||
#if SUBPROTOCOL_VERSION != 0
|
||||
int our_sub = protocol_version < PROTOCOL_VERSION ? 0 : SUBPROTOCOL_VERSION;
|
||||
#else
|
||||
int our_sub = 0;
|
||||
#endif
|
||||
int our_sub = get_subprotocol_version();
|
||||
|
||||
/* client_info starts with VER.SUB string if client is a pre-release. */
|
||||
if (!(their_protocol = atoi(client_info))
|
||||
@@ -176,8 +180,8 @@ void set_allow_inc_recurse(void)
|
||||
|
||||
void parse_compress_choice(int final_call)
|
||||
{
|
||||
if (valid_compressions.negotiated_name)
|
||||
do_compression = valid_compressions.negotiated_num;
|
||||
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) {
|
||||
@@ -199,8 +203,8 @@ void parse_compress_choice(int final_call)
|
||||
compress_choice = NULL;
|
||||
|
||||
/* Snag the compression name for both write_batch's option output & the following debug output. */
|
||||
if (valid_compressions.negotiated_name)
|
||||
compress_choice = valid_compressions.negotiated_name;
|
||||
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";
|
||||
@@ -210,7 +214,7 @@ void parse_compress_choice(int final_call)
|
||||
&& (do_compression != CPRES_NONE || do_compression_level != CLVL_NOT_SPECIFIED)) {
|
||||
rprintf(FINFO, "%s%s compress: %s (level %d)\n",
|
||||
am_server ? "Server" : "Client",
|
||||
valid_compressions.negotiated_name ? " negotiated" : "",
|
||||
valid_compressions.negotiated_nni ? " negotiated" : "",
|
||||
compress_choice, do_compression_level);
|
||||
}
|
||||
}
|
||||
@@ -223,6 +227,8 @@ struct name_num_item *get_nni_by_name(struct name_num_obj *nno, const char *name
|
||||
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;
|
||||
}
|
||||
@@ -257,10 +263,12 @@ static void init_nno_saw(struct name_num_obj *nno, int val)
|
||||
if (!nno->saw) {
|
||||
nno->saw = new_array0(uchar, nno->saw_len);
|
||||
|
||||
/* We'll take this opportunity to make sure that the main_name values are set right. */
|
||||
/* 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_name = nno->list[nno->saw[nni->num]-1].name;
|
||||
nni->main_nni = &nno->list[nno->saw[nni->num]-1];
|
||||
else
|
||||
nno->saw[nni->num] = cnt;
|
||||
}
|
||||
@@ -286,8 +294,8 @@ static int parse_nni_str(struct name_num_obj *nno, const char *from, char *tobuf
|
||||
struct name_num_item *nni = get_nni_by_name(nno, tok, to - tok);
|
||||
if (nni && !nno->saw[nni->num]) {
|
||||
nno->saw[nni->num] = ++cnt;
|
||||
if (nni->main_name) {
|
||||
to = tok + strlcpy(tok, nni->main_name, tobuf_len - (tok - tobuf));
|
||||
if (nni->main_nni) {
|
||||
to = tok + strlcpy(tok, nni->main_nni->name, tobuf_len - (tok - tobuf));
|
||||
if (to - tobuf >= tobuf_len) {
|
||||
to = tok - 1;
|
||||
break;
|
||||
@@ -321,13 +329,44 @@ static int parse_nni_str(struct name_num_obj *nno, const char *from, char *tobuf
|
||||
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)
|
||||
{
|
||||
struct name_num_item *ret = NULL;
|
||||
|
||||
if (len < 0)
|
||||
len = read_vstring(f_in, tmpbuf, MAX_NSTR_STRLEN);
|
||||
|
||||
@@ -338,37 +377,8 @@ static void recv_negotiate_str(int f_in, struct name_num_obj *nno, char *tmpbuf,
|
||||
rprintf(FINFO, "Server %s list (on client): %s\n", nno->type, tmpbuf);
|
||||
}
|
||||
|
||||
if (len > 0) {
|
||||
struct name_num_item *nni;
|
||||
int best = nno->saw_len; /* We want best == 1 from the client list, so start with a big number. */
|
||||
char *space, *tok = tmpbuf;
|
||||
while (tok) {
|
||||
while (*tok == ' ') tok++; /* Should be unneeded... */
|
||||
if (!*tok)
|
||||
break;
|
||||
if ((space = strchr(tok, ' ')) != NULL)
|
||||
*space = '\0';
|
||||
nni = get_nni_by_name(nno, tok, -1);
|
||||
if (space) {
|
||||
*space = ' ';
|
||||
tok = space + 1;
|
||||
} else
|
||||
tok = NULL;
|
||||
if (!nni || !nno->saw[nni->num] || best <= nno->saw[nni->num])
|
||||
continue;
|
||||
ret = nni;
|
||||
best = nno->saw[nni->num];
|
||||
if (best == 1 || am_server) /* The server side stops at the first acceptable client choice */
|
||||
break;
|
||||
}
|
||||
if (ret) {
|
||||
free(nno->saw);
|
||||
nno->saw = NULL;
|
||||
nno->negotiated_name = ret->main_name ? ret->main_name : ret->name;
|
||||
nno->negotiated_num = ret->num;
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (len > 0 && parse_negotiate_str(nno, tmpbuf))
|
||||
return;
|
||||
|
||||
if (!am_server || !do_negotiated_strings) {
|
||||
char *cp = tmpbuf;
|
||||
@@ -400,7 +410,7 @@ 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)
|
||||
if (write_batch)
|
||||
env_str = ntype == NSTR_COMPRESS ? "zlib" : protocol_version >= 30 ? "md5" : "md4";
|
||||
|
||||
if (am_server && env_str) {
|
||||
@@ -433,7 +443,7 @@ void validate_choice_vs_env(int ntype, int num1, int num2)
|
||||
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",
|
||||
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);
|
||||
@@ -464,8 +474,10 @@ int get_default_nno_list(struct name_num_obj *nno, char *to_buf, int to_buf_len,
|
||||
init_nno_saw(nno, 0);
|
||||
|
||||
for (nni = nno->list, len = 0; nni->name; nni++) {
|
||||
if (nni->main_name) {
|
||||
if (!dup_markup)
|
||||
if (nni->num == CSUM_gone)
|
||||
continue;
|
||||
if (nni->main_nni) {
|
||||
if (!dup_markup || nni->main_nni->num == CSUM_gone)
|
||||
continue;
|
||||
delim = dup_markup;
|
||||
}
|
||||
@@ -523,6 +535,8 @@ 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);
|
||||
|
||||
@@ -552,7 +566,7 @@ static void negotiate_the_strings(int f_in, int f_out)
|
||||
/* If the other side is too old to negotiate, the above steps just made sure that
|
||||
* the env didn't disallow the old algorithm. Mark things as non-negotiated. */
|
||||
if (!do_negotiated_strings)
|
||||
valid_checksums.negotiated_name = valid_compressions.negotiated_name = NULL;
|
||||
valid_checksums.negotiated_nni = valid_compressions.negotiated_nni = NULL;
|
||||
}
|
||||
|
||||
void setup_protocol(int f_out,int f_in)
|
||||
@@ -604,7 +618,7 @@ void setup_protocol(int f_out,int f_in)
|
||||
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 man page for an explanation)\n");
|
||||
rprintf(FERROR,"(see the rsync manpage for an explanation)\n");
|
||||
exit_cleanup(RERR_PROTOCOL);
|
||||
}
|
||||
if (remote_protocol < OLD_PROTOCOL_VERSION) {
|
||||
@@ -801,11 +815,77 @@ void setup_protocol(int f_out,int f_in)
|
||||
checksum_seed = read_int(f_in);
|
||||
}
|
||||
|
||||
parse_checksum_choice(1); /* Sets checksum_type & xfersum_type */
|
||||
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
|
||||
}
|
||||
|
||||
1210
config.guess
vendored
1210
config.guess
vendored
File diff suppressed because it is too large
Load Diff
676
config.sub
vendored
676
config.sub
vendored
File diff suppressed because it is too large
Load Diff
227
configure.ac
227
configure.ac
@@ -4,7 +4,6 @@ AC_INIT([rsync],[ ],[https://rsync.samba.org/bug-tracking.html])
|
||||
|
||||
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 compat.h sys/param.h ctype.h sys/wait.h sys/stat.h \
|
||||
@@ -13,16 +12,17 @@ AC_CHECK_HEADERS(sys/fcntl.h sys/select.h fcntl.h sys/time.h sys/unistd.h \
|
||||
netdb.h malloc.h float.h limits.h iconv.h libcharset.h langinfo.h mcheck.h \
|
||||
sys/acl.h acl/libacl.h attr/xattr.h sys/xattr.h sys/extattr.h dl.h \
|
||||
popt.h popt/popt.h linux/falloc.h netinet/in_systm.h netgroup.h \
|
||||
zlib.h xxhash.h openssl/md4.h openssl/md5.h zstd.h lz4.h sys/file.h)
|
||||
zlib.h xxhash.h openssl/md4.h openssl/md5.h zstd.h lz4.h sys/file.h \
|
||||
bsd/string.h)
|
||||
AC_CHECK_HEADERS([netinet/ip.h], [], [], [[#include <netinet/in.h>]])
|
||||
AC_HEADER_MAJOR_FIXED
|
||||
|
||||
AC_CONFIG_MACRO_DIR([m4])
|
||||
AC_CONFIG_SRCDIR([byteorder.h])
|
||||
AC_CONFIG_HEADER(config.h)
|
||||
AC_CONFIG_HEADERS([config.h])
|
||||
AC_PREREQ([2.69])
|
||||
|
||||
PACKAGE_VERSION=`sed 's/.*"\(.*\)".*/\1/' <$srcdir/version.h`
|
||||
PACKAGE_VERSION=`sed -n 's/.*RSYNC_VERSION.*"\(.*\)".*/\1/p' <$srcdir/version.h`
|
||||
|
||||
AC_MSG_NOTICE([Configuring rsync $PACKAGE_VERSION])
|
||||
|
||||
@@ -60,7 +60,6 @@ AC_PROG_AWK
|
||||
AC_PROG_EGREP
|
||||
AC_PROG_INSTALL
|
||||
AC_PROG_MKDIR_P
|
||||
AC_PROG_CC_STDC
|
||||
AC_SUBST(SHELL)
|
||||
AC_PATH_PROG([PERL], [perl])
|
||||
AC_PATH_PROG([PYTHON3], [python3])
|
||||
@@ -83,7 +82,7 @@ if test x"$enable_profile" = x"yes"; then
|
||||
CFLAGS="$CFLAGS -pg"
|
||||
fi
|
||||
|
||||
AC_MSG_CHECKING([if md2man can create man pages])
|
||||
AC_MSG_CHECKING([if md2man can create manpages])
|
||||
if test x"$ac_cv_path_PYTHON3" = x; then
|
||||
AC_MSG_RESULT(no - python3 not found)
|
||||
md2man_works=no
|
||||
@@ -101,7 +100,7 @@ fi
|
||||
|
||||
AC_MSG_CHECKING([if we require man-page building])
|
||||
AC_ARG_ENABLE([md2man],
|
||||
AS_HELP_STRING([--disable-md2man],[disable to omit man page creation]))
|
||||
AS_HELP_STRING([--disable-md2man],[disable to omit manpage creation]))
|
||||
if test x"$enable_md2man" != x"no"; then
|
||||
if test -f "$srcdir/rsync.1"; then
|
||||
AC_MSG_RESULT(optional)
|
||||
@@ -109,7 +108,7 @@ if test x"$enable_md2man" != x"no"; then
|
||||
AC_MSG_RESULT(required)
|
||||
if test x"$md2man_works" = x"no"; then
|
||||
err_msg="$err_msg$nl- You need python3 and either the cmarkgfm OR commonmark python3 lib in order"
|
||||
err_msg="$err_msg$nl to build man pages based on the git source (man pages are included in the"
|
||||
err_msg="$err_msg$nl to build manpages based on the git source (manpages are included in the"
|
||||
err_msg="$err_msg$nl official release tar files)."
|
||||
no_lib="$no_lib md2man"
|
||||
fi
|
||||
@@ -135,13 +134,24 @@ if test x"$GCC" = x"yes"; then
|
||||
CFLAGS="$CFLAGS -Wall -W"
|
||||
fi
|
||||
|
||||
AC_ARG_WITH(openssl-conf,
|
||||
AS_HELP_STRING([--with-openssl-conf=PATH],[set default OPENSSL_CONF path for rsync]))
|
||||
case "$with_openssl_conf" in
|
||||
*[^-/a-zA-Z0-9.,=@+_]*) AC_MSG_ERROR([Invalid path given to --with-openssl-conf]) ;;
|
||||
/*) CFLAGS="$CFLAGS -DSET_OPENSSL_CONF=$with_openssl_conf" ;;
|
||||
no|'') ;;
|
||||
yes) AC_MSG_ERROR([No path given to --with-openssl-conf]) ;;
|
||||
*) AC_MSG_ERROR([Non absolute path given to --with-openssl-conf]) ;;
|
||||
esac
|
||||
|
||||
AC_ARG_WITH(rrsync,
|
||||
AS_HELP_STRING([--with-rrsync],[also install the rrsync script and its man page]))
|
||||
AS_HELP_STRING([--with-rrsync],[also install the rrsync script and its manpage]))
|
||||
if test x"$with_rrsync" != x"yes"; then
|
||||
with_rrsync=no
|
||||
else
|
||||
MAKE_RRSYNC='rrsync'
|
||||
MAKE_RRSYNC_1='rrsync.1'
|
||||
GEN_RRSYNC='rrsync.1 rrsync.1.html'
|
||||
fi
|
||||
AC_SUBST(with_rrsync)
|
||||
|
||||
@@ -151,10 +161,10 @@ AC_ARG_WITH(included-popt,
|
||||
AC_ARG_WITH(included-zlib,
|
||||
AS_HELP_STRING([--with-included-zlib],[use bundled zlib library, not from system]))
|
||||
|
||||
AC_ARG_WITH(protected-args,
|
||||
AS_HELP_STRING([--with-protected-args],[make --protected-args option the default]))
|
||||
if test x"$with_protected_args" = x"yes"; then
|
||||
AC_DEFINE_UNQUOTED(RSYNC_USE_PROTECTED_ARGS, 1, [Define to 1 if --protected-args should be the default])
|
||||
AC_ARG_WITH(secluded-args,
|
||||
AS_HELP_STRING([--with-secluded-args],[make --secluded-args option the default]))
|
||||
if test x"$with_secluded_args" = x"yes"; then
|
||||
AC_DEFINE_UNQUOTED(RSYNC_USE_SECLUDED_ARGS, 1, [Define to 1 if --secluded-args should be the default])
|
||||
fi
|
||||
|
||||
AC_ARG_WITH(rsync-path,
|
||||
@@ -228,12 +238,12 @@ fi
|
||||
AC_DEFINE_UNQUOTED(NOBODY_USER, "$NOBODY_USER", [unprivileged user--e.g. nobody])
|
||||
AC_DEFINE_UNQUOTED(NOBODY_GROUP, "$NOBODY_GROUP", [unprivileged group for unprivileged user])
|
||||
|
||||
# SIMD optimizations
|
||||
SIMD=
|
||||
# rolling-checksum SIMD optimizations
|
||||
ROLL_SIMD=
|
||||
|
||||
AC_MSG_CHECKING([whether to enable SIMD optimizations])
|
||||
AC_ARG_ENABLE(simd,
|
||||
AS_HELP_STRING([--enable-simd],[enable/disable to control SIMD optimizations (requires c++)]))
|
||||
AC_MSG_CHECKING([whether to enable rolling-checksum SIMD optimizations])
|
||||
AC_ARG_ENABLE(roll-simd,
|
||||
AS_HELP_STRING([--enable-roll-simd],[enable/disable to control rolling-checksum SIMD optimizations (requires c++)]))
|
||||
|
||||
# Clag is crashing with -g -O2, so we'll get rid of -g for now.
|
||||
CXXFLAGS=`echo "$CXXFLAGS" | sed 's/-g //'`
|
||||
@@ -262,14 +272,14 @@ __attribute__ ((target("ssse3"))) void more_testing(char* buf, int len)
|
||||
}
|
||||
]])
|
||||
|
||||
if test x"$enable_simd" = x""; then
|
||||
if test x"$enable_roll_simd" = x""; then
|
||||
case "$host_os" in
|
||||
*linux*) ;;
|
||||
*) enable_simd=no ;;
|
||||
*) enable_roll_simd=no ;;
|
||||
esac
|
||||
fi
|
||||
|
||||
if test x"$enable_simd" != x"no"; then
|
||||
if test x"$enable_roll_simd" != x"no"; then
|
||||
# For x86-64 SIMD, g++ >=5 or clang++ >=7 is required
|
||||
if test x"$host_cpu" = x"x86_64" || test x"$host_cpu" = x"amd64"; then
|
||||
AC_LANG(C++)
|
||||
@@ -282,23 +292,23 @@ if test x"$enable_simd" != x"no"; then
|
||||
AC_LANG(C)
|
||||
if test x"$CXX_OK" = x"yes"; then
|
||||
# AC_MSG_RESULT() is called below.
|
||||
SIMD="$host_cpu"
|
||||
elif test x"$enable_simd" = x"yes"; then
|
||||
ROLL_SIMD="$host_cpu"
|
||||
elif test x"$enable_roll_simd" = x"yes"; then
|
||||
AC_MSG_RESULT(error)
|
||||
AC_MSG_ERROR(The SIMD compilation test failed.
|
||||
Omit --enable-simd to continue without it.)
|
||||
AC_MSG_ERROR(The rolling-checksum SIMD compilation test failed.
|
||||
Omit --enable-roll-simd to continue without it.)
|
||||
fi
|
||||
elif test x"$enable_simd" = x"yes"; then
|
||||
elif test x"$enable_roll_simd" = x"yes"; then
|
||||
AC_MSG_RESULT(unavailable)
|
||||
AC_MSG_ERROR(The SIMD optimizations are currently x86_64|amd64 only.
|
||||
Omit --enable-simd to continue without it.)
|
||||
AC_MSG_ERROR(The rolling-checksum SIMD optimizations are currently x86_64|amd64 only.
|
||||
Omit --enable-roll-simd to continue without it.)
|
||||
fi
|
||||
fi
|
||||
|
||||
if test x"$SIMD" != x""; then
|
||||
AC_MSG_RESULT([yes ($SIMD)])
|
||||
AC_DEFINE(HAVE_SIMD, 1, [Define to 1 to enable SIMD optimizations])
|
||||
SIMD='$(SIMD_'"$SIMD)"
|
||||
if test x"$ROLL_SIMD" != x""; then
|
||||
AC_MSG_RESULT([yes ($ROLL_SIMD)])
|
||||
AC_DEFINE(USE_ROLL_SIMD, 1, [Define to 1 to enable rolling-checksum SIMD optimizations])
|
||||
ROLL_SIMD='$(ROLL_SIMD_'"$ROLL_SIMD)"
|
||||
# We only use c++ for its target attribute dispatching, disable unneeded bulky features
|
||||
CXXFLAGS="$CXXFLAGS -fno-exceptions -fno-rtti"
|
||||
# Apple often has "g++" as a symlink for clang. Try to find out the truth.
|
||||
@@ -310,7 +320,7 @@ else
|
||||
AC_MSG_RESULT(no)
|
||||
fi
|
||||
|
||||
AC_SUBST(SIMD)
|
||||
AC_SUBST(ROLL_SIMD)
|
||||
|
||||
AC_MSG_CHECKING([if assembler accepts noexecstack])
|
||||
OLD_CFLAGS="$CFLAGS"
|
||||
@@ -321,52 +331,19 @@ AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[ ]], [[return 0;]])],
|
||||
CFLAGS="$OLD_CFLAGS"
|
||||
AC_SUBST(NOEXECSTACK)
|
||||
|
||||
ASM=
|
||||
|
||||
AC_MSG_CHECKING([whether to enable ASM optimizations])
|
||||
AC_ARG_ENABLE(asm,
|
||||
AS_HELP_STRING([--enable-asm],[enable/disable to control ASM optimizations]))
|
||||
|
||||
if test x"$enable_asm" = x""; then
|
||||
case "$host_os" in
|
||||
*linux*) ;;
|
||||
*) enable_asm=no ;;
|
||||
esac
|
||||
fi
|
||||
|
||||
if test x"$enable_asm" != x"no"; then
|
||||
if test x"$host_cpu" = x"x86_64" || test x"$host_cpu" = x"amd64"; then
|
||||
ASM="$host_cpu"
|
||||
elif test x"$enable_asm" = x"yes"; then
|
||||
AC_MSG_RESULT(unavailable)
|
||||
AC_MSG_ERROR(The ASM optimizations are currently x86_64|amd64 only.
|
||||
Omit --enable-asm to continue without it.)
|
||||
fi
|
||||
fi
|
||||
|
||||
if test x"$ASM" != x""; then
|
||||
AC_MSG_RESULT([yes ($ASM)])
|
||||
AC_DEFINE(HAVE_ASM, 1, [Define to 1 to enable ASM optimizations])
|
||||
ASM='$(ASM_'"$ASM)"
|
||||
else
|
||||
AC_MSG_RESULT(no)
|
||||
fi
|
||||
|
||||
AC_SUBST(ASM)
|
||||
|
||||
# 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_RUN_IFELSE([AC_LANG_SOURCE([[
|
||||
#define _FILE_OFFSET_BITS 64
|
||||
#include <stdio.h>
|
||||
#include <fcntl.h>
|
||||
#ifdef HAVE_SYS_TYPES_H
|
||||
#include <sys/types.h>
|
||||
$ac_includes_default
|
||||
#ifdef HAVE_FCNTL_H
|
||||
# include <fcntl.h>
|
||||
#elif defined HAVE_SYS_FCNTL_H
|
||||
# include <sys/fcntl.h>
|
||||
#endif
|
||||
#ifdef HAVE_SYS_WAIT_H
|
||||
#include <sys/wait.h>
|
||||
#if HAVE_UNISTD_H
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
|
||||
int main(void)
|
||||
@@ -411,7 +388,7 @@ AS_HELP_STRING([--disable-ipv6],[disable to omit ipv6 support]),
|
||||
;;
|
||||
esac ],
|
||||
|
||||
AC_TRY_RUN([ /* AF_INET6 avalable check */
|
||||
AC_RUN_IFELSE([AC_LANG_SOURCE([[ /* AF_INET6 availability check */
|
||||
#include <stdlib.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/socket.h>
|
||||
@@ -422,11 +399,11 @@ main()
|
||||
else
|
||||
exit(0);
|
||||
}
|
||||
],
|
||||
AC_MSG_RESULT(yes)
|
||||
AC_DEFINE(INET6, 1, [true if you have IPv6]),
|
||||
AC_MSG_RESULT(no),
|
||||
AC_MSG_RESULT(no)
|
||||
]])],
|
||||
[AC_MSG_RESULT(yes)
|
||||
AC_DEFINE(INET6, 1, true if you have IPv6)],
|
||||
[AC_MSG_RESULT(no)],
|
||||
[AC_MSG_RESULT(no)]
|
||||
))
|
||||
|
||||
dnl Do you want to disable use of locale functions
|
||||
@@ -455,19 +432,77 @@ AH_TEMPLATE([USE_OPENSSL],
|
||||
if test x"$enable_openssl" != x"no"; then
|
||||
if test x"$ac_cv_header_openssl_md4_h" = x"yes" && test x"$ac_cv_header_openssl_md5_h" = x"yes"; then
|
||||
AC_MSG_RESULT(yes)
|
||||
AC_SEARCH_LIBS(MD5_Init, crypto,
|
||||
[AC_DEFINE(USE_OPENSSL)],
|
||||
[err_msg="$err_msg$nl- Failed to find MD5_Init function in openssl crypto lib.";
|
||||
AC_SEARCH_LIBS(EVP_MD_CTX_copy, crypto,
|
||||
[AC_DEFINE(USE_OPENSSL)
|
||||
enable_openssl=yes],
|
||||
[err_msg="$err_msg$nl- Failed to find EVP_MD_CTX_copy function in openssl crypto lib.";
|
||||
no_lib="$no_lib openssl"])
|
||||
else
|
||||
AC_MSG_RESULT(no)
|
||||
err_msg="$err_msg$nl- Failed to find openssl/md4.h and openssl/md5.h for openssl crypto lib support."
|
||||
no_lib="$no_lib openssl"
|
||||
fi
|
||||
if test x"$enable_md5_asm" != x"yes"; then
|
||||
enable_md5_asm=no
|
||||
fi
|
||||
else
|
||||
AC_MSG_RESULT(no)
|
||||
fi
|
||||
|
||||
MD5_ASM=
|
||||
|
||||
AC_MSG_CHECKING([whether to enable MD5 ASM optimizations])
|
||||
AC_ARG_ENABLE(md5-asm,
|
||||
AS_HELP_STRING([--enable-md5-asm],[enable/disable to control MD5 ASM optimizations]))
|
||||
|
||||
if test x"$enable_md5_asm" = x""; then
|
||||
case "$host_os" in
|
||||
*linux*) ;;
|
||||
*) enable_md5_asm=no ;;
|
||||
esac
|
||||
fi
|
||||
|
||||
if test x"$enable_md5_asm" != x"no"; then
|
||||
if test x"$host_cpu" = x"x86_64" || test x"$host_cpu" = x"amd64"; then
|
||||
MD5_ASM="$host_cpu"
|
||||
elif test x"$enable_md5_asm" = x"yes"; then
|
||||
AC_MSG_RESULT(unavailable)
|
||||
AC_MSG_ERROR(The ASM optimizations are currently x86_64|amd64 only.
|
||||
Omit --enable-md5-asm to continue without it.)
|
||||
fi
|
||||
fi
|
||||
|
||||
if test x"$MD5_ASM" != x""; then
|
||||
AC_MSG_RESULT([yes ($MD5_ASM)])
|
||||
AC_DEFINE(USE_MD5_ASM, 1, [Define to 1 to enable MD5 ASM optimizations])
|
||||
MD5_ASM='$(MD5_ASM_'"$MD5_ASM)"
|
||||
else
|
||||
AC_MSG_RESULT(no)
|
||||
fi
|
||||
|
||||
AC_SUBST(MD5_ASM)
|
||||
|
||||
ROLL_ASM=
|
||||
|
||||
AC_MSG_CHECKING([whether to enable rolling-checksum ASM optimizations])
|
||||
AC_ARG_ENABLE(roll-asm,
|
||||
AS_HELP_STRING([--enable-roll-asm],[enable/disable to control rolling-checksum ASM optimizations (requires --enable-roll-simd)]))
|
||||
|
||||
if test x"$ROLL_SIMD" = x""; then
|
||||
enable_roll_asm=no
|
||||
fi
|
||||
|
||||
if test x"$enable_roll_asm" = x"yes"; then
|
||||
ROLL_ASM="$host_cpu"
|
||||
AC_MSG_RESULT([yes ($ROLL_ASM)])
|
||||
AC_DEFINE(USE_ROLL_ASM, 1, [Define to 1 to enable rolling-checksum ASM optimizations (requires --enable-roll-simd)])
|
||||
ROLL_ASM='$(ROLL_ASM_'"$ROLL_ASM)"
|
||||
else
|
||||
AC_MSG_RESULT(no)
|
||||
fi
|
||||
|
||||
AC_SUBST(ROLL_ASM)
|
||||
|
||||
AC_MSG_CHECKING([whether to enable xxhash checksum support])
|
||||
AC_ARG_ENABLE([xxhash],
|
||||
AS_HELP_STRING([--disable-xxhash],[disable to omit xxhash checksums]))
|
||||
@@ -491,7 +526,7 @@ fi
|
||||
|
||||
AC_MSG_CHECKING([whether to enable zstd compression])
|
||||
AC_ARG_ENABLE([zstd],
|
||||
AC_HELP_STRING([--disable-zstd], [disable to omit zstd compression]))
|
||||
AS_HELP_STRING([--disable-zstd], [disable to omit zstd compression]))
|
||||
AH_TEMPLATE([SUPPORT_ZSTD],
|
||||
[Undefine if you do not want zstd compression. By default this is defined.])
|
||||
if test x"$enable_zstd" != x"no"; then
|
||||
@@ -512,7 +547,7 @@ fi
|
||||
|
||||
AC_MSG_CHECKING([whether to enable LZ4 compression])
|
||||
AC_ARG_ENABLE([lz4],
|
||||
AC_HELP_STRING([--disable-lz4], [disable to omit LZ4 compression]))
|
||||
AS_HELP_STRING([--disable-lz4], [disable to omit LZ4 compression]))
|
||||
AH_TEMPLATE([SUPPORT_LZ4],
|
||||
[Undefine if you do not want LZ4 compression. By default this is defined.])
|
||||
if test x"$enable_lz4" != x"no"; then
|
||||
@@ -537,7 +572,7 @@ if test x"$no_lib" != x; then
|
||||
echo "$err_msg"
|
||||
echo ""
|
||||
echo "See the INSTALL file for hints on how to install the missing libraries and/or"
|
||||
echo "how to generate (or fetch) man pages:"
|
||||
echo "how to generate (or fetch) manpages:"
|
||||
echo " https://github.com/WayneD/rsync/blob/master/INSTALL.md"
|
||||
echo ""
|
||||
echo "To disable one or more features, the relevant configure options are:"
|
||||
@@ -598,7 +633,11 @@ fi
|
||||
|
||||
AC_TYPE_UID_T
|
||||
AC_CHECK_TYPES([mode_t,off_t,size_t,pid_t,id_t])
|
||||
AC_TYPE_GETGROUPS
|
||||
if test "$cross_compiling" = no; then
|
||||
AC_TYPE_GETGROUPS
|
||||
else
|
||||
AC_DEFINE([GETGROUPS_T],[gid_t],[Define to the type of elements in the array set by `getgroups'. Usually this is either `int' or `gid_t'.])
|
||||
fi
|
||||
AC_CHECK_MEMBERS([struct stat.st_rdev,
|
||||
struct stat.st_mtimensec,
|
||||
struct stat.st_mtimespec.tv_nsec,
|
||||
@@ -1040,21 +1079,6 @@ elif test x"$ac_cv_header_popt_h" != x"yes"; then
|
||||
with_included_popt=yes
|
||||
fi
|
||||
|
||||
if test x"$GCC" = x"yes"; then
|
||||
if test x"$with_included_popt" != x"yes"; then
|
||||
# Turn pedantic warnings into errors to ensure an array-init overflow is an error.
|
||||
CFLAGS="$CFLAGS -pedantic-errors"
|
||||
else
|
||||
# Our internal popt code cannot be compiled with pedantic warnings as errors, so try to
|
||||
# turn off pedantic warnings (which will not lose the error for array-init overflow).
|
||||
# Older gcc versions don't understand -Wno-pedantic, so check if --help=warnings lists
|
||||
# -Wpedantic and use that as a flag.
|
||||
case `$CC --help=warnings 2>/dev/null | grep Wpedantic` in
|
||||
*-Wpedantic*) CFLAGS="$CFLAGS -pedantic-errors -Wno-pedantic" ;;
|
||||
esac
|
||||
fi
|
||||
fi
|
||||
|
||||
AC_MSG_CHECKING([whether to use included libpopt])
|
||||
if test x"$with_included_popt" = x"yes"; then
|
||||
AC_MSG_RESULT($srcdir/popt)
|
||||
@@ -1091,7 +1115,7 @@ else
|
||||
fi
|
||||
|
||||
AC_CACHE_CHECK([for unsigned char],rsync_cv_SIGNED_CHAR_OK,[
|
||||
AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[]], [[signed char *s = ""]])],[rsync_cv_SIGNED_CHAR_OK=yes],[rsync_cv_SIGNED_CHAR_OK=no])])
|
||||
AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[]], [[signed char *s = (signed char *)""]])],[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
|
||||
@@ -1257,6 +1281,7 @@ AC_SUBST(BUILD_POPT)
|
||||
AC_SUBST(BUILD_ZLIB)
|
||||
AC_SUBST(MAKE_RRSYNC)
|
||||
AC_SUBST(MAKE_RRSYNC_1)
|
||||
AC_SUBST(GEN_RRSYNC)
|
||||
AC_SUBST(MAKE_MAN)
|
||||
|
||||
AC_CHECK_FUNCS(_acl __acl _facl __facl)
|
||||
|
||||
@@ -7,39 +7,54 @@ 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 greeting
|
||||
When the server accepts a connection, it prints a newline-terminated
|
||||
greeting line:
|
||||
|
||||
@RSYNCD: <version>.<subprotocol>
|
||||
@RSYNCD: <version>.<subprotocol> <digest1> <digestN>
|
||||
|
||||
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 <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).
|
||||
|
||||
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>
|
||||
|
||||
where <user> is the username they claim to be, and <response> is the
|
||||
base64 form of the MD4 hash of challenge+password.
|
||||
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).
|
||||
|
||||
At this point the server applies all remaining constraints before
|
||||
handing control to the client, including switching uid/gid, setting up
|
||||
@@ -76,6 +91,13 @@ 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
|
||||
|
||||
@@ -60,9 +60,9 @@ BOOL read_only True
|
||||
BOOL reverse_lookup True
|
||||
BOOL strict_modes True
|
||||
BOOL transfer_logging False
|
||||
BOOL use_chroot True
|
||||
BOOL write_only False
|
||||
|
||||
BOOL3 munge_symlinks Unset
|
||||
BOOL3 numeric_ids Unset
|
||||
BOOL3 open_noatime Unset
|
||||
BOOL3 use_chroot Unset
|
||||
|
||||
4
delete.c
4
delete.c
@@ -4,7 +4,7 @@
|
||||
* Copyright (C) 1996-2000 Andrew Tridgell
|
||||
* Copyright (C) 1996 Paul Mackerras
|
||||
* Copyright (C) 2002 Martin Pool <mbp@samba.org>
|
||||
* Copyright (C) 2003-2020 Wayne Davison
|
||||
* 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
|
||||
@@ -188,7 +188,7 @@ enum delret delete_item(char *fbuf, uint16 mode, uint16 flags)
|
||||
stats.deleted_symlinks++;
|
||||
#endif
|
||||
else if (IS_DEVICE(mode))
|
||||
stats.deleted_symlinks++;
|
||||
stats.deleted_devices++;
|
||||
else
|
||||
stats.deleted_specials++;
|
||||
}
|
||||
|
||||
339
exclude.c
339
exclude.c
@@ -4,7 +4,7 @@
|
||||
* Copyright (C) 1996-2001 Andrew Tridgell <tridge@samba.org>
|
||||
* Copyright (C) 1996 Paul Mackerras
|
||||
* Copyright (C) 2002 Martin Pool
|
||||
* Copyright (C) 2003-2020 Wayne Davison
|
||||
* 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
|
||||
@@ -25,16 +25,21 @@
|
||||
|
||||
extern int am_server;
|
||||
extern int am_sender;
|
||||
extern int am_generator;
|
||||
extern int eol_nulls;
|
||||
extern int io_error;
|
||||
extern int xfer_dirs;
|
||||
extern int recurse;
|
||||
extern int local_server;
|
||||
extern int prune_empty_dirs;
|
||||
extern int ignore_perishable;
|
||||
extern int relative_paths;
|
||||
extern int delete_mode;
|
||||
extern int delete_excluded;
|
||||
extern int cvs_exclude;
|
||||
extern int sanitize_paths;
|
||||
extern int protocol_version;
|
||||
extern int trust_sender_args;
|
||||
extern int module_id;
|
||||
|
||||
extern char curr_dir[MAXPATHLEN];
|
||||
@@ -44,8 +49,11 @@ extern unsigned int module_dirlen;
|
||||
filter_rule_list filter_list = { .debug_type = "" };
|
||||
filter_rule_list cvs_filter_list = { .debug_type = " [global CVS]" };
|
||||
filter_rule_list daemon_filter_list = { .debug_type = " [daemon]" };
|
||||
filter_rule_list implied_filter_list = { .debug_type = " [implied]" };
|
||||
|
||||
int saw_xattr_filter = 0;
|
||||
int trust_sender_args = 0;
|
||||
int trust_sender_filter = 0;
|
||||
|
||||
/* Need room enough for ":MODS " prefix plus some room to grow. */
|
||||
#define MAX_RULE_PREFIX (16)
|
||||
@@ -70,6 +78,10 @@ static filter_rule **mergelist_parents;
|
||||
static int mergelist_cnt = 0;
|
||||
static int mergelist_size = 0;
|
||||
|
||||
#define LOCAL_RULE 1
|
||||
#define REMOTE_RULE 2
|
||||
static uchar cur_elide_value = REMOTE_RULE;
|
||||
|
||||
/* Each filter_list_struct describes a singly-linked list by keeping track
|
||||
* of both the head and tail pointers. The list is slightly unusual in that
|
||||
* a parent-dir's content can be appended to the end of the local list in a
|
||||
@@ -152,13 +164,17 @@ static void add_rule(filter_rule_list *listp, const char *pat, unsigned int pat_
|
||||
{
|
||||
const char *cp;
|
||||
unsigned int pre_len, suf_len, slash_cnt = 0;
|
||||
char *mention_rule_suffix;
|
||||
|
||||
if (DEBUG_GTE(FILTER, 2)) {
|
||||
rprintf(FINFO, "[%s] add_rule(%s%.*s%s)%s\n",
|
||||
if (DEBUG_GTE(FILTER, 1) && pat_len && (pat[pat_len-1] == ' ' || pat[pat_len-1] == '\t'))
|
||||
mention_rule_suffix = " -- CAUTION: trailing whitespace!";
|
||||
else
|
||||
mention_rule_suffix = DEBUG_GTE(FILTER, 2) ? "" : NULL;
|
||||
if (mention_rule_suffix) {
|
||||
rprintf(FINFO, "[%s] add_rule(%s%.*s%s)%s%s\n",
|
||||
who_am_i(), get_rule_prefix(rule, pat, 0, NULL),
|
||||
(int)pat_len, pat,
|
||||
(rule->rflags & FILTRULE_DIRECTORY) ? "/" : "",
|
||||
listp->debug_type);
|
||||
(int)pat_len, pat, (rule->rflags & FILTRULE_DIRECTORY) ? "/" : "",
|
||||
listp->debug_type, mention_rule_suffix);
|
||||
}
|
||||
|
||||
/* These flags also indicate that we're reading a list that
|
||||
@@ -208,6 +224,7 @@ static void add_rule(filter_rule_list *listp, const char *pat, unsigned int pat_
|
||||
slash_cnt++;
|
||||
}
|
||||
}
|
||||
rule->elide = 0;
|
||||
strlcpy(rule->pattern + pre_len, pat, pat_len + 1);
|
||||
pat_len += pre_len;
|
||||
if (suf_len) {
|
||||
@@ -288,6 +305,271 @@ static void add_rule(filter_rule_list *listp, const char *pat, unsigned int pat_
|
||||
}
|
||||
}
|
||||
|
||||
/* If the wildcards failed, the remote shell might give us a file matching the literal
|
||||
* wildcards. Since "*" & "?" already match themselves, this just needs to deal with
|
||||
* failed "[foo]" idioms.
|
||||
*/
|
||||
static void maybe_add_literal_brackets_rule(filter_rule const *based_on, int arg_len)
|
||||
{
|
||||
filter_rule *rule;
|
||||
const char *arg = based_on->pattern, *cp;
|
||||
char *p;
|
||||
int cnt = 0;
|
||||
|
||||
if (arg_len < 0)
|
||||
arg_len = strlen(arg);
|
||||
|
||||
for (cp = arg; *cp; cp++) {
|
||||
if (*cp == '\\' && cp[1]) {
|
||||
cp++;
|
||||
} else if (*cp == '[')
|
||||
cnt++;
|
||||
}
|
||||
if (!cnt)
|
||||
return;
|
||||
|
||||
rule = new0(filter_rule);
|
||||
rule->rflags = based_on->rflags;
|
||||
rule->u.slash_cnt = based_on->u.slash_cnt;
|
||||
p = rule->pattern = new_array(char, arg_len + cnt + 1);
|
||||
for (cp = arg; *cp; ) {
|
||||
if (*cp == '\\' && cp[1]) {
|
||||
*p++ = *cp++;
|
||||
} else if (*cp == '[')
|
||||
*p++ = '\\';
|
||||
*p++ = *cp++;
|
||||
}
|
||||
*p++ = '\0';
|
||||
|
||||
rule->next = implied_filter_list.head;
|
||||
implied_filter_list.head = rule;
|
||||
if (DEBUG_GTE(FILTER, 3)) {
|
||||
rprintf(FINFO, "[%s] add_implied_include(%s%s)\n", who_am_i(), rule->pattern,
|
||||
rule->rflags & FILTRULE_DIRECTORY ? "/" : "");
|
||||
}
|
||||
}
|
||||
|
||||
static char *partial_string_buf = NULL;
|
||||
static int partial_string_len = 0;
|
||||
void implied_include_partial_string(const char *s_start, const char *s_end)
|
||||
{
|
||||
partial_string_len = s_end - s_start;
|
||||
if (partial_string_len <= 0 || partial_string_len >= MAXPATHLEN) { /* too-large should be impossible... */
|
||||
partial_string_len = 0;
|
||||
return;
|
||||
}
|
||||
if (!partial_string_buf)
|
||||
partial_string_buf = new_array(char, MAXPATHLEN);
|
||||
memcpy(partial_string_buf, s_start, partial_string_len);
|
||||
}
|
||||
|
||||
void free_implied_include_partial_string()
|
||||
{
|
||||
if (partial_string_buf) {
|
||||
if (partial_string_len)
|
||||
add_implied_include("", 0);
|
||||
free(partial_string_buf);
|
||||
partial_string_buf = NULL;
|
||||
}
|
||||
partial_string_len = 0; /* paranoia */
|
||||
}
|
||||
|
||||
/* Each arg the client sends to the remote sender turns into an implied include
|
||||
* that the receiver uses to validate the file list from the sender. */
|
||||
void add_implied_include(const char *arg, int skip_daemon_module)
|
||||
{
|
||||
int arg_len, saw_wild = 0, saw_live_open_brkt = 0, backslash_cnt = 0;
|
||||
int slash_cnt = 0;
|
||||
const char *cp;
|
||||
char *p;
|
||||
if (trust_sender_args)
|
||||
return;
|
||||
if (partial_string_len) {
|
||||
arg_len = strlen(arg);
|
||||
if (partial_string_len + arg_len >= MAXPATHLEN) {
|
||||
partial_string_len = 0;
|
||||
return; /* Should be impossible... */
|
||||
}
|
||||
memcpy(partial_string_buf + partial_string_len, arg, arg_len + 1);
|
||||
partial_string_len = 0;
|
||||
arg = partial_string_buf;
|
||||
}
|
||||
if (skip_daemon_module) {
|
||||
if ((cp = strchr(arg, '/')) != NULL)
|
||||
arg = cp + 1;
|
||||
else
|
||||
arg = "";
|
||||
}
|
||||
if (relative_paths) {
|
||||
if ((cp = strstr(arg, "/./")) != NULL)
|
||||
arg = cp + 3;
|
||||
} else if ((cp = strrchr(arg, '/')) != NULL) {
|
||||
arg = cp + 1;
|
||||
}
|
||||
if (*arg == '.' && arg[1] == '\0')
|
||||
arg++;
|
||||
arg_len = strlen(arg);
|
||||
if (arg_len) {
|
||||
char *new_pat;
|
||||
if (strpbrk(arg, "*[?")) {
|
||||
/* We need to add room to escape backslashes if wildcard chars are present. */
|
||||
for (cp = arg; (cp = strchr(cp, '\\')) != NULL; cp++)
|
||||
arg_len++;
|
||||
saw_wild = 1;
|
||||
}
|
||||
arg_len++; /* Leave room for the prefixed slash */
|
||||
p = new_pat = new_array(char, arg_len + 1);
|
||||
*p++ = '/';
|
||||
slash_cnt++;
|
||||
for (cp = arg; *cp; ) {
|
||||
switch (*cp) {
|
||||
case '\\':
|
||||
if (cp[1] == ']') {
|
||||
if (!saw_wild)
|
||||
cp++; /* A \] in a non-wild filter causes a problem, so drop the \ . */
|
||||
} else if (!strchr("*[?", cp[1])) {
|
||||
backslash_cnt++;
|
||||
if (saw_wild)
|
||||
*p++ = '\\';
|
||||
}
|
||||
*p++ = *cp++;
|
||||
break;
|
||||
case '/':
|
||||
if (p[-1] == '/') { /* This is safe because of the initial slash. */
|
||||
if (*++cp == '\0') {
|
||||
slash_cnt--;
|
||||
p--;
|
||||
}
|
||||
} else if (cp[1] == '\0') {
|
||||
cp++;
|
||||
} else {
|
||||
slash_cnt++;
|
||||
*p++ = *cp++;
|
||||
}
|
||||
break;
|
||||
case '.':
|
||||
if (p[-1] == '/') {
|
||||
if (cp[1] == '/') {
|
||||
cp += 2;
|
||||
if (!*cp) {
|
||||
slash_cnt--;
|
||||
p--;
|
||||
}
|
||||
} else if (cp[1] == '\0') {
|
||||
cp++;
|
||||
slash_cnt--;
|
||||
p--;
|
||||
} else
|
||||
*p++ = *cp++;
|
||||
} else
|
||||
*p++ = *cp++;
|
||||
break;
|
||||
case '[':
|
||||
saw_live_open_brkt = 1;
|
||||
*p++ = *cp++;
|
||||
break;
|
||||
default:
|
||||
*p++ = *cp++;
|
||||
break;
|
||||
}
|
||||
}
|
||||
*p = '\0';
|
||||
arg_len = p - new_pat;
|
||||
if (!arg_len)
|
||||
free(new_pat);
|
||||
else {
|
||||
filter_rule *rule = new0(filter_rule);
|
||||
rule->rflags = FILTRULE_INCLUDE + (saw_wild ? FILTRULE_WILD : 0);
|
||||
rule->u.slash_cnt = slash_cnt;
|
||||
arg = rule->pattern = new_pat;
|
||||
if (!implied_filter_list.head)
|
||||
implied_filter_list.head = implied_filter_list.tail = rule;
|
||||
else {
|
||||
rule->next = implied_filter_list.head;
|
||||
implied_filter_list.head = rule;
|
||||
}
|
||||
if (DEBUG_GTE(FILTER, 3))
|
||||
rprintf(FINFO, "[%s] add_implied_include(%s)\n", who_am_i(), arg);
|
||||
if (saw_live_open_brkt)
|
||||
maybe_add_literal_brackets_rule(rule, arg_len);
|
||||
if (relative_paths && slash_cnt) {
|
||||
int sub_slash_cnt = slash_cnt;
|
||||
while ((p = strrchr(new_pat, '/')) != NULL && p != new_pat) {
|
||||
filter_rule const *ent;
|
||||
filter_rule *R_rule;
|
||||
int found = 0;
|
||||
*p = '\0';
|
||||
for (ent = implied_filter_list.head; ent; ent = ent->next) {
|
||||
if (ent != rule && strcmp(ent->pattern, new_pat) == 0) {
|
||||
found = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (found) {
|
||||
*p = '/';
|
||||
break; /* We added all parent dirs already */
|
||||
}
|
||||
R_rule = new0(filter_rule);
|
||||
R_rule->rflags = FILTRULE_INCLUDE | FILTRULE_DIRECTORY;
|
||||
/* Check if our sub-path has wildcards or escaped backslashes */
|
||||
if (saw_wild && strpbrk(new_pat, "*[?\\"))
|
||||
R_rule->rflags |= FILTRULE_WILD;
|
||||
R_rule->pattern = strdup(new_pat);
|
||||
R_rule->u.slash_cnt = --sub_slash_cnt;
|
||||
R_rule->next = implied_filter_list.head;
|
||||
implied_filter_list.head = R_rule;
|
||||
if (DEBUG_GTE(FILTER, 3)) {
|
||||
rprintf(FINFO, "[%s] add_implied_include(%s/)\n",
|
||||
who_am_i(), R_rule->pattern);
|
||||
}
|
||||
if (saw_live_open_brkt)
|
||||
maybe_add_literal_brackets_rule(R_rule, -1);
|
||||
}
|
||||
for (p = new_pat; sub_slash_cnt < slash_cnt; sub_slash_cnt++) {
|
||||
p += strlen(p);
|
||||
*p = '/';
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (recurse || xfer_dirs) {
|
||||
/* Now create a rule with an added "/" & "**" or "*" at the end */
|
||||
filter_rule *rule = new0(filter_rule);
|
||||
rule->rflags = FILTRULE_INCLUDE | FILTRULE_WILD;
|
||||
if (recurse)
|
||||
rule->rflags |= FILTRULE_WILD2;
|
||||
/* We must leave enough room for / * * \0. */
|
||||
if (!saw_wild && backslash_cnt) {
|
||||
/* We are appending a wildcard, so now the backslashes need to be escaped. */
|
||||
p = rule->pattern = new_array(char, arg_len + backslash_cnt + 3 + 1);
|
||||
for (cp = arg; *cp; ) { /* Note that arg_len != 0 because backslash_cnt > 0 */
|
||||
if (*cp == '\\')
|
||||
*p++ = '\\';
|
||||
*p++ = *cp++;
|
||||
}
|
||||
} else {
|
||||
p = rule->pattern = new_array(char, arg_len + 3 + 1);
|
||||
if (arg_len) {
|
||||
memcpy(p, arg, arg_len);
|
||||
p += arg_len;
|
||||
}
|
||||
}
|
||||
*p++ = '/';
|
||||
*p++ = '*';
|
||||
if (recurse)
|
||||
*p++ = '*';
|
||||
*p = '\0';
|
||||
rule->u.slash_cnt = slash_cnt + 1;
|
||||
rule->next = implied_filter_list.head;
|
||||
implied_filter_list.head = rule;
|
||||
if (DEBUG_GTE(FILTER, 3))
|
||||
rprintf(FINFO, "[%s] add_implied_include(%s)\n", who_am_i(), rule->pattern);
|
||||
if (saw_live_open_brkt)
|
||||
maybe_add_literal_brackets_rule(rule, p - rule->pattern);
|
||||
}
|
||||
}
|
||||
|
||||
/* This frees any non-inherited items, leaving just inherited items on the list. */
|
||||
static void pop_filter_list(filter_rule_list *listp)
|
||||
{
|
||||
@@ -438,7 +720,8 @@ static BOOL setup_merge_file(int mergelist_num, filter_rule *ex,
|
||||
parent_dirscan = True;
|
||||
while (*y) {
|
||||
char save[MAXPATHLEN];
|
||||
strlcpy(save, y, MAXPATHLEN);
|
||||
/* copylen is strlen(y) which is < MAXPATHLEN. +1 for \0 */
|
||||
size_t copylen = strlcpy(save, y, MAXPATHLEN) + 1;
|
||||
*y = '\0';
|
||||
dirbuf_len = y - dirbuf;
|
||||
strlcpy(x, ex->pattern, MAXPATHLEN - (x - buf));
|
||||
@@ -452,7 +735,7 @@ static BOOL setup_merge_file(int mergelist_num, filter_rule *ex,
|
||||
lp->head = NULL;
|
||||
}
|
||||
lp->tail = NULL;
|
||||
strlcpy(y, save, MAXPATHLEN);
|
||||
strlcpy(y, save, copylen);
|
||||
while ((*x++ = *y++) != '/') {}
|
||||
}
|
||||
parent_dirscan = False;
|
||||
@@ -625,7 +908,7 @@ static int rule_matches(const char *fname, filter_rule *ex, int name_flags)
|
||||
const char *strings[16]; /* more than enough */
|
||||
const char *name = fname + (*fname == '/');
|
||||
|
||||
if (!*name)
|
||||
if (!*name || ex->elide == cur_elide_value)
|
||||
return 0;
|
||||
|
||||
if (!(name_flags & NAME_IS_XATTR) ^ !(ex->rflags & FILTRULE_XATTR))
|
||||
@@ -702,11 +985,12 @@ static void report_filter_result(enum logcode code, char const *name,
|
||||
filter_rule const *ent,
|
||||
int name_flags, const char *type)
|
||||
{
|
||||
int log_level = am_sender || am_generator ? 1 : 3;
|
||||
|
||||
/* If a trailing slash is present to match only directories,
|
||||
* then it is stripped out by add_rule(). So as a special
|
||||
* case we add it back in here. */
|
||||
|
||||
if (DEBUG_GTE(FILTER, 1)) {
|
||||
* case we add it back in the log output. */
|
||||
if (DEBUG_GTE(FILTER, log_level)) {
|
||||
static char *actions[2][2]
|
||||
= { {"show", "hid"}, {"risk", "protect"} };
|
||||
const char *w = who_am_i();
|
||||
@@ -714,7 +998,7 @@ static void report_filter_result(enum logcode code, char const *name,
|
||||
: name_flags & NAME_IS_DIR ? "directory"
|
||||
: "file";
|
||||
rprintf(code, "[%s] %sing %s %s because of pattern %s%s%s\n",
|
||||
w, actions[*w!='s'][!(ent->rflags & FILTRULE_INCLUDE)],
|
||||
w, actions[*w=='g'][!(ent->rflags & FILTRULE_INCLUDE)],
|
||||
t, name, ent->pattern,
|
||||
ent->rflags & FILTRULE_DIRECTORY ? "/" : "", type);
|
||||
}
|
||||
@@ -740,6 +1024,15 @@ int name_is_excluded(const char *fname, int name_flags, int filter_level)
|
||||
return 0;
|
||||
}
|
||||
|
||||
int check_server_filter(filter_rule_list *listp, enum logcode code, const char *name, int name_flags)
|
||||
{
|
||||
int ret;
|
||||
cur_elide_value = LOCAL_RULE;
|
||||
ret = check_filter(listp, code, name, name_flags);
|
||||
cur_elide_value = REMOTE_RULE;
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Return -1 if file "name" is defined to be excluded by the specified
|
||||
* exclude list, 1 if it is included, and 0 if it was not matched. */
|
||||
int check_filter(filter_rule_list *listp, enum logcode code,
|
||||
@@ -886,6 +1179,7 @@ static filter_rule *parse_rule_tok(const char **rulestr_ptr,
|
||||
}
|
||||
switch (ch) {
|
||||
case ':':
|
||||
trust_sender_filter = 1;
|
||||
rule->rflags |= FILTRULE_PERDIR_MERGE
|
||||
| FILTRULE_FINISH_SETUP;
|
||||
/* FALL THROUGH */
|
||||
@@ -1294,7 +1588,7 @@ char *get_rule_prefix(filter_rule *rule, const char *pat, int for_xfer,
|
||||
|
||||
static void send_rules(int f_out, filter_rule_list *flp)
|
||||
{
|
||||
filter_rule *ent, *prev = NULL;
|
||||
filter_rule *ent;
|
||||
|
||||
for (ent = flp->head; ent; ent = ent->next) {
|
||||
unsigned int len, plen, dlen;
|
||||
@@ -1309,21 +1603,15 @@ static void send_rules(int f_out, filter_rule_list *flp)
|
||||
* merge files as an optimization (since they can only have
|
||||
* include/exclude rules). */
|
||||
if (ent->rflags & FILTRULE_SENDER_SIDE)
|
||||
elide = am_sender ? 1 : -1;
|
||||
elide = am_sender ? LOCAL_RULE : REMOTE_RULE;
|
||||
if (ent->rflags & FILTRULE_RECEIVER_SIDE)
|
||||
elide = elide ? 0 : am_sender ? -1 : 1;
|
||||
elide = elide ? 0 : am_sender ? REMOTE_RULE : LOCAL_RULE;
|
||||
else if (delete_excluded && !elide
|
||||
&& (!(ent->rflags & FILTRULE_PERDIR_MERGE)
|
||||
|| ent->rflags & FILTRULE_NO_PREFIXES))
|
||||
elide = am_sender ? 1 : -1;
|
||||
if (elide < 0) {
|
||||
if (prev)
|
||||
prev->next = ent->next;
|
||||
else
|
||||
flp->head = ent->next;
|
||||
} else
|
||||
prev = ent;
|
||||
if (elide > 0)
|
||||
elide = am_sender ? LOCAL_RULE : REMOTE_RULE;
|
||||
ent->elide = elide;
|
||||
if (elide == LOCAL_RULE)
|
||||
continue;
|
||||
if (ent->rflags & FILTRULE_CVS_IGNORE
|
||||
&& !(ent->rflags & FILTRULE_MERGE_FILE)) {
|
||||
@@ -1351,7 +1639,6 @@ static void send_rules(int f_out, filter_rule_list *flp)
|
||||
if (dlen)
|
||||
write_byte(f_out, '/');
|
||||
}
|
||||
flp->tail = prev;
|
||||
}
|
||||
|
||||
/* This is only called by the client. */
|
||||
|
||||
46
fileio.c
46
fileio.c
@@ -3,7 +3,7 @@
|
||||
*
|
||||
* Copyright (C) 1998 Andrew Tridgell
|
||||
* Copyright (C) 2002 Martin Pool
|
||||
* Copyright (C) 2004-2020 Wayne Davison
|
||||
* Copyright (C) 2004-2023 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
|
||||
@@ -40,30 +40,34 @@ OFF_T preallocated_len = 0;
|
||||
static OFF_T sparse_seek = 0;
|
||||
static OFF_T sparse_past_write = 0;
|
||||
|
||||
int sparse_end(int f, OFF_T size)
|
||||
int sparse_end(int f, OFF_T size, int updating_basis_or_equiv)
|
||||
{
|
||||
int ret;
|
||||
int ret = 0;
|
||||
|
||||
sparse_past_write = 0;
|
||||
|
||||
if (!sparse_seek)
|
||||
return 0;
|
||||
|
||||
#ifdef HAVE_FTRUNCATE
|
||||
ret = do_ftruncate(f, size);
|
||||
#else
|
||||
if (do_lseek(f, sparse_seek-1, SEEK_CUR) != size-1)
|
||||
ret = -1;
|
||||
else {
|
||||
do {
|
||||
ret = write(f, "", 1);
|
||||
} while (ret < 0 && errno == EINTR);
|
||||
|
||||
ret = ret <= 0 ? -1 : 0;
|
||||
}
|
||||
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);
|
||||
|
||||
sparse_seek = 0;
|
||||
ret = ret <= 0 ? -1 : 0;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
sparse_past_write = sparse_seek = 0;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
66
flist.c
66
flist.c
@@ -4,7 +4,7 @@
|
||||
* Copyright (C) 1996 Andrew Tridgell
|
||||
* Copyright (C) 1996 Paul Mackerras
|
||||
* Copyright (C) 2001, 2002 Martin Pool <mbp@samba.org>
|
||||
* Copyright (C) 2002-2022 Wayne Davison
|
||||
* Copyright (C) 2002-2023 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,6 @@ extern int am_sender;
|
||||
extern int am_generator;
|
||||
extern int inc_recurse;
|
||||
extern int always_checksum;
|
||||
extern int checksum_type;
|
||||
extern int module_id;
|
||||
extern int ignore_errors;
|
||||
extern int numeric_ids;
|
||||
@@ -43,6 +42,7 @@ extern int use_qsort;
|
||||
extern int xfer_dirs;
|
||||
extern int filesfrom_fd;
|
||||
extern int one_file_system;
|
||||
extern int copy_devices;
|
||||
extern int copy_dirlinks;
|
||||
extern int preserve_uid;
|
||||
extern int preserve_gid;
|
||||
@@ -72,18 +72,20 @@ extern int need_unsorted_flist;
|
||||
extern int sender_symlink_iconv;
|
||||
extern int output_needs_newline;
|
||||
extern int sender_keeps_checksum;
|
||||
extern int trust_sender_filter;
|
||||
extern int unsort_ndx;
|
||||
extern uid_t our_uid;
|
||||
extern struct stats stats;
|
||||
extern char *filesfrom_host;
|
||||
extern char *usermap, *groupmap;
|
||||
|
||||
extern struct name_num_item *file_sum_nni;
|
||||
|
||||
extern char curr_dir[MAXPATHLEN];
|
||||
|
||||
extern struct chmod_mode_struct *chmod_modes;
|
||||
|
||||
extern filter_rule_list filter_list;
|
||||
extern filter_rule_list daemon_filter_list;
|
||||
extern filter_rule_list filter_list, implied_filter_list, daemon_filter_list;
|
||||
|
||||
#ifdef ICONV_OPTION
|
||||
extern int filesfrom_convert;
|
||||
@@ -144,7 +146,8 @@ void init_flist(void)
|
||||
rprintf(FINFO, "FILE_STRUCT_LEN=%d, EXTRA_LEN=%d\n",
|
||||
(int)FILE_STRUCT_LEN, (int)EXTRA_LEN);
|
||||
}
|
||||
flist_csum_len = csum_len_for_type(checksum_type, 1);
|
||||
/* Note that this isn't identical to file_sum_len in the case of CSUM_MD4_ARCHAIC: */
|
||||
flist_csum_len = csum_len_for_type(file_sum_nni->num, 1);
|
||||
|
||||
show_filelist_progress = INFO_GTE(FLIST, 1) && xfer_dirs && !am_server && !inc_recurse;
|
||||
}
|
||||
@@ -700,6 +703,7 @@ static struct file_struct *recv_file_entry(int f, struct file_list *flist, int x
|
||||
int alloc_len, basename_len, linkname_len;
|
||||
int extra_len = file_extra_cnt * EXTRA_LEN;
|
||||
int first_hlink_ndx = -1;
|
||||
char real_ISREG_entry;
|
||||
int64 file_length;
|
||||
#ifdef CAN_SET_NSEC
|
||||
uint32 modtime_nsec;
|
||||
@@ -752,7 +756,7 @@ static struct file_struct *recv_file_entry(int f, struct file_list *flist, int x
|
||||
if (*thisname
|
||||
&& (clean_fname(thisname, CFN_REFUSE_DOT_DOT_DIRS) < 0 || (!relative_paths && *thisname == '/'))) {
|
||||
rprintf(FERROR, "ABORTING due to unsafe pathname from sender: %s\n", thisname);
|
||||
exit_cleanup(RERR_PROTOCOL);
|
||||
exit_cleanup(RERR_UNSUPPORTED);
|
||||
}
|
||||
|
||||
if (sanitize_paths)
|
||||
@@ -814,6 +818,7 @@ static struct file_struct *recv_file_entry(int f, struct file_list *flist, int x
|
||||
linkname_len = strlen(F_SYMLINK(first)) + 1;
|
||||
else
|
||||
linkname_len = 0;
|
||||
real_ISREG_entry = S_ISREG(mode) ? 1 : 0;
|
||||
goto create_object;
|
||||
}
|
||||
}
|
||||
@@ -831,7 +836,7 @@ static struct file_struct *recv_file_entry(int f, struct file_list *flist, int x
|
||||
}
|
||||
#endif
|
||||
} else
|
||||
modtime = read_int(f);
|
||||
modtime = read_uint(f);
|
||||
}
|
||||
if (xflags & XMIT_MOD_NSEC)
|
||||
#ifndef CAN_SET_NSEC
|
||||
@@ -941,10 +946,20 @@ static struct file_struct *recv_file_entry(int f, struct file_list *flist, int x
|
||||
#endif
|
||||
linkname_len = 0;
|
||||
|
||||
if (copy_devices && IS_DEVICE(mode)) {
|
||||
/* This is impossible in the official release, but some pre-release patches
|
||||
* didn't convert the device into a file before sending, so we'll do it here
|
||||
* (even though the length is typically 0 and any checksum data is zeros). */
|
||||
mode = S_IFREG | (mode & ACCESSPERMS);
|
||||
modtime = time(NULL); /* The mtime on the device is not up-to-date, so set it to "now". */
|
||||
real_ISREG_entry = 0;
|
||||
} else
|
||||
real_ISREG_entry = S_ISREG(mode) ? 1 : 0;
|
||||
|
||||
#ifdef SUPPORT_HARD_LINKS
|
||||
create_object:
|
||||
if (preserve_hard_links) {
|
||||
if (protocol_version < 28 && S_ISREG(mode))
|
||||
if (protocol_version < 28 && real_ISREG_entry)
|
||||
xflags |= XMIT_HLINKED;
|
||||
if (xflags & XMIT_HLINKED)
|
||||
extra_len += (inc_recurse+1) * EXTRA_LEN;
|
||||
@@ -973,6 +988,19 @@ static struct file_struct *recv_file_entry(int f, struct file_list *flist, int x
|
||||
exit_cleanup(RERR_UNSUPPORTED);
|
||||
}
|
||||
|
||||
if (*thisname == '/' ? thisname[1] != '.' || thisname[2] != '\0' : *thisname != '.' || thisname[1] != '\0') {
|
||||
int filt_flags = S_ISDIR(mode) ? NAME_IS_DIR : NAME_IS_FILE;
|
||||
if (!trust_sender_filter /* a per-dir filter rule means we must trust the sender's filtering */
|
||||
&& filter_list.head && check_server_filter(&filter_list, FINFO, thisname, filt_flags) < 0) {
|
||||
rprintf(FERROR, "ERROR: rejecting excluded file-list name: %s\n", thisname);
|
||||
exit_cleanup(RERR_UNSUPPORTED);
|
||||
}
|
||||
if (implied_filter_list.head && check_filter(&implied_filter_list, FINFO, thisname, filt_flags) <= 0) {
|
||||
rprintf(FERROR, "ERROR: rejecting unrequested file-list name: %s\n", thisname);
|
||||
exit_cleanup(RERR_UNSUPPORTED);
|
||||
}
|
||||
}
|
||||
|
||||
if (inc_recurse && S_ISDIR(mode)) {
|
||||
if (one_file_system) {
|
||||
/* Room to save the dir's device for -x */
|
||||
@@ -1160,8 +1188,8 @@ static struct file_struct *recv_file_entry(int f, struct file_list *flist, int x
|
||||
}
|
||||
#endif
|
||||
|
||||
if (always_checksum && (S_ISREG(mode) || protocol_version < 28)) {
|
||||
if (S_ISREG(mode))
|
||||
if (always_checksum && (real_ISREG_entry || protocol_version < 28)) {
|
||||
if (real_ISREG_entry)
|
||||
bp = F_SUM(file);
|
||||
else {
|
||||
/* Prior to 28, we get a useless set of nulls. */
|
||||
@@ -1360,6 +1388,18 @@ struct file_struct *make_file(const char *fname, struct file_list *flist,
|
||||
linkname_len = 0;
|
||||
#endif
|
||||
|
||||
if (copy_devices && am_sender && IS_DEVICE(st.st_mode)) {
|
||||
if (st.st_size == 0) {
|
||||
int fd = do_open(fname, O_RDONLY, 0);
|
||||
if (fd >= 0) {
|
||||
st.st_size = get_device_size(fd, fname);
|
||||
close(fd);
|
||||
}
|
||||
}
|
||||
st.st_mode = S_IFREG | (st.st_mode & ACCESSPERMS);
|
||||
st.st_mtime = time(NULL); /* The mtime on the device is not up-to-date, so set it to "now". */
|
||||
}
|
||||
|
||||
#ifdef ST_MTIME_NSEC
|
||||
if (st.ST_MTIME_NSEC && protocol_version >= 31)
|
||||
extra_len += EXTRA_LEN;
|
||||
@@ -2327,7 +2367,7 @@ struct file_list *send_file_list(int f, int argc, char *argv[])
|
||||
}
|
||||
|
||||
dirlen = dir ? strlen(dir) : 0;
|
||||
if (dirlen != lastdir_len || memcmp(lastdir, dir, dirlen) != 0) {
|
||||
if (dirlen != lastdir_len || (dirlen && memcmp(lastdir, dir, dirlen) != 0)) {
|
||||
if (!change_pathname(NULL, dir, -dirlen))
|
||||
goto bad_path;
|
||||
lastdir = pathname;
|
||||
@@ -2602,7 +2642,7 @@ struct file_list *recv_file_list(int f, int dir_ndx)
|
||||
rprintf(FERROR,
|
||||
"ABORTING due to invalid path from sender: %s/%s\n",
|
||||
cur_dir, file->basename);
|
||||
exit_cleanup(RERR_PROTOCOL);
|
||||
exit_cleanup(RERR_UNSUPPORTED);
|
||||
}
|
||||
good_dirname = cur_dir;
|
||||
}
|
||||
@@ -2619,7 +2659,7 @@ struct file_list *recv_file_list(int f, int dir_ndx)
|
||||
} else if (S_ISLNK(file->mode))
|
||||
stats.num_symlinks++;
|
||||
else if (IS_DEVICE(file->mode))
|
||||
stats.num_symlinks++;
|
||||
stats.num_devices++;
|
||||
else
|
||||
stats.num_specials++;
|
||||
|
||||
|
||||
35
generator.c
35
generator.c
@@ -4,7 +4,7 @@
|
||||
* Copyright (C) 1996-2000 Andrew Tridgell
|
||||
* Copyright (C) 1996 Paul Mackerras
|
||||
* Copyright (C) 2002 Martin Pool <mbp@samba.org>
|
||||
* Copyright (C) 2003-2022 Wayne Davison
|
||||
* Copyright (C) 2003-2023 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
|
||||
@@ -35,11 +35,11 @@ extern int inc_recurse;
|
||||
extern int relative_paths;
|
||||
extern int implied_dirs;
|
||||
extern int keep_dirlinks;
|
||||
extern int write_devices;
|
||||
extern int preserve_acls;
|
||||
extern int preserve_xattrs;
|
||||
extern int preserve_links;
|
||||
extern int preserve_devices;
|
||||
extern int write_devices;
|
||||
extern int preserve_specials;
|
||||
extern int preserve_hard_links;
|
||||
extern int preserve_executability;
|
||||
@@ -532,7 +532,7 @@ void itemize(const char *fnamecmp, struct file_struct *file, int ndx, int statre
|
||||
iflags |= ITEM_REPORT_CRTIME;
|
||||
}
|
||||
#endif
|
||||
#if !defined HAVE_LCHMOD && !defined HAVE_SETATTRLIST
|
||||
#ifndef CAN_CHMOD_SYMLINK
|
||||
if (S_ISLNK(file->mode)) {
|
||||
;
|
||||
} else
|
||||
@@ -783,7 +783,7 @@ static int generate_and_send_sums(int fd, OFF_T len, int f_out, int f_copy)
|
||||
for (i = 0; i < sum.count; i++) {
|
||||
int32 n1 = (int32)MIN(len, (OFF_T)sum.blength);
|
||||
char *map = map_ptr(mapbuf, offset, n1);
|
||||
char sum2[SUM_LENGTH];
|
||||
char sum2[MAX_DIGEST_LEN];
|
||||
uint32 sum1;
|
||||
|
||||
len -= n1;
|
||||
@@ -875,9 +875,12 @@ static struct file_struct *find_fuzzy(struct file_struct *file, struct file_list
|
||||
len = strlen(name);
|
||||
suf = find_filename_suffix(name, len, &suf_len);
|
||||
|
||||
dist = fuzzy_distance(name, len, fname, fname_len);
|
||||
/* Add some extra weight to how well the suffixes match. */
|
||||
dist += fuzzy_distance(suf, suf_len, fname_suf, fname_suf_len) * 10;
|
||||
dist = fuzzy_distance(name, len, fname, fname_len, lowest_dist);
|
||||
/* Add some extra weight to how well the suffixes match unless we've already disqualified
|
||||
* this file based on a heuristic. */
|
||||
if (dist < 0xFFFF0000U) {
|
||||
dist += fuzzy_distance(suf, suf_len, fname_suf, fname_suf_len, 0xFFFF0000U) * 10;
|
||||
}
|
||||
if (DEBUG_GTE(FUZZY, 2)) {
|
||||
rprintf(FINFO, "fuzzy distance for %s = %d.%05d\n",
|
||||
f_name(fp, NULL), (int)(dist>>16), (int)(dist&0xFFFF));
|
||||
@@ -1793,6 +1796,12 @@ static void recv_generator(char *fname, struct file_struct *file, int ndx,
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
if (write_devices && IS_DEVICE(sx.st.st_mode) && sx.st.st_size == 0) {
|
||||
/* This early open into fd skips the regular open below. */
|
||||
if ((fd = do_open(fnamecmp, O_RDONLY, 0)) >= 0)
|
||||
real_sx.st.st_size = sx.st.st_size = get_device_size(fd, fnamecmp);
|
||||
}
|
||||
|
||||
if (fnamecmp_type <= FNAMECMP_BASIS_DIR_HIGH)
|
||||
;
|
||||
else if (fnamecmp_type >= FNAMECMP_FUZZY)
|
||||
@@ -1813,7 +1822,7 @@ static void recv_generator(char *fname, struct file_struct *file, int ndx,
|
||||
goto cleanup;
|
||||
return_with_success:
|
||||
if (!dry_run)
|
||||
send_msg_int(MSG_SUCCESS, ndx);
|
||||
send_msg_success(fname, ndx);
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
@@ -1858,7 +1867,7 @@ static void recv_generator(char *fname, struct file_struct *file, int ndx,
|
||||
}
|
||||
|
||||
/* open the file */
|
||||
if ((fd = do_open(fnamecmp, O_RDONLY, 0)) < 0) {
|
||||
if (fd < 0 && (fd = do_open(fnamecmp, O_RDONLY, 0)) < 0) {
|
||||
rsyserr(FERROR, errno, "failed to open %s, continuing",
|
||||
full_fname(fnamecmp));
|
||||
pretend_missing:
|
||||
@@ -1875,11 +1884,9 @@ static void recv_generator(char *fname, struct file_struct *file, int ndx,
|
||||
|
||||
if (inplace && make_backups > 0 && fnamecmp_type == FNAMECMP_FNAME) {
|
||||
if (!(backupptr = get_backup_name(fname))) {
|
||||
close(fd);
|
||||
goto cleanup;
|
||||
}
|
||||
if (!(back_file = make_file(fname, NULL, NULL, 0, NO_FILTERS))) {
|
||||
close(fd);
|
||||
goto pretend_missing;
|
||||
}
|
||||
if (robust_unlink(backupptr) && errno != ENOENT) {
|
||||
@@ -1887,14 +1894,12 @@ static void recv_generator(char *fname, struct file_struct *file, int ndx,
|
||||
full_fname(backupptr));
|
||||
unmake_file(back_file);
|
||||
back_file = NULL;
|
||||
close(fd);
|
||||
goto cleanup;
|
||||
}
|
||||
if ((f_copy = do_open(backupptr, O_WRONLY | O_CREAT | O_TRUNC | O_EXCL, 0600)) < 0) {
|
||||
rsyserr(FERROR_XFER, errno, "open %s", full_fname(backupptr));
|
||||
unmake_file(back_file);
|
||||
back_file = NULL;
|
||||
close(fd);
|
||||
goto cleanup;
|
||||
}
|
||||
fnamecmp_type = FNAMECMP_BACKUP;
|
||||
@@ -1945,7 +1950,6 @@ static void recv_generator(char *fname, struct file_struct *file, int ndx,
|
||||
write_sum_head(f_out, NULL);
|
||||
else if (sx.st.st_size <= 0) {
|
||||
write_sum_head(f_out, NULL);
|
||||
close(fd);
|
||||
} else {
|
||||
if (generate_and_send_sums(fd, sx.st.st_size, f_out, f_copy) < 0) {
|
||||
rprintf(FWARNING,
|
||||
@@ -1953,10 +1957,11 @@ static void recv_generator(char *fname, struct file_struct *file, int ndx,
|
||||
fnamecmp);
|
||||
write_sum_head(f_out, NULL);
|
||||
}
|
||||
close(fd);
|
||||
}
|
||||
|
||||
cleanup:
|
||||
if (fd >= 0)
|
||||
close(fd);
|
||||
if (back_file) {
|
||||
int save_preserve_xattrs = preserve_xattrs;
|
||||
if (f_copy >= 0)
|
||||
|
||||
174
hashtable.c
174
hashtable.c
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* Routines to provide a memory-efficient hashtable.
|
||||
*
|
||||
* Copyright (C) 2007-2020 Wayne Davison
|
||||
* 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
|
||||
@@ -350,6 +350,9 @@ void *hashtable_find(struct hashtable *tbl, int64 key, void *data_when_new)
|
||||
-------------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
#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 */
|
||||
@@ -390,7 +393,7 @@ uint32_t hashlittle(const void *key, size_t length)
|
||||
case 3 : a+=((uint32_t)k8[2])<<16; /* fall through */
|
||||
case 2 : a+=((uint32_t)k8[1])<<8; /* fall through */
|
||||
case 1 : a+=k8[0]; break;
|
||||
case 0 : return c;
|
||||
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 */
|
||||
@@ -436,7 +439,7 @@ uint32_t hashlittle(const void *key, size_t length)
|
||||
break;
|
||||
case 1 : a+=k8[0];
|
||||
break;
|
||||
case 0 : return c; /* zero length requires no mixing */
|
||||
case 0 : return NON_ZERO_32(c); /* zero length requires no mixing */
|
||||
}
|
||||
|
||||
} else { /* need to read the key one byte at a time */
|
||||
@@ -489,10 +492,171 @@ uint32_t hashlittle(const void *key, size_t length)
|
||||
/* FALLTHROUGH */
|
||||
case 1 : a+=k[0];
|
||||
break;
|
||||
case 0 : return c;
|
||||
case 0 : return NON_ZERO_32(c);
|
||||
}
|
||||
}
|
||||
|
||||
final(a,b,c);
|
||||
return 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
|
||||
|
||||
6
hlink.c
6
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-2020 Wayne Davison
|
||||
* Copyright (C) 2004-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
|
||||
@@ -446,7 +446,7 @@ int hard_link_check(struct file_struct *file, int ndx, char *fname,
|
||||
return -1;
|
||||
|
||||
if (remove_source_files == 1 && do_xfers)
|
||||
send_msg_int(MSG_SUCCESS, ndx);
|
||||
send_msg_success(fname, ndx);
|
||||
|
||||
return 1;
|
||||
}
|
||||
@@ -519,7 +519,7 @@ void finish_hard_link(struct file_struct *file, const char *fname, int fin_ndx,
|
||||
if (val < 0)
|
||||
continue;
|
||||
if (remove_source_files == 1 && do_xfers)
|
||||
send_msg_int(MSG_SUCCESS, ndx);
|
||||
send_msg_success(fname, ndx);
|
||||
}
|
||||
|
||||
if (inc_recurse) {
|
||||
|
||||
49
io.c
49
io.c
@@ -41,6 +41,7 @@ extern int am_server;
|
||||
extern int am_sender;
|
||||
extern int am_receiver;
|
||||
extern int am_generator;
|
||||
extern int local_server;
|
||||
extern int msgs2stderr;
|
||||
extern int inc_recurse;
|
||||
extern int io_error;
|
||||
@@ -84,6 +85,8 @@ int sock_f_out = -1;
|
||||
int64 total_data_read = 0;
|
||||
int64 total_data_written = 0;
|
||||
|
||||
char num_dev_ino_buf[4 + 8 + 8];
|
||||
|
||||
static struct {
|
||||
xbuf in, out, msg;
|
||||
int in_fd;
|
||||
@@ -376,6 +379,7 @@ static void forward_filesfrom_data(void)
|
||||
free_xbuf(&ff_xb);
|
||||
if (ff_reenable_multiplex >= 0)
|
||||
io_start_multiplex_out(ff_reenable_multiplex);
|
||||
free_implied_include_partial_string();
|
||||
}
|
||||
return;
|
||||
}
|
||||
@@ -419,6 +423,7 @@ static void forward_filesfrom_data(void)
|
||||
while (s != eob) {
|
||||
if (*s++ == '\0') {
|
||||
ff_xb.len = s - sob - 1;
|
||||
add_implied_include(sob, 0);
|
||||
if (iconvbufs(ic_send, &ff_xb, &iobuf.out, flags) < 0)
|
||||
exit_cleanup(RERR_PROTOCOL); /* impossible? */
|
||||
write_buf(iobuf.out_fd, s-1, 1); /* Send the '\0'. */
|
||||
@@ -434,6 +439,7 @@ static void forward_filesfrom_data(void)
|
||||
ff_lastchar = '\0';
|
||||
else {
|
||||
/* Handle a partial string specially, saving any incomplete chars. */
|
||||
implied_include_partial_string(sob, s);
|
||||
flags &= ~ICB_INCLUDE_INCOMPLETE;
|
||||
if (iconvbufs(ic_send, &ff_xb, &iobuf.out, flags) < 0) {
|
||||
if (errno == E2BIG)
|
||||
@@ -450,13 +456,17 @@ static void forward_filesfrom_data(void)
|
||||
char *f = ff_xb.buf + ff_xb.pos;
|
||||
char *t = ff_xb.buf;
|
||||
char *eob = f + len;
|
||||
char *cur = t;
|
||||
/* Eliminate any multi-'\0' runs. */
|
||||
while (f != eob) {
|
||||
if (!(*t++ = *f++)) {
|
||||
add_implied_include(cur, 0);
|
||||
cur = t;
|
||||
while (f != eob && *f == '\0')
|
||||
f++;
|
||||
}
|
||||
}
|
||||
implied_include_partial_string(cur, t);
|
||||
ff_lastchar = f[-1];
|
||||
if ((len = t - ff_xb.buf) != 0) {
|
||||
/* This will not circle back to perform_io() because we only get
|
||||
@@ -1057,6 +1067,24 @@ void send_msg_int(enum msgcode code, int num)
|
||||
send_msg(code, numbuf, 4, -1);
|
||||
}
|
||||
|
||||
void send_msg_success(const char *fname, int num)
|
||||
{
|
||||
if (local_server) {
|
||||
STRUCT_STAT st;
|
||||
|
||||
if (DEBUG_GTE(IO, 1))
|
||||
rprintf(FINFO, "[%s] send_msg_success(%d)\n", who_am_i(), num);
|
||||
|
||||
if (stat(fname, &st) < 0)
|
||||
memset(&st, 0, sizeof (STRUCT_STAT));
|
||||
SIVAL(num_dev_ino_buf, 0, num);
|
||||
SIVAL64(num_dev_ino_buf, 4, st.st_dev);
|
||||
SIVAL64(num_dev_ino_buf, 4+8, st.st_ino);
|
||||
send_msg(MSG_SUCCESS, num_dev_ino_buf, sizeof num_dev_ino_buf, -1);
|
||||
} else
|
||||
send_msg_int(MSG_SUCCESS, num);
|
||||
}
|
||||
|
||||
static void got_flist_entry_status(enum festatus status, int ndx)
|
||||
{
|
||||
struct file_list *flist = flist_for_ndx(ndx, "got_flist_entry_status");
|
||||
@@ -1071,8 +1099,12 @@ static void got_flist_entry_status(enum festatus status, int ndx)
|
||||
|
||||
switch (status) {
|
||||
case FES_SUCCESS:
|
||||
if (remove_source_files)
|
||||
send_msg_int(MSG_SUCCESS, ndx);
|
||||
if (remove_source_files) {
|
||||
if (local_server)
|
||||
send_msg(MSG_SUCCESS, num_dev_ino_buf, sizeof num_dev_ino_buf, -1);
|
||||
else
|
||||
send_msg_int(MSG_SUCCESS, ndx);
|
||||
}
|
||||
/* FALL THROUGH */
|
||||
case FES_NO_SEND:
|
||||
#ifdef SUPPORT_HARD_LINKS
|
||||
@@ -1567,14 +1599,15 @@ static void read_a_msg(void)
|
||||
}
|
||||
break;
|
||||
case MSG_SUCCESS:
|
||||
if (msg_bytes != 4) {
|
||||
if (msg_bytes != (local_server ? 4+8+8 : 4)) {
|
||||
invalid_msg:
|
||||
rprintf(FERROR, "invalid multi-message %d:%lu [%s%s]\n",
|
||||
tag, (unsigned long)msg_bytes, who_am_i(),
|
||||
inc_recurse ? "/inc" : "");
|
||||
exit_cleanup(RERR_STREAMIO);
|
||||
}
|
||||
val = raw_read_int();
|
||||
raw_read_buf(num_dev_ino_buf, msg_bytes);
|
||||
val = IVAL(num_dev_ino_buf, 0);
|
||||
iobuf.in_multiplexed = 1;
|
||||
if (am_generator)
|
||||
got_flist_entry_status(FES_SUCCESS, val);
|
||||
@@ -1751,6 +1784,13 @@ int32 read_int(int f)
|
||||
return num;
|
||||
}
|
||||
|
||||
uint32 read_uint(int f)
|
||||
{
|
||||
char b[4];
|
||||
read_buf(f, b, 4);
|
||||
return IVAL(b, 0);
|
||||
}
|
||||
|
||||
int32 read_varint(int f)
|
||||
{
|
||||
union {
|
||||
@@ -1843,6 +1883,7 @@ int64 read_longint(int f)
|
||||
#endif
|
||||
}
|
||||
|
||||
/* Debugging note: this will be named read_buf_() when using an external zlib. */
|
||||
void read_buf(int f, char *buf, size_t len)
|
||||
{
|
||||
if (f != iobuf.in_fd) {
|
||||
|
||||
@@ -1 +1 @@
|
||||
#define LATEST_YEAR "2022"
|
||||
#define LATEST_YEAR "2024"
|
||||
|
||||
@@ -1,11 +1,28 @@
|
||||
/* 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
|
||||
@@ -15,3 +32,6 @@
|
||||
#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
|
||||
|
||||
@@ -27,7 +27,7 @@
|
||||
#include "config.h"
|
||||
#include "md-defines.h"
|
||||
|
||||
#if !defined USE_OPENSSL && CSUM_CHUNK == 64
|
||||
#ifdef USE_MD5_ASM /* { */
|
||||
|
||||
#ifdef __APPLE__
|
||||
#define md5_process_asm _md5_process_asm
|
||||
@@ -698,4 +698,4 @@ md5_process_asm:
|
||||
pop %rbp
|
||||
ret
|
||||
|
||||
#endif /* !USE_OPENSSL ... */
|
||||
#endif /* } USE_MD5_ASM */
|
||||
|
||||
19
lib/md5.c
19
lib/md5.c
@@ -2,7 +2,7 @@
|
||||
* RFC 1321 compliant MD5 implementation
|
||||
*
|
||||
* Copyright (C) 2001-2003 Christophe Devine
|
||||
* Copyright (C) 2007-2020 Wayne Davison
|
||||
* 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
|
||||
@@ -20,7 +20,6 @@
|
||||
|
||||
#include "rsync.h"
|
||||
|
||||
#ifndef USE_OPENSSL
|
||||
void md5_begin(md_context *ctx)
|
||||
{
|
||||
ctx->A = 0x67452301;
|
||||
@@ -148,7 +147,10 @@ static void md5_process(md_context *ctx, const uchar data[CSUM_CHUNK])
|
||||
ctx->D += D;
|
||||
}
|
||||
|
||||
#if defined HAVE_ASM && CSUM_CHUNK == 64
|
||||
#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
|
||||
|
||||
@@ -176,20 +178,20 @@ void md5_update(md_context *ctx, const uchar *input, uint32 length)
|
||||
left = 0;
|
||||
}
|
||||
|
||||
#if defined HAVE_ASM && CSUM_CHUNK == 64
|
||||
#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
|
||||
#else /* } { */
|
||||
while (length >= CSUM_CHUNK) {
|
||||
md5_process(ctx, input);
|
||||
length -= CSUM_CHUNK;
|
||||
input += CSUM_CHUNK;
|
||||
}
|
||||
#endif
|
||||
#endif /* } */
|
||||
|
||||
if (length)
|
||||
memcpy(ctx->buffer + left, input, length);
|
||||
@@ -221,9 +223,8 @@ void md5_result(md_context *ctx, uchar digest[MD5_DIGEST_LEN])
|
||||
SIVALu(digest, 8, ctx->C);
|
||||
SIVALu(digest, 12, ctx->D);
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef TEST_MD5
|
||||
#ifdef TEST_MD5 /* { */
|
||||
|
||||
void get_md5(uchar *out, const uchar *input, int n)
|
||||
{
|
||||
@@ -317,4 +318,4 @@ int main(int argc, char *argv[])
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif
|
||||
#endif /* } */
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
/* The include file for both the MD4 and MD5 routines. */
|
||||
|
||||
#ifdef USE_OPENSSL
|
||||
#include "openssl/md4.h"
|
||||
#include "openssl/md5.h"
|
||||
#include <openssl/sha.h>
|
||||
#include <openssl/evp.h>
|
||||
#endif
|
||||
#include "md-defines.h"
|
||||
|
||||
@@ -17,13 +17,6 @@ void mdfour_begin(md_context *md);
|
||||
void mdfour_update(md_context *md, const uchar *in, uint32 length);
|
||||
void mdfour_result(md_context *md, uchar digest[MD4_DIGEST_LEN]);
|
||||
|
||||
#ifndef USE_OPENSSL
|
||||
#define MD5_CTX md_context
|
||||
#define MD5_Init md5_begin
|
||||
#define MD5_Update md5_update
|
||||
#define MD5_Final(digest, cptr) md5_result(cptr, digest)
|
||||
|
||||
void md5_begin(md_context *ctx);
|
||||
void md5_update(md_context *ctx, const uchar *input, uint32 length);
|
||||
void md5_result(md_context *ctx, uchar digest[MD5_DIGEST_LEN]);
|
||||
#endif
|
||||
|
||||
@@ -20,7 +20,7 @@
|
||||
* for string length. This covers a nasty loophole.
|
||||
*
|
||||
* The other functions are there to prevent NULL pointers from
|
||||
* causing nast effects.
|
||||
* causing nasty effects.
|
||||
*
|
||||
* More Recently:
|
||||
* Brandon Long <blong@fiction.net> 9/15/96 for mutt 0.43
|
||||
|
||||
178
lib/sysacls.c
178
lib/sysacls.c
@@ -2,7 +2,7 @@
|
||||
* Unix SMB/CIFS implementation.
|
||||
* Based on the Samba ACL support code.
|
||||
* Copyright (C) Jeremy Allison 2000.
|
||||
* Copyright (C) 2007-2020 Wayne Davison
|
||||
* Copyright (C) 2007-2022 Wayne Davison
|
||||
*
|
||||
* The permission functions have been changed to get/set all bits via
|
||||
* one call. Some functions that rsync doesn't need were also removed.
|
||||
@@ -175,7 +175,7 @@ int sys_acl_delete_def_file(const char *name)
|
||||
return acl_delete_def_file(name);
|
||||
}
|
||||
|
||||
int sys_acl_free_acl(SMB_ACL_T the_acl)
|
||||
int sys_acl_free_acl(SMB_ACL_T the_acl)
|
||||
{
|
||||
return acl_free(the_acl);
|
||||
}
|
||||
@@ -185,7 +185,7 @@ int sys_acl_free_acl(SMB_ACL_T the_acl)
|
||||
* The interface to DEC/Compaq Tru64 UNIX ACLs
|
||||
* is based on Draft 13 of the POSIX spec which is
|
||||
* slightly different from the Draft 16 interface.
|
||||
*
|
||||
*
|
||||
* Also, some of the permset manipulation functions
|
||||
* such as acl_clear_perm() and acl_add_perm() appear
|
||||
* to be broken on Tru64 so we have to manipulate
|
||||
@@ -310,7 +310,7 @@ int sys_acl_delete_def_file(const char *name)
|
||||
return acl_delete_def_file((char *)name);
|
||||
}
|
||||
|
||||
int sys_acl_free_acl(SMB_ACL_T the_acl)
|
||||
int sys_acl_free_acl(SMB_ACL_T the_acl)
|
||||
{
|
||||
return acl_free(the_acl);
|
||||
}
|
||||
@@ -457,7 +457,7 @@ SMB_ACL_T sys_acl_get_file(const char *path_p, SMB_ACL_TYPE_T type)
|
||||
break;
|
||||
}
|
||||
ndefault = count - naccess;
|
||||
|
||||
|
||||
/*
|
||||
* if the caller wants the default ACL we have to copy
|
||||
* the entries down to the start of the acl[] buffer
|
||||
@@ -517,7 +517,7 @@ SMB_ACL_T sys_acl_get_fd(int fd)
|
||||
if (acl_d->acl[naccess].a_type & ACL_DEFAULT)
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
acl_d->count = naccess;
|
||||
|
||||
return acl_d;
|
||||
@@ -532,7 +532,7 @@ int sys_acl_get_info(SMB_ACL_ENTRY_T entry, SMB_ACL_TAG_T *tag_type_p, uint32 *b
|
||||
|
||||
if (*tag_type_p == SMB_ACL_USER || *tag_type_p == SMB_ACL_GROUP)
|
||||
*u_g_id_p = entry->a_id;
|
||||
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -633,7 +633,7 @@ static int acl_sort(SMB_ACL_T acl_d)
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int sys_acl_valid(SMB_ACL_T acl_d)
|
||||
{
|
||||
return acl_sort(acl_d);
|
||||
@@ -755,11 +755,11 @@ int sys_acl_delete_def_file(const char *path)
|
||||
ret = acl(path, SETACL, acl_d->count, acl_d->acl);
|
||||
|
||||
sys_acl_free_acl(acl_d);
|
||||
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int sys_acl_free_acl(SMB_ACL_T acl_d)
|
||||
int sys_acl_free_acl(SMB_ACL_T acl_d)
|
||||
{
|
||||
SAFE_FREE(acl_d);
|
||||
return 0;
|
||||
@@ -895,10 +895,10 @@ SMB_ACL_T sys_acl_get_file(const char *path_p, SMB_ACL_TYPE_T type)
|
||||
int ndefault; /* # of default ACL entries */
|
||||
|
||||
if (hpux_acl_call_presence() == False) {
|
||||
/* Looks like we don't have the acl() system call on HPUX.
|
||||
/* Looks like we don't have the acl() system call on HPUX.
|
||||
* May be the system doesn't have the latest version of JFS.
|
||||
*/
|
||||
return NULL;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (type != SMB_ACL_TYPE_ACCESS && type != SMB_ACL_TYPE_DEFAULT) {
|
||||
@@ -949,7 +949,7 @@ SMB_ACL_T sys_acl_get_file(const char *path_p, SMB_ACL_TYPE_T type)
|
||||
break;
|
||||
}
|
||||
ndefault = count - naccess;
|
||||
|
||||
|
||||
/*
|
||||
* if the caller wants the default ACL we have to copy
|
||||
* the entries down to the start of the acl[] buffer
|
||||
@@ -1109,9 +1109,9 @@ struct hpux_acl_types {
|
||||
* aclp - Array of ACL structures.
|
||||
* acl_type_count - Pointer to acl_types structure. Should already be
|
||||
* allocated.
|
||||
* Output:
|
||||
* Output:
|
||||
*
|
||||
* acl_type_count - This structure is filled up with counts of various
|
||||
* acl_type_count - This structure is filled up with counts of various
|
||||
* acl types.
|
||||
*/
|
||||
|
||||
@@ -1123,28 +1123,28 @@ static void hpux_count_obj(int acl_count, struct acl *aclp, struct hpux_acl_type
|
||||
|
||||
for (i = 0; i < acl_count; i++) {
|
||||
switch (aclp[i].a_type) {
|
||||
case USER:
|
||||
case USER:
|
||||
acl_type_count->n_user++;
|
||||
break;
|
||||
case USER_OBJ:
|
||||
case USER_OBJ:
|
||||
acl_type_count->n_user_obj++;
|
||||
break;
|
||||
case DEF_USER_OBJ:
|
||||
case DEF_USER_OBJ:
|
||||
acl_type_count->n_def_user_obj++;
|
||||
break;
|
||||
case GROUP:
|
||||
case GROUP:
|
||||
acl_type_count->n_group++;
|
||||
break;
|
||||
case GROUP_OBJ:
|
||||
case GROUP_OBJ:
|
||||
acl_type_count->n_group_obj++;
|
||||
break;
|
||||
case DEF_GROUP_OBJ:
|
||||
case DEF_GROUP_OBJ:
|
||||
acl_type_count->n_def_group_obj++;
|
||||
break;
|
||||
case OTHER_OBJ:
|
||||
case OTHER_OBJ:
|
||||
acl_type_count->n_other_obj++;
|
||||
break;
|
||||
case DEF_OTHER_OBJ:
|
||||
case DEF_OTHER_OBJ:
|
||||
acl_type_count->n_def_other_obj++;
|
||||
break;
|
||||
case CLASS_OBJ:
|
||||
@@ -1159,14 +1159,14 @@ static void hpux_count_obj(int acl_count, struct acl *aclp, struct hpux_acl_type
|
||||
case DEF_GROUP:
|
||||
acl_type_count->n_def_group++;
|
||||
break;
|
||||
default:
|
||||
default:
|
||||
acl_type_count->n_illegal_obj++;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* swap_acl_entries: Swaps two ACL entries.
|
||||
/* swap_acl_entries: Swaps two ACL entries.
|
||||
*
|
||||
* Inputs: aclp0, aclp1 - ACL entries to be swapped.
|
||||
*/
|
||||
@@ -1189,25 +1189,25 @@ static void hpux_swap_acl_entries(struct acl *aclp0, struct acl *aclp1)
|
||||
}
|
||||
|
||||
/* prohibited_duplicate_type
|
||||
* Identifies if given ACL type can have duplicate entries or
|
||||
* Identifies if given ACL type can have duplicate entries or
|
||||
* not.
|
||||
*
|
||||
* Inputs: acl_type - ACL Type.
|
||||
*
|
||||
* Outputs:
|
||||
* Outputs:
|
||||
*
|
||||
* Return..
|
||||
* Return..
|
||||
*
|
||||
* True - If the ACL type matches any of the prohibited types.
|
||||
* False - If the ACL type doesn't match any of the prohibited types.
|
||||
*/
|
||||
*/
|
||||
|
||||
static BOOL hpux_prohibited_duplicate_type(int acl_type)
|
||||
{
|
||||
switch (acl_type) {
|
||||
case USER:
|
||||
case GROUP:
|
||||
case DEF_USER:
|
||||
case DEF_USER:
|
||||
case DEF_GROUP:
|
||||
return True;
|
||||
default:
|
||||
@@ -1217,7 +1217,7 @@ static BOOL hpux_prohibited_duplicate_type(int acl_type)
|
||||
|
||||
/* get_needed_class_perm
|
||||
* Returns the permissions of a ACL structure only if the ACL
|
||||
* type matches one of the pre-determined types for computing
|
||||
* type matches one of the pre-determined types for computing
|
||||
* CLASS_OBJ permissions.
|
||||
*
|
||||
* Inputs: aclp - Pointer to ACL structure.
|
||||
@@ -1226,17 +1226,17 @@ static BOOL hpux_prohibited_duplicate_type(int acl_type)
|
||||
static int hpux_get_needed_class_perm(struct acl *aclp)
|
||||
{
|
||||
switch (aclp->a_type) {
|
||||
case USER:
|
||||
case GROUP_OBJ:
|
||||
case GROUP:
|
||||
case DEF_USER_OBJ:
|
||||
case USER:
|
||||
case GROUP_OBJ:
|
||||
case GROUP:
|
||||
case DEF_USER_OBJ:
|
||||
case DEF_USER:
|
||||
case DEF_GROUP_OBJ:
|
||||
case DEF_GROUP_OBJ:
|
||||
case DEF_GROUP:
|
||||
case DEF_CLASS_OBJ:
|
||||
case DEF_OTHER_OBJ:
|
||||
case DEF_OTHER_OBJ:
|
||||
return aclp->a_perm;
|
||||
default:
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
@@ -1267,15 +1267,15 @@ static int hpux_acl_sort(int acl_count, int calclass, struct acl *aclp)
|
||||
#if !defined(HAVE_HPUX_ACLSORT)
|
||||
/*
|
||||
* The aclsort() system call is available on the latest HPUX General
|
||||
* Patch Bundles. So for HPUX, we developed our version of acl_sort
|
||||
* function. Because, we don't want to update to a new
|
||||
* Patch Bundles. So for HPUX, we developed our version of acl_sort
|
||||
* function. Because, we don't want to update to a new
|
||||
* HPUX GR bundle just for aclsort() call.
|
||||
*/
|
||||
|
||||
struct hpux_acl_types acl_obj_count;
|
||||
int n_class_obj_perm = 0;
|
||||
int i, j;
|
||||
|
||||
|
||||
if (!acl_count) {
|
||||
DEBUG(10, ("Zero acl count passed. Returning Success\n"));
|
||||
return 0;
|
||||
@@ -1290,8 +1290,8 @@ static int hpux_acl_sort(int acl_count, int calclass, struct acl *aclp)
|
||||
|
||||
hpux_count_obj(acl_count, aclp, &acl_obj_count);
|
||||
|
||||
/* There should be only one entry each of type USER_OBJ, GROUP_OBJ,
|
||||
* CLASS_OBJ and OTHER_OBJ
|
||||
/* There should be only one entry each of type USER_OBJ, GROUP_OBJ,
|
||||
* CLASS_OBJ and OTHER_OBJ
|
||||
*/
|
||||
|
||||
if (acl_obj_count.n_user_obj != 1
|
||||
@@ -1313,15 +1313,15 @@ or DEF_USER_OBJ or DEF_GROUP_OBJ or DEF_OTHER_OBJ\n"));
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* We now have proper number of OBJ and DEF_OBJ entries. Now sort the acl
|
||||
* structures.
|
||||
/* We now have proper number of OBJ and DEF_OBJ entries. Now sort the acl
|
||||
* structures.
|
||||
*
|
||||
* Sorting crieteria - First sort by ACL type. If there are multiple entries of
|
||||
* same ACL type, sort by ACL id.
|
||||
*
|
||||
* I am using the trivial kind of sorting method here because, performance isn't
|
||||
* I am using the trivial kind of sorting method here because, performance isn't
|
||||
* really effected by the ACLs feature. More over there aren't going to be more
|
||||
* than 17 entries on HPUX.
|
||||
* than 17 entries on HPUX.
|
||||
*/
|
||||
|
||||
for (i = 0; i < acl_count; i++) {
|
||||
@@ -1390,7 +1390,7 @@ static int acl_sort(SMB_ACL_T acl_d)
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int sys_acl_valid(SMB_ACL_T acl_d)
|
||||
{
|
||||
return acl_sort(acl_d);
|
||||
@@ -1405,11 +1405,11 @@ int sys_acl_set_file(const char *name, SMB_ACL_TYPE_T type, SMB_ACL_T acl_d)
|
||||
int ret;
|
||||
|
||||
if (hpux_acl_call_presence() == False) {
|
||||
/* Looks like we don't have the acl() system call on HPUX.
|
||||
/* Looks like we don't have the acl() system call on HPUX.
|
||||
* May be the system doesn't have the latest version of JFS.
|
||||
*/
|
||||
errno=ENOSYS;
|
||||
return -1;
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (type != SMB_ACL_TYPE_ACCESS && type != SMB_ACL_TYPE_DEFAULT) {
|
||||
@@ -1538,11 +1538,11 @@ int sys_acl_delete_def_file(const char *path)
|
||||
ret = acl(path, ACL_SET, acl_d->count, acl_d->acl);
|
||||
|
||||
sys_acl_free_acl(acl_d);
|
||||
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int sys_acl_free_acl(SMB_ACL_T acl_d)
|
||||
int sys_acl_free_acl(SMB_ACL_T acl_d)
|
||||
{
|
||||
free(acl_d);
|
||||
return 0;
|
||||
@@ -1723,7 +1723,7 @@ int sys_acl_delete_def_file(const char *name)
|
||||
return acl_delete_def_file(name);
|
||||
}
|
||||
|
||||
int sys_acl_free_acl(SMB_ACL_T acl_d)
|
||||
int sys_acl_free_acl(SMB_ACL_T acl_d)
|
||||
{
|
||||
if (acl_d->freeaclp) {
|
||||
acl_free(acl_d->aclp);
|
||||
@@ -1834,12 +1834,12 @@ SMB_ACL_T sys_acl_get_file(const char *path_p, SMB_ACL_TYPE_T type)
|
||||
}
|
||||
|
||||
/* Get the acl using statacl */
|
||||
|
||||
|
||||
DEBUG(10, ("Entering sys_acl_get_file\n"));
|
||||
DEBUG(10, ("path_p is %s\n", path_p));
|
||||
|
||||
file_acl = (struct acl *)SMB_MALLOC(BUFSIZ);
|
||||
|
||||
|
||||
if (file_acl == NULL) {
|
||||
errno=ENOMEM;
|
||||
DEBUG(0, ("Error in AIX sys_acl_get_file: %d\n", errno));
|
||||
@@ -1931,9 +1931,9 @@ SMB_ACL_T sys_acl_get_file(const char *path_p, SMB_ACL_TYPE_T type)
|
||||
* to be specified but, it's better than leaving it 0 */
|
||||
|
||||
acl_entry_link->entryp->ace_type = acl_entry->ace_type;
|
||||
|
||||
|
||||
acl_entry_link->entryp->ace_access = acl_entry->ace_access;
|
||||
|
||||
|
||||
memcpy(acl_entry_link->entryp->ace_id, idp, sizeof (struct ace_id));
|
||||
|
||||
/* The access in the acl entries must be left shifted by *
|
||||
@@ -1962,7 +1962,7 @@ SMB_ACL_T sys_acl_get_file(const char *path_p, SMB_ACL_TYPE_T type)
|
||||
|
||||
DEBUG(10, ("acl_entry = %d\n", acl_entry));
|
||||
DEBUG(10, ("The ace_type is %d\n", acl_entry->ace_type));
|
||||
|
||||
|
||||
acl_entry = acl_nxt(acl_entry);
|
||||
}
|
||||
} /* end of if enabled */
|
||||
@@ -2014,12 +2014,12 @@ SMB_ACL_T sys_acl_get_file(const char *path_p, SMB_ACL_TYPE_T type)
|
||||
new_acl_entry->ace_access = file_acl->o_access << 6;
|
||||
idp->id_type = SMB_ACL_OTHER;
|
||||
break;
|
||||
|
||||
|
||||
case 1:
|
||||
new_acl_entry->ace_access = file_acl->u_access << 6;
|
||||
idp->id_type = SMB_ACL_USER_OBJ;
|
||||
break;
|
||||
|
||||
|
||||
default:
|
||||
return NULL;
|
||||
|
||||
@@ -2048,7 +2048,7 @@ SMB_ACL_T sys_acl_get_fd(int fd)
|
||||
int rc = 0;
|
||||
|
||||
/* Get the acl using fstatacl */
|
||||
|
||||
|
||||
DEBUG(10, ("Entering sys_acl_get_fd\n"));
|
||||
DEBUG(10, ("fd is %d\n", fd));
|
||||
file_acl = (struct acl *)SMB_MALLOC(BUFSIZ);
|
||||
@@ -2095,12 +2095,12 @@ SMB_ACL_T sys_acl_get_fd(int fd)
|
||||
|
||||
DEBUG(10, ("acl_entry is %d\n", acl_entry));
|
||||
DEBUG(10, ("acl_last(file_acl) id %d\n", acl_last(file_acl)));
|
||||
|
||||
|
||||
/* Check if the extended acl bit is on. *
|
||||
* If it isn't, do not show the *
|
||||
* contents of the acl since AIX intends *
|
||||
* the extended info to remain unused */
|
||||
|
||||
|
||||
if (file_acl->acl_mode & S_IXACL){
|
||||
/* while we are not pointing to the very end */
|
||||
while (acl_entry < acl_last(file_acl)) {
|
||||
@@ -2115,7 +2115,7 @@ SMB_ACL_T sys_acl_get_fd(int fd)
|
||||
}
|
||||
|
||||
idp = acl_entry->ace_id;
|
||||
|
||||
|
||||
/* Check if this is the first entry in the linked list. *
|
||||
* The first entry needs to keep prevp pointing to NULL *
|
||||
* and already has entryp allocated. */
|
||||
@@ -2177,7 +2177,7 @@ SMB_ACL_T sys_acl_get_fd(int fd)
|
||||
|
||||
DEBUG(10, ("acl_entry = %d\n", acl_entry));
|
||||
DEBUG(10, ("The ace_type is %d\n", acl_entry->ace_type));
|
||||
|
||||
|
||||
acl_entry = acl_nxt(acl_entry);
|
||||
}
|
||||
} /* end of if enabled */
|
||||
@@ -2210,43 +2210,43 @@ SMB_ACL_T sys_acl_get_fd(int fd)
|
||||
}
|
||||
|
||||
acl_entry_link->nextp = NULL;
|
||||
|
||||
|
||||
new_acl_entry = acl_entry_link->entryp;
|
||||
idp = new_acl_entry->ace_id;
|
||||
|
||||
|
||||
new_acl_entry->ace_len = sizeof (struct acl_entry);
|
||||
new_acl_entry->ace_type = ACC_PERMIT;
|
||||
idp->id_len = sizeof (struct ace_id);
|
||||
DEBUG(10, ("idp->id_len = %d\n", idp->id_len));
|
||||
memset(idp->id_data, 0, sizeof (uid_t));
|
||||
|
||||
|
||||
switch (i) {
|
||||
case 2:
|
||||
new_acl_entry->ace_access = file_acl->g_access << 6;
|
||||
idp->id_type = SMB_ACL_GROUP_OBJ;
|
||||
break;
|
||||
|
||||
|
||||
case 3:
|
||||
new_acl_entry->ace_access = file_acl->o_access << 6;
|
||||
idp->id_type = SMB_ACL_OTHER;
|
||||
break;
|
||||
|
||||
|
||||
case 1:
|
||||
new_acl_entry->ace_access = file_acl->u_access << 6;
|
||||
idp->id_type = SMB_ACL_USER_OBJ;
|
||||
break;
|
||||
|
||||
|
||||
default:
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
acl_entry_link_head->count++;
|
||||
DEBUG(10, ("new_acl_entry->ace_access = %d\n", new_acl_entry->ace_access));
|
||||
}
|
||||
|
||||
acl_entry_link_head->count = 0;
|
||||
SAFE_FREE(file_acl);
|
||||
|
||||
|
||||
return acl_entry_link_head;
|
||||
}
|
||||
#endif
|
||||
@@ -2274,7 +2274,7 @@ int sys_acl_get_info(SMB_ACL_ENTRY_T entry, SMB_ACL_TAG_T *tag_type_p, uint32 *b
|
||||
SMB_ACL_T sys_acl_init(int count)
|
||||
{
|
||||
struct acl_entry_link *theacl = NULL;
|
||||
|
||||
|
||||
if (count < 0) {
|
||||
errno = EINVAL;
|
||||
return NULL;
|
||||
@@ -2383,9 +2383,9 @@ int sys_acl_valid(SMB_ACL_T theacl)
|
||||
}
|
||||
|
||||
DEBUG(10, ("user_obj=%d, group_obj=%d, other_obj=%d\n", user_obj, group_obj, other_obj));
|
||||
|
||||
|
||||
if (user_obj != 1 || group_obj != 1 || other_obj != 1)
|
||||
return -1;
|
||||
return -1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -2404,7 +2404,7 @@ int sys_acl_set_file(const char *name, SMB_ACL_TYPE_T acltype, SMB_ACL_T theacl)
|
||||
|
||||
DEBUG(10, ("Entering sys_acl_set_file\n"));
|
||||
DEBUG(10, ("File name is %s\n", name));
|
||||
|
||||
|
||||
/* AIX has no default ACL */
|
||||
if (acltype == SMB_ACL_TYPE_DEFAULT)
|
||||
return 0;
|
||||
@@ -2449,7 +2449,7 @@ int sys_acl_set_file(const char *name, SMB_ACL_TYPE_T acltype, SMB_ACL_T theacl)
|
||||
errno = ENOMEM;
|
||||
DEBUG(0, ("Error in sys_acl_set_file is %d\n", errno));
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
memcpy(file_acl_temp, file_acl, file_acl->acl_len);
|
||||
SAFE_FREE(file_acl);
|
||||
@@ -2460,15 +2460,15 @@ int sys_acl_set_file(const char *name, SMB_ACL_TYPE_T acltype, SMB_ACL_T theacl)
|
||||
file_acl->acl_len += sizeof (struct acl_entry);
|
||||
acl_entry->ace_len = acl_entry_link->entryp->ace_len;
|
||||
acl_entry->ace_access = acl_entry_link->entryp->ace_access;
|
||||
|
||||
|
||||
/* In order to use this, we'll need to wait until we can get denies */
|
||||
/* if (!acl_entry->ace_access && acl_entry->ace_type == ACC_PERMIT)
|
||||
acl_entry->ace_type = ACC_SPECIFY; */
|
||||
|
||||
acl_entry->ace_type = ACC_SPECIFY;
|
||||
|
||||
|
||||
ace_id = acl_entry->ace_id;
|
||||
|
||||
|
||||
ace_id->id_type = acl_entry_link->entryp->ace_id->id_type;
|
||||
DEBUG(10, ("The id type is %d\n", ace_id->id_type));
|
||||
ace_id->id_len = acl_entry_link->entryp->ace_id->id_len;
|
||||
@@ -2496,7 +2496,7 @@ int sys_acl_set_fd(int fd, SMB_ACL_T theacl)
|
||||
uint user_id;
|
||||
uint acl_length;
|
||||
uint rc;
|
||||
|
||||
|
||||
DEBUG(10, ("Entering sys_acl_set_fd\n"));
|
||||
acl_length = BUFSIZ;
|
||||
file_acl = (struct acl *)SMB_MALLOC(BUFSIZ);
|
||||
@@ -2508,7 +2508,7 @@ int sys_acl_set_fd(int fd, SMB_ACL_T theacl)
|
||||
}
|
||||
|
||||
memset(file_acl, 0, BUFSIZ);
|
||||
|
||||
|
||||
file_acl->acl_len = ACL_SIZ;
|
||||
file_acl->acl_mode = S_IXACL;
|
||||
|
||||
@@ -2550,22 +2550,22 @@ int sys_acl_set_fd(int fd, SMB_ACL_T theacl)
|
||||
file_acl->acl_len += sizeof (struct acl_entry);
|
||||
acl_entry->ace_len = acl_entry_link->entryp->ace_len;
|
||||
acl_entry->ace_access = acl_entry_link->entryp->ace_access;
|
||||
|
||||
|
||||
/* In order to use this, we'll need to wait until we can get denies */
|
||||
/* if (!acl_entry->ace_access && acl_entry->ace_type == ACC_PERMIT)
|
||||
acl_entry->ace_type = ACC_SPECIFY; */
|
||||
|
||||
|
||||
acl_entry->ace_type = ACC_SPECIFY;
|
||||
|
||||
|
||||
ace_id = acl_entry->ace_id;
|
||||
|
||||
|
||||
ace_id->id_type = acl_entry_link->entryp->ace_id->id_type;
|
||||
DEBUG(10, ("The id type is %d\n", ace_id->id_type));
|
||||
ace_id->id_len = acl_entry_link->entryp->ace_id->id_len;
|
||||
memcpy(&user_id, acl_entry_link->entryp->ace_id->id_data, sizeof (uid_t));
|
||||
memcpy(ace_id->id_data, &user_id, sizeof (uid_t));
|
||||
}
|
||||
|
||||
|
||||
rc = fchacl(fd, file_acl, file_acl->acl_len);
|
||||
DEBUG(10, ("errno is %d\n", errno));
|
||||
DEBUG(10, ("return code is %d\n", rc));
|
||||
@@ -2594,7 +2594,7 @@ int sys_acl_free_acl(SMB_ACL_T posix_acl)
|
||||
SAFE_FREE(acl_entry_link->prevp);
|
||||
SAFE_FREE(acl_entry_link->entryp);
|
||||
SAFE_FREE(acl_entry_link);
|
||||
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
* Version 2.2.x
|
||||
* Portable SMB ACL interface
|
||||
* Copyright (C) Jeremy Allison 2000
|
||||
* Copyright (C) 2007-2020 Wayne Davison
|
||||
* 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
|
||||
@@ -232,7 +232,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
|
||||
|
||||
|
||||
10
log.c
10
log.c
@@ -36,8 +36,6 @@ extern int protocol_version;
|
||||
extern int always_checksum;
|
||||
extern int preserve_mtimes;
|
||||
extern int msgs2stderr;
|
||||
extern int xfersum_type;
|
||||
extern int checksum_type;
|
||||
extern int stdout_format_has_i;
|
||||
extern int stdout_format_has_o_or_i;
|
||||
extern int logfile_format_has_i;
|
||||
@@ -62,6 +60,8 @@ 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;
|
||||
static FILE *logfile_fp;
|
||||
@@ -680,12 +680,12 @@ static void log_formatted(enum logcode code, const char *format, const char *op,
|
||||
n = NULL;
|
||||
if (S_ISREG(file->mode)) {
|
||||
if (always_checksum)
|
||||
n = sum_as_hex(checksum_type, F_SUM(file), 1);
|
||||
n = sum_as_hex(file_sum_nni->num, F_SUM(file), 1);
|
||||
else if (iflags & ITEM_TRANSFER)
|
||||
n = sum_as_hex(xfersum_type, sender_file_sum, 0);
|
||||
n = sum_as_hex(xfer_sum_nni->num, sender_file_sum, 0);
|
||||
}
|
||||
if (!n) {
|
||||
int sum_len = csum_len_for_type(always_checksum ? checksum_type : xfersum_type,
|
||||
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';
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
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],
|
||||
|
||||
56
main.c
56
main.c
@@ -48,6 +48,7 @@ extern int called_from_signal_handler;
|
||||
extern int need_messages_from_generator;
|
||||
extern int kluge_around_eof;
|
||||
extern int got_xfer_error;
|
||||
extern int old_style_args;
|
||||
extern int msgs2stderr;
|
||||
extern int module_id;
|
||||
extern int read_only;
|
||||
@@ -88,6 +89,8 @@ extern int backup_dir_len;
|
||||
extern int basis_dir_cnt;
|
||||
extern int default_af_hint;
|
||||
extern int stdout_format_has_i;
|
||||
extern int trust_sender_filter;
|
||||
extern int trust_sender_args;
|
||||
extern struct stats stats;
|
||||
extern char *stdout_format;
|
||||
extern char *logfile_format;
|
||||
@@ -103,7 +106,7 @@ extern char curr_dir[MAXPATHLEN];
|
||||
extern char backup_dir_buf[MAXPATHLEN];
|
||||
extern char *basis_dir[MAX_BASIS_DIRS+1];
|
||||
extern struct file_list *first_flist;
|
||||
extern filter_rule_list daemon_filter_list;
|
||||
extern filter_rule_list daemon_filter_list, implied_filter_list;
|
||||
|
||||
uid_t our_uid;
|
||||
gid_t our_gid;
|
||||
@@ -477,7 +480,7 @@ static void show_malloc_stats(void)
|
||||
|
||||
#define PRINT_ALLOC_NUM(title, descr, num) \
|
||||
rprintf(FINFO, " %-11s%10" SIZE_T_FMT_MOD "d (" descr ")\n", \
|
||||
title ":", (SIZE_T_FMT_CAST)(num));
|
||||
title ":", (SIZE_T_FMT_CAST)(num));
|
||||
|
||||
PRINT_ALLOC_NUM("arena", "bytes from sbrk", mi.arena);
|
||||
PRINT_ALLOC_NUM("ordblks", "chunks not in use", mi.ordblks);
|
||||
@@ -659,6 +662,16 @@ static pid_t do_cmd(char *cmd, char *machine, char *user, char **remote_argv, in
|
||||
return pid;
|
||||
}
|
||||
|
||||
/* Older versions turn an empty string as a reference to the current directory.
|
||||
* We now treat this as an error unless --old-args was used. */
|
||||
static char *dot_dir_or_error()
|
||||
{
|
||||
if (old_style_args || am_server)
|
||||
return ".";
|
||||
rprintf(FERROR, "Empty destination arg specified (use \".\" or see --old-args).\n");
|
||||
exit_cleanup(RERR_SYNTAX);
|
||||
}
|
||||
|
||||
/* The receiving side operates in one of two modes:
|
||||
*
|
||||
* 1. it receives any number of files into a destination directory,
|
||||
@@ -686,9 +699,8 @@ static char *get_local_name(struct file_list *flist, char *dest_path)
|
||||
if (!dest_path || list_only)
|
||||
return NULL;
|
||||
|
||||
/* Treat an empty string as a copy into the current directory. */
|
||||
if (!*dest_path)
|
||||
dest_path = ".";
|
||||
dest_path = dot_dir_or_error();
|
||||
|
||||
if (daemon_filter_list.head) {
|
||||
char *slash = strrchr(dest_path, '/');
|
||||
@@ -1075,6 +1087,7 @@ static int do_recv(int f_in, int f_out, char *local_name)
|
||||
}
|
||||
|
||||
am_generator = 1;
|
||||
implied_filter_list.head = implied_filter_list.tail = NULL;
|
||||
flist_receiving_enabled = True;
|
||||
|
||||
io_end_multiplex_in(MPLX_SWITCHING);
|
||||
@@ -1370,15 +1383,6 @@ int client_run(int f_in, int f_out, pid_t pid, int argc, char *argv[])
|
||||
return MAX(exit_code, exit_code2);
|
||||
}
|
||||
|
||||
static void dup_argv(char *argv[])
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; argv[i]; i++)
|
||||
argv[i] = strdup(argv[i]);
|
||||
}
|
||||
|
||||
|
||||
/* Start a client for either type of remote connection. Work out
|
||||
* whether the arguments request a remote shell or rsyncd connection,
|
||||
* and call the appropriate connection function, then run_client.
|
||||
@@ -1394,10 +1398,6 @@ static int start_client(int argc, char *argv[])
|
||||
int ret;
|
||||
pid_t pid;
|
||||
|
||||
/* Don't clobber argv[] so that ps(1) can still show the right
|
||||
* command line. */
|
||||
dup_argv(argv);
|
||||
|
||||
if (!read_batch) { /* for read_batch, NO source is specified */
|
||||
char *path = check_for_hostspec(argv[0], &shell_machine, &rsync_port);
|
||||
if (path) { /* source is remote */
|
||||
@@ -1430,6 +1430,8 @@ static int start_client(int argc, char *argv[])
|
||||
|
||||
if (argc > 1) {
|
||||
p = argv[--argc];
|
||||
if (!*p)
|
||||
p = dot_dir_or_error();
|
||||
remote_argv = argv + argc;
|
||||
} else {
|
||||
static char *dotarg[1] = { "." };
|
||||
@@ -1470,6 +1472,12 @@ static int start_client(int argc, char *argv[])
|
||||
rsync_port = 0;
|
||||
}
|
||||
|
||||
/* A local transfer doesn't unbackslash anything, so leave the args alone. */
|
||||
if (local_server) {
|
||||
old_style_args = 2;
|
||||
trust_sender_args = trust_sender_filter = 1;
|
||||
}
|
||||
|
||||
if (!rsync_port && remote_argc && !**remote_argv) /* Turn an empty arg into a dot dir. */
|
||||
*remote_argv = ".";
|
||||
|
||||
@@ -1495,6 +1503,8 @@ static int start_client(int argc, char *argv[])
|
||||
char *dummy_host;
|
||||
int dummy_port = rsync_port;
|
||||
int i;
|
||||
if (filesfrom_fd < 0)
|
||||
add_implied_include(remote_argv[0], daemon_connection);
|
||||
/* For remote source, any extra source args must have either
|
||||
* the same hostname or an empty hostname. */
|
||||
for (i = 1; i < remote_argc; i++) {
|
||||
@@ -1518,6 +1528,7 @@ static int start_client(int argc, char *argv[])
|
||||
if (!rsync_port && !*arg) /* Turn an empty arg into a dot dir. */
|
||||
arg = ".";
|
||||
remote_argv[i] = arg;
|
||||
add_implied_include(arg, daemon_connection);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1734,6 +1745,17 @@ int main(int argc,char *argv[])
|
||||
|
||||
unset_env_var("DISPLAY");
|
||||
|
||||
#if defined USE_OPENSSL && defined SET_OPENSSL_CONF
|
||||
#define TO_STR2(x) #x
|
||||
#define TO_STR(x) TO_STR2(x)
|
||||
/* ./configure --with-openssl-conf=/etc/ssl/openssl-rsync.cnf
|
||||
* defines SET_OPENSSL_CONF as that unquoted pathname. */
|
||||
if (!getenv("OPENSSL_CONF")) /* Don't override it if it's already set. */
|
||||
set_env_str("OPENSSL_CONF", TO_STR(SET_OPENSSL_CONF));
|
||||
#undef TO_STR
|
||||
#undef TO_STR2
|
||||
#endif
|
||||
|
||||
memset(&stats, 0, sizeof(stats));
|
||||
|
||||
/* Even a non-daemon runs needs the default config values to be set, e.g.
|
||||
|
||||
22
match.c
22
match.c
@@ -3,7 +3,7 @@
|
||||
*
|
||||
* Copyright (C) 1996 Andrew Tridgell
|
||||
* Copyright (C) 1996 Paul Mackerras
|
||||
* Copyright (C) 2003-2020 Wayne Davison
|
||||
* Copyright (C) 2003-2023 Wayne Davison
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
@@ -24,7 +24,9 @@
|
||||
|
||||
extern int checksum_seed;
|
||||
extern int append_mode;
|
||||
extern int xfersum_type;
|
||||
|
||||
extern struct name_num_item *xfer_sum_nni;
|
||||
extern int xfer_sum_len;
|
||||
|
||||
int updating_basis_file;
|
||||
char sender_file_sum[MAX_DIGEST_LEN];
|
||||
@@ -140,7 +142,7 @@ static void hash_search(int f,struct sum_struct *s,
|
||||
{
|
||||
OFF_T offset, aligned_offset, end;
|
||||
int32 k, want_i, aligned_i, backup;
|
||||
char sum2[SUM_LENGTH];
|
||||
char sum2[MAX_DIGEST_LEN];
|
||||
uint32 s1, s2, sum;
|
||||
int more;
|
||||
schar *map;
|
||||
@@ -356,15 +358,13 @@ static void hash_search(int f,struct sum_struct *s,
|
||||
**/
|
||||
void match_sums(int f, struct sum_struct *s, struct map_struct *buf, OFF_T len)
|
||||
{
|
||||
int sum_len;
|
||||
|
||||
last_match = 0;
|
||||
false_alarms = 0;
|
||||
hash_hits = 0;
|
||||
matches = 0;
|
||||
data_transfer = 0;
|
||||
|
||||
sum_init(xfersum_type, checksum_seed);
|
||||
sum_init(xfer_sum_nni, checksum_seed);
|
||||
|
||||
if (append_mode > 0) {
|
||||
if (append_mode == 2) {
|
||||
@@ -405,22 +405,22 @@ void match_sums(int f, struct sum_struct *s, struct map_struct *buf, OFF_T len)
|
||||
matched(f, s, buf, len, -1);
|
||||
}
|
||||
|
||||
sum_len = sum_end(sender_file_sum);
|
||||
sum_end(sender_file_sum);
|
||||
|
||||
/* If we had a read error, send a bad checksum. We use all bits
|
||||
* off as long as the checksum doesn't happen to be that, in
|
||||
* which case we turn the last 0 bit into a 1. */
|
||||
if (buf && buf->status != 0) {
|
||||
int i;
|
||||
for (i = 0; i < sum_len && sender_file_sum[i] == 0; i++) {}
|
||||
memset(sender_file_sum, 0, sum_len);
|
||||
if (i == sum_len)
|
||||
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))
|
||||
rprintf(FINFO,"sending file_sum\n");
|
||||
write_buf(f, sender_file_sum, sum_len);
|
||||
write_buf(f, sender_file_sum, xfer_sum_len);
|
||||
|
||||
if (DEBUG_GTE(DELTASUM, 2)) {
|
||||
rprintf(FINFO, "false_alarms=%d hash_hits=%d matches=%d\n",
|
||||
|
||||
@@ -8,6 +8,7 @@ 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.
|
||||
@@ -32,4 +33,10 @@ if [ ! -f "$flagfile" ]; then
|
||||
fi
|
||||
fi
|
||||
|
||||
"$srcdir/md-convert" "$srcdir/$inname"
|
||||
if [ -f "$force_flagfile" ]; then
|
||||
opt='--force-link-text'
|
||||
else
|
||||
opt=''
|
||||
fi
|
||||
|
||||
"$srcdir/md-convert" $opt "$srcdir/$inname"
|
||||
|
||||
197
md-convert
197
md-convert
@@ -32,6 +32,8 @@
|
||||
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 = """\
|
||||
@@ -47,7 +49,7 @@ body {
|
||||
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; vertical-align: top; }
|
||||
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; }
|
||||
@@ -111,6 +113,22 @@ 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 = { }
|
||||
|
||||
@@ -125,15 +143,15 @@ def main():
|
||||
|
||||
|
||||
def parse_md_file(mdfn):
|
||||
fi = re.match(r'^(?P<fn>(?P<srcdir>.+/)?(?P<name>(?P<prog>[^/]+?)(\.(?P<sect>\d+))?)\.md)$', 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 + ') man page'
|
||||
fi.title = fi.prog + '(' + fi.sect + ') manpage'
|
||||
else:
|
||||
fi.title = fi.prog
|
||||
fi.title = fi.prog + ' for rsync'
|
||||
|
||||
if fi.want_manpage:
|
||||
if not env_subs:
|
||||
@@ -172,6 +190,8 @@ def parse_md_file(mdfn):
|
||||
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)
|
||||
@@ -194,6 +214,7 @@ def find_man_substitutions():
|
||||
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:
|
||||
@@ -205,24 +226,26 @@ def find_man_substitutions():
|
||||
|
||||
with open(srcdir + 'version.h', 'r', encoding='utf-8') as fh:
|
||||
txt = fh.read()
|
||||
m = re.search(r'"(.+?)"', txt)
|
||||
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 = re.match(r'^(\w+)=(.+)', line)
|
||||
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 re.search(r'\$\{', val):
|
||||
val = re.sub(r'\$\{(\w+)\}', lambda m: env_subs[m.group(1)], val)
|
||||
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.localtime(mtime))
|
||||
env_subs['date'] = time.strftime('%d %b %Y', time.gmtime(mtime + tz_offset)).lstrip('0')
|
||||
|
||||
|
||||
def html_via_commonmark(txt):
|
||||
@@ -251,9 +274,13 @@ class TransformHtml(HTMLParser):
|
||||
derived_hashtags = set(),
|
||||
referenced_hashtags = set(),
|
||||
bad_hashtags = set(),
|
||||
prior_target = None,
|
||||
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:
|
||||
@@ -276,11 +303,11 @@ class TransformHtml(HTMLParser):
|
||||
fi.man_out = ''.join(st.man_out)
|
||||
st.man_out = None
|
||||
|
||||
for href, txt in st.derived_hashtags:
|
||||
derived = txt2target(txt, href[1:])
|
||||
for tgt, txt in st.derived_hashtags:
|
||||
derived = txt2target(txt, tgt)
|
||||
if derived not in st.created_hashtags:
|
||||
txt = re.sub(r'[\1-\7]+', '', txt.replace(NBR_DASH[0], '-').replace(NBR_SPACE[0], ' '))
|
||||
warn('Unknown derived hashtag link in', self.fn, 'based on:', (href, txt))
|
||||
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:
|
||||
@@ -291,6 +318,13 @@ class TransformHtml(HTMLParser):
|
||||
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:
|
||||
@@ -330,7 +364,7 @@ class TransformHtml(HTMLParser):
|
||||
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 man page
|
||||
tag = 'u' # Change it into underline to be more like the manpage
|
||||
st.txt += UNDR_FONT[0]
|
||||
elif tag == 'ol':
|
||||
start = 1
|
||||
@@ -362,13 +396,26 @@ class TransformHtml(HTMLParser):
|
||||
st.a_href = None
|
||||
for var, val in attrs_list:
|
||||
if var == 'href':
|
||||
if val in ('#', '#opt', '#daemon-opt'):
|
||||
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
|
||||
elif val.startswith('#'):
|
||||
st.referenced_hashtags.add(val[1:])
|
||||
if val[1:] == st.prior_target:
|
||||
warn('Found link to the current section in', self.fn + ':', val)
|
||||
elif not val.startswith(('https://', 'http://', 'mailto:', 'ftp:', './')):
|
||||
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) + '>')
|
||||
@@ -379,25 +426,36 @@ class TransformHtml(HTMLParser):
|
||||
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' or tag == 'h2':
|
||||
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_target(txt)
|
||||
st.opt_prefix = 'daemon-opt' if txt == 'DAEMON OPTIONS' else 'opt'
|
||||
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_target(txt)
|
||||
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_target(txt)
|
||||
self.add_targets(tag, txt)
|
||||
st.dt_from = None
|
||||
elif txt != '':
|
||||
st.man_out.append(manify(txt) + "\n")
|
||||
@@ -421,7 +479,7 @@ class TransformHtml(HTMLParser):
|
||||
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 man page
|
||||
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':
|
||||
@@ -434,16 +492,26 @@ class TransformHtml(HTMLParser):
|
||||
elif tag == 'hr':
|
||||
return
|
||||
elif tag == 'a':
|
||||
if st.a_href:
|
||||
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]:
|
||||
derived = txt2target(atxt, st.a_href[1:])
|
||||
if derived == st.prior_target:
|
||||
warn('Found link to the current section in', self.fn + ':', derived)
|
||||
st.derived_hashtags.add((st.a_href, atxt))
|
||||
st.html_out[j] = st.html_out[j].replace(find, 'href="#' + derived + '"')
|
||||
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)
|
||||
@@ -472,23 +540,47 @@ class TransformHtml(HTMLParser):
|
||||
if st.in_pre:
|
||||
html = htmlify(txt)
|
||||
else:
|
||||
txt = re.sub(r'\s--(\s)', NBR_SPACE[0] + r'--\1', txt).replace('--', NBR_DASH[0]*2)
|
||||
txt = re.sub(r'(^|\W)-', r'\1' + NBR_DASH[0], txt)
|
||||
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 = re.sub(r'\s', NBR_SPACE[0], txt)
|
||||
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_target(self, txt):
|
||||
def add_targets(self, tag, txt, suf=None):
|
||||
st = self.state
|
||||
txt = txt2target(txt, st.opt_prefix)
|
||||
if txt:
|
||||
st.html_out.append('<a id="' + txt + '" href="#' + txt + '" class="tgt"></a>')
|
||||
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.prior_target = txt
|
||||
st.latest_targets = targets
|
||||
|
||||
|
||||
def output_debug(self, event, extra):
|
||||
@@ -505,24 +597,27 @@ class TransformHtml(HTMLParser):
|
||||
|
||||
|
||||
def txt2target(txt, opt_prefix):
|
||||
txt = re.sub(r'[%s](.+?)[=%s].*' % (BOLD_FONT[0], NORM_FONT[0]), r'\1', txt.strip())
|
||||
txt = re.sub(r'[%s]' % NBR_DASH[0], '-', txt)
|
||||
txt = re.sub(r'[\1-\7]+', '', txt)
|
||||
txt = re.sub(r'[^-A-Za-z0-9._]', '_', txt)
|
||||
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 = re.sub(r'^([^A-Za-z])', r't\1', txt)
|
||||
txt = INVALID_START_CHAR_RE.sub(r't\1', txt)
|
||||
return txt
|
||||
|
||||
|
||||
def manify(txt):
|
||||
return re.sub(r"^(['.])", r'\&\1', txt.replace('\\', '\\\\')
|
||||
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]), flags=re.M)
|
||||
.replace(UNDR_FONT[0], UNDR_FONT[1]))
|
||||
|
||||
|
||||
def htmlify(txt):
|
||||
@@ -541,11 +636,13 @@ def die(*msg):
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
parser = argparse.ArgumentParser(description="Output html and (optionally) nroff for markdown pages.", add_help=False)
|
||||
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", nargs='+', help="The source .md files to convert.")
|
||||
parser.add_argument("mdfiles", metavar='FILE.md', nargs='+', help="One or more .md files to convert.")
|
||||
args = parser.parse_args()
|
||||
|
||||
try:
|
||||
|
||||
12
mkgitver
12
mkgitver
@@ -1,14 +1,16 @@
|
||||
#!/bin/sh
|
||||
|
||||
srcdir=`dirname $0`
|
||||
gitver=`git describe --abbrev=8 2>/dev/null`
|
||||
|
||||
if [ ! -f git-version.h ]; then
|
||||
touch git-version.h
|
||||
fi
|
||||
|
||||
case "$gitver" in
|
||||
*.*)
|
||||
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"
|
||||
@@ -16,5 +18,5 @@ case "$gitver" in
|
||||
else
|
||||
rm git-version.h.new
|
||||
fi
|
||||
;;
|
||||
esac
|
||||
fi
|
||||
fi
|
||||
|
||||
220
options.c
220
options.c
@@ -3,7 +3,7 @@
|
||||
*
|
||||
* Copyright (C) 1998-2001 Andrew Tridgell <tridge@samba.org>
|
||||
* Copyright (C) 2000, 2001, 2002 Martin Pool <mbp@samba.org>
|
||||
* Copyright (C) 2002-2022 Wayne Davison
|
||||
* Copyright (C) 2002-2023 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,6 +27,8 @@
|
||||
extern int module_id;
|
||||
extern int local_server;
|
||||
extern int sanitize_paths;
|
||||
extern int trust_sender_args;
|
||||
extern int trust_sender_filter;
|
||||
extern unsigned int module_dirlen;
|
||||
extern filter_rule_list filter_list;
|
||||
extern filter_rule_list daemon_filter_list;
|
||||
@@ -47,6 +49,7 @@ int append_mode = 0;
|
||||
int keep_dirlinks = 0;
|
||||
int copy_dirlinks = 0;
|
||||
int copy_links = 0;
|
||||
int copy_devices = 0;
|
||||
int write_devices = 0;
|
||||
int preserve_links = 0;
|
||||
int preserve_hard_links = 0;
|
||||
@@ -63,6 +66,7 @@ int preserve_atimes = 0;
|
||||
int preserve_crtimes = 0;
|
||||
int omit_dir_times = 0;
|
||||
int omit_link_times = 0;
|
||||
int trust_sender = 0;
|
||||
int update_only = 0;
|
||||
int open_noatime = 0;
|
||||
int cvs_exclude = 0;
|
||||
@@ -196,6 +200,7 @@ int remote_option_cnt = 0;
|
||||
const char **remote_options = NULL;
|
||||
const char *checksum_choice = NULL;
|
||||
const char *compress_choice = NULL;
|
||||
static const char *empty_argv[1];
|
||||
|
||||
int quiet = 0;
|
||||
int output_motd = 1;
|
||||
@@ -292,7 +297,7 @@ static struct output_struct debug_words[COUNT_DEBUG+1] = {
|
||||
DEBUG_WORD(DELTASUM, W_SND|W_REC, "Debug delta-transfer checksumming (levels 1-4)"),
|
||||
DEBUG_WORD(DUP, W_REC, "Debug weeding of duplicate names"),
|
||||
DEBUG_WORD(EXIT, W_CLI|W_SRV, "Debug exit events (levels 1-3)"),
|
||||
DEBUG_WORD(FILTER, W_SND|W_REC, "Debug filter actions (levels 1-2)"),
|
||||
DEBUG_WORD(FILTER, W_SND|W_REC, "Debug filter actions (levels 1-3)"),
|
||||
DEBUG_WORD(FLIST, W_SND|W_REC, "Debug file-list operations (levels 1-4)"),
|
||||
DEBUG_WORD(FUZZY, W_REC, "Debug fuzzy scoring (levels 1-2)"),
|
||||
DEBUG_WORD(GENR, W_REC, "Debug generator functions"),
|
||||
@@ -656,6 +661,7 @@ static struct poptOption long_options[] = {
|
||||
{"no-D", 0, POPT_ARG_NONE, 0, OPT_NO_D, 0, 0 },
|
||||
{"devices", 0, POPT_ARG_VAL, &preserve_devices, 1, 0, 0 },
|
||||
{"no-devices", 0, POPT_ARG_VAL, &preserve_devices, 0, 0, 0 },
|
||||
{"copy-devices", 0, POPT_ARG_NONE, ©_devices, 0, 0, 0 },
|
||||
{"write-devices", 0, POPT_ARG_VAL, &write_devices, 1, 0, 0 },
|
||||
{"no-write-devices", 0, POPT_ARG_VAL, &write_devices, 0, 0, 0 },
|
||||
{"specials", 0, POPT_ARG_VAL, &preserve_specials, 1, 0, 0 },
|
||||
@@ -783,9 +789,12 @@ static struct poptOption long_options[] = {
|
||||
{"no-from0", 0, POPT_ARG_VAL, &eol_nulls, 0, 0, 0},
|
||||
{"old-args", 0, POPT_ARG_NONE, 0, OPT_OLD_ARGS, 0, 0},
|
||||
{"no-old-args", 0, POPT_ARG_VAL, &old_style_args, 0, 0, 0},
|
||||
{"protect-args", 's', POPT_ARG_VAL, &protect_args, 1, 0, 0},
|
||||
{"secluded-args", 's', POPT_ARG_VAL, &protect_args, 1, 0, 0},
|
||||
{"no-secluded-args", 0, POPT_ARG_VAL, &protect_args, 0, 0, 0},
|
||||
{"protect-args", 0, POPT_ARG_VAL, &protect_args, 1, 0, 0},
|
||||
{"no-protect-args", 0, POPT_ARG_VAL, &protect_args, 0, 0, 0},
|
||||
{"no-s", 0, POPT_ARG_VAL, &protect_args, 0, 0, 0},
|
||||
{"trust-sender", 0, POPT_ARG_VAL, &trust_sender, 1, 0, 0},
|
||||
{"numeric-ids", 0, POPT_ARG_VAL, &numeric_ids, 1, 0, 0 },
|
||||
{"no-numeric-ids", 0, POPT_ARG_VAL, &numeric_ids, 0, 0, 0 },
|
||||
{"usermap", 0, POPT_ARG_STRING, 0, OPT_USERMAP, 0, 0 },
|
||||
@@ -944,11 +953,12 @@ static void set_refuse_options(void)
|
||||
if (!am_daemon
|
||||
|| op->shortName == 'e' /* Required for compatibility flags */
|
||||
|| op->shortName == '0' /* --from0 just modifies --files-from, so refuse that instead (or not) */
|
||||
|| op->shortName == 's' /* --protect-args is always OK */
|
||||
|| op->shortName == 's' /* --secluded-args is always OK */
|
||||
|| op->shortName == 'n' /* --dry-run is always OK */
|
||||
|| strcmp("iconv", longName) == 0
|
||||
|| strcmp("no-iconv", longName) == 0
|
||||
|| strcmp("checksum-seed", longName) == 0
|
||||
|| strcmp("copy-devices", longName) == 0 /* disable wild-match (it gets refused below) */
|
||||
|| strcmp("write-devices", longName) == 0 /* disable wild-match (it gets refused below) */
|
||||
|| strcmp("log-format", longName) == 0 /* aka out-format (NOT log-file-format) */
|
||||
|| strcmp("sender", longName) == 0
|
||||
@@ -960,6 +970,7 @@ static void set_refuse_options(void)
|
||||
assert(list_end != NULL);
|
||||
|
||||
if (am_daemon) { /* Refused by default, but can be accepted via a negated exact match. */
|
||||
parse_one_refuse_match(0, "copy-devices", list_end);
|
||||
parse_one_refuse_match(0, "write-devices", list_end);
|
||||
}
|
||||
|
||||
@@ -1337,7 +1348,7 @@ char *alt_dest_opt(int type)
|
||||
**/
|
||||
int parse_arguments(int *argc_p, const char ***argv_p)
|
||||
{
|
||||
static poptContext pc;
|
||||
poptContext pc;
|
||||
const char *arg, **argv = *argv_p;
|
||||
int argc = *argc_p;
|
||||
int opt, want_dest_type;
|
||||
@@ -1357,10 +1368,6 @@ int parse_arguments(int *argc_p, const char ***argv_p)
|
||||
|
||||
/* TODO: Call poptReadDefaultConfig; handle errors. */
|
||||
|
||||
/* The context leaks in case of an error, but if there's a
|
||||
* problem we always exit anyhow. */
|
||||
if (pc)
|
||||
poptFreeContext(pc);
|
||||
pc = poptGetContext(RSYNC_NAME, argc, argv, long_options, 0);
|
||||
if (!am_server) {
|
||||
poptReadDefaultConfig(pc, 0);
|
||||
@@ -1403,7 +1410,7 @@ int parse_arguments(int *argc_p, const char ***argv_p)
|
||||
strlcpy(err_buf,
|
||||
"Attempt to hack rsync thwarted!\n",
|
||||
sizeof err_buf);
|
||||
return 0;
|
||||
goto cleanup;
|
||||
}
|
||||
#ifdef ICONV_OPTION
|
||||
iconv_opt = NULL;
|
||||
@@ -1449,7 +1456,7 @@ int parse_arguments(int *argc_p, const char ***argv_p)
|
||||
if (tmpdir && strlen(tmpdir) >= MAXPATHLEN - 10) {
|
||||
snprintf(err_buf, sizeof err_buf,
|
||||
"the --temp-dir path is WAY too long.\n");
|
||||
return 0;
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
if (!daemon_opt) {
|
||||
@@ -1459,8 +1466,16 @@ int parse_arguments(int *argc_p, const char ***argv_p)
|
||||
exit_cleanup(RERR_SYNTAX);
|
||||
}
|
||||
|
||||
*argv_p = argv = poptGetArgs(pc);
|
||||
*argc_p = argc = count_args(argv);
|
||||
argv = poptGetArgs(pc);
|
||||
argc = count_args(argv);
|
||||
if (!argc) {
|
||||
*argv_p = empty_argv;
|
||||
*argc_p = 0;
|
||||
} else if (poptDupArgv(argc, argv, argc_p, argv_p) != 0)
|
||||
out_of_memory("parse_arguments");
|
||||
argv = *argv_p;
|
||||
poptFreeContext(pc);
|
||||
|
||||
am_starting_up = 0;
|
||||
daemon_opt = 0;
|
||||
am_daemon = 1;
|
||||
@@ -1515,7 +1530,7 @@ int parse_arguments(int *argc_p, const char ***argv_p)
|
||||
case 'a':
|
||||
if (refused_archive_part) {
|
||||
create_refuse_error(refused_archive_part);
|
||||
return 0;
|
||||
goto cleanup;
|
||||
}
|
||||
if (!recurse) /* preserve recurse == 2 */
|
||||
recurse = 1;
|
||||
@@ -1585,7 +1600,7 @@ int parse_arguments(int *argc_p, const char ***argv_p)
|
||||
case 'P':
|
||||
if (refused_partial || refused_progress) {
|
||||
create_refuse_error(refused_partial ? refused_partial : refused_progress);
|
||||
return 0;
|
||||
goto cleanup;
|
||||
}
|
||||
do_progress = 1;
|
||||
keep_partial = 1;
|
||||
@@ -1620,7 +1635,7 @@ int parse_arguments(int *argc_p, const char ***argv_p)
|
||||
if (*arg != '-') {
|
||||
snprintf(err_buf, sizeof err_buf,
|
||||
"Remote option must start with a dash: %s\n", arg);
|
||||
return 0;
|
||||
goto cleanup;
|
||||
}
|
||||
if (remote_option_cnt+2 >= remote_option_alloc) {
|
||||
remote_option_alloc += 16;
|
||||
@@ -1662,27 +1677,27 @@ int parse_arguments(int *argc_p, const char ***argv_p)
|
||||
ssize_t size;
|
||||
arg = poptGetOptArg(pc);
|
||||
if ((size = parse_size_arg(arg, 'b', "block-size", 0, max_blength, False)) < 0)
|
||||
return 0;
|
||||
goto cleanup;
|
||||
block_size = (int32)size;
|
||||
break;
|
||||
}
|
||||
|
||||
case OPT_MAX_SIZE:
|
||||
if ((max_size = parse_size_arg(max_size_arg, 'b', "max-size", 0, -1, False)) < 0)
|
||||
return 0;
|
||||
goto cleanup;
|
||||
max_size_arg = strdup(do_big_num(max_size, 0, NULL));
|
||||
break;
|
||||
|
||||
case OPT_MIN_SIZE:
|
||||
if ((min_size = parse_size_arg(min_size_arg, 'b', "min-size", 0, -1, False)) < 0)
|
||||
return 0;
|
||||
goto cleanup;
|
||||
min_size_arg = strdup(do_big_num(min_size, 0, NULL));
|
||||
break;
|
||||
|
||||
case OPT_BWLIMIT: {
|
||||
ssize_t size = parse_size_arg(bwlimit_arg, 'K', "bwlimit", 512, -1, True);
|
||||
if (size < 0)
|
||||
return 0;
|
||||
goto cleanup;
|
||||
bwlimit_arg = strdup(do_big_num(size, 0, NULL));
|
||||
bwlimit = (size + 512) / 1024;
|
||||
break;
|
||||
@@ -1711,7 +1726,7 @@ int parse_arguments(int *argc_p, const char ***argv_p)
|
||||
snprintf(err_buf, sizeof err_buf,
|
||||
"ERROR: the %s option conflicts with the %s option\n",
|
||||
alt_dest_opt(want_dest_type), alt_dest_opt(0));
|
||||
return 0;
|
||||
goto cleanup;
|
||||
}
|
||||
alt_dest_type = want_dest_type;
|
||||
|
||||
@@ -1719,7 +1734,7 @@ int parse_arguments(int *argc_p, const char ***argv_p)
|
||||
snprintf(err_buf, sizeof err_buf,
|
||||
"ERROR: at most %d %s args may be specified\n",
|
||||
MAX_BASIS_DIRS, alt_dest_opt(0));
|
||||
return 0;
|
||||
goto cleanup;
|
||||
}
|
||||
/* We defer sanitizing this arg until we know what
|
||||
* our destination directory is going to be. */
|
||||
@@ -1732,7 +1747,7 @@ int parse_arguments(int *argc_p, const char ***argv_p)
|
||||
snprintf(err_buf, sizeof err_buf,
|
||||
"Invalid argument passed to --chmod (%s)\n",
|
||||
arg);
|
||||
return 0;
|
||||
goto cleanup;
|
||||
}
|
||||
break;
|
||||
|
||||
@@ -1751,11 +1766,11 @@ int parse_arguments(int *argc_p, const char ***argv_p)
|
||||
if (usermap_via_chown) {
|
||||
snprintf(err_buf, sizeof err_buf,
|
||||
"--usermap conflicts with prior --chown.\n");
|
||||
return 0;
|
||||
goto cleanup;
|
||||
}
|
||||
snprintf(err_buf, sizeof err_buf,
|
||||
"You can only specify --usermap once.\n");
|
||||
return 0;
|
||||
goto cleanup;
|
||||
}
|
||||
usermap = (char *)poptGetOptArg(pc);
|
||||
usermap_via_chown = False;
|
||||
@@ -1767,11 +1782,11 @@ int parse_arguments(int *argc_p, const char ***argv_p)
|
||||
if (groupmap_via_chown) {
|
||||
snprintf(err_buf, sizeof err_buf,
|
||||
"--groupmap conflicts with prior --chown.\n");
|
||||
return 0;
|
||||
goto cleanup;
|
||||
}
|
||||
snprintf(err_buf, sizeof err_buf,
|
||||
"You can only specify --groupmap once.\n");
|
||||
return 0;
|
||||
goto cleanup;
|
||||
}
|
||||
groupmap = (char *)poptGetOptArg(pc);
|
||||
groupmap_via_chown = False;
|
||||
@@ -1790,11 +1805,11 @@ int parse_arguments(int *argc_p, const char ***argv_p)
|
||||
if (!usermap_via_chown) {
|
||||
snprintf(err_buf, sizeof err_buf,
|
||||
"--chown conflicts with prior --usermap.\n");
|
||||
return 0;
|
||||
goto cleanup;
|
||||
}
|
||||
snprintf(err_buf, sizeof err_buf,
|
||||
"You can only specify a user-affecting --chown once.\n");
|
||||
return 0;
|
||||
goto cleanup;
|
||||
}
|
||||
if (asprintf(&usermap, "*:%.*s", len, chown) < 0)
|
||||
out_of_memory("parse_arguments");
|
||||
@@ -1806,11 +1821,11 @@ int parse_arguments(int *argc_p, const char ***argv_p)
|
||||
if (!groupmap_via_chown) {
|
||||
snprintf(err_buf, sizeof err_buf,
|
||||
"--chown conflicts with prior --groupmap.\n");
|
||||
return 0;
|
||||
goto cleanup;
|
||||
}
|
||||
snprintf(err_buf, sizeof err_buf,
|
||||
"You can only specify a group-affecting --chown once.\n");
|
||||
return 0;
|
||||
goto cleanup;
|
||||
}
|
||||
if (asprintf(&groupmap, "*:%s", arg) < 0)
|
||||
out_of_memory("parse_arguments");
|
||||
@@ -1838,7 +1853,7 @@ int parse_arguments(int *argc_p, const char ***argv_p)
|
||||
snprintf(err_buf,sizeof(err_buf),
|
||||
"ACLs are not supported on this %s\n",
|
||||
am_server ? "server" : "client");
|
||||
return 0;
|
||||
goto cleanup;
|
||||
#endif
|
||||
|
||||
case 'X':
|
||||
@@ -1849,7 +1864,7 @@ int parse_arguments(int *argc_p, const char ***argv_p)
|
||||
snprintf(err_buf,sizeof(err_buf),
|
||||
"extended attributes are not supported on this %s\n",
|
||||
am_server ? "server" : "client");
|
||||
return 0;
|
||||
goto cleanup;
|
||||
#endif
|
||||
|
||||
case OPT_STOP_AFTER: {
|
||||
@@ -1858,7 +1873,7 @@ int parse_arguments(int *argc_p, const char ***argv_p)
|
||||
stop_at_utime = time(NULL);
|
||||
if ((val = atol(arg) * 60) <= 0 || LONG_MAX - val < stop_at_utime || (long)(time_t)val != val) {
|
||||
snprintf(err_buf, sizeof err_buf, "invalid --stop-after value: %s\n", arg);
|
||||
return 0;
|
||||
goto cleanup;
|
||||
}
|
||||
stop_at_utime += val;
|
||||
break;
|
||||
@@ -1869,11 +1884,11 @@ int parse_arguments(int *argc_p, const char ***argv_p)
|
||||
arg = poptGetOptArg(pc);
|
||||
if ((stop_at_utime = parse_time(arg)) == (time_t)-1) {
|
||||
snprintf(err_buf, sizeof err_buf, "invalid --stop-at format: %s\n", arg);
|
||||
return 0;
|
||||
goto cleanup;
|
||||
}
|
||||
if (stop_at_utime <= time(NULL)) {
|
||||
snprintf(err_buf, sizeof err_buf, "--stop-at time is not in the future: %s\n", arg);
|
||||
return 0;
|
||||
goto cleanup;
|
||||
}
|
||||
break;
|
||||
#endif
|
||||
@@ -1891,7 +1906,7 @@ int parse_arguments(int *argc_p, const char ***argv_p)
|
||||
else {
|
||||
snprintf(err_buf, sizeof err_buf,
|
||||
"--stderr mode \"%s\" is not one of errors, all, or client\n", arg);
|
||||
return 0;
|
||||
goto cleanup;
|
||||
}
|
||||
saw_stderr_opt = 1;
|
||||
break;
|
||||
@@ -1902,13 +1917,13 @@ int parse_arguments(int *argc_p, const char ***argv_p)
|
||||
* turned this option off. */
|
||||
if (opt >= OPT_REFUSED_BASE) {
|
||||
create_refuse_error(opt);
|
||||
return 0;
|
||||
goto cleanup;
|
||||
}
|
||||
snprintf(err_buf, sizeof err_buf, "%s%s: %s\n",
|
||||
am_server ? "on remote machine: " : "",
|
||||
poptBadOption(pc, POPT_BADOPTION_NOALIAS),
|
||||
poptStrerror(opt));
|
||||
return 0;
|
||||
goto cleanup;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1916,7 +1931,7 @@ int parse_arguments(int *argc_p, const char ***argv_p)
|
||||
saw_stderr_opt = 1;
|
||||
|
||||
if (version_opt_cnt) {
|
||||
print_rsync_version(FINFO);
|
||||
print_rsync_version(version_opt_cnt > 1 && !am_server ? FNONE : FINFO);
|
||||
exit_cleanup(0);
|
||||
}
|
||||
|
||||
@@ -1928,15 +1943,25 @@ int parse_arguments(int *argc_p, const char ***argv_p)
|
||||
if (max_alloc_arg) {
|
||||
ssize_t size = parse_size_arg(max_alloc_arg, 'B', "max-alloc", 1024*1024, -1, True);
|
||||
if (size < 0)
|
||||
return 0;
|
||||
goto cleanup;
|
||||
max_alloc = size;
|
||||
}
|
||||
if (!max_alloc)
|
||||
max_alloc = SIZE_MAX;
|
||||
|
||||
if (old_style_args < 0) {
|
||||
if (!am_server && (arg = getenv("RSYNC_OLD_ARGS")) != NULL && *arg)
|
||||
if (!am_server && protect_args <= 0 && (arg = getenv("RSYNC_OLD_ARGS")) != NULL && *arg) {
|
||||
protect_args = 0;
|
||||
old_style_args = atoi(arg);
|
||||
else
|
||||
} else
|
||||
old_style_args = 0;
|
||||
} else if (old_style_args) {
|
||||
if (protect_args > 0) {
|
||||
snprintf(err_buf, sizeof err_buf,
|
||||
"--secluded-args conflicts with --old-args.\n");
|
||||
goto cleanup;
|
||||
}
|
||||
protect_args = 0;
|
||||
}
|
||||
|
||||
if (protect_args < 0) {
|
||||
@@ -1945,7 +1970,7 @@ int parse_arguments(int *argc_p, const char ***argv_p)
|
||||
else if ((arg = getenv("RSYNC_PROTECT_ARGS")) != NULL && *arg)
|
||||
protect_args = atoi(arg) ? 1 : 0;
|
||||
else {
|
||||
#ifdef RSYNC_USE_PROTECTED_ARGS
|
||||
#ifdef RSYNC_USE_SECLUDED_ARGS
|
||||
protect_args = 1;
|
||||
#else
|
||||
protect_args = 0;
|
||||
@@ -1979,7 +2004,7 @@ int parse_arguments(int *argc_p, const char ***argv_p)
|
||||
do_compression = CPRES_AUTO;
|
||||
if (do_compression && refused_compress) {
|
||||
create_refuse_error(refused_compress);
|
||||
return 0;
|
||||
goto cleanup;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2004,7 +2029,7 @@ int parse_arguments(int *argc_p, const char ***argv_p)
|
||||
default:
|
||||
snprintf(err_buf, sizeof err_buf,
|
||||
"Invalid --outbuf setting -- specify N, L, or B.\n");
|
||||
return 0;
|
||||
goto cleanup;
|
||||
}
|
||||
setvbuf(stdout, (char *)NULL, mode, 0);
|
||||
}
|
||||
@@ -2032,7 +2057,7 @@ int parse_arguments(int *argc_p, const char ***argv_p)
|
||||
}
|
||||
if (refused_no_iconv && !iconv_opt) {
|
||||
create_refuse_error(refused_no_iconv);
|
||||
return 0;
|
||||
goto cleanup;
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -2043,18 +2068,30 @@ int parse_arguments(int *argc_p, const char ***argv_p)
|
||||
if (orig_protect_args == 2 && am_server)
|
||||
protect_args = orig_protect_args;
|
||||
|
||||
if (protect_args == 1 && am_server)
|
||||
if (protect_args == 1 && am_server) {
|
||||
poptFreeContext(pc);
|
||||
return 1;
|
||||
}
|
||||
|
||||
*argv_p = argv = poptGetArgs(pc);
|
||||
*argc_p = argc = count_args(argv);
|
||||
/* Because popt 1.19 has started to free the returned args data, we now
|
||||
* make a copy of the array and then do an immediate cleanup. */
|
||||
argv = poptGetArgs(pc);
|
||||
argc = count_args(argv);
|
||||
if (!argc) {
|
||||
*argv_p = empty_argv;
|
||||
*argc_p = 0;
|
||||
} else if (poptDupArgv(argc, argv, argc_p, argv_p) != 0)
|
||||
out_of_memory("parse_arguments");
|
||||
argv = *argv_p;
|
||||
poptFreeContext(pc);
|
||||
pc = NULL;
|
||||
|
||||
#ifndef SUPPORT_LINKS
|
||||
if (preserve_links && !am_sender) {
|
||||
snprintf(err_buf, sizeof err_buf,
|
||||
"symlinks are not supported on this %s\n",
|
||||
am_server ? "server" : "client");
|
||||
return 0;
|
||||
goto cleanup;
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -2063,7 +2100,7 @@ int parse_arguments(int *argc_p, const char ***argv_p)
|
||||
snprintf(err_buf, sizeof err_buf,
|
||||
"hard links are not supported on this %s\n",
|
||||
am_server ? "server" : "client");
|
||||
return 0;
|
||||
goto cleanup;
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -2071,20 +2108,20 @@ int parse_arguments(int *argc_p, const char ***argv_p)
|
||||
if (am_root < 0 && preserve_xattrs > 1) {
|
||||
snprintf(err_buf, sizeof err_buf,
|
||||
"--fake-super conflicts with -XX\n");
|
||||
return 0;
|
||||
goto cleanup;
|
||||
}
|
||||
#else
|
||||
if (am_root < 0) {
|
||||
snprintf(err_buf, sizeof err_buf,
|
||||
"--fake-super requires an rsync with extended attributes enabled\n");
|
||||
return 0;
|
||||
goto cleanup;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (write_batch && read_batch) {
|
||||
snprintf(err_buf, sizeof err_buf,
|
||||
"--write-batch and --read-batch can not be used together\n");
|
||||
return 0;
|
||||
goto cleanup;
|
||||
}
|
||||
if (write_batch > 0 || read_batch) {
|
||||
if (am_server) {
|
||||
@@ -2103,25 +2140,25 @@ int parse_arguments(int *argc_p, const char ***argv_p)
|
||||
if (read_batch && files_from) {
|
||||
snprintf(err_buf, sizeof err_buf,
|
||||
"--read-batch cannot be used with --files-from\n");
|
||||
return 0;
|
||||
goto cleanup;
|
||||
}
|
||||
if (read_batch && remove_source_files) {
|
||||
snprintf(err_buf, sizeof err_buf,
|
||||
"--read-batch cannot be used with --remove-%s-files\n",
|
||||
remove_source_files == 1 ? "source" : "sent");
|
||||
return 0;
|
||||
goto cleanup;
|
||||
}
|
||||
if (batch_name && strlen(batch_name) > MAX_BATCH_NAME_LEN) {
|
||||
snprintf(err_buf, sizeof err_buf,
|
||||
"the batch-file name must be %d characters or less.\n",
|
||||
MAX_BATCH_NAME_LEN);
|
||||
return 0;
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
if (tmpdir && strlen(tmpdir) >= MAXPATHLEN - 10) {
|
||||
snprintf(err_buf, sizeof err_buf,
|
||||
"the --temp-dir path is WAY too long.\n");
|
||||
return 0;
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
if (max_delete < 0 && max_delete != INT_MIN) {
|
||||
@@ -2155,7 +2192,7 @@ int parse_arguments(int *argc_p, const char ***argv_p)
|
||||
if (delete_before + !!delete_during + delete_after > 1) {
|
||||
snprintf(err_buf, sizeof err_buf,
|
||||
"You may not combine multiple --delete-WHEN options.\n");
|
||||
return 0;
|
||||
goto cleanup;
|
||||
}
|
||||
if (delete_before || delete_during || delete_after)
|
||||
delete_mode = 1;
|
||||
@@ -2166,7 +2203,7 @@ int parse_arguments(int *argc_p, const char ***argv_p)
|
||||
delete_during = 1;
|
||||
else {
|
||||
create_refuse_error(refused_delete_before);
|
||||
return 0;
|
||||
goto cleanup;
|
||||
}
|
||||
} else if (refused_delete_during)
|
||||
delete_before = 1;
|
||||
@@ -2175,14 +2212,14 @@ int parse_arguments(int *argc_p, const char ***argv_p)
|
||||
if (!xfer_dirs && delete_mode) {
|
||||
snprintf(err_buf, sizeof err_buf,
|
||||
"--delete does not work without --recursive (-r) or --dirs (-d).\n");
|
||||
return 0;
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
if (missing_args == 3) /* simplify if both options were specified */
|
||||
missing_args = 2;
|
||||
if (refused_delete && (delete_mode || missing_args == 2)) {
|
||||
create_refuse_error(refused_delete);
|
||||
return 0;
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
if (remove_source_files) {
|
||||
@@ -2191,7 +2228,7 @@ int parse_arguments(int *argc_p, const char ***argv_p)
|
||||
* options. */
|
||||
if (refused_delete && am_sender) {
|
||||
create_refuse_error(refused_delete);
|
||||
return 0;
|
||||
goto cleanup;
|
||||
}
|
||||
need_messages_from_generator = 1;
|
||||
}
|
||||
@@ -2245,7 +2282,7 @@ int parse_arguments(int *argc_p, const char ***argv_p)
|
||||
snprintf(err_buf, sizeof err_buf,
|
||||
"--suffix cannot contain slashes: %s\n",
|
||||
backup_suffix);
|
||||
return 0;
|
||||
goto cleanup;
|
||||
}
|
||||
if (backup_dir) {
|
||||
size_t len;
|
||||
@@ -2258,7 +2295,7 @@ int parse_arguments(int *argc_p, const char ***argv_p)
|
||||
if (len > sizeof backup_dir_buf - 128) {
|
||||
snprintf(err_buf, sizeof err_buf,
|
||||
"the --backup-dir path is WAY too long.\n");
|
||||
return 0;
|
||||
goto cleanup;
|
||||
}
|
||||
backup_dir_len = (int)len;
|
||||
if (!backup_dir_len) {
|
||||
@@ -2277,7 +2314,7 @@ int parse_arguments(int *argc_p, const char ***argv_p)
|
||||
"--suffix cannot be empty %s\n", backup_dir_len < 0
|
||||
? "when --backup-dir is the same as the dest dir"
|
||||
: "without a --backup-dir");
|
||||
return 0;
|
||||
goto cleanup;
|
||||
} else if (make_backups && delete_mode && !delete_excluded && !am_server) {
|
||||
snprintf(backup_dir_buf, sizeof backup_dir_buf,
|
||||
"P *%s", backup_suffix);
|
||||
@@ -2305,7 +2342,7 @@ int parse_arguments(int *argc_p, const char ***argv_p)
|
||||
if (do_progress && !am_server) {
|
||||
if (!log_before_transfer && INFO_EQ(NAME, 0))
|
||||
parse_output_words(info_words, info_levels, "name", DEFAULT_PRIORITY);
|
||||
parse_output_words(info_words, info_levels, "flist2,progress", DEFAULT_PRIORITY);
|
||||
parse_output_words(info_words, info_levels, "FLIST2,PROGRESS", DEFAULT_PRIORITY);
|
||||
}
|
||||
|
||||
if (dry_run)
|
||||
@@ -2346,11 +2383,11 @@ int parse_arguments(int *argc_p, const char ***argv_p)
|
||||
if (whole_file > 0) {
|
||||
snprintf(err_buf, sizeof err_buf,
|
||||
"--append cannot be used with --whole-file\n");
|
||||
return 0;
|
||||
goto cleanup;
|
||||
}
|
||||
if (refused_inplace) {
|
||||
create_refuse_error(refused_inplace);
|
||||
return 0;
|
||||
goto cleanup;
|
||||
}
|
||||
inplace = 1;
|
||||
}
|
||||
@@ -2358,7 +2395,7 @@ int parse_arguments(int *argc_p, const char ***argv_p)
|
||||
if (write_devices) {
|
||||
if (refused_inplace) {
|
||||
create_refuse_error(refused_inplace);
|
||||
return 0;
|
||||
goto cleanup;
|
||||
}
|
||||
inplace = 1;
|
||||
}
|
||||
@@ -2373,13 +2410,13 @@ int parse_arguments(int *argc_p, const char ***argv_p)
|
||||
"--%s cannot be used with --%s\n",
|
||||
append_mode ? "append" : "inplace",
|
||||
delay_updates ? "delay-updates" : "partial-dir");
|
||||
return 0;
|
||||
goto cleanup;
|
||||
}
|
||||
/* --inplace implies --partial for refusal purposes, but we
|
||||
* clear the keep_partial flag for internal logic purposes. */
|
||||
if (refused_partial) {
|
||||
create_refuse_error(refused_partial);
|
||||
return 0;
|
||||
goto cleanup;
|
||||
}
|
||||
keep_partial = 0;
|
||||
#else
|
||||
@@ -2387,7 +2424,7 @@ int parse_arguments(int *argc_p, const char ***argv_p)
|
||||
"--%s is not supported on this %s\n",
|
||||
append_mode ? "append" : "inplace",
|
||||
am_server ? "server" : "client");
|
||||
return 0;
|
||||
goto cleanup;
|
||||
#endif
|
||||
} else {
|
||||
if (keep_partial && !partial_dir && !am_server) {
|
||||
@@ -2401,7 +2438,7 @@ int parse_arguments(int *argc_p, const char ***argv_p)
|
||||
partial_dir = NULL;
|
||||
if (!partial_dir && refused_partial) {
|
||||
create_refuse_error(refused_partial);
|
||||
return 0;
|
||||
goto cleanup;
|
||||
}
|
||||
keep_partial = 1;
|
||||
}
|
||||
@@ -2422,14 +2459,14 @@ int parse_arguments(int *argc_p, const char ***argv_p)
|
||||
if (am_server) {
|
||||
snprintf(err_buf, sizeof err_buf,
|
||||
"The --files-from sent to the server cannot specify a host.\n");
|
||||
return 0;
|
||||
goto cleanup;
|
||||
}
|
||||
files_from = p;
|
||||
filesfrom_host = h;
|
||||
if (strcmp(files_from, "-") == 0) {
|
||||
snprintf(err_buf, sizeof err_buf,
|
||||
"Invalid --files-from remote filename\n");
|
||||
return 0;
|
||||
goto cleanup;
|
||||
}
|
||||
} else {
|
||||
if (sanitize_paths)
|
||||
@@ -2448,11 +2485,16 @@ int parse_arguments(int *argc_p, const char ***argv_p)
|
||||
snprintf(err_buf, sizeof err_buf,
|
||||
"failed to open files-from file %s: %s\n",
|
||||
files_from, strerror(errno));
|
||||
return 0;
|
||||
goto cleanup;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (trust_sender || am_server || read_batch)
|
||||
trust_sender_args = trust_sender_filter = 1;
|
||||
else if (old_style_args || filesfrom_host != NULL)
|
||||
trust_sender_args = 1;
|
||||
|
||||
am_starting_up = 0;
|
||||
|
||||
return 1;
|
||||
@@ -2460,6 +2502,9 @@ int parse_arguments(int *argc_p, const char ***argv_p)
|
||||
options_rejected:
|
||||
snprintf(err_buf, sizeof err_buf,
|
||||
"Your options have been rejected by the server.\n");
|
||||
cleanup:
|
||||
if (pc)
|
||||
poptFreeContext(pc);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -2475,17 +2520,24 @@ static char SPLIT_ARG_WHEN_OLD[1];
|
||||
**/
|
||||
char *safe_arg(const char *opt, const char *arg)
|
||||
{
|
||||
#define SHELL_CHARS "!#$&;|<>(){}\"' \t\\"
|
||||
#define SHELL_CHARS "!#$&;|<>(){}\"'` \t\\"
|
||||
#define WILD_CHARS "*?[]" /* We don't allow remote brace expansion */
|
||||
BOOL is_filename_arg = !opt;
|
||||
char *escapes = is_filename_arg ? SHELL_CHARS : WILD_CHARS SHELL_CHARS;
|
||||
BOOL escape_leading_dash = is_filename_arg && *arg == '-';
|
||||
BOOL escape_leading_tilde = 0;
|
||||
int len1 = opt && *opt ? strlen(opt) + 1 : 0;
|
||||
int len2 = strlen(arg);
|
||||
int extras = escape_leading_dash ? 2 : 0;
|
||||
char *ret;
|
||||
if (!protect_args && old_style_args < 2 && (!old_style_args || (!is_filename_arg && opt != SPLIT_ARG_WHEN_OLD))) {
|
||||
const char *f;
|
||||
if (*arg == '~' && is_filename_arg && !am_sender && !trust_sender_args
|
||||
&& ((relative_paths && !strstr(arg, "/./"))
|
||||
|| !strchr(arg, '/'))) {
|
||||
extras++;
|
||||
escape_leading_tilde = 1;
|
||||
}
|
||||
for (f = arg; *f; f++) {
|
||||
if (strchr(escapes, *f))
|
||||
extras++;
|
||||
@@ -2508,8 +2560,13 @@ char *safe_arg(const char *opt, const char *arg)
|
||||
else {
|
||||
const char *f = arg;
|
||||
char *t = ret + len1;
|
||||
if (escape_leading_tilde)
|
||||
*t++ = '\\';
|
||||
while (*f) {
|
||||
if (strchr(escapes, *f))
|
||||
if (*f == '\\') {
|
||||
if (!is_filename_arg || !strchr(WILD_CHARS, f[1]))
|
||||
*t++ = '\\';
|
||||
} else if (strchr(escapes, *f))
|
||||
*t++ = '\\';
|
||||
*t++ = *f++;
|
||||
}
|
||||
@@ -2909,6 +2966,9 @@ void server_options(char **args, int *argc_p)
|
||||
else if (remove_source_files)
|
||||
args[ac++] = "--remove-sent-files";
|
||||
|
||||
if (copy_devices && !am_sender)
|
||||
args[ac++] = "--copy-devices";
|
||||
|
||||
if (preallocate_files && am_sender)
|
||||
args[ac++] = "--preallocate";
|
||||
|
||||
|
||||
@@ -27,6 +27,7 @@ long_opts = { # These include some extra long-args that BackupPC uses:
|
||||
'recursive': 0,
|
||||
'stderr': 1,
|
||||
'times': 0,
|
||||
'copy-devices': -1,
|
||||
'write-devices': -1,
|
||||
}
|
||||
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
Summary: A fast, versatile, remote (and local) file-copying tool
|
||||
Name: rsync
|
||||
Version: 3.2.4
|
||||
%define fullversion %{version}pre2
|
||||
Release: 0.1.pre2
|
||||
%define srcdir src-previews
|
||||
Version: 3.3.0
|
||||
%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
|
||||
@@ -79,8 +79,8 @@ rm -rf $RPM_BUILD_ROOT
|
||||
%dir /etc/rsync-ssl/certs
|
||||
|
||||
%changelog
|
||||
* Sat Jan 15 2022 Wayne Davison <wayne@opencoder.net>
|
||||
Released 3.2.4pre2.
|
||||
* Sat Apr 06 2024 Wayne Davison <wayne@opencoder.net>
|
||||
Released 3.3.0.
|
||||
|
||||
* Fri Mar 21 2008 Wayne Davison <wayne@opencoder.net>
|
||||
Added installation of /etc/xinetd.d/rsync file and some commented-out
|
||||
|
||||
18
packaging/openssl-rsync.cnf
Normal file
18
packaging/openssl-rsync.cnf
Normal file
@@ -0,0 +1,18 @@
|
||||
# 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
|
||||
@@ -32,7 +32,7 @@ def _tweak_opts(cmd, opts, **maybe_set_args):
|
||||
opts = opts.copy()
|
||||
_maybe_set(opts, **maybe_set_args)
|
||||
|
||||
if type(cmd) == str:
|
||||
if isinstance(cmd, str):
|
||||
_maybe_set(opts, shell=True)
|
||||
|
||||
want_raw = opts.pop('raw', False)
|
||||
@@ -176,12 +176,12 @@ def mandate_gensend_hook():
|
||||
print('Creating hook file:', hook)
|
||||
cmd_chk(['./rsync', '-a', 'packaging/pre-push', hook])
|
||||
else:
|
||||
ct = cmd_txt(['fgrep', 'make gensend', hook], discard='output')
|
||||
ct = cmd_txt(['grep', 'make gensend', hook], discard='output')
|
||||
if ct.rc:
|
||||
die('Please add a "make gensend" into your', hook, 'script.')
|
||||
|
||||
|
||||
# Snag the GENFILES values out of the Makefile.in file and return them as a list.
|
||||
# Snag the GENFILES values out of the Makefile file and return them as a list.
|
||||
def get_gen_files(want_dir_plus_list=False):
|
||||
cont_re = re.compile(r'\\\n')
|
||||
|
||||
@@ -189,7 +189,7 @@ def get_gen_files(want_dir_plus_list=False):
|
||||
|
||||
auto_dir = os.path.join('auto-build-save', cmd_txt('git rev-parse --abbrev-ref HEAD').out.strip().replace('/', '%'))
|
||||
|
||||
with open('Makefile.in', 'r', encoding='utf-8') as fh:
|
||||
with open(auto_dir + '/Makefile', 'r', encoding='utf-8') as fh:
|
||||
for line in fh:
|
||||
if not gen_files:
|
||||
chk = re.sub(r'^GENFILES=', '', line)
|
||||
|
||||
@@ -105,6 +105,8 @@ def main():
|
||||
if not re.match(r'^del', ans, flags=re.I):
|
||||
die("Aborted")
|
||||
cmd_chk(['git', 'tag', '-d', v_ver])
|
||||
if os.path.isdir('patches/.git'):
|
||||
cmd_chk(f"cd patches && git tag -d '{v_ver}'")
|
||||
|
||||
version = re.sub(r'[-.]*pre[-.]*', 'pre', version)
|
||||
if 'pre' in version and not curversion.endswith('dev'):
|
||||
@@ -193,7 +195,9 @@ About to:
|
||||
with open(fn, 'r', encoding='utf-8') as fh:
|
||||
old_txt = txt = fh.read()
|
||||
if fn == 'version.h':
|
||||
txt = f'#define RSYNC_VERSION "{version}"\n'
|
||||
x_re = re.compile(r'^(#define RSYNC_VERSION).*', re.M)
|
||||
msg = f"Unable to update RSYNC_VERSION in {fn}"
|
||||
txt = replace_or_die(x_re, r'\1 "%s"' % version, txt, msg)
|
||||
elif '.spec' in fn:
|
||||
for var, val in specvars.items():
|
||||
x_re = re.compile(r'^%s .*' % re.escape(var), re.M)
|
||||
@@ -206,10 +210,10 @@ About to:
|
||||
txt = replace_or_die(x_re, repl, txt, f"Unable to find SUBPROTOCOL_VERSION define in {fn}")
|
||||
elif fn == 'NEWS.md':
|
||||
efv = re.escape(finalversion)
|
||||
x_re = re.compile(r'^<.+>\s+# NEWS for rsync %s \(UNRELEASED\)\s+## Changes in this version:\n' % efv
|
||||
x_re = re.compile(r'^# NEWS for rsync %s \(UNRELEASED\)\s+## Changes in this version:\n' % efv
|
||||
+ r'(\n### PROTOCOL NUMBER:\s+- The protocol number was changed to \d+\.\n)?')
|
||||
rel_day = 'UNRELEASED' if pre else today
|
||||
repl = (f'<a name="{finalversion}"></a>\n\n# NEWS for rsync {finalversion} ({rel_day})\n\n'
|
||||
repl = (f'# NEWS for rsync {finalversion} ({rel_day})\n\n'
|
||||
+ '## Changes in this version:\n')
|
||||
if proto_changed:
|
||||
repl += f'\n### PROTOCOL NUMBER:\n\n - The protocol number was changed to {protocol_version}.\n'
|
||||
@@ -230,7 +234,7 @@ About to:
|
||||
cmd_chk(['packaging/year-tweak'])
|
||||
|
||||
print(dash_line)
|
||||
cmd_run("git diff")
|
||||
cmd_run("git diff".split())
|
||||
|
||||
srctar_name = f"{rsync_ver}.tar.gz"
|
||||
pattar_name = f"rsync-patches-{version}.tar.gz"
|
||||
@@ -245,20 +249,20 @@ About to:
|
||||
|
||||
About to:
|
||||
- git commit all changes
|
||||
- generate the manpages
|
||||
- run a full build, ensuring that the manpages & configure.sh are up-to-date
|
||||
- merge the {args.master_branch} branch into the patch/{args.master_branch}/* branches
|
||||
- update the files in the "patches" dir and OPTIONALLY (if you type 'y') to
|
||||
run patch-update with the --make option (which opens a shell on error)
|
||||
""")
|
||||
ans = input("<Press Enter OR 'y' to continue> ")
|
||||
|
||||
s = cmd_run(['git', 'commit', '-a', '-m', f'Preparing for release of {version}'])
|
||||
s = cmd_run(['git', 'commit', '-a', '-m', f'Preparing for release of {version} [buildall]'])
|
||||
if s.returncode:
|
||||
die('Aborting')
|
||||
|
||||
cmd_chk('make gen')
|
||||
cmd_chk('touch configure.ac && packaging/smart-make && make gen')
|
||||
|
||||
print(f'Creating any missing patch branches.')
|
||||
print('Creating any missing patch branches.')
|
||||
s = cmd_run(f'packaging/branch-from-patch --branch={args.master_branch} --add-missing')
|
||||
if s.returncode:
|
||||
die('Aborting')
|
||||
@@ -341,7 +345,7 @@ About to:
|
||||
md_files = 'README.md NEWS.md INSTALL.md'.split()
|
||||
html_files = [ fn for fn in gen_pathnames if fn.endswith('.html') ]
|
||||
cmd_chk(['rsync', '-a', *md_files, *html_files, dest])
|
||||
cmd_chk(["./md-convert"] + [ dest +'/'+ fn for fn in md_files ])
|
||||
cmd_chk(["./md-convert", "--dest", dest, *md_files])
|
||||
|
||||
cmd_chk(f"git log --name-status | gzip -9 >{dest}/ChangeLog.gz")
|
||||
|
||||
|
||||
@@ -7,6 +7,7 @@ Documentation=man:rsync(1) man:rsyncd.conf(5)
|
||||
[Service]
|
||||
ExecStart=/usr/bin/rsync --daemon --no-detach
|
||||
RestartSec=1
|
||||
Restart=on-failure
|
||||
|
||||
# Citing README.md:
|
||||
#
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
#
|
||||
# build build the config files [the default w/no arg]
|
||||
# fetch fetch the latest dev autoconfig files
|
||||
# fetchgen fetch all the latest dev generated files (including man pages)
|
||||
# fetchgen fetch all the latest dev generated files (including manpages)
|
||||
# fetchSRC fetch the latest dev source files [NON-GENERATED FILES]
|
||||
#
|
||||
# The script stops after the first successful action.
|
||||
|
||||
50
receiver.c
50
receiver.c
@@ -3,7 +3,7 @@
|
||||
*
|
||||
* Copyright (C) 1996-2000 Andrew Tridgell
|
||||
* Copyright (C) 1996 Paul Mackerras
|
||||
* Copyright (C) 2003-2022 Wayne Davison
|
||||
* Copyright (C) 2003-2023 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
|
||||
@@ -56,7 +56,6 @@ extern int inplace;
|
||||
extern int inplace_partial;
|
||||
extern int allowed_lull;
|
||||
extern int delay_updates;
|
||||
extern int xfersum_type;
|
||||
extern BOOL want_progress_now;
|
||||
extern mode_t orig_umask;
|
||||
extern struct stats stats;
|
||||
@@ -68,6 +67,9 @@ extern struct file_list *cur_flist, *first_flist, *dir_flist;
|
||||
extern filter_rule_list daemon_filter_list;
|
||||
extern OFF_T preallocated_len;
|
||||
|
||||
extern struct name_num_item *xfer_sum_nni;
|
||||
extern int xfer_sum_len;
|
||||
|
||||
static struct bitbag *delayed_bits = NULL;
|
||||
static int phase = 0, redoing = 0;
|
||||
static flist_ndx_list batch_redo_list;
|
||||
@@ -240,7 +242,6 @@ static int receive_data(int f_in, char *fname_r, int fd_r, OFF_T size_r,
|
||||
static char file_sum1[MAX_DIGEST_LEN];
|
||||
struct map_struct *mapbuf;
|
||||
struct sum_struct sum;
|
||||
int sum_len;
|
||||
int32 len;
|
||||
OFF_T total_size = F_LENGTH(file);
|
||||
OFF_T offset = 0;
|
||||
@@ -280,7 +281,7 @@ static int receive_data(int f_in, char *fname_r, int fd_r, OFF_T size_r,
|
||||
} else
|
||||
mapbuf = NULL;
|
||||
|
||||
sum_init(xfersum_type, checksum_seed);
|
||||
sum_init(xfer_sum_nni, checksum_seed);
|
||||
|
||||
if (append_mode > 0) {
|
||||
OFF_T j;
|
||||
@@ -371,7 +372,7 @@ static int receive_data(int f_in, char *fname_r, int fd_r, OFF_T size_r,
|
||||
|
||||
if (fd != -1 && offset > 0) {
|
||||
if (sparse_files > 0) {
|
||||
if (sparse_end(fd, offset) != 0)
|
||||
if (sparse_end(fd, offset, updating_basis_or_equiv) != 0)
|
||||
goto report_write_error;
|
||||
} else if (flush_write_file(fd) < 0) {
|
||||
report_write_error:
|
||||
@@ -393,7 +394,7 @@ static int receive_data(int f_in, char *fname_r, int fd_r, OFF_T size_r,
|
||||
if (INFO_GTE(PROGRESS, 1))
|
||||
end_progress(total_size);
|
||||
|
||||
sum_len = sum_end(file_sum1);
|
||||
sum_end(file_sum1);
|
||||
|
||||
if (do_fsync && fd != -1 && fsync(fd) != 0) {
|
||||
rsyserr(FERROR, errno, "fsync failed on %s", full_fname(fname));
|
||||
@@ -403,10 +404,10 @@ static int receive_data(int f_in, char *fname_r, int fd_r, OFF_T size_r,
|
||||
if (mapbuf)
|
||||
unmap_file(mapbuf);
|
||||
|
||||
read_buf(f_in, sender_file_sum, sum_len);
|
||||
read_buf(f_in, sender_file_sum, xfer_sum_len);
|
||||
if (DEBUG_GTE(DELTASUM, 2))
|
||||
rprintf(FINFO,"got file_sum\n");
|
||||
if (fd != -1 && memcmp(file_sum1, sender_file_sum, sum_len) != 0)
|
||||
if (fd != -1 && memcmp(file_sum1, sender_file_sum, xfer_sum_len) != 0)
|
||||
return 0;
|
||||
return 1;
|
||||
}
|
||||
@@ -439,9 +440,8 @@ static void handle_delayed_updates(char *local_name)
|
||||
"rename failed for %s (from %s)",
|
||||
full_fname(fname), partialptr);
|
||||
} else {
|
||||
if (remove_source_files
|
||||
|| (preserve_hard_links && F_IS_HLINKED(file)))
|
||||
send_msg_int(MSG_SUCCESS, ndx);
|
||||
if (remove_source_files || (preserve_hard_links && F_IS_HLINKED(file)))
|
||||
send_msg_success(fname, ndx);
|
||||
handle_partial_dir(partialptr, PDIR_DELETE);
|
||||
}
|
||||
}
|
||||
@@ -593,10 +593,13 @@ int recv_files(int f_in, int f_out, char *local_name)
|
||||
if (DEBUG_GTE(RECV, 1))
|
||||
rprintf(FINFO, "recv_files(%s)\n", fname);
|
||||
|
||||
if (daemon_filter_list.head && (*fname != '.' || fname[1] != '\0')
|
||||
&& check_filter(&daemon_filter_list, FLOG, fname, 0) < 0) {
|
||||
rprintf(FERROR, "attempt to hack rsync failed.\n");
|
||||
exit_cleanup(RERR_PROTOCOL);
|
||||
if (daemon_filter_list.head && (*fname != '.' || fname[1] != '\0')) {
|
||||
int filt_flags = S_ISDIR(file->mode) ? NAME_IS_DIR : NAME_IS_FILE;
|
||||
if (check_filter(&daemon_filter_list, FLOG, fname, filt_flags) < 0) {
|
||||
rprintf(FERROR, "ERROR: rejecting file transfer request for daemon excluded file: %s\n",
|
||||
fname);
|
||||
exit_cleanup(RERR_PROTOCOL);
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef SUPPORT_XATTRS
|
||||
@@ -695,7 +698,7 @@ int recv_files(int f_in, int f_out, char *local_name)
|
||||
if (!am_server)
|
||||
discard_receive_data(f_in, file);
|
||||
if (inc_recurse)
|
||||
send_msg_int(MSG_SUCCESS, ndx);
|
||||
send_msg_success(fname, ndx);
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -808,14 +811,16 @@ int recv_files(int f_in, int f_out, char *local_name)
|
||||
continue;
|
||||
}
|
||||
|
||||
if (fd1 != -1 && !(S_ISREG(st.st_mode) || (write_devices && IS_DEVICE(st.st_mode)))) {
|
||||
if (write_devices && IS_DEVICE(st.st_mode)) {
|
||||
if (fd1 != -1 && st.st_size == 0)
|
||||
st.st_size = get_device_size(fd1, fname);
|
||||
/* Mark the file entry as a device so that we don't try to truncate it later on. */
|
||||
file->mode = S_IFBLK | (file->mode & ACCESSPERMS);
|
||||
} else if (fd1 != -1 && !(S_ISREG(st.st_mode))) {
|
||||
close(fd1);
|
||||
fd1 = -1;
|
||||
}
|
||||
|
||||
if (fd1 != -1 && IS_DEVICE(st.st_mode) && st.st_size == 0)
|
||||
st.st_size = get_device_size(fd1, fname);
|
||||
|
||||
/* If we're not preserving permissions, change the file-list's
|
||||
* mode based on the local permissions and some heuristics. */
|
||||
if (!preserve_perms) {
|
||||
@@ -921,9 +926,8 @@ int recv_files(int f_in, int f_out, char *local_name)
|
||||
case 2:
|
||||
break;
|
||||
case 1:
|
||||
if (remove_source_files || inc_recurse
|
||||
|| (preserve_hard_links && F_IS_HLINKED(file)))
|
||||
send_msg_int(MSG_SUCCESS, ndx);
|
||||
if (remove_source_files || inc_recurse || (preserve_hard_links && F_IS_HLINKED(file)))
|
||||
send_msg_success(fname, ndx);
|
||||
break;
|
||||
case 0: {
|
||||
enum logcode msgtype = redoing ? FERROR_XFER : FWARNING;
|
||||
|
||||
@@ -8,8 +8,8 @@ rsync-ssl - a helper script for connecting to an ssl rsync daemon
|
||||
rsync-ssl [--type=SSL_TYPE] RSYNC_ARGS
|
||||
```
|
||||
|
||||
The online version of this man page (that includes cross-linking of topics)
|
||||
is available at <https://download.samba.org/pub/rsync/rsync.1>.
|
||||
The online version of this manpage (that includes cross-linking of topics)
|
||||
is available at <https://download.samba.org/pub/rsync/rsync-ssl.1>.
|
||||
|
||||
## DESCRIPTION
|
||||
|
||||
@@ -94,9 +94,14 @@ The ssl helper scripts are affected by the following environment variables:
|
||||
|
||||
> rsync-ssl -aiv rsync://example.com:9874/mod/ dest
|
||||
|
||||
## THE SERVER SIDE
|
||||
|
||||
For help setting up an SSL/TLS supporting rsync, see the [instructions in
|
||||
rsyncd.conf](rsyncd.conf.5#SSL_TLS_Daemon_Setup).
|
||||
|
||||
## SEE ALSO
|
||||
|
||||
[**rsync**(1)](./rsync.1), [**rsyncd.conf**(5)](./rsyncd.conf.5)
|
||||
[**rsync**(1)](rsync.1), [**rsyncd.conf**(5)](rsyncd.conf.5)
|
||||
|
||||
## CAVEATS
|
||||
|
||||
@@ -117,12 +122,12 @@ Please report bugs! See the web site at <https://rsync.samba.org/>.
|
||||
|
||||
## VERSION
|
||||
|
||||
This man page is current for version @VERSION@ of rsync.
|
||||
This manpage is current for version @VERSION@ of rsync.
|
||||
|
||||
## CREDITS
|
||||
|
||||
rsync is distributed under the GNU General Public License. See the file
|
||||
[COPYING](./COPYING) for details.
|
||||
Rsync is distributed under the GNU General Public License. See the file
|
||||
[COPYING](COPYING) for details.
|
||||
|
||||
A web site is available at <https://rsync.samba.org/>. The site includes an
|
||||
FAQ-O-Matic which may cover questions unanswered by this manual page.
|
||||
|
||||
1418
rsync.1.md
1418
rsync.1.md
File diff suppressed because it is too large
Load Diff
2
rsync.c
2
rsync.c
@@ -642,7 +642,7 @@ int set_file_attrs(const char *fname, struct file_struct *file, stat_x *sxp,
|
||||
#ifdef SUPPORT_ACLS
|
||||
/* It's OK to call set_acl() now, even for a dir, as the generator
|
||||
* will enable owner-writability using chmod, if necessary.
|
||||
*
|
||||
*
|
||||
* If set_acl() changes permission bits in the process of setting
|
||||
* an access ACL, it changes sxp->st.st_mode so we know whether we
|
||||
* need to chmod(). */
|
||||
|
||||
38
rsync.h
38
rsync.h
@@ -18,11 +18,6 @@
|
||||
* with this program; if not, visit the http://fsf.org website.
|
||||
*/
|
||||
|
||||
/* a non-zero CHAR_OFFSET makes the rolling sum stronger, but is
|
||||
incompatible with older versions :-( */
|
||||
#define CHAR_OFFSET 0
|
||||
|
||||
#ifndef AVX2_ASM /* do not include the rest of file for assembly */
|
||||
#define False 0
|
||||
#define True 1
|
||||
#define Unset (-1) /* Our BOOL values are always an int. */
|
||||
@@ -43,6 +38,9 @@
|
||||
|
||||
#define BACKUP_SUFFIX "~"
|
||||
|
||||
/* a non-zero CHAR_OFFSET makes the rolling sum stronger, but is
|
||||
incompatible with older versions :-( */
|
||||
#define CHAR_OFFSET 0
|
||||
|
||||
/* These flags are only used during the flist transfer. */
|
||||
|
||||
@@ -340,6 +338,9 @@ enum delret {
|
||||
# endif
|
||||
# include <string.h>
|
||||
#endif
|
||||
#ifdef HAVE_BSD_STRING_H
|
||||
# include <bsd/string.h>
|
||||
#endif
|
||||
#ifdef HAVE_STRINGS_H
|
||||
# include <strings.h>
|
||||
#endif
|
||||
@@ -365,16 +366,10 @@ enum delret {
|
||||
#include <sys/socket.h>
|
||||
#endif
|
||||
|
||||
#ifdef TIME_WITH_SYS_TIME
|
||||
#include <sys/time.h>
|
||||
#include <time.h>
|
||||
#else
|
||||
#ifdef HAVE_SYS_TIME_H
|
||||
#include <sys/time.h>
|
||||
#else
|
||||
#endif
|
||||
#include <time.h>
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_FCNTL_H
|
||||
#include <fcntl.h>
|
||||
@@ -825,6 +820,7 @@ extern int uid_ndx;
|
||||
extern int gid_ndx;
|
||||
extern int acls_ndx;
|
||||
extern int xattrs_ndx;
|
||||
extern int file_sum_extra_cnt;
|
||||
|
||||
#ifdef USE_FLEXIBLE_ARRAY
|
||||
#define FILE_STRUCT_LEN (sizeof (struct file_struct))
|
||||
@@ -835,7 +831,7 @@ extern int xattrs_ndx;
|
||||
#define DEV_EXTRA_CNT 2
|
||||
#define DIRNODE_EXTRA_CNT 3
|
||||
#define EXTRA64_CNT ((sizeof (union file_extras64) + EXTRA_LEN - 1) / EXTRA_LEN)
|
||||
#define SUM_EXTRA_CNT ((MAX_DIGEST_LEN + EXTRA_LEN - 1) / EXTRA_LEN)
|
||||
#define SUM_EXTRA_CNT file_sum_extra_cnt
|
||||
|
||||
#define REQ_EXTRA(f,ndx) ((union file_extras*)(f) - (ndx))
|
||||
#define OPT_EXTRA(f,bump) ((union file_extras*)(f) - file_extra_cnt - 1 - (bump))
|
||||
@@ -1022,6 +1018,7 @@ typedef struct filter_struct {
|
||||
int slash_cnt;
|
||||
struct filter_list_struct *mergelist;
|
||||
} u;
|
||||
uchar elide;
|
||||
} filter_rule;
|
||||
|
||||
typedef struct filter_list_struct {
|
||||
@@ -1161,19 +1158,23 @@ typedef struct {
|
||||
#define NSTR_COMPRESS 1
|
||||
|
||||
struct name_num_item {
|
||||
int num;
|
||||
const char *name, *main_name;
|
||||
int num, flags;
|
||||
const char *name;
|
||||
struct name_num_item *main_nni;
|
||||
};
|
||||
|
||||
struct name_num_obj {
|
||||
const char *type;
|
||||
const char *negotiated_name;
|
||||
struct name_num_item *negotiated_nni;
|
||||
uchar *saw;
|
||||
int saw_len;
|
||||
int negotiated_num;
|
||||
struct name_num_item list[10]; /* we'll get a compile error/warning if this is ever too small */
|
||||
struct name_num_item *list;
|
||||
};
|
||||
|
||||
#ifdef EXTERNAL_ZLIB
|
||||
#define read_buf read_buf_
|
||||
#endif
|
||||
|
||||
#ifndef __cplusplus
|
||||
#include "proto.h"
|
||||
#endif
|
||||
@@ -1477,7 +1478,6 @@ const char *get_panic_action(void);
|
||||
fprintf(stderr, "%s in %s at line %d\n", msg, __FILE__, __LINE__); \
|
||||
exit_cleanup(RERR_UNSUPPORTED); \
|
||||
} while (0)
|
||||
#endif /* AVX2_ASM */
|
||||
|
||||
#ifdef HAVE_MALLINFO2
|
||||
#define MEM_ALLOC_INFO mallinfo2
|
||||
|
||||
175
rsyncd.conf.5.md
175
rsyncd.conf.5.md
@@ -6,7 +6,7 @@ rsyncd.conf - configuration file for rsync in daemon mode
|
||||
|
||||
rsyncd.conf
|
||||
|
||||
The online version of this man page (that includes cross-linking of topics)
|
||||
The online version of this manpage (that includes cross-linking of topics)
|
||||
is available at <https://download.samba.org/pub/rsync/rsyncd.conf.5>.
|
||||
|
||||
## DESCRIPTION
|
||||
@@ -45,8 +45,7 @@ Case is not significant in boolean values, but is preserved in string values.
|
||||
|
||||
## LAUNCHING THE RSYNC DAEMON
|
||||
|
||||
The rsync daemon is launched by specifying the `--daemon` option to
|
||||
rsync.
|
||||
The rsync daemon is launched by specifying the `--daemon` option to rsync.
|
||||
|
||||
The daemon must run with root privileges if you wish to use chroot, to bind to
|
||||
a port numbered under 1024 (as is the default 873), or to set file ownership.
|
||||
@@ -75,33 +74,15 @@ reread the `rsyncd.conf` file. The file is re-read on each client connection.
|
||||
## GLOBAL PARAMETERS
|
||||
|
||||
The first parameters in the file (before a [module] header) are the global
|
||||
parameters. Rsync also allows for the use of a "[global]" module name to
|
||||
indicate the start of one or more global-parameter sections (the name must be
|
||||
lower case).
|
||||
|
||||
You may also include any module parameters in the global part of the config
|
||||
file in which case the supplied value will override the default for that
|
||||
parameter.
|
||||
|
||||
You may use references to environment variables in the values of parameters.
|
||||
String parameters will have %VAR% references expanded as late as possible (when
|
||||
the string is first used in the program), allowing for the use of variables
|
||||
that rsync sets at connection time, such as RSYNC_USER_NAME. Non-string
|
||||
parameters (such as true/false settings) are expanded when read from the config
|
||||
file. If a variable does not exist in the environment, or if a sequence of
|
||||
characters is not a valid reference (such as an un-paired percent sign), the
|
||||
raw characters are passed through unchanged. This helps with backward
|
||||
compatibility and safety (e.g. expanding a non-existent %VAR% to an empty
|
||||
string in a path could result in a very unsafe path). The safest way to insert
|
||||
a literal % into a value is to use %%.
|
||||
parameters:
|
||||
|
||||
[comment]: # (An OL starting at 0 is converted into a DL by the parser.)
|
||||
|
||||
0. `motd file`
|
||||
|
||||
This parameter allows you to specify a "message of the day" to display to
|
||||
clients on each connect. This usually contains site information and any
|
||||
legal notices. The default is no motd file. This can be overridden by the
|
||||
This parameter allows you to specify a "message of the day" (MOTD) to display
|
||||
to clients on each connect. This usually contains site information and any
|
||||
legal notices. The default is no MOTD file. This can be overridden by the
|
||||
`--dparam=motdfile=FILE` command-line option when starting the daemon.
|
||||
|
||||
0. `pid file`
|
||||
@@ -129,7 +110,7 @@ a literal % into a value is to use %%.
|
||||
|
||||
This parameter can provide endless fun for people who like to tune their
|
||||
systems to the utmost degree. You can set all sorts of socket options which
|
||||
may make transfers faster (or slower!). Read the man page for the
|
||||
may make transfers faster (or slower!). Read the manpage for the
|
||||
**setsockopt()** system call for details on some of the options you may be
|
||||
able to set. By default no special socket options are set. These settings
|
||||
can also be specified via the `--sockopts` command-line option.
|
||||
@@ -139,6 +120,22 @@ a literal % into a value is to use %%.
|
||||
You can override the default backlog value when the daemon listens for
|
||||
connections. It defaults to 5.
|
||||
|
||||
You may also include any [MODULE PARAMETERS](#) in the global part of the
|
||||
config file, in which case the supplied value will override the default for
|
||||
that parameter.
|
||||
|
||||
You may use references to environment variables in the values of parameters.
|
||||
String parameters will have %VAR% references expanded as late as possible (when
|
||||
the string is first used in the program), allowing for the use of variables
|
||||
that rsync sets at connection time, such as RSYNC_USER_NAME. Non-string
|
||||
parameters (such as true/false settings) are expanded when read from the config
|
||||
file. If a variable does not exist in the environment, or if a sequence of
|
||||
characters is not a valid reference (such as an un-paired percent sign), the
|
||||
raw characters are passed through unchanged. This helps with backward
|
||||
compatibility and safety (e.g. expanding a non-existent %VAR% to an empty
|
||||
string in a path could result in a very unsafe path). The safest way to insert
|
||||
a literal % into a value is to use %%.
|
||||
|
||||
## MODULE PARAMETERS
|
||||
|
||||
After the global parameters you should define a number of modules, each module
|
||||
@@ -147,11 +144,17 @@ a module name in square brackets [module] followed by the parameters for that
|
||||
module. The module name cannot contain a slash or a closing square bracket.
|
||||
If the name contains whitespace, each internal sequence of whitespace will be
|
||||
changed into a single space, while leading or trailing whitespace will be
|
||||
discarded. Also, the name cannot be "global" as that exact name indicates that
|
||||
global parameters follow (see above).
|
||||
discarded.
|
||||
|
||||
As with GLOBAL PARAMETERS, you may use references to environment variables in
|
||||
the values of parameters. See the GLOBAL PARAMETERS section for more details.
|
||||
There is also a special module name of "[global]" that does not define a module
|
||||
but instead switches back to the global settings context where default
|
||||
parameters can be specified. Because each defined module gets its full set of
|
||||
parameters as a combination of the default values that are set at that position
|
||||
in the config file plus its own parameter list, the use of a "[global]" section
|
||||
can help to maintain shared config values for multiple modules.
|
||||
|
||||
As with [GLOBAL PARAMETERS](#), you may use references to environment variables
|
||||
in the values of parameters. See that section for details.
|
||||
|
||||
0. `comment`
|
||||
|
||||
@@ -165,6 +168,16 @@ the values of parameters. See the GLOBAL PARAMETERS section for more details.
|
||||
available in this module. You must specify this parameter for each module
|
||||
in `rsyncd.conf`.
|
||||
|
||||
If the value contains a "/./" element then the path will be divided at that
|
||||
point into a chroot dir and an inner-chroot subdir. If [`use chroot`](#)
|
||||
is set to false, though, the extraneous dot dir is just cleaned out of the
|
||||
path. An example of this idiom is:
|
||||
|
||||
> path = /var/rsync/./module1
|
||||
|
||||
This will (when chrooting) chroot to "/var/rsync" and set the inside-chroot
|
||||
path to "/module1".
|
||||
|
||||
You may base the path's value off of an environment variable by surrounding
|
||||
the variable name with percent signs. You can even reference a variable
|
||||
that is set by rsync when the user connects. For example, this would use
|
||||
@@ -188,29 +201,47 @@ the values of parameters. See the GLOBAL PARAMETERS section for more details.
|
||||
path, and of complicating the preservation of users and groups by name (see
|
||||
below).
|
||||
|
||||
As an additional safety feature, you can specify a dot-dir in the module's
|
||||
"[path](#)" to indicate the point where the chroot should occur. This allows
|
||||
rsync to run in a chroot with a non-"/" path for the top of the transfer
|
||||
hierarchy. Doing this guards against unintended library loading (since
|
||||
those absolute paths will not be inside the transfer hierarchy unless you
|
||||
have used an unwise pathname), and lets you setup libraries for the chroot
|
||||
that are outside of the transfer. For example, specifying
|
||||
"/var/rsync/./module1" will chroot to the "/var/rsync" directory and set
|
||||
the inside-chroot path to "/module1". If you had omitted the dot-dir, the
|
||||
chroot would have used the whole path, and the inside-chroot path would
|
||||
have been "/".
|
||||
If `use chroot` is not set, it defaults to trying to enable a chroot but
|
||||
allows the daemon to continue (after logging a warning) if it fails. The
|
||||
one exception to this is when a module's [`path`](#) has a "/./" chroot
|
||||
divider in it -- this causes an unset value to be treated as true for that
|
||||
module.
|
||||
|
||||
When both "use chroot" and "[daemon chroot](#)" are false, OR the inside-chroot
|
||||
path of "use chroot" is not "/", rsync will: (1) munge symlinks by default
|
||||
for security reasons (see "[munge symlinks](#)" for a way to turn this off, but
|
||||
only if you trust your users), (2) substitute leading slashes in absolute
|
||||
paths with the module's path (so that options such as `--backup-dir`,
|
||||
`--compare-dest`, etc. interpret an absolute path as rooted in the module's
|
||||
"[path](#)" dir), and (3) trim ".." path elements from args if rsync believes
|
||||
they would escape the module hierarchy. The default for "use chroot" is
|
||||
true, and is the safer choice (especially if the module is not read-only).
|
||||
Prior to rsync 3.2.7, the default value was "true". The new "unset"
|
||||
default makes it easier to setup an rsync daemon as a non-root user or to
|
||||
run a daemon on a system where chroot fails. Explicitly setting the value
|
||||
to "true" in rsyncd.conf will always require the chroot to succeed.
|
||||
|
||||
When this parameter is enabled *and* the "[name converter](#)" parameter is
|
||||
It is also possible to specify a dot-dir in the module's "[path](#)" to
|
||||
indicate that you want to chdir to the earlier part of the path and then
|
||||
serve files from inside the latter part of the path (with sanitizing and
|
||||
default symlink munging). This can be useful if you need some library dirs
|
||||
inside the chroot (typically for uid & gid lookups) but don't want to put
|
||||
the lib dir into the top of the served path (even though they can be hidden
|
||||
with an [`exclude`](#) directive). However, a better choice for a modern
|
||||
rsync setup is to use a [`name converter`](#)" and try to avoid inner lib
|
||||
dirs altogether. See also the [`daemon chroot`](#) parameter, which causes
|
||||
rsync to chroot into its own chroot area before doing any path-related
|
||||
chrooting.
|
||||
|
||||
If the daemon is serving the "/" dir (either directly or due to being
|
||||
chrooted to the module's path), rsync does not do any path sanitizing or
|
||||
(default) munging.
|
||||
|
||||
When it has to limit access to a particular subdir (either due to chroot
|
||||
being disabled or having an inside-chroot path set), rsync will munge
|
||||
symlinks (by default) and sanitize paths. Those that dislike munged
|
||||
symlinks (and really, really trust their users to not break out of the
|
||||
subdir) can disable the symlink munging via the "[munge symlinks](#)"
|
||||
parameter.
|
||||
|
||||
When rsync is sanitizing paths, it trims ".." path elements from args that
|
||||
it believes would escape the module hierarchy. It also substitutes leading
|
||||
slashes in absolute paths with the module's path (so that options such as
|
||||
`--backup-dir` & `--compare-dest` interpret an absolute path as rooted in
|
||||
the module's "[path](#)" dir).
|
||||
|
||||
When a chroot is in effect *and* the "[name converter](#)" parameter is
|
||||
*not* set, the "[numeric ids](#)" parameter will default to being enabled
|
||||
(disabling name lookups). This means that if you manually setup
|
||||
name-lookup libraries in your chroot (instead of using a name converter)
|
||||
@@ -717,7 +748,7 @@ the values of parameters. See the GLOBAL PARAMETERS section for more details.
|
||||
addresses which match the masked IP address will be allowed in.
|
||||
- a hostname pattern using wildcards. If the hostname of the connecting IP
|
||||
(as determined by a reverse lookup) matches the wildcarded name (using
|
||||
the same rules as normal unix filename matching), the client is allowed
|
||||
the same rules as normal Unix filename matching), the client is allowed
|
||||
in. This only works if "[reverse lookup](#)" is enabled (the default).
|
||||
- a hostname. A plain hostname is matched against the reverse DNS of the
|
||||
connecting IP (if "[reverse lookup](#)" is enabled), and/or the IP of the
|
||||
@@ -895,7 +926,7 @@ the values of parameters. See the GLOBAL PARAMETERS section for more details.
|
||||
> refuse options = * !a !v !compress*
|
||||
|
||||
Don't worry that the "`*`" will refuse certain vital options such as
|
||||
`--dry-run`, `--server`, `--no-iconv`, `--protect-args`, etc. These
|
||||
`--dry-run`, `--server`, `--no-iconv`, `--seclude-args`, etc. These
|
||||
important options are not matched by wild-card, so they must be overridden
|
||||
by their exact name. For instance, if you're forcing iconv transfers you
|
||||
could use something like this:
|
||||
@@ -934,9 +965,10 @@ the values of parameters. See the GLOBAL PARAMETERS section for more details.
|
||||
If you are un-refusing the compress option, you may want to match
|
||||
"`!compress*`" if you also want to allow the `--compress-level` option.
|
||||
|
||||
Note that the "write-devices" option is refused by default, but can be
|
||||
explicitly accepted with "`!write-devices`". The options "log-file" and
|
||||
"log-file-format" are forcibly refused and cannot be accepted.
|
||||
Note that the "copy-devices" & "write-devices" options are refused by
|
||||
default, but they can be explicitly accepted with "`!copy-devices`" and/or
|
||||
"`!write-devices`". The options "log-file" and "log-file-format" are
|
||||
forcibly refused and cannot be accepted.
|
||||
|
||||
Here are all the options that are not matched by wild-cards:
|
||||
|
||||
@@ -948,7 +980,7 @@ the values of parameters. See the GLOBAL PARAMETERS section for more details.
|
||||
`--log-file-format`.
|
||||
- `--sender`: Use "[write only](#)" parameter instead of refusing this.
|
||||
- `--dry-run`, `-n`: Who would want to disable this?
|
||||
- `--protect-args`, `-s`: This actually makes transfers safer.
|
||||
- `--seclude-args`, `-s`: Is the oldest arg-protection method.
|
||||
- `--from0`, `-0`: Makes it easier to accept/refuse `--files-from` without
|
||||
affecting this helpful modifier.
|
||||
- `--iconv`: This is auto-disabled based on "[charset](#)" parameter.
|
||||
@@ -991,7 +1023,7 @@ the values of parameters. See the GLOBAL PARAMETERS section for more details.
|
||||
_not_ displayed if the script returns success. The other programs cannot
|
||||
send any text to the user. All output except for the `pre-xfer exec`
|
||||
stdout goes to the corresponding daemon's stdout/stderr, which is typically
|
||||
discarded. See the `--no-detatch` option for a way to see the daemon's
|
||||
discarded. See the `--no-detach` option for a way to see the daemon's
|
||||
output, which can assist with debugging.
|
||||
|
||||
Note that the `early exec` command runs before any part of the transfer
|
||||
@@ -1114,15 +1146,15 @@ SSL proxy.
|
||||
## SSL/TLS Daemon Setup
|
||||
|
||||
When setting up an rsync daemon for access via SSL/TLS, you will need to
|
||||
configure a proxy (such as haproxy or nginx) as the front-end that handles the
|
||||
encryption.
|
||||
configure a TCP proxy (such as haproxy or nginx) as the front-end that handles
|
||||
the encryption.
|
||||
|
||||
- You should limit the access to the backend-rsyncd port to only allow the
|
||||
proxy to connect. If it is on the same host as the proxy, then configuring
|
||||
it to only listen on localhost is a good idea.
|
||||
- You should consider turning on the `proxy protocol` parameter if your proxy
|
||||
supports sending that information. The examples below assume that this is
|
||||
enabled.
|
||||
- You should consider turning on the `proxy protocol` rsync-daemon parameter if
|
||||
your proxy supports sending that information. The examples below assume that
|
||||
this is enabled.
|
||||
|
||||
An example haproxy setup is as follows:
|
||||
|
||||
@@ -1149,14 +1181,14 @@ An example nginx proxy setup is as follows:
|
||||
> ssl_certificate_key /etc/letsencrypt/example.com/privkey.pem;
|
||||
>
|
||||
> proxy_pass localhost:873;
|
||||
> proxy_protocol on; # Requires "proxy protocol = true"
|
||||
> proxy_protocol on; # Requires rsyncd.conf "proxy protocol = true"
|
||||
> proxy_timeout 1m;
|
||||
> proxy_connect_timeout 5s;
|
||||
> }
|
||||
> }
|
||||
> ```
|
||||
|
||||
## EXAMPLES
|
||||
## DAEMON CONFIG EXAMPLES
|
||||
|
||||
A simple rsyncd.conf file that allow anonymous rsync to a ftp area at
|
||||
`/home/ftp` would be:
|
||||
@@ -1211,7 +1243,7 @@ The /etc/rsyncd.secrets file would look something like this:
|
||||
|
||||
## SEE ALSO
|
||||
|
||||
[**rsync**(1)](./rsync.1), [**rsync-ssl**(1)](./rsync-ssl.1)
|
||||
[**rsync**(1)](rsync.1), [**rsync-ssl**(1)](rsync-ssl.1)
|
||||
|
||||
## BUGS
|
||||
|
||||
@@ -1220,12 +1252,12 @@ Please report bugs! The rsync bug tracking system is online at
|
||||
|
||||
## VERSION
|
||||
|
||||
This man page is current for version @VERSION@ of rsync.
|
||||
This manpage is current for version @VERSION@ of rsync.
|
||||
|
||||
## CREDITS
|
||||
|
||||
rsync is distributed under the GNU General Public License. See the file
|
||||
[COPYING](./COPYING) for details.
|
||||
Rsync is distributed under the GNU General Public License. See the file
|
||||
[COPYING](COPYING) for details.
|
||||
|
||||
An rsync web site is available at <https://rsync.samba.org/> and its github
|
||||
project is <https://github.com/WayneD/rsync>.
|
||||
@@ -1237,8 +1269,9 @@ Thanks to Karsten Thygesen for his many suggestions and documentation!
|
||||
|
||||
## AUTHOR
|
||||
|
||||
rsync was written by Andrew Tridgell and Paul Mackerras. Many people have
|
||||
later contributed to it.
|
||||
Rsync was originally written by Andrew Tridgell and Paul Mackerras. Many
|
||||
people have later contributed to it. It is currently maintained by Wayne
|
||||
Davison.
|
||||
|
||||
Mailing lists for support and development are available at
|
||||
<https://lists.samba.org/>.
|
||||
|
||||
19
sender.c
19
sender.c
@@ -25,6 +25,7 @@
|
||||
extern int do_xfers;
|
||||
extern int am_server;
|
||||
extern int am_daemon;
|
||||
extern int local_server;
|
||||
extern int inc_recurse;
|
||||
extern int log_before_transfer;
|
||||
extern int stdout_format_has_i;
|
||||
@@ -37,6 +38,7 @@ extern int io_error;
|
||||
extern int flist_eof;
|
||||
extern int whole_file;
|
||||
extern int allowed_lull;
|
||||
extern int copy_devices;
|
||||
extern int preserve_xattrs;
|
||||
extern int protocol_version;
|
||||
extern int remove_source_files;
|
||||
@@ -50,6 +52,7 @@ extern int file_old_total;
|
||||
extern BOOL want_progress_now;
|
||||
extern struct stats stats;
|
||||
extern struct file_list *cur_flist, *first_flist, *dir_flist;
|
||||
extern char num_dev_ino_buf[4 + 8 + 8];
|
||||
|
||||
BOOL extra_flist_sending_enabled;
|
||||
|
||||
@@ -143,6 +146,13 @@ void successful_send(int ndx)
|
||||
goto failed;
|
||||
}
|
||||
|
||||
if (local_server
|
||||
&& (int64)st.st_dev == IVAL64(num_dev_ino_buf, 4)
|
||||
&& (int64)st.st_ino == IVAL64(num_dev_ino_buf, 4 + 8)) {
|
||||
rprintf(FERROR_XFER, "ERROR: Skipping sender remove of destination file: %s\n", fname);
|
||||
return;
|
||||
}
|
||||
|
||||
if (st.st_size != F_LENGTH(file) || st.st_mtime != file->modtime
|
||||
#ifdef ST_MTIME_NSEC
|
||||
|| (NSEC_BUMP(file) && (uint32)st.ST_MTIME_NSEC != F_MOD_NSEC(file))
|
||||
@@ -366,6 +376,15 @@ void send_files(int f_in, int f_out)
|
||||
exit_cleanup(RERR_FILEIO);
|
||||
}
|
||||
|
||||
if (IS_DEVICE(st.st_mode)) {
|
||||
if (!copy_devices) {
|
||||
rprintf(FERROR, "attempt to copy device contents without --copy-devices\n");
|
||||
exit_cleanup(RERR_PROTOCOL);
|
||||
}
|
||||
if (st.st_size == 0)
|
||||
st.st_size = get_device_size(fd, fname);
|
||||
}
|
||||
|
||||
if (append_mode > 0 && st.st_size < F_LENGTH(file)) {
|
||||
rprintf(FWARNING, "skipped diminished file: %s\n",
|
||||
full_fname(fname));
|
||||
|
||||
@@ -1,15 +1,21 @@
|
||||
#include "config.h"
|
||||
|
||||
#ifdef USE_ROLL_ASM /* { */
|
||||
|
||||
#define CHAR_OFFSET 0 /* Keep this the same as rsync.h, which isn't likely to change. */
|
||||
|
||||
#ifdef __APPLE__
|
||||
#define get_checksum1_avx2 _get_checksum1_avx2
|
||||
#define get_checksum1_avx2_asm _get_checksum1_avx2_asm
|
||||
#endif
|
||||
|
||||
.intel_syntax noprefix
|
||||
.text
|
||||
|
||||
.p2align 5
|
||||
.globl get_checksum1_avx2
|
||||
.globl get_checksum1_avx2_asm
|
||||
|
||||
# rdi=*buf, esi=len, edx=i, rcx= *ps1, r8= *ps2
|
||||
get_checksum1_avx2:
|
||||
get_checksum1_avx2_asm:
|
||||
vmovd xmm6,[rcx] # load *ps1
|
||||
lea eax, [rsi-128] # at least 128 bytes to process?
|
||||
cmp edx, eax
|
||||
@@ -167,3 +173,5 @@ get_checksum1_avx2:
|
||||
.byte 3
|
||||
.byte 2
|
||||
.byte 1
|
||||
|
||||
#endif /* } USE_ROLL_ASM */
|
||||
|
||||
@@ -51,12 +51,12 @@
|
||||
* GCC 4.x are not supported to ease configure.ac logic.
|
||||
*/
|
||||
|
||||
#ifdef __x86_64__
|
||||
#ifdef __cplusplus
|
||||
#ifdef __x86_64__ /* { */
|
||||
#ifdef __cplusplus /* { */
|
||||
|
||||
#include "rsync.h"
|
||||
|
||||
#ifdef HAVE_SIMD
|
||||
#ifdef USE_ROLL_SIMD /* { */
|
||||
|
||||
#include <immintrin.h>
|
||||
|
||||
@@ -85,6 +85,9 @@ typedef long long __m256i_u __attribute__((__vector_size__(32), __may_alias__, _
|
||||
#define SSE2_HADDS_EPI16(a, b) _mm_adds_epi16(SSE2_INTERLEAVE_EVEN_EPI16(a, b), SSE2_INTERLEAVE_ODD_EPI16(a, b))
|
||||
#define SSE2_MADDUBS_EPI16(a, b) _mm_adds_epi16(SSE2_MULU_EVEN_EPI8(a, b), SSE2_MULU_ODD_EPI8(a, b))
|
||||
|
||||
#ifndef USE_ROLL_ASM
|
||||
__attribute__ ((target("default"))) MVSTATIC int32 get_checksum1_avx2_64(schar* buf, int32 len, int32 i, uint32* ps1, uint32* ps2) { return i; }
|
||||
#endif
|
||||
__attribute__ ((target("default"))) MVSTATIC int32 get_checksum1_ssse3_32(schar* buf, int32 len, int32 i, uint32* ps1, uint32* ps2) { return i; }
|
||||
__attribute__ ((target("default"))) MVSTATIC int32 get_checksum1_sse2_32(schar* buf, int32 len, int32 i, uint32* ps1, uint32* ps2) { return i; }
|
||||
|
||||
@@ -245,7 +248,7 @@ __attribute__ ((target("sse2"))) MVSTATIC int32 get_checksum1_sse2_32(schar* buf
|
||||
|
||||
// (4*buf[i] + 3*buf[i+1]), (2*buf[i+2], buf[i+3]), ... 2*[int16*8]
|
||||
__m128i mul_const = _mm_set1_epi32(4 + (3 << 8) + (2 << 16) + (1 << 24));
|
||||
__m128i mul_add16_1 = SSE2_MADDUBS_EPI16(mul_const, in8_1);
|
||||
__m128i mul_add16_1 = SSE2_MADDUBS_EPI16(mul_const, in8_1);
|
||||
__m128i mul_add16_2 = SSE2_MADDUBS_EPI16(mul_const, in8_2);
|
||||
|
||||
// s2 += 32*s1
|
||||
@@ -310,7 +313,127 @@ __attribute__ ((target("sse2"))) MVSTATIC int32 get_checksum1_sse2_32(schar* buf
|
||||
return i;
|
||||
}
|
||||
|
||||
extern "C" __attribute__ ((target("avx2"))) int32 get_checksum1_avx2(schar* buf, int32 len, int32 i, uint32* ps1, uint32* ps2);
|
||||
#ifdef USE_ROLL_ASM /* { */
|
||||
|
||||
extern "C" __attribute__ ((target("avx2"))) int32 get_checksum1_avx2_asm(schar* buf, int32 len, int32 i, uint32* ps1, uint32* ps2);
|
||||
|
||||
#else /* } { */
|
||||
|
||||
/*
|
||||
AVX2 loop per 64 bytes:
|
||||
int16 t1[16];
|
||||
int16 t2[16];
|
||||
for (int j = 0; j < 16; j++) {
|
||||
t1[j] = buf[j*4 + i] + buf[j*4 + i+1] + buf[j*4 + i+2] + buf[j*4 + i+3];
|
||||
t2[j] = 4*buf[j*4 + i] + 3*buf[j*4 + i+1] + 2*buf[j*4 + i+2] + buf[j*4 + i+3];
|
||||
}
|
||||
s2 += 64*s1 + (uint32)(
|
||||
60*t1[0] + 56*t1[1] + 52*t1[2] + 48*t1[3] + 44*t1[4] + 40*t1[5] + 36*t1[6] + 32*t1[7] + 28*t1[8] + 24*t1[9] + 20*t1[10] + 16*t1[11] + 12*t1[12] + 8*t1[13] + 4*t1[14] +
|
||||
t2[0] + t2[1] + t2[2] + t2[3] + t2[4] + t2[5] + t2[6] + t2[7] + t2[8] + t2[9] + t2[10] + t2[11] + t2[12] + t2[13] + t2[14] + t2[15]
|
||||
) + 2080*CHAR_OFFSET;
|
||||
s1 += (uint32)(t1[0] + t1[1] + t1[2] + t1[3] + t1[4] + t1[5] + t1[6] + t1[7] + t1[8] + t1[9] + t1[10] + t1[11] + t1[12] + t1[13] + t1[14] + t1[15]) +
|
||||
64*CHAR_OFFSET;
|
||||
*/
|
||||
|
||||
__attribute__ ((target("avx2"))) MVSTATIC int32 get_checksum1_avx2_64(schar* buf, int32 len, int32 i, uint32* ps1, uint32* ps2)
|
||||
{
|
||||
if (len > 64) {
|
||||
|
||||
uint32 x[4] = {0};
|
||||
__m128i ss1 = _mm_cvtsi32_si128(*ps1);
|
||||
__m128i ss2 = _mm_cvtsi32_si128(*ps2);
|
||||
|
||||
const char mul_t1_buf[16] = {60, 56, 52, 48, 44, 40, 36, 32, 28, 24, 20, 16, 12, 8, 4, 0};
|
||||
__m128i tmp = _mm_load_si128((__m128i*) mul_t1_buf);
|
||||
__m256i mul_t1 = _mm256_cvtepu8_epi16(tmp);
|
||||
__m256i mul_const = _mm256_broadcastd_epi32(_mm_cvtsi32_si128(4 | (3 << 8) | (2 << 16) | (1 << 24)));
|
||||
__m256i mul_one;
|
||||
mul_one = _mm256_abs_epi8(_mm256_cmpeq_epi16(mul_one,mul_one)); // set all vector elements to 1
|
||||
|
||||
for (; i < (len-64); i+=64) {
|
||||
// Load ... 4*[int8*16]
|
||||
__m256i in8_1, in8_2;
|
||||
__m128i in8_1_low, in8_2_low, in8_1_high, in8_2_high;
|
||||
in8_1_low = _mm_loadu_si128((__m128i_u*)&buf[i]);
|
||||
in8_2_low = _mm_loadu_si128((__m128i_u*)&buf[i+16]);
|
||||
in8_1_high = _mm_loadu_si128((__m128i_u*)&buf[i+32]);
|
||||
in8_2_high = _mm_loadu_si128((__m128i_u*)&buf[i+48]);
|
||||
in8_1 = _mm256_inserti128_si256(_mm256_castsi128_si256(in8_1_low), in8_1_high,1);
|
||||
in8_2 = _mm256_inserti128_si256(_mm256_castsi128_si256(in8_2_low), in8_2_high,1);
|
||||
|
||||
// (1*buf[i] + 1*buf[i+1]), (1*buf[i+2], 1*buf[i+3]), ... 2*[int16*8]
|
||||
// Fastest, even though multiply by 1
|
||||
__m256i add16_1 = _mm256_maddubs_epi16(mul_one, in8_1);
|
||||
__m256i add16_2 = _mm256_maddubs_epi16(mul_one, in8_2);
|
||||
|
||||
// (4*buf[i] + 3*buf[i+1]), (2*buf[i+2], buf[i+3]), ... 2*[int16*8]
|
||||
__m256i mul_add16_1 = _mm256_maddubs_epi16(mul_const, in8_1);
|
||||
__m256i mul_add16_2 = _mm256_maddubs_epi16(mul_const, in8_2);
|
||||
|
||||
// s2 += 64*s1
|
||||
ss2 = _mm_add_epi32(ss2, _mm_slli_epi32(ss1, 6));
|
||||
|
||||
// [sum(t1[0]..t1[7]), X, X, X] [int32*4]; faster than multiple _mm_hadds_epi16
|
||||
__m256i sum_add32 = _mm256_add_epi16(add16_1, add16_2);
|
||||
sum_add32 = _mm256_add_epi16(sum_add32, _mm256_srli_epi32(sum_add32, 16));
|
||||
sum_add32 = _mm256_add_epi16(sum_add32, _mm256_srli_si256(sum_add32, 4));
|
||||
sum_add32 = _mm256_add_epi16(sum_add32, _mm256_srli_si256(sum_add32, 8));
|
||||
|
||||
// [sum(t2[0]..t2[7]), X, X, X] [int32*4]; faster than multiple _mm_hadds_epi16
|
||||
__m256i sum_mul_add32 = _mm256_add_epi16(mul_add16_1, mul_add16_2);
|
||||
sum_mul_add32 = _mm256_add_epi16(sum_mul_add32, _mm256_srli_epi32(sum_mul_add32, 16));
|
||||
sum_mul_add32 = _mm256_add_epi16(sum_mul_add32, _mm256_srli_si256(sum_mul_add32, 4));
|
||||
sum_mul_add32 = _mm256_add_epi16(sum_mul_add32, _mm256_srli_si256(sum_mul_add32, 8));
|
||||
|
||||
// s1 += t1[0] + t1[1] + t1[2] + t1[3] + t1[4] + t1[5] + t1[6] + t1[7]
|
||||
__m128i sum_add32_hi = _mm256_extracti128_si256(sum_add32, 0x1);
|
||||
ss1 = _mm_add_epi32(ss1, _mm256_castsi256_si128(sum_add32));
|
||||
ss1 = _mm_add_epi32(ss1, sum_add32_hi);
|
||||
|
||||
// s2 += t2[0] + t2[1] + t2[2] + t2[3] + t2[4] + t2[5] + t2[6] + t2[7]
|
||||
__m128i sum_mul_add32_hi = _mm256_extracti128_si256(sum_mul_add32, 0x1);
|
||||
ss2 = _mm_add_epi32(ss2, _mm256_castsi256_si128(sum_mul_add32));
|
||||
ss2 = _mm_add_epi32(ss2, sum_mul_add32_hi);
|
||||
|
||||
// [t1[0] + t1[1], t1[2] + t1[3] ...] [int16*8]
|
||||
// We could've combined this with generating sum_add32 above and
|
||||
// save an instruction but benchmarking shows that as being slower
|
||||
__m256i add16 = _mm256_hadds_epi16(add16_1, add16_2);
|
||||
|
||||
// [t1[0], t1[1], ...] -> [t1[0]*28 + t1[1]*24, ...] [int32*4]
|
||||
__m256i mul32 = _mm256_madd_epi16(add16, mul_t1);
|
||||
|
||||
// [sum(mul32), X, X, X] [int32*4]; faster than multiple _mm_hadd_epi32
|
||||
mul32 = _mm256_add_epi32(mul32, _mm256_srli_si256(mul32, 4));
|
||||
mul32 = _mm256_add_epi32(mul32, _mm256_srli_si256(mul32, 8));
|
||||
// prefetch 2 cacheline ahead
|
||||
_mm_prefetch(&buf[i + 160], _MM_HINT_T0);
|
||||
|
||||
// s2 += 28*t1[0] + 24*t1[1] + 20*t1[2] + 16*t1[3] + 12*t1[4] + 8*t1[5] + 4*t1[6]
|
||||
__m128i mul32_hi = _mm256_extracti128_si256(mul32, 0x1);
|
||||
ss2 = _mm_add_epi32(ss2, _mm256_castsi256_si128(mul32));
|
||||
ss2 = _mm_add_epi32(ss2, mul32_hi);
|
||||
|
||||
#if CHAR_OFFSET != 0
|
||||
// s1 += 32*CHAR_OFFSET
|
||||
__m128i char_offset_multiplier = _mm_set1_epi32(32 * CHAR_OFFSET);
|
||||
ss1 = _mm_add_epi32(ss1, char_offset_multiplier);
|
||||
|
||||
// s2 += 528*CHAR_OFFSET
|
||||
char_offset_multiplier = _mm_set1_epi32(528 * CHAR_OFFSET);
|
||||
ss2 = _mm_add_epi32(ss2, char_offset_multiplier);
|
||||
#endif
|
||||
}
|
||||
|
||||
_mm_store_si128((__m128i_u*)x, ss1);
|
||||
*ps1 = x[0];
|
||||
_mm_store_si128((__m128i_u*)x, ss2);
|
||||
*ps2 = x[0];
|
||||
}
|
||||
return i;
|
||||
}
|
||||
|
||||
#endif /* } !USE_ROLL_ASM */
|
||||
|
||||
static int32 get_checksum1_default_1(schar* buf, int32 len, int32 i, uint32* ps1, uint32* ps2)
|
||||
{
|
||||
@@ -338,7 +461,11 @@ static inline uint32 get_checksum1_cpp(char *buf1, int32 len)
|
||||
uint32 s2 = 0;
|
||||
|
||||
// multiples of 64 bytes using AVX2 (if available)
|
||||
i = get_checksum1_avx2((schar*)buf1, len, i, &s1, &s2);
|
||||
#ifdef USE_ROLL_ASM
|
||||
i = get_checksum1_avx2_asm((schar*)buf1, len, i, &s1, &s2);
|
||||
#else
|
||||
i = get_checksum1_avx2_64((schar*)buf1, len, i, &s1, &s2);
|
||||
#endif
|
||||
|
||||
// multiples of 32 bytes using SSSE3 (if available)
|
||||
i = get_checksum1_ssse3_32((schar*)buf1, len, i, &s1, &s2);
|
||||
@@ -407,7 +534,11 @@ int main() {
|
||||
benchmark("Raw-C", get_checksum1_default_1, (schar*)buf, BLOCK_LEN);
|
||||
benchmark("SSE2", get_checksum1_sse2_32, (schar*)buf, BLOCK_LEN);
|
||||
benchmark("SSSE3", get_checksum1_ssse3_32, (schar*)buf, BLOCK_LEN);
|
||||
benchmark("AVX2", get_checksum1_avx2, (schar*)buf, BLOCK_LEN);
|
||||
#ifdef USE_ROLL_ASM
|
||||
benchmark("AVX2-ASM", get_checksum1_avx2_asm, (schar*)buf, BLOCK_LEN);
|
||||
#else
|
||||
benchmark("AVX2", get_checksum1_avx2_64, (schar*)buf, BLOCK_LEN);
|
||||
#endif
|
||||
|
||||
free(buf);
|
||||
return 0;
|
||||
@@ -417,6 +548,6 @@ int main() {
|
||||
#pragma clang optimize on
|
||||
#endif /* BENCHMARK_SIMD_CHECKSUM1 */
|
||||
|
||||
#endif /* HAVE_SIMD */
|
||||
#endif /* __cplusplus */
|
||||
#endif /* __x86_64__ */
|
||||
#endif /* } USE_ROLL_SIMD */
|
||||
#endif /* } __cplusplus */
|
||||
#endif /* } __x86_64__ */
|
||||
|
||||
@@ -1,42 +1,63 @@
|
||||
#!/usr/bin/env perl
|
||||
#
|
||||
#!/usr/bin/env python3
|
||||
# This script finds all CVS/Entries files in the current directory and below
|
||||
# and creates a local .cvsinclude file with non-inherited rules including each
|
||||
# checked-in file. Then, use this option whenever using --cvs-exclude (-C):
|
||||
#
|
||||
# -f ': .cvsinclude'
|
||||
# -f ': .cvsinclude'
|
||||
#
|
||||
# That ensures that all checked-in files/dirs are included in the transfer.
|
||||
# (You could alternately put ": .cvsinclude" into an .rsync-filter file and
|
||||
# use the -F option, which is easier to type.)
|
||||
#
|
||||
# The downside is that you need to remember to re-run cvs2includes whenever
|
||||
# you add a new file to the project.
|
||||
use strict;
|
||||
# CVS gets an added or removed file. Maybe just run it before every copy.
|
||||
|
||||
open(FIND, 'find . -name CVS -type d |') or die $!;
|
||||
while (<FIND>) {
|
||||
chomp;
|
||||
s#^\./##;
|
||||
import os, argparse
|
||||
|
||||
my $entries = "$_/Entries";
|
||||
s/CVS$/.cvsinclude/;
|
||||
my $filter = $_;
|
||||
INC_NAME = '.cvsinclude'
|
||||
|
||||
open(ENTRIES, $entries) or die "Unable to open $entries: $!\n";
|
||||
my @includes;
|
||||
while (<ENTRIES>) {
|
||||
push(@includes, $1) if m#/(.+?)/#;
|
||||
}
|
||||
close ENTRIES;
|
||||
if (@includes) {
|
||||
open(FILTER, ">$filter") or die "Unable to write $filter: $!\n";
|
||||
print FILTER map "+ /$_\n", @includes;
|
||||
close FILTER;
|
||||
print "Updated $filter\n";
|
||||
} elsif (-f $filter) {
|
||||
unlink($filter);
|
||||
print "Removed $filter\n";
|
||||
}
|
||||
}
|
||||
close FIND;
|
||||
def main():
|
||||
if args.dir:
|
||||
os.chdir(args.dir)
|
||||
|
||||
cvs_includes = set()
|
||||
for root, dirs, files in os.walk('.'):
|
||||
if INC_NAME in files:
|
||||
cvs_includes.add((root + '/' + INC_NAME)[2:])
|
||||
if root.endswith('/CVS') and 'Entries' in files:
|
||||
entries = root[2:] + '/Entries'
|
||||
includes = [ ]
|
||||
with open(entries) as fh:
|
||||
for line in fh:
|
||||
if line.startswith(('/', 'D/')):
|
||||
includes.append(line.split('/', 2)[1])
|
||||
if includes:
|
||||
inc = root[2:-3] + INC_NAME
|
||||
cvs_includes.discard(inc)
|
||||
try:
|
||||
with open(inc) as fh:
|
||||
old_txt = fh.read()
|
||||
except OSError:
|
||||
old_txt = ''
|
||||
txt = ''.join(f"+ /{x}\n" for x in includes)
|
||||
if txt == old_txt:
|
||||
print("Unchanged", inc)
|
||||
else:
|
||||
print("Updating", inc)
|
||||
with open(inc, 'w') as fh:
|
||||
fh.write(txt)
|
||||
dirs.sort()
|
||||
|
||||
for inc in sorted(cvs_includes):
|
||||
print("Removing", inc)
|
||||
os.unlink(inc)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
parser = argparse.ArgumentParser(description=f"Transform CVS/Entries into {INC_NAME} files.", add_help=False)
|
||||
parser.add_argument("--help", "-h", action="help", help="Output this help message and exit.")
|
||||
parser.add_argument("dir", nargs='?', help="The top CVS dir. Defaults to the current directory.")
|
||||
args = parser.parse_args()
|
||||
main()
|
||||
|
||||
# vim: sw=4 et
|
||||
|
||||
@@ -1,27 +1,37 @@
|
||||
#!/usr/bin/env perl
|
||||
# This script takes an input of filenames and outputs a set of
|
||||
# include/exclude directives that can be used by rsync to copy
|
||||
# just the indicated files using an --exclude-from=FILE option.
|
||||
use strict;
|
||||
#!/usr/bin/env python3
|
||||
# This script takes an input of filenames and outputs a set of include/exclude
|
||||
# directives that can be used by rsync to copy just the indicated files using
|
||||
# an --exclude-from=FILE or -f'. FILE' option. To be able to delete files on
|
||||
# the receiving side, either use --delete-excluded or change the exclude (-)
|
||||
# rules to hide filter rules (H) that only affect the sending side.
|
||||
|
||||
my %hash;
|
||||
import os, fileinput, argparse
|
||||
|
||||
while (<>) {
|
||||
chomp;
|
||||
s#^/+##;
|
||||
my $path = '/';
|
||||
while (m#([^/]+/)/*#g) {
|
||||
$path .= $1;
|
||||
print "+ $path\n" unless $hash{$path}++;
|
||||
}
|
||||
if (m#([^/]+)$#) {
|
||||
print "+ $path$1\n";
|
||||
} else {
|
||||
delete $hash{$path};
|
||||
}
|
||||
}
|
||||
def main():
|
||||
paths = set()
|
||||
for line in fileinput.input(args.files):
|
||||
dirs = line.strip().lstrip('/').split('/')
|
||||
if not dirs:
|
||||
continue
|
||||
for j in range(1, len(dirs)):
|
||||
if dirs[j] == '':
|
||||
continue
|
||||
path = '/' + '/'.join(dirs[:j]) + '/'
|
||||
if path not in paths:
|
||||
print('+', path)
|
||||
paths.add(path)
|
||||
print('+', '/' + '/'.join(dirs))
|
||||
|
||||
foreach (sort keys %hash) {
|
||||
print "- $_*\n";
|
||||
}
|
||||
print "- /*\n";
|
||||
for path in sorted(paths):
|
||||
print('-', path + '*')
|
||||
print('-', '/*')
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
parser = argparse.ArgumentParser(description="Transform a list of files into a set of include/exclude rules.", add_help=False)
|
||||
parser.add_argument("--help", "-h", action="help", help="Output this help message and exit.")
|
||||
parser.add_argument("files", metavar="FILE", default='-', nargs='*', help="The file(s) that hold the pathnames to translate. Defaults to stdin.")
|
||||
args = parser.parse_args()
|
||||
main()
|
||||
|
||||
# vim: sw=4 et
|
||||
|
||||
@@ -38,7 +38,7 @@ def main():
|
||||
print_line(fn, mtime, mtime)
|
||||
ls.discard(fn)
|
||||
|
||||
cmd = git + 'log -r --name-only --no-color --pretty=raw --no-renames -z'.split()
|
||||
cmd = git + 'log -r --name-only --format=%x00commit%x20%H%n%x00commit_time%x20%ct%n --no-renames -z'.split()
|
||||
if args.tree:
|
||||
cmd.append(args.tree)
|
||||
cmd += ['--'] + args.files
|
||||
@@ -46,7 +46,7 @@ def main():
|
||||
proc = subprocess.Popen(cmd, stdout=subprocess.PIPE, encoding='utf-8')
|
||||
for line in proc.stdout:
|
||||
line = line.strip()
|
||||
m = re.match(r'^committer .*? (\d+) [-+]\d+$', line)
|
||||
m = re.match(r'^\0commit_time (\d+)$', line)
|
||||
if m:
|
||||
commit_time = int(m[1])
|
||||
elif NULL_COMMIT_RE.search(line):
|
||||
|
||||
45
support/idmap
Executable file
45
support/idmap
Executable file
@@ -0,0 +1,45 @@
|
||||
#!/usr/bin/env python3
|
||||
# This helper script makes it easy to use a passwd or group file to map values
|
||||
# in a LOCAL transfer. For instance, if you mount a backup that does not have
|
||||
# the same passwd setup as the local machine, you can do a copy to/from the
|
||||
# backup area as follows and get the differing ID values mapped just like a
|
||||
# remote transfer to/from the backed-up machine would do:
|
||||
#
|
||||
# rsync -av --usermap=`idmap --to /mnt/backup/etc/passwd` \
|
||||
# --groupmap=`idmap --to /mnt/backup/etc/group` \
|
||||
# /some/src/ /mnt/backup/some/dest/
|
||||
#
|
||||
# rsync -av --usermap=`idmap --from /mnt/backup/etc/passwd` \
|
||||
# --groupmap=`idmap --from /mnt/backup/etc/group` \
|
||||
# /mnt/backup/some/src/ /some/dest/
|
||||
|
||||
import re, fileinput, argparse
|
||||
|
||||
NAME_ID_RE = re.compile(r'^(\w+):[^:]+:(\d+)')
|
||||
|
||||
def main():
|
||||
maps = [ ]
|
||||
for line in fileinput.input(args.files):
|
||||
m = NAME_ID_RE.match(line)
|
||||
if not m:
|
||||
continue
|
||||
if args.to:
|
||||
pair = (m[1], m[2])
|
||||
else:
|
||||
pair = (m[2], m[1])
|
||||
maps.append(':'.join(pair))
|
||||
print(','.join(maps))
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
parser = argparse.ArgumentParser(description="Output usermap or groupmap args for rsync.", add_help=False)
|
||||
action = parser.add_argument_group()
|
||||
action = parser.add_mutually_exclusive_group(required=True)
|
||||
action.add_argument("--from", action="store_true", help="Output the map for use on the sending side.")
|
||||
action.add_argument("--to", action="store_true", help="Output the map for use on the receiving side.")
|
||||
parser.add_argument("--help", "-h", action="help", help="Output this help message and exit.")
|
||||
parser.add_argument("files", metavar="FILE", default='-', nargs='*', help="The file(s) that hold the name & id pairs. Defaults to stdin.")
|
||||
args = parser.parse_args()
|
||||
main()
|
||||
|
||||
# vim: sw=4 et
|
||||
93
support/json-rsync-version
Executable file
93
support/json-rsync-version
Executable file
@@ -0,0 +1,93 @@
|
||||
#!/usr/bin/env python3
|
||||
|
||||
import sys, argparse, subprocess, json
|
||||
|
||||
TWEAK_NAME = {
|
||||
'asm': 'asm_roll',
|
||||
'ASM': 'asm_roll',
|
||||
'hardlink_special': 'hardlink_specials',
|
||||
'protect_args': 'secluded_args',
|
||||
'protected_args': 'secluded_args',
|
||||
'SIMD': 'SIMD_roll',
|
||||
}
|
||||
|
||||
MOVE_OPTIM = set('asm_roll SIMD_roll'.split())
|
||||
|
||||
def main():
|
||||
if not args.rsync or args.rsync == '-':
|
||||
ver_out = sys.stdin.read().strip()
|
||||
else:
|
||||
ver_out = subprocess.check_output([args.rsync, '--version', '--version'], encoding='utf-8').strip()
|
||||
if ver_out.startswith('{'):
|
||||
print(ver_out)
|
||||
return
|
||||
info = { }
|
||||
misplaced_optims = { }
|
||||
for line in ver_out.splitlines():
|
||||
if line.startswith('rsync '):
|
||||
prog, vstr, ver, pstr, vstr2, proto = line.split()
|
||||
info['program'] = prog
|
||||
if ver.startswith('v'):
|
||||
ver = ver[1:]
|
||||
info[vstr] = ver
|
||||
if '.' not in proto:
|
||||
proto += '.0'
|
||||
else:
|
||||
proto = proto.replace('.PR', '.')
|
||||
info[pstr] = proto
|
||||
elif line.startswith('Copyright '):
|
||||
info['copyright'] = line[10:]
|
||||
elif line.startswith('Web site: '):
|
||||
info['url'] = line[10:]
|
||||
elif line.startswith(' '):
|
||||
if not saw_comma and ',' in line:
|
||||
saw_comma = True
|
||||
info[sect_name] = { }
|
||||
if saw_comma:
|
||||
for x in line.strip(' ,').split(', '):
|
||||
if ' ' in x:
|
||||
val, var = x.split(' ', 1)
|
||||
if val == 'no':
|
||||
val = False
|
||||
elif val.endswith('-bit'):
|
||||
var = var[:-1] + '_bits'
|
||||
val = int(val.split('-')[0])
|
||||
else:
|
||||
var = x
|
||||
val = True
|
||||
var = var.replace(' ', '_').replace('-', '_')
|
||||
if var in TWEAK_NAME:
|
||||
var = TWEAK_NAME[var]
|
||||
if sect_name[0] != 'o' and var in MOVE_OPTIM:
|
||||
misplaced_optims[var] = val
|
||||
else:
|
||||
info[sect_name][var] = val
|
||||
else:
|
||||
info[sect_name] += [ x for x in line.split() if not x.startswith('(') ]
|
||||
elif line == '':
|
||||
break
|
||||
else:
|
||||
sect_name = line.strip(' :').replace(' ', '_').lower()
|
||||
info[sect_name] = [ ]
|
||||
saw_comma = False
|
||||
for chk in 'capabilities optimizations'.split():
|
||||
if chk not in info:
|
||||
info[chk] = { }
|
||||
if misplaced_optims:
|
||||
info['optimizations'].update(misplaced_optims)
|
||||
for chk in 'checksum_list compress_list daemon_auth_list'.split():
|
||||
if chk not in info:
|
||||
info[chk] = [ ]
|
||||
info['license'] = 'GPLv3' if ver[0] == '3' else 'GPLv2'
|
||||
info['caveat'] = 'rsync comes with ABSOLUTELY NO WARRANTY'
|
||||
print(json.dumps(info))
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
parser = argparse.ArgumentParser(description="Output rsync's version data in JSON format, even if the rsync doesn't support a native json-output method.", add_help=False)
|
||||
parser.add_argument('rsync', nargs='?', help="Specify an rsync command to run. Otherwise stdin is consumed.")
|
||||
parser.add_argument("--help", "-h", action="help", help="Output this help message and exit.")
|
||||
args = parser.parse_args()
|
||||
main()
|
||||
|
||||
# vim: sw=4 et
|
||||
@@ -1,15 +0,0 @@
|
||||
#!/usr/bin/env perl
|
||||
# This helper script makes it easy to use a passwd or group file to map
|
||||
# values in a LOCAL transfer. For instance, if you mount a backup that
|
||||
# does not have the same passwd setup as the local machine, you can do
|
||||
# a copy FROM the backup area as follows and get the differing ID values
|
||||
# mapped just like a remote transfer FROM the backed-up machine would do:
|
||||
#
|
||||
# rsync -av --usermap=`mapfrom /mnt/backup/etc/passwd` \
|
||||
# --groupmap=`mapfrom /mnt/backup/etc/group` \
|
||||
# /mnt/backup/some/src/ /some/dest/
|
||||
|
||||
while (<>) {
|
||||
push @_, "$2:$1" if /^(\w+):[^:]+:(\d+)/;
|
||||
}
|
||||
print join(',', @_), "\n";
|
||||
@@ -1,15 +0,0 @@
|
||||
#!/usr/bin/env perl
|
||||
# This helper script makes it easy to use a passwd or group file to map
|
||||
# values in a LOCAL transfer. For instance, if you mount a backup that
|
||||
# does not have the same passwd setup as the local machine, you can do
|
||||
# a copy TO the backup area as follows and get the differing ID values
|
||||
# mapped just like a remote transfer TO the backed-up machine would do:
|
||||
#
|
||||
# rsync -av --usermap=`mapto /mnt/backup/etc/passwd` \
|
||||
# --groupmap=`mapto /mnt/backup/etc/group` \
|
||||
# /some/src/ /mnt/backup/some/dest/
|
||||
|
||||
while (<>) {
|
||||
push @_, "$1:$2" if /^(\w+):[^:]+:(\d+)/;
|
||||
}
|
||||
print join(',', @_), "\n";
|
||||
@@ -1,4 +1,4 @@
|
||||
#!/usr/bin/env perl
|
||||
#!/usr/bin/env python3
|
||||
# This script takes a command-line arg of a source directory
|
||||
# that will be passed to rsync, and generates a set of excludes
|
||||
# that will exclude all mount points from the list. This is
|
||||
@@ -27,23 +27,33 @@
|
||||
# awk '{print $2}' /proc/mounts | grep -v '^/$' | \
|
||||
# rsync -avf 'merge,/- -' /dir host:/dest/
|
||||
|
||||
use strict;
|
||||
use warnings;
|
||||
use Cwd 'abs_path';
|
||||
import os, argparse
|
||||
|
||||
my $file = '/proc/mounts';
|
||||
my $dir = shift || '/';
|
||||
my $trailing_slash = $dir =~ m{./$} ? '/' : '';
|
||||
$dir = abs_path($dir) . $trailing_slash;
|
||||
$dir =~ s{([^/]*)$}{};
|
||||
my $trailing = $1;
|
||||
$trailing = '' if $trailing eq '.' || !-d "$dir$trailing";
|
||||
$trailing .= '/' if $trailing ne '';
|
||||
MNT_FILE = '/proc/mounts';
|
||||
|
||||
open(IN, $file) or die "Unable to open $file: $!\n";
|
||||
while (<IN>) {
|
||||
$_ = (split)[1];
|
||||
next unless s{^\Q$dir$trailing\E}{}o && $_ ne '';
|
||||
print "- /$trailing$_\n";
|
||||
}
|
||||
close IN;
|
||||
def main():
|
||||
trailing_slash = '/' if args.path.endswith(('/', '/.')) and args.path != '/' else ''
|
||||
args.path = os.path.realpath(args.path) + trailing_slash
|
||||
parent_dir = os.path.dirname(args.path)
|
||||
trailing = os.path.basename(args.path)
|
||||
if not os.path.isdir(args.path):
|
||||
trailing = ''
|
||||
elif trailing != '':
|
||||
trailing += '/'
|
||||
want_path = os.path.join(parent_dir, trailing)
|
||||
wp_len = len(want_path)
|
||||
|
||||
with open(MNT_FILE) as fh:
|
||||
for line in fh:
|
||||
mnt_path = line.split()[1]
|
||||
if mnt_path.startswith(want_path) and mnt_path != want_path:
|
||||
print(f"- /{trailing}{mnt_path[wp_len:]}")
|
||||
|
||||
if __name__ == '__main__':
|
||||
parser = argparse.ArgumentParser(description="Output mount points as rsync excludes.", add_help=False)
|
||||
parser.add_argument("--help", "-h", action="help", help="Output this help message and exit.")
|
||||
parser.add_argument('path', metavar='PATH', nargs='?', default='/', help="Limit output to those within the PATH hierarchy.")
|
||||
args = parser.parse_args()
|
||||
main()
|
||||
|
||||
# vim: sw=4 et
|
||||
|
||||
@@ -47,6 +47,7 @@ long_opts = {
|
||||
'compress-choice': 1,
|
||||
'compress-level': 1,
|
||||
'copy-dest': 2,
|
||||
'copy-devices': -1,
|
||||
'copy-unsafe-links': 0,
|
||||
'daemon': -1,
|
||||
'debug': 1,
|
||||
@@ -257,6 +258,9 @@ def main():
|
||||
|
||||
if args.munge:
|
||||
rsync_opts.append('--munge-links')
|
||||
|
||||
if args.no_overwrite:
|
||||
rsync_opts.append('--ignore-existing')
|
||||
|
||||
if not rsync_args:
|
||||
rsync_args = [ '.' ]
|
||||
@@ -363,6 +367,7 @@ if __name__ == '__main__':
|
||||
arg_parser.add_argument('-munge', action='store_true', help="Enable rsync's --munge-links on the server side.")
|
||||
arg_parser.add_argument('-no-del', action='store_true', help="Disable rsync's --delete* and --remove* options.")
|
||||
arg_parser.add_argument('-no-lock', action='store_true', help="Avoid the single-run (per-user) lock check.")
|
||||
arg_parser.add_argument('-no-overwrite', action='store_true', help="Prevent overwriting existing files by enforcing --ignore-existing")
|
||||
arg_parser.add_argument('-help', '-h', action='help', help="Output this help message and exit.")
|
||||
arg_parser.add_argument('dir', metavar='DIR', help="The restricted directory to use.")
|
||||
args = arg_parser.parse_args()
|
||||
|
||||
@@ -5,17 +5,26 @@ rrsync - a script to setup restricted rsync users via ssh logins
|
||||
## SYNOPSIS
|
||||
|
||||
```
|
||||
rrsync [-ro|-rw] [-munge] [-no-del] [-no-lock] DIR
|
||||
rrsync [-ro|-rw] [-munge] [-no-del] [-no-lock] [-no-overwrite] DIR
|
||||
```
|
||||
|
||||
The online version of this man page (that includes cross-linking of topics)
|
||||
The single non-option argument specifies the restricted _DIR_ to use. It can be
|
||||
relative to the user's home directory or an absolute path.
|
||||
|
||||
The online version of this manpage (that includes cross-linking of topics)
|
||||
is available at <https://download.samba.org/pub/rsync/rrsync.1>.
|
||||
|
||||
## DESCRIPTION
|
||||
|
||||
A user's ssh login can be restricted to only allow the running of an rsync
|
||||
transfer in one of two easy ways: forcing the running of the rrsync script
|
||||
or forcing the running of an rsync daemon-over-ssh command.
|
||||
transfer in one of two easy ways:
|
||||
|
||||
* forcing the running of the rrsync script
|
||||
* forcing the running of an rsync daemon-over-ssh command.
|
||||
|
||||
Both of these setups use a feature of ssh that allows a command to be forced to
|
||||
run instead of an interactive shell. However, if the user's home shell is bash,
|
||||
please see [BASH SECURITY ISSUE](#) for a potential issue.
|
||||
|
||||
To use the rrsync script, edit the user's `~/.ssh/authorized_keys` file and add
|
||||
a prefix like one of the following (followed by a space) in front of each
|
||||
@@ -30,7 +39,7 @@ ssh-key line that should be restricted:
|
||||
Then, ensure that the rrsync script has your desired option restrictions. You
|
||||
may want to copy the script to a local bin dir with a unique name if you want
|
||||
to have multiple configurations. One or more rrsync options can be specified
|
||||
prior to the `DIR` if you want to further restrict the transfer.
|
||||
prior to the _DIR_ if you want to further restrict the transfer.
|
||||
|
||||
To use an rsync daemon setup, edit the user's `~/.ssh/authorized_keys` file and
|
||||
add a prefix like one of the following (followed by a space) in front of each
|
||||
@@ -43,43 +52,61 @@ ssh-key line that should be restricted:
|
||||
|
||||
Then, ensure that the rsyncd.conf file is created with one or more module names
|
||||
with the appropriate path and option restrictions. If rsync's
|
||||
[`--config`](./rsync.1#daemon-opt--config) option is omitted, it defaults to
|
||||
`~/rsyncd.conf`. See the `rsyncd.conf` man page for details of how to
|
||||
[`--config`](rsync.1#dopt) option is omitted, it defaults to `~/rsyncd.conf`.
|
||||
See the [**rsyncd.conf**(5)](rsyncd.conf.5) manpage for details of how to
|
||||
configure an rsync daemon.
|
||||
|
||||
When using rrsync, there can be just one restricted dir per authorized key. A
|
||||
daemon setup, on the other hand, allows multiple module names inside the config
|
||||
file, each one with its own path setting.
|
||||
|
||||
The remainder of this man page is dedicated to using the rrsync script.
|
||||
The remainder of this manpage is dedicated to using the rrsync script.
|
||||
|
||||
## OPTION SUMMARY
|
||||
## OPTIONS
|
||||
|
||||
```
|
||||
-ro Allow only reading from the DIR. Implies -no-del and -no-lock.
|
||||
-wo Allow only writing to the DIR.
|
||||
-munge Enable rsync's --munge-links on the server side.
|
||||
-no-del Disable rsync's --delete* and --remove* options.
|
||||
-no-lock Avoid the single-run (per-user) lock check.
|
||||
-help, -h Output this help message and exit.
|
||||
```
|
||||
0. `-ro`
|
||||
|
||||
A single non-option argument specifies the restricted DIR to use. It can be
|
||||
relative to the user's home directory or an absolute path.
|
||||
Allow only reading from the DIR. Implies [`-no-del`](#opt) and
|
||||
[`-no-lock`](#opt).
|
||||
|
||||
0. `-wo`
|
||||
|
||||
Allow only writing to the DIR.
|
||||
|
||||
0. `-munge`
|
||||
|
||||
Enable rsync's [`--munge-links`](rsync.1#opt) on the server side.
|
||||
|
||||
0. `-no-del`
|
||||
|
||||
Disable rsync's `--delete*` and `--remove*` options.
|
||||
|
||||
0. `-no-lock`
|
||||
|
||||
Avoid the single-run (per-user) lock check. Useful with [`-munge`](#opt).
|
||||
|
||||
0. `-no-overwrite`
|
||||
|
||||
Enforce `--ignore-existing` on the server. Prevents overwriting existing
|
||||
files when the server is the receiver.
|
||||
|
||||
0. `-help`, `-h`
|
||||
|
||||
Output this help message and exit.
|
||||
|
||||
## SECURITY RESTRICTIONS
|
||||
|
||||
The rrsync script validates the path arguments it is sent to try to restrict
|
||||
them to staying within the specified DIR.
|
||||
|
||||
The rrsync script rejects rsync's [`--copy-links`](./rsync.1#opt--copy-links)
|
||||
option (by default) so that a copy cannot dereference a symlink within the DIR
|
||||
to get to a file outside the DIR.
|
||||
The rrsync script rejects rsync's [`--copy-links`](rsync.1#opt) option (by
|
||||
default) so that a copy cannot dereference a symlink within the DIR to get to a
|
||||
file outside the DIR.
|
||||
|
||||
The rrsync script rejects rsync's
|
||||
[`--protect-args`](./rsync.1#opt--protect-args) (`-s`) option because it would
|
||||
allow options to be sent to the server-side that the script cannot check. If
|
||||
you want to support `--protect-args`, use a daemon-over-ssh setup.
|
||||
The rrsync script rejects rsync's [`--protect-args`](rsync.1#opt) (`-s`) option
|
||||
because it would allow options to be sent to the server-side that the script
|
||||
cannot check. If you want to support `--protect-args`, use a daemon-over-ssh
|
||||
setup.
|
||||
|
||||
The rrsync script accepts just a subset of rsync's options that the real rsync
|
||||
uses when running the server command. A few extra convenience options are also
|
||||
@@ -89,6 +116,26 @@ overrides.
|
||||
The script (or a copy of it) can be manually edited if you want it to customize
|
||||
the option handling.
|
||||
|
||||
## BASH SECURITY ISSUE
|
||||
|
||||
If your users have bash set as their home shell, bash may try to be overly
|
||||
helpful and ensure that the user's login bashrc files are run prior to
|
||||
executing the forced command. This can be a problem if the user can somehow
|
||||
update their home bashrc files, perhaps via the restricted copy, a shared home
|
||||
directory, or something similar.
|
||||
|
||||
One simple way to avoid the issue is to switch the user to a simpler shell,
|
||||
such as dash. When choosing the new home shell, make sure that you're not
|
||||
choosing bash in disguise, as it is unclear if it avoids the security issue.
|
||||
|
||||
Another potential fix is to ensure that the user's home directory is not a
|
||||
shared mount and that they have no means of copying files outside of their
|
||||
restricted directories. This may require you to force the enabling of symlink
|
||||
munging on the server side.
|
||||
|
||||
A future version of openssh may have a change to the handling of forced
|
||||
commands that allows it to avoid using the user's home shell.
|
||||
|
||||
## EXAMPLES
|
||||
|
||||
The `~/.ssh/authorized_keys` file might have lines in it like this:
|
||||
@@ -104,16 +151,16 @@ The `~/.ssh/authorized_keys` file might have lines in it like this:
|
||||
|
||||
## SEE ALSO
|
||||
|
||||
[**rsync**(1)](./rsync.1)
|
||||
[**rsync**(1)](rsync.1), [**rsyncd.conf**(5)](rsyncd.conf.5)
|
||||
|
||||
## VERSION
|
||||
|
||||
This man page is current for version @VERSION@ of rsync.
|
||||
This manpage is current for version @VERSION@ of rsync.
|
||||
|
||||
## CREDITS
|
||||
|
||||
rsync is distributed under the GNU General Public License. See the file
|
||||
[COPYING](./COPYING) for details.
|
||||
[COPYING](COPYING) for details.
|
||||
|
||||
An rsync web site is available at <https://rsync.samba.org/> and its github
|
||||
project is <https://github.com/WayneD/rsync>.
|
||||
|
||||
@@ -247,7 +247,7 @@ int do_chmod(const char *path, mode_t mode)
|
||||
else if (errno != ENOTSUP)
|
||||
break;
|
||||
#endif
|
||||
|
||||
/* FALLTHROUGH */
|
||||
default:
|
||||
if (S_ISLNK(mode)) {
|
||||
# if defined HAVE_SETATTRLIST
|
||||
@@ -257,7 +257,10 @@ int do_chmod(const char *path, mode_t mode)
|
||||
memset(&attrList, 0, sizeof attrList);
|
||||
attrList.bitmapcount = ATTR_BIT_MAP_COUNT;
|
||||
attrList.commonattr = ATTR_CMN_ACCESSMASK;
|
||||
code = setattrlist(path, &attrList, &m, sizeof m, FSOPT_NOFOLLOW);
|
||||
if ((code = setattrlist(path, &attrList, &m, sizeof m, FSOPT_NOFOLLOW)) == 0)
|
||||
break;
|
||||
if (errno == ENOTSUP)
|
||||
code = 1;
|
||||
# else
|
||||
code = 1;
|
||||
# endif
|
||||
|
||||
1
t_stub.c
1
t_stub.c
@@ -29,7 +29,6 @@ int protect_args = 0;
|
||||
int module_id = -1;
|
||||
int relative_paths = 0;
|
||||
int module_dirlen = 0;
|
||||
int preserve_mtimes = 0;
|
||||
int preserve_xattrs = 0;
|
||||
int preserve_perms = 0;
|
||||
int preserve_executability = 0;
|
||||
|
||||
@@ -1,9 +1,11 @@
|
||||
#!/bin/sh
|
||||
|
||||
test_fail() {
|
||||
echo "$@" >&2
|
||||
exit 1
|
||||
}
|
||||
# Test some foundational things.
|
||||
|
||||
. "$suitedir/rsync.fns"
|
||||
|
||||
RSYNC_RSH="$scratchdir/src/support/lsh.sh"
|
||||
export RSYNC_RSH
|
||||
|
||||
echo $0 running
|
||||
|
||||
@@ -12,3 +14,48 @@ $RSYNC --version || test_fail '--version output failed'
|
||||
$RSYNC --info=help || test_fail '--info=help output failed'
|
||||
|
||||
$RSYNC --debug=help || test_fail '--debug=help output failed'
|
||||
|
||||
weird_name="A weird)name"
|
||||
|
||||
mkdir "$fromdir"
|
||||
mkdir "$fromdir/$weird_name"
|
||||
|
||||
append_line() {
|
||||
echo "$1"
|
||||
echo "$1" >>"$fromdir/$weird_name/file"
|
||||
}
|
||||
|
||||
append_line test1
|
||||
checkit "$RSYNC -ai '$fromdir/' '$todir/'" "$fromdir" "$todir"
|
||||
|
||||
copy_weird() {
|
||||
checkit "$RSYNC $1 --rsync-path='$RSYNC' '$2$fromdir/$weird_name/' '$3$todir/$weird_name'" "$fromdir" "$todir"
|
||||
}
|
||||
|
||||
append_line test2
|
||||
copy_weird '-ai' 'lh:' ''
|
||||
|
||||
append_line test3
|
||||
copy_weird '-ai' '' 'lh:'
|
||||
|
||||
append_line test4
|
||||
copy_weird '-ais' 'lh:' ''
|
||||
|
||||
append_line test5
|
||||
copy_weird '-ais' '' 'lh:'
|
||||
|
||||
echo test6
|
||||
|
||||
touch "$fromdir/one" "$fromdir/two"
|
||||
(cd "$fromdir" && $RSYNC -ai --old-args --rsync-path="$RSYNC" lh:'one two' "$todir/")
|
||||
if [ ! -f "$todir/one" ] || [ ! -f "$todir/two" ]; then
|
||||
test_fail "old-args copy of 'one two' failed"
|
||||
fi
|
||||
|
||||
echo test7
|
||||
|
||||
rm "$todir/one" "$todir/two"
|
||||
(cd "$fromdir" && RSYNC_OLD_ARGS=1 $RSYNC -ai --rsync-path="$RSYNC" lh:'one two' "$todir/")
|
||||
|
||||
# The script would have aborted on error, so getting here means we've won.
|
||||
exit 0
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
|
||||
. $suitedir/rsync.fns
|
||||
|
||||
$RSYNC --version | grep "[, ] ACLs" >/dev/null || test_skipped "Rsync is configured without ACL support"
|
||||
$RSYNC -VV | grep '"ACLs": true' >/dev/null || test_skipped "Rsync is configured without ACL support"
|
||||
|
||||
case "$setfacl_nodef" in
|
||||
true) test_skipped "I don't know how to use your setfacl command" ;;
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
|
||||
. $suitedir/rsync.fns
|
||||
|
||||
$RSYNC --version | grep "[, ] ACLs" >/dev/null || test_skipped "Rsync is configured without ACL support"
|
||||
$RSYNC -VV | grep '"ACLs": true' >/dev/null || test_skipped "Rsync is configured without ACL support"
|
||||
|
||||
makepath "$fromdir/foo"
|
||||
echo something >"$fromdir/file1"
|
||||
|
||||
68
testsuite/alt-dest.test
Normal file
68
testsuite/alt-dest.test
Normal file
@@ -0,0 +1,68 @@
|
||||
#!/bin/sh
|
||||
|
||||
# Copyright (C) 2004-2022 Wayne Davison
|
||||
|
||||
# This program is distributable under the terms of the GNU GPL (see
|
||||
# COPYING).
|
||||
|
||||
# Test rsync handling of --compare-dest and similar options.
|
||||
|
||||
. "$suitedir/rsync.fns"
|
||||
|
||||
alt1dir="$tmpdir/alt1"
|
||||
alt2dir="$tmpdir/alt2"
|
||||
alt3dir="$tmpdir/alt3"
|
||||
|
||||
SSH="$scratchdir/src/support/lsh.sh"
|
||||
|
||||
# Build some files/dirs/links to copy
|
||||
|
||||
hands_setup
|
||||
|
||||
# Setup the alt and chk dirs
|
||||
$RSYNC -av --include=text --include='*/' --exclude='*' "$fromdir/" "$alt1dir/"
|
||||
$RSYNC -av --include=etc-ltr-list --include='*/' --exclude='*' "$fromdir/" "$alt2dir/"
|
||||
|
||||
# Create a side dir where there is a candidate destfile of the same name as a sourcefile
|
||||
echo "This is a test file" >"$fromdir/likely"
|
||||
|
||||
mkdir "$alt3dir"
|
||||
echo "This is a test file" >"$alt3dir/likely"
|
||||
|
||||
sleep 1
|
||||
touch "$fromdir/dir/text" "$fromdir/likely"
|
||||
|
||||
$RSYNC -av --exclude=/text --exclude=etc-ltr-list "$fromdir/" "$chkdir/"
|
||||
|
||||
# Let's do it!
|
||||
checkit "$RSYNC -avv --no-whole-file \
|
||||
--compare-dest='$alt1dir' --compare-dest='$alt2dir' \
|
||||
'$fromdir/' '$todir/'" "$chkdir" "$todir"
|
||||
|
||||
rm -rf "$todir"
|
||||
checkit "$RSYNC -avv --no-whole-file \
|
||||
--copy-dest='$alt1dir' --copy-dest='$alt2dir' \
|
||||
'$fromdir/' '$todir/'" "$fromdir" "$todir"
|
||||
|
||||
# Test that copy_file() works correctly with tmpfiles
|
||||
for maybe_inplace in '' --inplace; do
|
||||
rm -rf "$todir"
|
||||
checkit "$RSYNC -av $maybe_inplace --copy-dest='$alt3dir' \
|
||||
'$fromdir/' '$todir/'" "$fromdir" "$todir"
|
||||
|
||||
for srchost in '' 'localhost:'; do
|
||||
if [ -z "$srchost" ]; then
|
||||
desthost='localhost:'
|
||||
else
|
||||
desthost=''
|
||||
fi
|
||||
|
||||
rm -rf "$todir"
|
||||
checkit "$RSYNC -ave '$SSH' --rsync-path='$RSYNC' $maybe_inplace \
|
||||
--copy-dest='$alt3dir' '$srchost$fromdir/' '$desthost$todir/'" \
|
||||
"$fromdir" "$todir"
|
||||
done
|
||||
done
|
||||
|
||||
# The script would have aborted on error, so getting here means we've won.
|
||||
exit 0
|
||||
@@ -4,7 +4,7 @@
|
||||
|
||||
. "$suitedir/rsync.fns"
|
||||
|
||||
$RSYNC --version | grep "[, ] atimes" >/dev/null || test_skipped "Rsync is configured without atimes support"
|
||||
$RSYNC -VV | grep '"atimes": true' >/dev/null || test_skipped "Rsync is configured without atimes support"
|
||||
|
||||
mkdir "$fromdir"
|
||||
|
||||
|
||||
@@ -15,7 +15,7 @@
|
||||
|
||||
case $0 in
|
||||
*fake*)
|
||||
$RSYNC --version | grep "[, ] xattrs" >/dev/null || test_skipped "Rsync needs xattrs for fake device tests"
|
||||
$RSYNC -VV | grep '"xattrs": true' >/dev/null || test_skipped "Rsync needs xattrs for fake device tests"
|
||||
RSYNC="$RSYNC --fake-super"
|
||||
TLS_ARGS="$TLS_ARGS --fake-super"
|
||||
case "$HOST_OS" in
|
||||
|
||||
@@ -1,37 +0,0 @@
|
||||
#!/bin/sh
|
||||
|
||||
# Copyright (C) 2004-2022 Wayne Davison
|
||||
|
||||
# This program is distributable under the terms of the GNU GPL (see
|
||||
# COPYING).
|
||||
|
||||
# Test rsync handling of the --compare-dest option.
|
||||
|
||||
. "$suitedir/rsync.fns"
|
||||
|
||||
alt1dir="$tmpdir/alt1"
|
||||
alt2dir="$tmpdir/alt2"
|
||||
|
||||
# Build some files/dirs/links to copy
|
||||
|
||||
hands_setup
|
||||
|
||||
# Setup the alt and chk dirs
|
||||
$RSYNC -av --include=text --include='*/' --exclude='*' "$fromdir/" "$alt1dir/"
|
||||
$RSYNC -av --include=etc-ltr-list --include='*/' --exclude='*' "$fromdir/" "$alt2dir/"
|
||||
|
||||
sleep 1
|
||||
touch "$fromdir/dir/text"
|
||||
|
||||
$RSYNC -av --exclude=/text --exclude=etc-ltr-list "$fromdir/" "$chkdir/"
|
||||
|
||||
# Let's do it!
|
||||
checkit "$RSYNC -avv --no-whole-file \
|
||||
--compare-dest='$alt1dir' --compare-dest='$alt2dir' \
|
||||
'$fromdir/' '$todir/'" "$chkdir" "$todir"
|
||||
checkit "$RSYNC -avv --no-whole-file \
|
||||
--copy-dest='$alt1dir' --copy-dest='$alt2dir' \
|
||||
'$fromdir/' '$todir/'" "$fromdir" "$todir"
|
||||
|
||||
# The script would have aborted on error, so getting here means we've won.
|
||||
exit 0
|
||||
@@ -4,13 +4,13 @@
|
||||
|
||||
. "$suitedir/rsync.fns"
|
||||
|
||||
$RSYNC --version | grep "[, ] crtimes" >/dev/null || test_skipped "Rsync is configured without crtimes support"
|
||||
$RSYNC -VV | grep '"crtimes": true' >/dev/null || test_skipped "Rsync is configured without crtimes support"
|
||||
|
||||
# Setting an older time via touch sets the create time to the mtime.
|
||||
# Setting it to a newer time affects just the mtime.
|
||||
|
||||
mkdir "$fromdir"
|
||||
echo hiho "$fromdir/foo"
|
||||
echo hiho >"$fromdir/foo"
|
||||
|
||||
touch -t 200101011111.11 "$fromdir"
|
||||
touch -t 200202022222.22 "$fromdir"
|
||||
|
||||
@@ -81,7 +81,7 @@ drwxr-xr-x DIR ####/##/## ##:##:## foo
|
||||
EOT
|
||||
diff $diffopt "$chkfile" "$outfile" || test_fail "test 3 failed"
|
||||
|
||||
if $RSYNC --version | grep "[, ] atimes" >/dev/null; then
|
||||
if $RSYNC -VV | grep '"atimes": true' >/dev/null; then
|
||||
checkdiff "$RSYNC -rU localhost::test-from/f*" \
|
||||
"sed -e '$FILE_REPL' -e '$DIR_REPL' -e '$LS_REPL'" <<EOT
|
||||
drwxr-xr-x DIR ####/##/## ##:##:## foo
|
||||
|
||||
@@ -13,7 +13,7 @@
|
||||
|
||||
case $0 in
|
||||
*fake*)
|
||||
$RSYNC --version | grep "[, ] xattrs" >/dev/null || test_skipped "Rsync needs xattrs for fake device tests"
|
||||
$RSYNC -VV | grep '"xattrs": true' >/dev/null || test_skipped "Rsync needs xattrs for fake device tests"
|
||||
RSYNC="$RSYNC --fake-super"
|
||||
TLS_ARGS="$TLS_ARGS --fake-super"
|
||||
case "$HOST_OS" in
|
||||
@@ -94,7 +94,7 @@ esac
|
||||
|
||||
# TODO: Need to test whether hardlinks are possible on this OS/filesystem
|
||||
|
||||
$RSYNC --version | grep "[, ] hardlink-special" >/dev/null && CAN_HLINK_SPECIAL=yes || CAN_HLINK_SPECIAL=no
|
||||
$RSYNC -VV | grep '"hardlink_specials": true' >/dev/null && CAN_HLINK_SPECIAL=yes || CAN_HLINK_SPECIAL=no
|
||||
|
||||
mkdir "$fromdir"
|
||||
mkdir "$todir"
|
||||
|
||||
1
testsuite/exclude-lsh.test
Symbolic link
1
testsuite/exclude-lsh.test
Symbolic link
@@ -0,0 +1 @@
|
||||
exclude.test
|
||||
@@ -15,6 +15,19 @@
|
||||
CVSIGNORE='*.junk'
|
||||
export CVSIGNORE
|
||||
|
||||
case $0 in
|
||||
*-lsh.*)
|
||||
RSYNC_RSH="$scratchdir/src/support/lsh.sh"
|
||||
export RSYNC_RSH
|
||||
rpath=" --rsync-path='$RSYNC'"
|
||||
host='lh:'
|
||||
;;
|
||||
*)
|
||||
rpath=''
|
||||
host=''
|
||||
;;
|
||||
esac
|
||||
|
||||
# Build some files/dirs/links to copy
|
||||
|
||||
makepath "$fromdir/foo/down/to/you"
|
||||
@@ -106,8 +119,8 @@ home-cvs-exclude
|
||||
EOF
|
||||
|
||||
# Start with a check of --prune-empty-dirs:
|
||||
$RSYNC -av -f -_foo/too/ -f -_foo/down/ -f -_foo/and/ -f -_new/ "$fromdir/" "$chkdir/"
|
||||
checkit "$RSYNC -av --prune-empty-dirs '$fromdir/' '$todir/'" "$chkdir" "$todir"
|
||||
$RSYNC -av --rsync-path="$RSYNC" -f -_foo/too/ -f -_foo/down/ -f -_foo/and/ -f -_new/ "$host$fromdir/" "$chkdir/"
|
||||
checkit "$RSYNC -av$rpath --prune-empty-dirs '$host$fromdir/' '$todir/'" "$chkdir" "$todir"
|
||||
rm -rf "$todir"
|
||||
|
||||
# Add a directory symlink.
|
||||
@@ -120,7 +133,7 @@ touch "$scratchdir/up1/same-newness" "$scratchdir/up2/same-newness"
|
||||
touch "$scratchdir/up1/extra-src" "$scratchdir/up2/extra-dest"
|
||||
|
||||
# Create chkdir with what we expect to be excluded.
|
||||
checkit "$RSYNC -avv '$fromdir/' '$chkdir/'" "$fromdir" "$chkdir"
|
||||
checkit "$RSYNC -avv$rpath '$host$fromdir/' '$chkdir/'" "$fromdir" "$chkdir"
|
||||
sleep 1 # Ensures that the rm commands will tweak the directory times.
|
||||
rm -r "$chkdir"/foo/down
|
||||
rm -r "$chkdir"/mid/for/foo/and
|
||||
@@ -135,12 +148,12 @@ touch "$scratchdir/up1/src-newness" "$scratchdir/up2/dst-newness"
|
||||
|
||||
# Un-tweak the directory times in our first (weak) exclude test (though
|
||||
# it's a good test of the --existing option).
|
||||
$RSYNC -av --existing --include='*/' --exclude='*' "$fromdir/" "$chkdir/"
|
||||
$RSYNC -av --rsync-path="$RSYNC" --existing --include='*/' --exclude='*' "$host$fromdir/" "$chkdir/"
|
||||
|
||||
# Now, test if rsync excludes the same files.
|
||||
|
||||
checkit "$RSYNC -avv --exclude-from='$excl' \
|
||||
--delete-during '$fromdir/' '$todir/'" "$chkdir" "$todir"
|
||||
checkit "$RSYNC -avv$rpath --exclude-from='$excl' \
|
||||
--delete-during '$host$fromdir/' '$todir/'" "$chkdir" "$todir"
|
||||
|
||||
# Modify the chk dir by removing cvs-ignored files and then tweaking the dir times.
|
||||
|
||||
@@ -150,13 +163,15 @@ rm "$chkdir"/bar/down/to/foo/*.junk
|
||||
rm "$chkdir"/bar/down/to/home-cvs-exclude
|
||||
rm "$chkdir"/mid/one-in-one-out
|
||||
|
||||
$RSYNC -av --existing --filter='exclude,! */' "$fromdir/" "$chkdir/"
|
||||
$RSYNC -av --rsync-path="$RSYNC" --existing --filter='exclude,! */' "$host$fromdir/" "$chkdir/"
|
||||
|
||||
# Now, test if rsync excludes the same files, this time with --cvs-exclude
|
||||
# and --delete-excluded.
|
||||
|
||||
checkit "$RSYNC -avvC --filter='merge $excl' --delete-excluded \
|
||||
--delete-during '$fromdir/' '$todir/'" "$chkdir" "$todir"
|
||||
# The -C option gets applied in a different order when pushing & pulling, so we instead
|
||||
# add the 2 --cvs-exclude filter rules (":C" & "-C") via -f to keep the order the same.
|
||||
checkit "$RSYNC -avv$rpath --filter='merge $excl' -f:C -f-C --delete-excluded \
|
||||
--delete-during '$host$fromdir/' '$todir/'" "$chkdir" "$todir"
|
||||
|
||||
# Modify the chk dir for our merge-exclude test and then tweak the dir times.
|
||||
|
||||
@@ -165,19 +180,19 @@ rm "$chkdir"/bar/down/to/bar/baz/*.deep
|
||||
cp_touch "$fromdir"/bar/down/to/foo/*.junk "$chkdir"/bar/down/to/foo
|
||||
cp_touch "$fromdir"/bar/down/to/foo/to "$chkdir"/bar/down/to/foo
|
||||
|
||||
$RSYNC -av --existing -f 'show .filt*' -f 'hide,! */' --del "$fromdir/" "$todir/"
|
||||
$RSYNC -av --rsync-path="$RSYNC" --existing -f 'show .filt*' -f 'hide,! */' --del "$host$fromdir/" "$todir/"
|
||||
|
||||
echo retained >"$todir"/bar/down/to/bar/baz/nodel.deep
|
||||
cp_touch "$todir"/bar/down/to/bar/baz/nodel.deep "$chkdir"/bar/down/to/bar/baz
|
||||
|
||||
$RSYNC -av --existing --filter='-! */' "$fromdir/" "$chkdir/"
|
||||
$RSYNC -av --rsync-path="$RSYNC" --existing --filter='-! */' "$host$fromdir/" "$chkdir/"
|
||||
|
||||
# Now, test if rsync excludes the same files, this time with a merge-exclude
|
||||
# file.
|
||||
|
||||
checkit "sed '/!/d' '$excl' |
|
||||
$RSYNC -avv -f dir-merge_.filt -f merge_- \
|
||||
--delete-during '$fromdir/' '$todir/'" "$chkdir" "$todir"
|
||||
$RSYNC -avv$rpath -f dir-merge_.filt -f merge_- \
|
||||
--delete-during '$host$fromdir/' '$todir/'" "$chkdir" "$todir"
|
||||
|
||||
# Remove the files that will be deleted.
|
||||
|
||||
@@ -188,14 +203,14 @@ rm "$chkdir"/bar/down/to/foo/.filt2
|
||||
rm "$chkdir"/bar/down/to/bar/.filt2
|
||||
rm "$chkdir"/mid/.filt
|
||||
|
||||
$RSYNC -av --protocol=28 --existing --include='*/' --exclude='*' "$fromdir/" "$chkdir/"
|
||||
$RSYNC -av --rsync-path="$RSYNC" --existing --include='*/' --exclude='*' "$host$fromdir/" "$chkdir/"
|
||||
|
||||
# Now, try the prior command with --delete-before and some side-specific
|
||||
# rules.
|
||||
|
||||
checkit "sed '/!/d' '$excl' |
|
||||
$RSYNC -avv -f :s_.filt -f .s_- -f P_nodel.deep \
|
||||
--delete-before '$fromdir/' '$todir/'" "$chkdir" "$todir"
|
||||
$RSYNC -avv$rpath -f :s_.filt -f .s_- -f P_nodel.deep \
|
||||
--delete-before '$host$fromdir/' '$todir/'" "$chkdir" "$todir"
|
||||
|
||||
# Next, we'll test some rule-restricted filter files.
|
||||
|
||||
@@ -206,26 +221,26 @@ cat >"$fromdir/bar/down/to/foo/.excl" <<EOF
|
||||
+ file3
|
||||
*.bak
|
||||
EOF
|
||||
$RSYNC -av --del "$fromdir/" "$chkdir/"
|
||||
$RSYNC -av --rsync-path="$RSYNC" --del "$host$fromdir/" "$chkdir/"
|
||||
rm "$chkdir/bar/down/to/foo/file1.bak"
|
||||
rm "$chkdir/bar/down/to/foo/file3"
|
||||
rm "$chkdir/bar/down/to/foo/+ file3"
|
||||
$RSYNC -av --existing --filter='-! */' "$fromdir/" "$chkdir/"
|
||||
$RSYNC -av --delete-excluded --exclude='*' "$fromdir/" "$todir/"
|
||||
$RSYNC -av --rsync-path="$RSYNC" --existing --filter='-! */' "$host$fromdir/" "$chkdir/"
|
||||
$RSYNC -av --rsync-path="$RSYNC" --delete-excluded --exclude='*' "$host$fromdir/" "$todir/"
|
||||
|
||||
checkit "$RSYNC -avv -f dir-merge,-_.excl \
|
||||
'$fromdir/' '$todir/'" "$chkdir" "$todir"
|
||||
checkit "$RSYNC -avv$rpath -f dir-merge,-_.excl \
|
||||
'$host$fromdir/' '$todir/'" "$chkdir" "$todir"
|
||||
|
||||
relative_opts='--relative --chmod=Du+w --copy-unsafe-links'
|
||||
$RSYNC -av $relative_opts "$fromdir/foo" "$chkdir/"
|
||||
$RSYNC -av --rsync-path="$RSYNC" $relative_opts "$host$fromdir/foo" "$chkdir/"
|
||||
rm -rf "$chkdir$fromdir/foo/down"
|
||||
$RSYNC -av $relative_opts --existing --filter='-! */' "$fromdir/foo" "$chkdir/"
|
||||
|
||||
checkit "$RSYNC -avv $relative_opts --exclude='$fromdir/foo/down' \
|
||||
'$fromdir/foo' '$todir'" "$chkdir$fromdir/foo" "$todir$fromdir/foo"
|
||||
checkit "$RSYNC -avv$rpath $relative_opts --exclude='$fromdir/foo/down' \
|
||||
'$host$fromdir/foo' '$todir'" "$chkdir$fromdir/foo" "$todir$fromdir/foo"
|
||||
|
||||
# Now we'll test the --update option.
|
||||
checkdiff "$RSYNC -aiiO --update --info=skip '$scratchdir/up1/' '$scratchdir/up2/'" \
|
||||
checkdiff "$RSYNC -aiiO$rpath --update --info=skip '$host$scratchdir/up1/' '$scratchdir/up2/'" \
|
||||
"grep -v '^\.d$allspace'" <<EOT
|
||||
dst-newness is newer
|
||||
>f$all_plus extra-src
|
||||
|
||||
@@ -25,7 +25,7 @@ ln "$fromdir/foo/config1" "$fromdir/foo/extra"
|
||||
rm -f "$to2dir"
|
||||
|
||||
# Check if rsync is set to hard-link symlinks.
|
||||
if $RSYNC --version | grep "[, ] hardlink-symlinks" >/dev/null; then
|
||||
if $RSYNC -VV | grep '"hardlink_symlinks": true' >/dev/null; then
|
||||
L=hL
|
||||
sym_dots="$allspace"
|
||||
L_sym_dots=".L$allspace"
|
||||
@@ -45,7 +45,7 @@ case "$RSYNC" in
|
||||
T=.T
|
||||
;;
|
||||
*)
|
||||
if $RSYNC --version | grep "[, ] symtimes" >/dev/null; then
|
||||
if $RSYNC -VV | grep '"symtimes": true' >/dev/null; then
|
||||
T=.t
|
||||
else
|
||||
T=.T
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
. $suitedir/rsync.fns
|
||||
lnkdir="$tmpdir/lnk"
|
||||
|
||||
$RSYNC --version | grep "[, ] xattrs" >/dev/null || test_skipped "Rsync is configured without xattr support"
|
||||
$RSYNC -VV | grep '"xattrs": true' >/dev/null || test_skipped "Rsync is configured without xattr support"
|
||||
|
||||
case "$HOST_OS" in
|
||||
darwin*)
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
*
|
||||
* Copyright (C) 1996 Andrew Tridgell
|
||||
* Copyright (C) 1996 Paul Mackerras
|
||||
* Copyright (C) 2004-2020 Wayne Davison
|
||||
* Copyright (C) 2004-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
|
||||
@@ -210,7 +210,7 @@ static int is_in_group(gid_t gid)
|
||||
ngroups = getgroups(ngroups, gidset);
|
||||
/* The default gid might not be in the list on some systems. */
|
||||
for (n = 0; n < ngroups; n++) {
|
||||
if (gidset[n] == our_gid)
|
||||
if ((gid_t)gidset[n] == our_gid)
|
||||
break;
|
||||
}
|
||||
if (n == ngroups)
|
||||
@@ -229,7 +229,7 @@ static int is_in_group(gid_t gid)
|
||||
|
||||
last_in = gid;
|
||||
for (n = 0; n < ngroups; n++) {
|
||||
if (gidset[n] == gid)
|
||||
if ((gid_t)gidset[n] == gid)
|
||||
return last_out = 1;
|
||||
}
|
||||
return last_out = 0;
|
||||
|
||||
167
usage.c
167
usage.c
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* Some usage & version related functions.
|
||||
*
|
||||
* Copyright (C) 2002-2020 Wayne Davison
|
||||
* Copyright (C) 2002-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
|
||||
@@ -22,9 +22,9 @@
|
||||
#include "latest-year.h"
|
||||
#include "git-version.h"
|
||||
#include "default-cvsignore.h"
|
||||
#include "itypes.h"
|
||||
|
||||
extern struct name_num_obj valid_checksums;
|
||||
extern struct name_num_obj valid_compressions;
|
||||
extern struct name_num_obj valid_checksums, valid_compressions, valid_auth_checksums;
|
||||
|
||||
static char *istring(const char *fmt, int val)
|
||||
{
|
||||
@@ -37,7 +37,8 @@ static char *istring(const char *fmt, int val)
|
||||
static void print_info_flags(enum logcode f)
|
||||
{
|
||||
STRUCT_STAT *dumstat;
|
||||
char line_buf[75];
|
||||
BOOL as_json = f == FNONE ? 1 : 0; /* We use 1 == first attribute, 2 == need closing array */
|
||||
char line_buf[75], item_buf[32];
|
||||
int line_len, j;
|
||||
char *info_flags[] = {
|
||||
|
||||
@@ -110,12 +111,12 @@ static void print_info_flags(enum logcode f)
|
||||
#endif
|
||||
"xattrs",
|
||||
|
||||
#ifdef RSYNC_USE_PROTECTED_ARGS
|
||||
#ifdef RSYNC_USE_SECLUDED_ARGS
|
||||
"default "
|
||||
#else
|
||||
"optional "
|
||||
#endif
|
||||
"protect-args",
|
||||
"secluded-args",
|
||||
|
||||
#ifndef ICONV_OPTION
|
||||
"no "
|
||||
@@ -139,64 +140,162 @@ static void print_info_flags(enum logcode f)
|
||||
|
||||
"*Optimizations",
|
||||
|
||||
#ifndef HAVE_SIMD
|
||||
#ifndef USE_ROLL_SIMD
|
||||
"no "
|
||||
#endif
|
||||
"SIMD",
|
||||
"SIMD-roll",
|
||||
|
||||
#ifndef HAVE_ASM
|
||||
#ifndef USE_ROLL_ASM
|
||||
"no "
|
||||
#endif
|
||||
"asm",
|
||||
"asm-roll",
|
||||
|
||||
#ifndef USE_OPENSSL
|
||||
"no "
|
||||
#endif
|
||||
"openssl-crypto",
|
||||
|
||||
#ifndef USE_MD5_ASM
|
||||
"no "
|
||||
#endif
|
||||
"asm-MD5",
|
||||
|
||||
NULL
|
||||
};
|
||||
|
||||
for (line_len = 0, j = 0; ; j++) {
|
||||
char *str = info_flags[j], *next_nfo = str ? info_flags[j+1] : NULL;
|
||||
int str_len = str && *str != '*' ? strlen(str) : 1000;
|
||||
int need_comma = next_nfo && *next_nfo != '*' ? 1 : 0;
|
||||
if (line_len && line_len + 1 + str_len + need_comma >= (int)sizeof line_buf) {
|
||||
rprintf(f, " %s\n", line_buf);
|
||||
int item_len;
|
||||
if (!str || *str == '*')
|
||||
item_len = 1000;
|
||||
else if (as_json) {
|
||||
char *space = strchr(str, ' ');
|
||||
int is_no = space && strncmp(str, "no ", 3) == 0;
|
||||
int is_bits = space && isDigit(str);
|
||||
char *quot = space && !is_no && !is_bits ? "\"" : "";
|
||||
char *item = space ? space + 1 : str;
|
||||
char *val = !space ? "true" : is_no ? "false" : str;
|
||||
int val_len = !space ? 4 : is_no ? 5 : space - str;
|
||||
if (is_bits && (space = strchr(val, '-')) != NULL)
|
||||
val_len = space - str;
|
||||
item_len = snprintf(item_buf, sizeof item_buf,
|
||||
" \"%s%s\": %s%.*s%s%s", item, is_bits ? "bits" : "",
|
||||
quot, val_len, val, quot, need_comma ? "," : "");
|
||||
if (is_bits)
|
||||
item_buf[strlen(item)+2-1] = '_'; /* Turn the 's' into a '_' */
|
||||
for (space = item; (space = strpbrk(space, " -")) != NULL; space++)
|
||||
item_buf[space - item + 2] = '_';
|
||||
} else
|
||||
item_len = snprintf(item_buf, sizeof item_buf, " %s%s", str, need_comma ? "," : "");
|
||||
if (line_len && line_len + item_len >= (int)sizeof line_buf) {
|
||||
if (as_json)
|
||||
printf(" %s\n", line_buf);
|
||||
else
|
||||
rprintf(f, " %s\n", line_buf);
|
||||
line_len = 0;
|
||||
}
|
||||
if (!str)
|
||||
break;
|
||||
if (*str == '*') {
|
||||
rprintf(f, "%s:\n", str+1);
|
||||
continue;
|
||||
if (as_json) {
|
||||
if (as_json == 2)
|
||||
printf(" }");
|
||||
else
|
||||
as_json = 2;
|
||||
printf(",\n \"%c%s\": {\n", toLower(str+1), str+2);
|
||||
} else
|
||||
rprintf(f, "%s:\n", str+1);
|
||||
} else {
|
||||
strlcpy(line_buf + line_len, item_buf, sizeof line_buf - line_len);
|
||||
line_len += item_len;
|
||||
}
|
||||
line_len += snprintf(line_buf+line_len, sizeof line_buf - line_len, " %s%s", str, need_comma ? "," : "");
|
||||
}
|
||||
if (as_json == 2)
|
||||
printf(" }");
|
||||
}
|
||||
|
||||
static void output_nno_list(enum logcode f, const char *name, struct name_num_obj *nno)
|
||||
{
|
||||
char namebuf[64], tmpbuf[256];
|
||||
char *tok, *next_tok, *comma = ",";
|
||||
char *cp;
|
||||
|
||||
/* Using '(' ensures that we get a trailing "none" but also includes aliases. */
|
||||
get_default_nno_list(nno, tmpbuf, sizeof tmpbuf - 1, '(');
|
||||
if (f != FNONE) {
|
||||
rprintf(f, "%s:\n", name);
|
||||
rprintf(f, " %s\n", tmpbuf);
|
||||
return;
|
||||
}
|
||||
|
||||
strlcpy(namebuf, name, sizeof namebuf);
|
||||
for (cp = namebuf; *cp; cp++) {
|
||||
if (*cp == ' ')
|
||||
*cp = '_';
|
||||
else if (isUpper(cp))
|
||||
*cp = toLower(cp);
|
||||
}
|
||||
|
||||
printf(",\n \"%s\": [\n ", namebuf);
|
||||
|
||||
for (tok = strtok(tmpbuf, " "); tok; tok = next_tok) {
|
||||
next_tok = strtok(NULL, " ");
|
||||
if (*tok != '(') /* Ignore the alises in the JSON output */
|
||||
printf(" \"%s\"%s", tok, comma + (next_tok ? 0 : 1));
|
||||
}
|
||||
|
||||
printf("\n ]");
|
||||
}
|
||||
|
||||
/* A request of f == FNONE wants json on stdout. */
|
||||
void print_rsync_version(enum logcode f)
|
||||
{
|
||||
char tmpbuf[256], *subprotocol = "";
|
||||
char copyright[] = "(C) 1996-" LATEST_YEAR " by Andrew Tridgell, Wayne Davison, and others.";
|
||||
char url[] = "https://rsync.samba.org/";
|
||||
BOOL first_line = 1;
|
||||
|
||||
#define json_line(name, value) \
|
||||
do { \
|
||||
printf("%c\n \"%s\": \"%s\"", first_line ? '{' : ',', name, value); \
|
||||
first_line = 0; \
|
||||
} while (0)
|
||||
|
||||
if (f == FNONE) {
|
||||
char verbuf[32];
|
||||
json_line("program", RSYNC_NAME);
|
||||
json_line("version", rsync_version());
|
||||
(void)snprintf(verbuf, sizeof verbuf, "%d.%d", PROTOCOL_VERSION, SUBPROTOCOL_VERSION);
|
||||
json_line("protocol", verbuf);
|
||||
json_line("copyright", copyright);
|
||||
json_line("url", url);
|
||||
} else {
|
||||
#if SUBPROTOCOL_VERSION != 0
|
||||
subprotocol = istring(".PR%d", SUBPROTOCOL_VERSION);
|
||||
char *subprotocol = istring(".PR%d", SUBPROTOCOL_VERSION);
|
||||
#else
|
||||
char *subprotocol = "";
|
||||
#endif
|
||||
rprintf(f, "%s version %s protocol version %d%s\n",
|
||||
RSYNC_NAME, rsync_version(), PROTOCOL_VERSION, subprotocol);
|
||||
|
||||
rprintf(f, "Copyright (C) 1996-" LATEST_YEAR " by Andrew Tridgell, Wayne Davison, and others.\n");
|
||||
rprintf(f, "Web site: https://rsync.samba.org/\n");
|
||||
rprintf(f, "%s version %s protocol version %d%s\n",
|
||||
RSYNC_NAME, rsync_version(), PROTOCOL_VERSION, subprotocol);
|
||||
rprintf(f, "Copyright %s\n", copyright);
|
||||
rprintf(f, "Web site: %s\n", url);
|
||||
}
|
||||
|
||||
print_info_flags(f);
|
||||
|
||||
rprintf(f, "Checksum list:\n");
|
||||
get_default_nno_list(&valid_checksums, tmpbuf, sizeof tmpbuf, '(');
|
||||
rprintf(f, " %s\n", tmpbuf);
|
||||
init_checksum_choices();
|
||||
|
||||
rprintf(f, "Compress list:\n");
|
||||
get_default_nno_list(&valid_compressions, tmpbuf, sizeof tmpbuf, '(');
|
||||
rprintf(f, " %s\n", tmpbuf);
|
||||
output_nno_list(f, "Checksum list", &valid_checksums);
|
||||
output_nno_list(f, "Compress list", &valid_compressions);
|
||||
output_nno_list(f, "Daemon auth list", &valid_auth_checksums);
|
||||
|
||||
if (f == FNONE) {
|
||||
json_line("license", "GPLv3");
|
||||
json_line("caveat", "rsync comes with ABSOLUTELY NO WARRANTY");
|
||||
printf("\n}\n");
|
||||
fflush(stdout);
|
||||
return;
|
||||
}
|
||||
|
||||
#ifdef MAINTAINER_MODE
|
||||
rprintf(f, "Panic Action: \"%s\"\n", get_panic_action());
|
||||
@@ -240,7 +339,7 @@ void usage(enum logcode F)
|
||||
#include "help-rsync.h"
|
||||
rprintf(F,"\n");
|
||||
rprintf(F,"Use \"rsync --daemon --help\" to see the daemon-mode command-line options.\n");
|
||||
rprintf(F,"Please see the rsync(1) and rsyncd.conf(5) man pages for full documentation.\n");
|
||||
rprintf(F,"Please see the rsync(1) and rsyncd.conf(5) manpages for full documentation.\n");
|
||||
rprintf(F,"See https://rsync.samba.org/ for updates, bug reports, and answers\n");
|
||||
}
|
||||
|
||||
@@ -253,16 +352,18 @@ void daemon_usage(enum logcode F)
|
||||
#include "help-rsyncd.h"
|
||||
rprintf(F,"\n");
|
||||
rprintf(F,"If you were not trying to invoke rsync as a daemon, avoid using any of the\n");
|
||||
rprintf(F,"daemon-specific rsync options. See also the rsyncd.conf(5) man page.\n");
|
||||
rprintf(F,"daemon-specific rsync options. See also the rsyncd.conf(5) manpage.\n");
|
||||
}
|
||||
|
||||
const char *rsync_version(void)
|
||||
{
|
||||
char *ver;
|
||||
#ifdef RSYNC_GITVER
|
||||
return RSYNC_GITVER;
|
||||
ver = RSYNC_GITVER;
|
||||
#else
|
||||
return RSYNC_VERSION;
|
||||
ver = RSYNC_VERSION;
|
||||
#endif
|
||||
return *ver == 'v' ? ver+1 : ver;
|
||||
}
|
||||
|
||||
const char *default_cvsignore(void)
|
||||
|
||||
71
util1.c
71
util1.c
@@ -31,7 +31,6 @@ extern int do_fsync;
|
||||
extern int protect_args;
|
||||
extern int modify_window;
|
||||
extern int relative_paths;
|
||||
extern int preserve_mtimes;
|
||||
extern int preserve_xattrs;
|
||||
extern int omit_link_times;
|
||||
extern int preallocate_files;
|
||||
@@ -320,16 +319,48 @@ static int safe_read(int desc, char *ptr, size_t len)
|
||||
return n_chars;
|
||||
}
|
||||
|
||||
/* Copy a file. If ofd < 0, copy_file unlinks and opens the "dest" file.
|
||||
* Otherwise, it just writes to and closes the provided file descriptor.
|
||||
/* Remove existing file @dest and reopen, creating a new file with @mode */
|
||||
static int unlink_and_reopen(const char *dest, mode_t mode)
|
||||
{
|
||||
int ofd;
|
||||
|
||||
if (robust_unlink(dest) && errno != ENOENT) {
|
||||
int save_errno = errno;
|
||||
rsyserr(FERROR_XFER, errno, "unlink %s", full_fname(dest));
|
||||
errno = save_errno;
|
||||
return -1;
|
||||
}
|
||||
|
||||
#ifdef SUPPORT_XATTRS
|
||||
if (preserve_xattrs)
|
||||
mode |= S_IWUSR;
|
||||
#endif
|
||||
mode &= INITACCESSPERMS;
|
||||
if ((ofd = do_open(dest, O_WRONLY | O_CREAT | O_TRUNC | O_EXCL, mode)) < 0) {
|
||||
int save_errno = errno;
|
||||
rsyserr(FERROR_XFER, save_errno, "open %s", full_fname(dest));
|
||||
errno = save_errno;
|
||||
return -1;
|
||||
}
|
||||
return ofd;
|
||||
}
|
||||
|
||||
/* Copy contents of file @source to file @dest with mode @mode.
|
||||
*
|
||||
* If @tmpfilefd is < 0, copy_file unlinks @dest and then opens a new
|
||||
* file with name @dest.
|
||||
*
|
||||
* Otherwise, copy_file writes to and closes the provided file
|
||||
* descriptor.
|
||||
*
|
||||
* In either case, if --xattrs are being preserved, the dest file will
|
||||
* have its xattrs set from the source file.
|
||||
*
|
||||
* This is used in conjunction with the --temp-dir, --backup, and
|
||||
* --copy-dest options. */
|
||||
int copy_file(const char *source, const char *dest, int ofd, mode_t mode)
|
||||
int copy_file(const char *source, const char *dest, int tmpfilefd, mode_t mode)
|
||||
{
|
||||
int ifd;
|
||||
int ifd, ofd;
|
||||
char buf[1024 * 8];
|
||||
int len; /* Number of bytes read into `buf'. */
|
||||
OFF_T prealloc_len = 0, offset = 0;
|
||||
@@ -341,23 +372,12 @@ int copy_file(const char *source, const char *dest, int ofd, mode_t mode)
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (ofd < 0) {
|
||||
if (robust_unlink(dest) && errno != ENOENT) {
|
||||
if (tmpfilefd >= 0) {
|
||||
ofd = tmpfilefd;
|
||||
} else {
|
||||
ofd = unlink_and_reopen(dest, mode);
|
||||
if (ofd < 0) {
|
||||
int save_errno = errno;
|
||||
rsyserr(FERROR_XFER, errno, "unlink %s", full_fname(dest));
|
||||
close(ifd);
|
||||
errno = save_errno;
|
||||
return -1;
|
||||
}
|
||||
|
||||
#ifdef SUPPORT_XATTRS
|
||||
if (preserve_xattrs)
|
||||
mode |= S_IWUSR;
|
||||
#endif
|
||||
mode &= INITACCESSPERMS;
|
||||
if ((ofd = do_open(dest, O_WRONLY | O_CREAT | O_TRUNC | O_EXCL, mode)) < 0) {
|
||||
int save_errno = errno;
|
||||
rsyserr(FERROR_XFER, save_errno, "open %s", full_fname(dest));
|
||||
close(ifd);
|
||||
errno = save_errno;
|
||||
return -1;
|
||||
@@ -1467,12 +1487,19 @@ const char *find_filename_suffix(const char *fn, int fn_len, int *len_ptr)
|
||||
|
||||
#define UNIT (1 << 16)
|
||||
|
||||
uint32 fuzzy_distance(const char *s1, unsigned len1, const char *s2, unsigned len2)
|
||||
uint32 fuzzy_distance(const char *s1, unsigned len1, const char *s2, unsigned len2, uint32 upperlimit)
|
||||
{
|
||||
uint32 a[MAXPATHLEN], diag, above, left, diag_inc, above_inc, left_inc;
|
||||
int32 cost;
|
||||
unsigned i1, i2;
|
||||
|
||||
/* Check to see if the Levenshtein distance must be greater than the
|
||||
* upper limit defined by the previously found lowest distance using
|
||||
* the heuristic that the Levenshtein distance is greater than the
|
||||
* difference in length of the two strings */
|
||||
if ((len1 > len2 ? len1 - len2 : len2 - len1) * UNIT > upperlimit)
|
||||
return 0xFFFFU * UNIT + 1;
|
||||
|
||||
if (!len1 || !len2) {
|
||||
if (!len1) {
|
||||
s1 = s2;
|
||||
|
||||
4
util2.c
4
util2.c
@@ -4,7 +4,7 @@
|
||||
* Copyright (C) 1996-2000 Andrew Tridgell
|
||||
* Copyright (C) 1996 Paul Mackerras
|
||||
* Copyright (C) 2001, 2002 Martin Pool <mbp@samba.org>
|
||||
* Copyright (C) 2003-2020 Wayne Davison
|
||||
* 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
|
||||
@@ -72,7 +72,7 @@ int msleep(int t)
|
||||
|
||||
void *my_alloc(void *ptr, size_t num, size_t size, const char *file, int line)
|
||||
{
|
||||
if (max_alloc && num >= max_alloc/size) {
|
||||
if (num >= max_alloc/size) {
|
||||
if (!file)
|
||||
return NULL;
|
||||
rprintf(FERROR, "[%s] exceeded --max-alloc=%s setting (file=%s, line=%d)\n",
|
||||
|
||||
@@ -1 +1,2 @@
|
||||
#define RSYNC_VERSION "3.2.4pre2"
|
||||
#define RSYNC_VERSION "3.3.0"
|
||||
#define MAINTAINER_TZ_OFFSET -7.0
|
||||
|
||||
43
xattrs.c
43
xattrs.c
@@ -39,9 +39,13 @@ extern int preserve_specials;
|
||||
extern int checksum_seed;
|
||||
extern int saw_xattr_filter;
|
||||
|
||||
extern struct name_num_item *xattr_sum_nni;
|
||||
extern int xattr_sum_len;
|
||||
|
||||
#define RSYNC_XAL_INITIAL 5
|
||||
#define RSYNC_XAL_LIST_INITIAL 100
|
||||
|
||||
#define MAX_XATTR_DIGEST_LEN MD5_DIGEST_LEN
|
||||
#define MAX_FULL_DATUM 32
|
||||
|
||||
#define HAS_PREFIX(str, prfx) (*(str) == *(prfx) && strncmp(str, prfx, sizeof (prfx) - 1) == 0)
|
||||
@@ -269,8 +273,8 @@ static int rsync_xal_get(const char *fname, item_list *xalp)
|
||||
|
||||
if (datum_len > MAX_FULL_DATUM) {
|
||||
/* For large datums, we store a flag and a checksum. */
|
||||
name_offset = 1 + MAX_DIGEST_LEN;
|
||||
sum_init(-1, checksum_seed);
|
||||
name_offset = 1 + MAX_XATTR_DIGEST_LEN;
|
||||
sum_init(xattr_sum_nni, checksum_seed);
|
||||
sum_update(ptr, datum_len);
|
||||
free(ptr);
|
||||
|
||||
@@ -377,20 +381,14 @@ static int64 xattr_lookup_hash(const item_list *xalp)
|
||||
{
|
||||
const rsync_xa *rxas = xalp->items;
|
||||
size_t i;
|
||||
int64 key = hashlittle(&xalp->count, sizeof xalp->count);
|
||||
int64 key = hashlittle2(&xalp->count, sizeof xalp->count);
|
||||
|
||||
for (i = 0; i < xalp->count; i++) {
|
||||
key += hashlittle(rxas[i].name, rxas[i].name_len);
|
||||
key += hashlittle2(rxas[i].name, rxas[i].name_len);
|
||||
if (rxas[i].datum_len > MAX_FULL_DATUM)
|
||||
key += hashlittle(rxas[i].datum, MAX_DIGEST_LEN);
|
||||
key += hashlittle2(rxas[i].datum, xattr_sum_len);
|
||||
else
|
||||
key += hashlittle(rxas[i].datum, rxas[i].datum_len);
|
||||
}
|
||||
|
||||
if (key == 0) {
|
||||
/* This is very unlikely, but we should never
|
||||
* return 0 as hashtable_find() doesn't like it. */
|
||||
return 1;
|
||||
key += hashlittle2(rxas[i].datum, rxas[i].datum_len);
|
||||
}
|
||||
|
||||
return key;
|
||||
@@ -435,7 +433,7 @@ static int find_matching_xattr(const item_list *xalp)
|
||||
if (rxas1[j].datum_len > MAX_FULL_DATUM) {
|
||||
if (memcmp(rxas1[j].datum + 1,
|
||||
rxas2[j].datum + 1,
|
||||
MAX_DIGEST_LEN) != 0)
|
||||
xattr_sum_len) != 0)
|
||||
break;
|
||||
} else {
|
||||
if (memcmp(rxas1[j].datum, rxas2[j].datum,
|
||||
@@ -471,8 +469,6 @@ static int rsync_xal_store(item_list *xalp)
|
||||
|
||||
if (rsync_xal_h == NULL)
|
||||
rsync_xal_h = hashtable_create(512, HT_KEY64);
|
||||
if (rsync_xal_h == NULL)
|
||||
out_of_memory("rsync_xal_h hashtable_create()");
|
||||
|
||||
new_ref = new0(rsync_xa_list_ref);
|
||||
new_ref->ndx = ndx;
|
||||
@@ -535,7 +531,7 @@ int send_xattr(int f, stat_x *sxp)
|
||||
#endif
|
||||
write_buf(f, name, name_len);
|
||||
if (rxa->datum_len > MAX_FULL_DATUM)
|
||||
write_buf(f, rxa->datum + 1, MAX_DIGEST_LEN);
|
||||
write_buf(f, rxa->datum + 1, xattr_sum_len);
|
||||
else
|
||||
write_bigbuf(f, rxa->datum, rxa->datum_len);
|
||||
}
|
||||
@@ -588,7 +584,7 @@ int xattr_diff(struct file_struct *file, stat_x *sxp, int find_all)
|
||||
else if (snd_rxa->datum_len > MAX_FULL_DATUM) {
|
||||
same = cmp == 0 && snd_rxa->datum_len == rec_rxa->datum_len
|
||||
&& memcmp(snd_rxa->datum + 1, rec_rxa->datum + 1,
|
||||
MAX_DIGEST_LEN) == 0;
|
||||
xattr_sum_len) == 0;
|
||||
/* Flag unrequested items that we need. */
|
||||
if (!same && find_all && snd_rxa->datum[0] == XSTATE_ABBREV)
|
||||
snd_rxa->datum[0] = XSTATE_TODO;
|
||||
@@ -797,7 +793,7 @@ void receive_xattr(int f, struct file_struct *file)
|
||||
rsync_xa *rxa;
|
||||
size_t name_len = read_varint(f);
|
||||
size_t datum_len = read_varint(f);
|
||||
size_t dget_len = datum_len > MAX_FULL_DATUM ? 1 + MAX_DIGEST_LEN : datum_len;
|
||||
size_t dget_len = datum_len > MAX_FULL_DATUM ? 1 + (size_t)xattr_sum_len : datum_len;
|
||||
size_t extra_len = MIGHT_NEED_RPRE ? RPRE_LEN : 0;
|
||||
if (SIZE_MAX - dget_len < extra_len || SIZE_MAX - dget_len - extra_len < name_len)
|
||||
overflow_exit("receive_xattr");
|
||||
@@ -812,7 +808,7 @@ void receive_xattr(int f, struct file_struct *file)
|
||||
read_buf(f, ptr, dget_len);
|
||||
else {
|
||||
*ptr = XSTATE_ABBREV;
|
||||
read_buf(f, ptr + 1, MAX_DIGEST_LEN);
|
||||
read_buf(f, ptr + 1, xattr_sum_len);
|
||||
}
|
||||
|
||||
if (saw_xattr_filter) {
|
||||
@@ -943,7 +939,7 @@ static int rsync_xal_set(const char *fname, item_list *xalp,
|
||||
rsync_xa *rxas = xalp->items;
|
||||
ssize_t list_len;
|
||||
size_t i, len;
|
||||
char *name, *ptr, sum[MAX_DIGEST_LEN];
|
||||
char *name, *ptr, sum[MAX_XATTR_DIGEST_LEN];
|
||||
#ifdef HAVE_LINUX_XATTRS
|
||||
int user_only = am_root <= 0;
|
||||
#endif
|
||||
@@ -958,7 +954,6 @@ static int rsync_xal_set(const char *fname, item_list *xalp,
|
||||
name = rxas[i].name;
|
||||
|
||||
if (XATTR_ABBREV(rxas[i])) {
|
||||
int sum_len;
|
||||
/* See if the fnamecmp version is identical. */
|
||||
len = name_len = rxas[i].name_len;
|
||||
if ((ptr = get_xattr_data(fnamecmp, name, &len, 1)) == NULL) {
|
||||
@@ -975,10 +970,10 @@ static int rsync_xal_set(const char *fname, item_list *xalp,
|
||||
goto still_abbrev;
|
||||
}
|
||||
|
||||
sum_init(-1, checksum_seed);
|
||||
sum_init(xattr_sum_nni, checksum_seed);
|
||||
sum_update(ptr, len);
|
||||
sum_len = sum_end(sum);
|
||||
if (memcmp(sum, rxas[i].datum + 1, sum_len) != 0) {
|
||||
sum_end(sum);
|
||||
if (memcmp(sum, rxas[i].datum + 1, xattr_sum_len) != 0) {
|
||||
free(ptr);
|
||||
goto still_abbrev;
|
||||
}
|
||||
|
||||
@@ -227,11 +227,6 @@ int ZEXPORT deflateInit2_(strm, level, method, windowBits, memLevel, strategy,
|
||||
int wrap = 1;
|
||||
static const char my_version[] = ZLIB_VERSION;
|
||||
|
||||
ushf *overlay;
|
||||
/* We overlay pending_buf and d_buf+l_buf. This works since the average
|
||||
* output size for (length,distance) codes is <= 24 bits.
|
||||
*/
|
||||
|
||||
if (version == Z_NULL || version[0] != my_version[0] ||
|
||||
stream_size != sizeof(z_stream)) {
|
||||
return Z_VERSION_ERROR;
|
||||
@@ -300,9 +295,47 @@ int ZEXPORT deflateInit2_(strm, level, method, windowBits, memLevel, strategy,
|
||||
|
||||
s->lit_bufsize = 1 << (memLevel + 6); /* 16K elements by default */
|
||||
|
||||
overlay = (ushf *) ZALLOC(strm, s->lit_bufsize, sizeof(ush)+2);
|
||||
s->pending_buf = (uchf *) overlay;
|
||||
s->pending_buf_size = (ulg)s->lit_bufsize * (sizeof(ush)+2L);
|
||||
/* We overlay pending_buf and sym_buf. This works since the average size
|
||||
* for length/distance pairs over any compressed block is assured to be 31
|
||||
* bits or less.
|
||||
*
|
||||
* Analysis: The longest fixed codes are a length code of 8 bits plus 5
|
||||
* extra bits, for lengths 131 to 257. The longest fixed distance codes are
|
||||
* 5 bits plus 13 extra bits, for distances 16385 to 32768. The longest
|
||||
* possible fixed-codes length/distance pair is then 31 bits total.
|
||||
*
|
||||
* sym_buf starts one-fourth of the way into pending_buf. So there are
|
||||
* three bytes in sym_buf for every four bytes in pending_buf. Each symbol
|
||||
* in sym_buf is three bytes -- two for the distance and one for the
|
||||
* literal/length. As each symbol is consumed, the pointer to the next
|
||||
* sym_buf value to read moves forward three bytes. From that symbol, up to
|
||||
* 31 bits are written to pending_buf. The closest the written pending_buf
|
||||
* bits gets to the next sym_buf symbol to read is just before the last
|
||||
* code is written. At that time, 31*(n-2) bits have been written, just
|
||||
* after 24*(n-2) bits have been consumed from sym_buf. sym_buf starts at
|
||||
* 8*n bits into pending_buf. (Note that the symbol buffer fills when n-1
|
||||
* symbols are written.) The closest the writing gets to what is unread is
|
||||
* then n+14 bits. Here n is lit_bufsize, which is 16384 by default, and
|
||||
* can range from 128 to 32768.
|
||||
*
|
||||
* Therefore, at a minimum, there are 142 bits of space between what is
|
||||
* written and what is read in the overlain buffers, so the symbols cannot
|
||||
* be overwritten by the compressed data. That space is actually 139 bits,
|
||||
* due to the three-bit fixed-code block header.
|
||||
*
|
||||
* That covers the case where either Z_FIXED is specified, forcing fixed
|
||||
* codes, or when the use of fixed codes is chosen, because that choice
|
||||
* results in a smaller compressed block than dynamic codes. That latter
|
||||
* condition then assures that the above analysis also covers all dynamic
|
||||
* blocks. A dynamic-code block will only be chosen to be emitted if it has
|
||||
* fewer bits than a fixed-code block would for the same set of symbols.
|
||||
* Therefore its average symbol length is assured to be less than 31. So
|
||||
* the compressed data for a dynamic block also cannot overwrite the
|
||||
* symbols from which it is being constructed.
|
||||
*/
|
||||
|
||||
s->pending_buf = (uchf *) ZALLOC(strm, s->lit_bufsize, 4);
|
||||
s->pending_buf_size = (ulg)s->lit_bufsize * 4;
|
||||
|
||||
if (s->window == Z_NULL || s->prev == Z_NULL || s->head == Z_NULL ||
|
||||
s->pending_buf == Z_NULL) {
|
||||
@@ -311,8 +344,12 @@ int ZEXPORT deflateInit2_(strm, level, method, windowBits, memLevel, strategy,
|
||||
deflateEnd (strm);
|
||||
return Z_MEM_ERROR;
|
||||
}
|
||||
s->d_buf = overlay + s->lit_bufsize/sizeof(ush);
|
||||
s->l_buf = s->pending_buf + (1+sizeof(ush))*s->lit_bufsize;
|
||||
s->sym_buf = s->pending_buf + s->lit_bufsize;
|
||||
s->sym_end = (s->lit_bufsize - 1) * 3;
|
||||
/* We avoid equality with lit_bufsize*3 because of wraparound at 64K
|
||||
* on 16 bit machines and because stored blocks are restricted to
|
||||
* 64K-1 bytes.
|
||||
*/
|
||||
|
||||
s->level = level;
|
||||
s->strategy = strategy;
|
||||
@@ -473,7 +510,7 @@ int ZEXPORT deflatePrime (strm, bits, value)
|
||||
|
||||
if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR;
|
||||
s = strm->state;
|
||||
if ((Bytef *)(s->d_buf) < s->pending_out + ((Buf_size + 7) >> 3))
|
||||
if (s->sym_buf < s->pending_out + ((Buf_size + 7) >> 3))
|
||||
return Z_BUF_ERROR;
|
||||
do {
|
||||
put = Buf_size - s->bi_valid;
|
||||
@@ -1022,7 +1059,6 @@ int ZEXPORT deflateCopy (dest, source)
|
||||
#else
|
||||
deflate_state *ds;
|
||||
deflate_state *ss;
|
||||
ushf *overlay;
|
||||
|
||||
|
||||
if (source == Z_NULL || dest == Z_NULL || source->state == Z_NULL) {
|
||||
@@ -1042,8 +1078,7 @@ int ZEXPORT deflateCopy (dest, source)
|
||||
ds->window = (Bytef *) ZALLOC(dest, ds->w_size, 2*sizeof(Byte));
|
||||
ds->prev = (Posf *) ZALLOC(dest, ds->w_size, sizeof(Pos));
|
||||
ds->head = (Posf *) ZALLOC(dest, ds->hash_size, sizeof(Pos));
|
||||
overlay = (ushf *) ZALLOC(dest, ds->lit_bufsize, sizeof(ush)+2);
|
||||
ds->pending_buf = (uchf *) overlay;
|
||||
ds->pending_buf = (uchf *) ZALLOC(dest, ds->lit_bufsize, 4);
|
||||
|
||||
if (ds->window == Z_NULL || ds->prev == Z_NULL || ds->head == Z_NULL ||
|
||||
ds->pending_buf == Z_NULL) {
|
||||
@@ -1057,8 +1092,7 @@ int ZEXPORT deflateCopy (dest, source)
|
||||
zmemcpy(ds->pending_buf, ss->pending_buf, (uInt)ds->pending_buf_size);
|
||||
|
||||
ds->pending_out = ds->pending_buf + (ss->pending_out - ss->pending_buf);
|
||||
ds->d_buf = overlay + ds->lit_bufsize/sizeof(ush);
|
||||
ds->l_buf = ds->pending_buf + (1+sizeof(ush))*ds->lit_bufsize;
|
||||
ds->sym_buf = ds->pending_buf + ds->lit_bufsize;
|
||||
|
||||
ds->l_desc.dyn_tree = ds->dyn_ltree;
|
||||
ds->d_desc.dyn_tree = ds->dyn_dtree;
|
||||
@@ -1737,7 +1771,7 @@ local block_state deflate_fast(s, flush)
|
||||
FLUSH_BLOCK(s, 1);
|
||||
return finish_done;
|
||||
}
|
||||
if (s->last_lit)
|
||||
if (s->sym_next)
|
||||
FLUSH_BLOCK(s, 0);
|
||||
return block_done;
|
||||
}
|
||||
@@ -1878,7 +1912,7 @@ local block_state deflate_slow(s, flush)
|
||||
FLUSH_BLOCK(s, 1);
|
||||
return finish_done;
|
||||
}
|
||||
if (s->last_lit)
|
||||
if (s->sym_next)
|
||||
FLUSH_BLOCK(s, 0);
|
||||
return block_done;
|
||||
}
|
||||
@@ -1953,7 +1987,7 @@ local block_state deflate_rle(s, flush)
|
||||
FLUSH_BLOCK(s, 1);
|
||||
return finish_done;
|
||||
}
|
||||
if (s->last_lit)
|
||||
if (s->sym_next)
|
||||
FLUSH_BLOCK(s, 0);
|
||||
return block_done;
|
||||
}
|
||||
@@ -1992,7 +2026,7 @@ local block_state deflate_huff(s, flush)
|
||||
FLUSH_BLOCK(s, 1);
|
||||
return finish_done;
|
||||
}
|
||||
if (s->last_lit)
|
||||
if (s->sym_next)
|
||||
FLUSH_BLOCK(s, 0);
|
||||
return block_done;
|
||||
}
|
||||
|
||||
@@ -214,7 +214,7 @@ typedef struct internal_state {
|
||||
/* Depth of each subtree used as tie breaker for trees of equal frequency
|
||||
*/
|
||||
|
||||
uchf *l_buf; /* buffer for literals or lengths */
|
||||
uchf *sym_buf; /* buffer for distances and literals/lengths */
|
||||
|
||||
uInt lit_bufsize;
|
||||
/* Size of match buffer for literals/lengths. There are 4 reasons for
|
||||
@@ -236,13 +236,8 @@ typedef struct internal_state {
|
||||
* - I can't count above 4
|
||||
*/
|
||||
|
||||
uInt last_lit; /* running index in l_buf */
|
||||
|
||||
ushf *d_buf;
|
||||
/* Buffer for distances. To simplify the code, d_buf and l_buf have
|
||||
* the same number of elements. To use different lengths, an extra flag
|
||||
* array would be necessary.
|
||||
*/
|
||||
uInt sym_next; /* running index in sym_buf */
|
||||
uInt sym_end; /* symbol table full when sym_next reaches this */
|
||||
|
||||
ulg opt_len; /* bit length of current block with optimal trees */
|
||||
ulg static_len; /* bit length of current block with static trees */
|
||||
@@ -322,20 +317,22 @@ void ZLIB_INTERNAL _tr_stored_block OF((deflate_state *s, charf *buf,
|
||||
|
||||
# define _tr_tally_lit(s, c, flush) \
|
||||
{ uch cc = (c); \
|
||||
s->d_buf[s->last_lit] = 0; \
|
||||
s->l_buf[s->last_lit++] = cc; \
|
||||
s->sym_buf[s->sym_next++] = 0; \
|
||||
s->sym_buf[s->sym_next++] = 0; \
|
||||
s->sym_buf[s->sym_next++] = cc; \
|
||||
s->dyn_ltree[cc].Freq++; \
|
||||
flush = (s->last_lit == s->lit_bufsize-1); \
|
||||
flush = (s->sym_next == s->sym_end); \
|
||||
}
|
||||
# define _tr_tally_dist(s, distance, length, flush) \
|
||||
{ uch len = (length); \
|
||||
ush dist = (distance); \
|
||||
s->d_buf[s->last_lit] = dist; \
|
||||
s->l_buf[s->last_lit++] = len; \
|
||||
s->sym_buf[s->sym_next++] = dist; \
|
||||
s->sym_buf[s->sym_next++] = dist >> 8; \
|
||||
s->sym_buf[s->sym_next++] = len; \
|
||||
dist--; \
|
||||
s->dyn_ltree[_length_code[len]+LITERALS+1].Freq++; \
|
||||
s->dyn_dtree[d_code(dist)].Freq++; \
|
||||
flush = (s->last_lit == s->lit_bufsize-1); \
|
||||
flush = (s->sym_next == s->sym_end); \
|
||||
}
|
||||
#else
|
||||
# define _tr_tally_lit(s, c, flush) flush = _tr_tally(s, 0, c)
|
||||
|
||||
@@ -740,8 +740,9 @@ int flush;
|
||||
if (copy > have) copy = have;
|
||||
if (copy) {
|
||||
if (state->head != Z_NULL &&
|
||||
state->head->extra != Z_NULL) {
|
||||
len = state->head->extra_len - state->length;
|
||||
state->head->extra != Z_NULL &&
|
||||
(len = state->head->extra_len - state->length) <
|
||||
state->head->extra_max) {
|
||||
zmemcpy(state->head->extra + len, next,
|
||||
len + copy > state->head->extra_max ?
|
||||
state->head->extra_max - len : copy);
|
||||
|
||||
50
zlib/trees.c
50
zlib/trees.c
@@ -418,7 +418,7 @@ local void init_block(s)
|
||||
|
||||
s->dyn_ltree[END_BLOCK].Freq = 1;
|
||||
s->opt_len = s->static_len = 0L;
|
||||
s->last_lit = s->matches = 0;
|
||||
s->sym_next = s->matches = 0;
|
||||
}
|
||||
|
||||
#define SMALLEST 1
|
||||
@@ -943,7 +943,7 @@ void ZLIB_INTERNAL _tr_flush_block(s, buf, stored_len, last)
|
||||
|
||||
Tracev((stderr, "\nopt %lu(%lu) stat %lu(%lu) stored %lu lit %u ",
|
||||
opt_lenb, s->opt_len, static_lenb, s->static_len, stored_len,
|
||||
s->last_lit));
|
||||
s->sym_next / 3));
|
||||
|
||||
if (static_lenb <= opt_lenb) opt_lenb = static_lenb;
|
||||
|
||||
@@ -1012,8 +1012,9 @@ int ZLIB_INTERNAL _tr_tally (s, dist, lc)
|
||||
unsigned dist; /* distance of matched string */
|
||||
unsigned lc; /* match length-MIN_MATCH or unmatched char (if dist==0) */
|
||||
{
|
||||
s->d_buf[s->last_lit] = (ush)dist;
|
||||
s->l_buf[s->last_lit++] = (uch)lc;
|
||||
s->sym_buf[s->sym_next++] = dist;
|
||||
s->sym_buf[s->sym_next++] = dist >> 8;
|
||||
s->sym_buf[s->sym_next++] = lc;
|
||||
if (dist == 0) {
|
||||
/* lc is the unmatched char */
|
||||
s->dyn_ltree[lc].Freq++;
|
||||
@@ -1028,30 +1029,7 @@ int ZLIB_INTERNAL _tr_tally (s, dist, lc)
|
||||
s->dyn_ltree[_length_code[lc]+LITERALS+1].Freq++;
|
||||
s->dyn_dtree[d_code(dist)].Freq++;
|
||||
}
|
||||
|
||||
#ifdef TRUNCATE_BLOCK
|
||||
/* Try to guess if it is profitable to stop the current block here */
|
||||
if ((s->last_lit & 0x1fff) == 0 && s->level > 2) {
|
||||
/* Compute an upper bound for the compressed length */
|
||||
ulg out_length = (ulg)s->last_lit*8L;
|
||||
ulg in_length = (ulg)((long)s->strstart - s->block_start);
|
||||
int dcode;
|
||||
for (dcode = 0; dcode < D_CODES; dcode++) {
|
||||
out_length += (ulg)s->dyn_dtree[dcode].Freq *
|
||||
(5L+extra_dbits[dcode]);
|
||||
}
|
||||
out_length >>= 3;
|
||||
Tracev((stderr,"\nlast_lit %u, in %ld, out ~%ld(%ld%%) ",
|
||||
s->last_lit, in_length, out_length,
|
||||
100L - out_length*100L/in_length));
|
||||
if (s->matches < s->last_lit/2 && out_length < in_length/2) return 1;
|
||||
}
|
||||
#endif
|
||||
return (s->last_lit == s->lit_bufsize-1);
|
||||
/* We avoid equality with lit_bufsize because of wraparound at 64K
|
||||
* on 16 bit machines and because stored blocks are restricted to
|
||||
* 64K-1 bytes.
|
||||
*/
|
||||
return (s->sym_next == s->sym_end);
|
||||
}
|
||||
|
||||
/* ===========================================================================
|
||||
@@ -1064,13 +1042,14 @@ local void compress_block(s, ltree, dtree)
|
||||
{
|
||||
unsigned dist; /* distance of matched string */
|
||||
int lc; /* match length or unmatched char (if dist == 0) */
|
||||
unsigned lx = 0; /* running index in l_buf */
|
||||
unsigned sx = 0; /* running index in sym_buf */
|
||||
unsigned code; /* the code to send */
|
||||
int extra; /* number of extra bits to send */
|
||||
|
||||
if (s->last_lit != 0) do {
|
||||
dist = s->d_buf[lx];
|
||||
lc = s->l_buf[lx++];
|
||||
if (s->sym_next != 0) do {
|
||||
dist = s->sym_buf[sx++] & 0xff;
|
||||
dist += (unsigned)(s->sym_buf[sx++] & 0xff) << 8;
|
||||
lc = s->sym_buf[sx++];
|
||||
if (dist == 0) {
|
||||
send_code(s, lc, ltree); /* send a literal byte */
|
||||
Tracecv(isgraph(lc), (stderr," '%c' ", lc));
|
||||
@@ -1095,11 +1074,10 @@ local void compress_block(s, ltree, dtree)
|
||||
}
|
||||
} /* literal or match pair ? */
|
||||
|
||||
/* Check that the overlay between pending_buf and d_buf+l_buf is ok: */
|
||||
Assert((uInt)(s->pending) < s->lit_bufsize + 2*lx,
|
||||
"pendingBuf overflow");
|
||||
/* Check that the overlay between pending_buf and sym_buf is ok: */
|
||||
Assert(s->pending < s->lit_bufsize + sx, "pendingBuf overflow");
|
||||
|
||||
} while (lx < s->last_lit);
|
||||
} while (sx < s->sym_next);
|
||||
|
||||
send_code(s, END_BLOCK, ltree);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user