mirror of
https://github.com/RsyncProject/rsync.git
synced 2026-05-25 07:15:35 -04:00
Compare commits
384 Commits
v3.1.1pre2
...
v3.2.0pre2
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
6f0c56304f | ||
|
|
2452ad3663 | ||
|
|
1fa38546a0 | ||
|
|
249e28c75a | ||
|
|
6273153c5f | ||
|
|
628dcceb8d | ||
|
|
00ec415a69 | ||
|
|
ec8035cef9 | ||
|
|
775f64f4b8 | ||
|
|
660274bfb7 | ||
|
|
59cf9ff797 | ||
|
|
ff272503b0 | ||
|
|
43a939e3f2 | ||
|
|
b65b6db304 | ||
|
|
7b1f8f57c3 | ||
|
|
c32012d199 | ||
|
|
9ba6ce1b67 | ||
|
|
ca9e247762 | ||
|
|
f27a630e46 | ||
|
|
243a9d9be0 | ||
|
|
c528f8d5c8 | ||
|
|
1d1c0f14e1 | ||
|
|
e63ff70eae | ||
|
|
8a70f1420b | ||
|
|
cdf58a7aba | ||
|
|
1d6c9676f9 | ||
|
|
3d29fa99ec | ||
|
|
d167935874 | ||
|
|
d326961290 | ||
|
|
7dec4029ee | ||
|
|
ab0189c813 | ||
|
|
bb484a799e | ||
|
|
ad9f1571ce | ||
|
|
f800557824 | ||
|
|
13f81f4aa7 | ||
|
|
d3ae752c53 | ||
|
|
e3437244b5 | ||
|
|
1efeb59166 | ||
|
|
d4fc18f375 | ||
|
|
58680edb12 | ||
|
|
34141954c7 | ||
|
|
cba00be622 | ||
|
|
de78dd685b | ||
|
|
88abb50229 | ||
|
|
6d6b8595df | ||
|
|
66bd4774a8 | ||
|
|
c117fa4bf9 | ||
|
|
b040825b86 | ||
|
|
3c793ef153 | ||
|
|
cff0764b7f | ||
|
|
a3377921eb | ||
|
|
a61ffbafe5 | ||
|
|
190b474610 | ||
|
|
85e90b0f80 | ||
|
|
516ca6a442 | ||
|
|
fe993ca94d | ||
|
|
f8683063fb | ||
|
|
7c83eb6e63 | ||
|
|
58e8ecf48f | ||
|
|
c5e44330a5 | ||
|
|
ae82762c31 | ||
|
|
2ac7401b44 | ||
|
|
44af79223e | ||
|
|
03fc62ad2f | ||
|
|
68c865c9e6 | ||
|
|
6dc94e39a7 | ||
|
|
8146b04ffb | ||
|
|
5b19cf7875 | ||
|
|
53fae55652 | ||
|
|
bd66a92e7c | ||
|
|
165ef61de3 | ||
|
|
7dbbde8c5e | ||
|
|
888f4f9503 | ||
|
|
2c6f0581ac | ||
|
|
916faecb83 | ||
|
|
5d7b71b7a7 | ||
|
|
0dde65a26b | ||
|
|
b177311aee | ||
|
|
778f0dff9b | ||
|
|
342579aa6f | ||
|
|
01b9bbb0f9 | ||
|
|
852a0b29c3 | ||
|
|
55290c8584 | ||
|
|
e633091d23 | ||
|
|
4c9fdb9f74 | ||
|
|
e0d30a22d7 | ||
|
|
42ec4e3090 | ||
|
|
3735002751 | ||
|
|
d47a80c05e | ||
|
|
9dd9952138 | ||
|
|
71c4ae2336 | ||
|
|
c0268d9217 | ||
|
|
da448cdc99 | ||
|
|
d619a87aa5 | ||
|
|
a931301bef | ||
|
|
265b0bc9bb | ||
|
|
13f249a826 | ||
|
|
c66e08acb3 | ||
|
|
f5446552f3 | ||
|
|
364d302bca | ||
|
|
60e71c1b8b | ||
|
|
342921eb97 | ||
|
|
df0ed76a76 | ||
|
|
d7521f5428 | ||
|
|
c7f10de442 | ||
|
|
f60bd811e9 | ||
|
|
cd0637a953 | ||
|
|
8809f65b13 | ||
|
|
c906619620 | ||
|
|
5710d2fe2e | ||
|
|
32fe5fbc11 | ||
|
|
bcb0a24a8f | ||
|
|
96ed96dabd | ||
|
|
8ad2ca9ae2 | ||
|
|
23a37ecac4 | ||
|
|
47bae3abf6 | ||
|
|
dff9dd56a0 | ||
|
|
7182508a75 | ||
|
|
cb0fe9e195 | ||
|
|
87f2984df0 | ||
|
|
24ce3e9d54 | ||
|
|
98cddfaf7a | ||
|
|
d1fcb8ce9d | ||
|
|
b4ace35304 | ||
|
|
888ce058d8 | ||
|
|
c394e86184 | ||
|
|
4aaadc2f29 | ||
|
|
abef92c037 | ||
|
|
87019d7721 | ||
|
|
fc265c5a92 | ||
|
|
d999efe6e5 | ||
|
|
97e8c55ee8 | ||
|
|
739fa96737 | ||
|
|
d474f2986e | ||
|
|
a863c62cd1 | ||
|
|
5ac353d845 | ||
|
|
faecd066a6 | ||
|
|
6efc43cc0a | ||
|
|
4496e0e8e7 | ||
|
|
64d5ea39c0 | ||
|
|
4af8403aa2 | ||
|
|
2f84a6bd73 | ||
|
|
eda15d52a8 | ||
|
|
741d5f10c6 | ||
|
|
4f92fd8ddd | ||
|
|
7f2359a5cc | ||
|
|
6e942e5898 | ||
|
|
1c9bb168bb | ||
|
|
799de21af6 | ||
|
|
1cb1edeb68 | ||
|
|
15c1162b24 | ||
|
|
a7175ee029 | ||
|
|
68516f91be | ||
|
|
531ffa8104 | ||
|
|
d7212df0f1 | ||
|
|
a28bc3ebf6 | ||
|
|
55bb4dab7a | ||
|
|
5fa4209ca0 | ||
|
|
4f6c8c6652 | ||
|
|
a7303a3d3d | ||
|
|
70c6b408dc | ||
|
|
be7af36c51 | ||
|
|
3b36bde953 | ||
|
|
c3986d4c5a | ||
|
|
b3a1a0ca9d | ||
|
|
e448d31d63 | ||
|
|
37de48979e | ||
|
|
08f955e17b | ||
|
|
3435ae9bd0 | ||
|
|
7a9295778c | ||
|
|
f7746d0000 | ||
|
|
96a6ea0f26 | ||
|
|
6242786158 | ||
|
|
b430ceec7a | ||
|
|
3a7bf54ad5 | ||
|
|
c1cb307b4b | ||
|
|
af6118d98b | ||
|
|
ea3337a210 | ||
|
|
035a13f7e4 | ||
|
|
f14adfd75e | ||
|
|
d218be3482 | ||
|
|
f4c077e85e | ||
|
|
1c7785ab1e | ||
|
|
87257f869c | ||
|
|
b936741032 | ||
|
|
2b2a3c87b6 | ||
|
|
6e962ac51e | ||
|
|
991ab811cb | ||
|
|
3249824264 | ||
|
|
1c465dc33a | ||
|
|
2a87d78f69 | ||
|
|
3ba4db7030 | ||
|
|
d29702134a | ||
|
|
1c82a1e1e5 | ||
|
|
2d0c7adba9 | ||
|
|
0b4b31a960 | ||
|
|
8a21e5a8c6 | ||
|
|
fa9c8d04d4 | ||
|
|
c5fabfb068 | ||
|
|
e2aee6c4af | ||
|
|
2598ca668b | ||
|
|
cd7ad50bc8 | ||
|
|
5e4a1441cb | ||
|
|
9dea2ae87c | ||
|
|
795268bb7c | ||
|
|
70cbc66b7f | ||
|
|
b63276e70f | ||
|
|
b0c03e2be9 | ||
|
|
8475e0e492 | ||
|
|
7f06cc7ed0 | ||
|
|
10d40508e6 | ||
|
|
daf8f7a669 | ||
|
|
15fa9ab06d | ||
|
|
7e70e4842b | ||
|
|
9e9d33a2db | ||
|
|
b32aa4797d | ||
|
|
826ddc5403 | ||
|
|
3bd4e1e8cd | ||
|
|
51e23e0ab7 | ||
|
|
08650cb14c | ||
|
|
24c28cd715 | ||
|
|
c0c6a97c35 | ||
|
|
d47d379216 | ||
|
|
eb1b138ec2 | ||
|
|
13f596433b | ||
|
|
3fe4469bfa | ||
|
|
8eb50bce43 | ||
|
|
fc10fafa25 | ||
|
|
efcbec3df5 | ||
|
|
3e2e4b5a33 | ||
|
|
79332c0d66 | ||
|
|
bdfc296faf | ||
|
|
2ad1c4e800 | ||
|
|
0da7ba57b5 | ||
|
|
b3d12c5a3d | ||
|
|
bc7402aa3a | ||
|
|
f233dffbd6 | ||
|
|
c2da3809f7 | ||
|
|
48346c878f | ||
|
|
a0274c08b5 | ||
|
|
f627e27749 | ||
|
|
0b6cae6792 | ||
|
|
e5610f1877 | ||
|
|
c376170644 | ||
|
|
48163179eb | ||
|
|
b4c1b27e03 | ||
|
|
c90b87e021 | ||
|
|
ad17b21889 | ||
|
|
a366868535 | ||
|
|
f55d35c5a0 | ||
|
|
6af8e11450 | ||
|
|
1a288c06d9 | ||
|
|
4aeb093206 | ||
|
|
1eb7a7061a | ||
|
|
eec6ab7615 | ||
|
|
5df9847f06 | ||
|
|
fb7a162f53 | ||
|
|
d73762eea3 | ||
|
|
d58405a353 | ||
|
|
0f8e9e2d86 | ||
|
|
c4a3f55be3 | ||
|
|
473108ae6e | ||
|
|
e401959b89 | ||
|
|
7706303828 | ||
|
|
f5e8a17e09 | ||
|
|
5509597dec | ||
|
|
70aeb5fddd | ||
|
|
3e06d40029 | ||
|
|
416e719bea | ||
|
|
9f5dc9309d | ||
|
|
b984e9dbd4 | ||
|
|
c60d9fcab1 | ||
|
|
47a63d90e7 | ||
|
|
bc112b0e7f | ||
|
|
8a82feeb7c | ||
|
|
0350f95e7b | ||
|
|
9a480deec4 | ||
|
|
c252546cee | ||
|
|
7b8a4ecd6f | ||
|
|
17b849c97a | ||
|
|
276a9836bd | ||
|
|
c140b2e749 | ||
|
|
b547302943 | ||
|
|
136c6c7734 | ||
|
|
3fb1634f21 | ||
|
|
881addc9e1 | ||
|
|
b7799aaefe | ||
|
|
ce854cf021 | ||
|
|
9e7b8ab7cf | ||
|
|
87bc224011 | ||
|
|
a4e8b552d6 | ||
|
|
62652202c4 | ||
|
|
001adf5096 | ||
|
|
ff66fd4bb6 | ||
|
|
e02b89d0d3 | ||
|
|
d1a1fec134 | ||
|
|
f3873b3d88 | ||
|
|
6e3b2102bc | ||
|
|
cc29b94d0f | ||
|
|
6eb71beaff | ||
|
|
39d7e3ec25 | ||
|
|
ac97bc14f6 | ||
|
|
31e93c3228 | ||
|
|
a720d81d0a | ||
|
|
359758d611 | ||
|
|
1f83b51d71 | ||
|
|
a5a7d3a297 | ||
|
|
4fc78878e0 | ||
|
|
b973bffa94 | ||
|
|
d1c80404fe | ||
|
|
9a12959ab6 | ||
|
|
070c810e2d | ||
|
|
71ec4609eb | ||
|
|
0f7db203fb | ||
|
|
4e25abc9a9 | ||
|
|
839dbff2aa | ||
|
|
f6f5ea4173 | ||
|
|
9a37d9cb1e | ||
|
|
16b49716d5 | ||
|
|
58faa1e8b9 | ||
|
|
9250e9ac23 | ||
|
|
3623d94fe7 | ||
|
|
cbc42b9c16 | ||
|
|
6ff5824c25 | ||
|
|
32de6b7cb4 | ||
|
|
bb853b3205 | ||
|
|
cce44865c1 | ||
|
|
1983198097 | ||
|
|
2a7355fb56 | ||
|
|
3da1dc4d18 | ||
|
|
abfb41e63e | ||
|
|
9d1cd2437c | ||
|
|
f8d2ecd223 | ||
|
|
453914e35b | ||
|
|
3f26e38f86 | ||
|
|
81d1ca0683 | ||
|
|
289ccbd02f | ||
|
|
85d3877be9 | ||
|
|
e203245d76 | ||
|
|
dfbcc4f7ec | ||
|
|
0bcb8b639a | ||
|
|
77f750f167 | ||
|
|
23afe20780 | ||
|
|
e12a6c087c | ||
|
|
6feb7d37df | ||
|
|
81ff413bb0 | ||
|
|
eac858085e | ||
|
|
2ac35b4507 | ||
|
|
3bc319766d | ||
|
|
a689fb1f5f | ||
|
|
b560a96b2c | ||
|
|
51e3c3da85 | ||
|
|
461086bbe7 | ||
|
|
00694610a6 | ||
|
|
8e3a6db842 | ||
|
|
8354cad53e | ||
|
|
317a0e8ca5 | ||
|
|
066ad8c719 | ||
|
|
ec4f644d2f | ||
|
|
4bf342c60f | ||
|
|
a2f733c664 | ||
|
|
3ea74eb388 | ||
|
|
962f8b9004 | ||
|
|
ae189e18de | ||
|
|
5b34561cf7 | ||
|
|
5546dab329 | ||
|
|
6128f56694 | ||
|
|
743f5a30d5 | ||
|
|
a955e93316 | ||
|
|
aca7dd3bff | ||
|
|
bc55aa04df | ||
|
|
f438d5abe0 | ||
|
|
6fe798392b | ||
|
|
6ceb9ea012 | ||
|
|
6900d35cce | ||
|
|
7cb0de6326 | ||
|
|
61e74afc42 | ||
|
|
0466e46b9f | ||
|
|
aa4c6db043 | ||
|
|
edb0d9c792 | ||
|
|
6ffd8f2169 | ||
|
|
ba43e88527 | ||
|
|
ff08acd4f2 | ||
|
|
03bb593f81 |
31
.github/workflows/ccpp.yml
vendored
Normal file
31
.github/workflows/ccpp.yml
vendored
Normal file
@@ -0,0 +1,31 @@
|
||||
name: C CI
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [ master ]
|
||||
pull_request:
|
||||
branches: [ master ]
|
||||
|
||||
jobs:
|
||||
build:
|
||||
|
||||
runs-on: ubuntu-20.04
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- name: prepare-packages
|
||||
run: sudo apt-get install fakeroot acl libacl1-dev attr libattr1-dev liblz4-dev libzstd-dev libxxhash-dev python3-cmarkgfm
|
||||
- name: prepare-source
|
||||
run: ./prepare-source
|
||||
- name: configure
|
||||
run: ./configure --with-included-popt --with-protected-args --with-included-zlib --enable-simd
|
||||
- name: make
|
||||
run: make
|
||||
- name: version-summary
|
||||
run: ./rsync --version
|
||||
- name: make check
|
||||
run: make check
|
||||
- name: make check30
|
||||
run: make check30
|
||||
- name: make check29
|
||||
run: make check29
|
||||
12
.gitignore
vendored
12
.gitignore
vendored
@@ -12,10 +12,14 @@ config.h.in
|
||||
config.h.in.old
|
||||
config.log
|
||||
config.status
|
||||
aclocal.m4
|
||||
/proto.h
|
||||
/proto.h-tstamp
|
||||
/rsync.1
|
||||
/rsyncd.conf.5
|
||||
/rsync*.1
|
||||
/rsync*.5
|
||||
/rsync*.html
|
||||
/help-rsync*.h
|
||||
/.md2man-works
|
||||
/autom4te*.cache
|
||||
/confdefs.h
|
||||
/conftest*
|
||||
@@ -23,8 +27,6 @@ config.status
|
||||
/getgroups
|
||||
/gmon.out
|
||||
/rsync
|
||||
/rsync-ssl
|
||||
/stunnel-rsync
|
||||
/stunnel-rsyncd.conf
|
||||
/shconfig
|
||||
/testdir
|
||||
@@ -44,3 +46,5 @@ config.status
|
||||
/testsuite/devices-fake.test
|
||||
/testsuite/xattrs-hlink.test
|
||||
/patches
|
||||
/SaVeDiR
|
||||
.deps
|
||||
|
||||
9
COPYING
9
COPYING
@@ -672,3 +672,12 @@ may consider it more useful to permit linking proprietary applications with
|
||||
the library. If this is what you want to do, use the GNU Lesser General
|
||||
Public License instead of this License. But first, please read
|
||||
<http://www.gnu.org/philosophy/why-not-lgpl.html>.
|
||||
|
||||
REGARDING OPENSSL AND XXHASH
|
||||
|
||||
In addition, as a special exception, the copyright holders give
|
||||
permission to dynamically link rsync with the OpenSSL and xxhash
|
||||
libraries when those libraries are being distributed in compliance
|
||||
with their license terms, and to distribute a dynamically linked
|
||||
combination of rsync and these libraries. This is also considered
|
||||
to be covered under the GPL's System Libraries exception.
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
To build and install rsync:
|
||||
|
||||
$ ./configure
|
||||
$ make
|
||||
# make install
|
||||
$ ./configure
|
||||
$ make
|
||||
# make install
|
||||
|
||||
You may set the installation directory and other parameters by options
|
||||
to ./configure. To see them, use:
|
||||
|
||||
$ ./configure --help
|
||||
$ ./configure --help
|
||||
|
||||
Configure tries to figure out if the local system uses group "nobody" or
|
||||
"nogroup" by looking in the /etc/group file. (This is only used for the
|
||||
114
Makefile.in
114
Makefile.in
@@ -4,16 +4,19 @@
|
||||
prefix=@prefix@
|
||||
datarootdir=@datarootdir@
|
||||
exec_prefix=@exec_prefix@
|
||||
stunnel4=@STUNNEL4@
|
||||
bindir=@bindir@
|
||||
libdir=@libdir@/rsync
|
||||
mandir=@mandir@
|
||||
|
||||
LIBS=@LIBS@
|
||||
CC=@CC@
|
||||
CFLAGS=@CFLAGS@
|
||||
CPPFLAGS=@CPPFLAGS@
|
||||
CXX=@CXX@
|
||||
CXXFLAGS=@CXXFLAGS@
|
||||
EXEEXT=@EXEEXT@
|
||||
LDFLAGS=@LDFLAGS@
|
||||
LIBOBJDIR=lib/
|
||||
|
||||
INSTALLCMD=@INSTALL@
|
||||
INSTALLMAN=@INSTALL@
|
||||
@@ -28,7 +31,10 @@ VERSION=@RSYNC_VERSION@
|
||||
.SUFFIXES:
|
||||
.SUFFIXES: .c .o
|
||||
|
||||
GENFILES=configure.sh config.h.in proto.h proto.h-tstamp rsync.1 rsyncd.conf.5
|
||||
SIMD_x86_64=simd-checksum-x86_64.o lib/md5-asm-x86_64.o
|
||||
|
||||
GENFILES=configure.sh aclocal.m4 config.h.in proto.h proto.h-tstamp rsync.1 rsync.1.html \
|
||||
rsync-ssl.1 rsync-ssl.1.html rsyncd.conf.5 rsyncd.conf.5.html
|
||||
HEADERS=byteorder.h config.h errcode.h proto.h rsync.h ifuncs.h itypes.h inums.h \
|
||||
lib/pool_alloc.h
|
||||
LIBOBJ=lib/wildmatch.o lib/compat.o lib/snprintf.o lib/mdfour.o lib/md5.o \
|
||||
@@ -43,9 +49,9 @@ OBJS3=progress.o pipe.o
|
||||
DAEMON_OBJ = params.o loadparm.o clientserver.o access.o connection.o authenticate.o
|
||||
popt_OBJS=popt/findme.o popt/popt.o popt/poptconfig.o \
|
||||
popt/popthelp.o popt/poptparse.o
|
||||
OBJS=$(OBJS1) $(OBJS2) $(OBJS3) $(DAEMON_OBJ) $(LIBOBJ) @BUILD_ZLIB@ @BUILD_POPT@
|
||||
OBJS=$(OBJS1) $(OBJS2) $(OBJS3) @SIMD@ $(DAEMON_OBJ) $(LIBOBJ) @BUILD_ZLIB@ @BUILD_POPT@
|
||||
|
||||
TLS_OBJ = tls.o syscall.o lib/compat.o lib/snprintf.o lib/permstring.o lib/sysxattrs.o @BUILD_POPT@
|
||||
TLS_OBJ = tls.o syscall.o t_stub.o lib/compat.o lib/snprintf.o lib/permstring.o lib/sysxattrs.o @BUILD_POPT@
|
||||
|
||||
# Programs we must have to run the test cases
|
||||
CHECK_PROGS = rsync$(EXEEXT) tls$(EXEEXT) getgroups$(EXEEXT) getfsdev$(EXEEXT) \
|
||||
@@ -62,24 +68,23 @@ CHECK_OBJS=tls.o testrun.o getgroups.o getfsdev.o t_stub.o t_unsafe.o trimslash.
|
||||
$(CC) -I. -I$(srcdir) $(CFLAGS) $(CPPFLAGS) -c $< @CC_SHOBJ_FLAG@
|
||||
@OBJ_RESTORE@
|
||||
|
||||
all: Makefile rsync$(EXEEXT) rsync-ssl stunnel-rsync stunnel-rsyncd.conf @MAKE_MAN@
|
||||
.PHONY: all
|
||||
all: Makefile rsync$(EXEEXT) stunnel-rsyncd.conf man
|
||||
|
||||
.PHONY: install
|
||||
install: all
|
||||
-${MKDIR_P} ${DESTDIR}${bindir}
|
||||
${INSTALLCMD} ${INSTALL_STRIP} -m 755 rsync$(EXEEXT) ${DESTDIR}${bindir}
|
||||
${INSTALLCMD} -m 755 rsync-ssl ${DESTDIR}${bindir}
|
||||
-${MKDIR_P} ${DESTDIR}${mandir}/man1
|
||||
-${MKDIR_P} ${DESTDIR}${mandir}/man5
|
||||
if test -f rsync.1; then ${INSTALLMAN} -m 644 rsync.1 ${DESTDIR}${mandir}/man1; fi
|
||||
if test -f rsync-ssl.1; then ${INSTALLMAN} -m 644 rsync-ssl.1 ${DESTDIR}${mandir}/man1; fi
|
||||
if test -f rsyncd.conf.5; then ${INSTALLMAN} -m 644 rsyncd.conf.5 ${DESTDIR}${mandir}/man5; fi
|
||||
|
||||
install-ssl-client: rsync-ssl stunnel-rsync
|
||||
-${MKDIR_P} ${DESTDIR}${bindir}
|
||||
${INSTALLCMD} ${INSTALL_STRIP} -m 755 rsync-ssl ${DESTDIR}${bindir}
|
||||
${INSTALLCMD} ${INSTALL_STRIP} -m 755 stunnel-rsync ${DESTDIR}${bindir}
|
||||
|
||||
install-ssl-daemon: stunnel-rsyncd.conf
|
||||
-${MKDIR_P} ${DESTDIR}/etc/stunnel
|
||||
${INSTALLCMD} ${INSTALL_STRIP} -m 644 stunnel-rsyncd.conf ${DESTDIR}/etc/stunnel/rsyncd.conf
|
||||
${INSTALLCMD} -m 644 stunnel-rsyncd.conf ${DESTDIR}/etc/stunnel/rsyncd.conf
|
||||
@if ! ls /etc/rsync-ssl/certs/server.* >/dev/null 2>/dev/null; then \
|
||||
echo "Note that you'll need to install the certificate used by /etc/stunnel/rsyncd.conf"; \
|
||||
fi
|
||||
@@ -94,10 +99,14 @@ rsync$(EXEEXT): $(OBJS)
|
||||
|
||||
$(OBJS): $(HEADERS)
|
||||
$(CHECK_OBJS): $(HEADERS)
|
||||
options.o: latest-year.h help-rsync.h help-rsyncd.h
|
||||
|
||||
flist.o: rounding.h
|
||||
|
||||
rounding.h: rounding.c rsync.h
|
||||
help-rsync.h help-rsyncd.h: rsync.1.md
|
||||
./help-from-md "$(srcdir)/$<" $@
|
||||
|
||||
rounding.h: rounding.c rsync.h proto.h
|
||||
@for r in 0 1 3; do \
|
||||
if $(CC) $(CFLAGS) $(CPPFLAGS) $(LDFLAGS) -o rounding -DEXTRA_ROUNDING=$$r -I. $(srcdir)/rounding.c >rounding.out 2>&1; then \
|
||||
echo "#define EXTRA_ROUNDING $$r" >rounding.h; \
|
||||
@@ -115,6 +124,12 @@ rounding.h: rounding.c rsync.h
|
||||
fi
|
||||
@rm -f rounding.out
|
||||
|
||||
simd-checksum-x86_64.o: simd-checksum-x86_64.cpp
|
||||
$(CXX) $(CXXFLAGS) $(CPPFLAGS) -c -o $@ $<
|
||||
|
||||
lib/md5-asm-x86_64.o: lib/md5-asm-x86_64.s
|
||||
$(CC) -c -o $@ $<
|
||||
|
||||
tls$(EXEEXT): $(TLS_OBJ)
|
||||
$(CC) $(CFLAGS) $(LDFLAGS) -o $@ $(TLS_OBJ) $(LIBS)
|
||||
|
||||
@@ -127,7 +142,7 @@ getgroups$(EXEEXT): getgroups.o
|
||||
getfsdev$(EXEEXT): getfsdev.o
|
||||
$(CC) $(CFLAGS) $(LDFLAGS) -o $@ getfsdev.o $(LIBS)
|
||||
|
||||
TRIMSLASH_OBJ = trimslash.o syscall.o lib/compat.o lib/snprintf.o
|
||||
TRIMSLASH_OBJ = trimslash.o syscall.o t_stub.o lib/compat.o lib/snprintf.o
|
||||
trimslash$(EXEEXT): $(TRIMSLASH_OBJ)
|
||||
$(CC) $(CFLAGS) $(LDFLAGS) -o $@ $(TRIMSLASH_OBJ) $(LIBS)
|
||||
|
||||
@@ -135,13 +150,18 @@ T_UNSAFE_OBJ = t_unsafe.o syscall.o util.o util2.o t_stub.o lib/compat.o lib/snp
|
||||
t_unsafe$(EXEEXT): $(T_UNSAFE_OBJ)
|
||||
$(CC) $(CFLAGS) $(LDFLAGS) -o $@ $(T_UNSAFE_OBJ) $(LIBS)
|
||||
|
||||
.PHONY: conf
|
||||
conf: configure.sh config.h.in
|
||||
|
||||
.PHONY: gen
|
||||
gen: conf proto.h man
|
||||
|
||||
.PHONY: gensend
|
||||
gensend: gen
|
||||
rsync -aivzc $(GENFILES) samba.org:/home/ftp/pub/rsync/generated-files/
|
||||
rsync -aic $(GENFILES) $${SAMBA_HOST-samba.org}:/home/ftp/pub/rsync/generated-files/
|
||||
|
||||
conf:
|
||||
cd $(srcdir) && $(MAKE) -f prepare-source.mak conf
|
||||
aclocal.m4: $(srcdir)/m4/*.m4
|
||||
aclocal -I $(srcdir)/m4
|
||||
|
||||
configure.sh config.h.in: configure.ac aclocal.m4
|
||||
@if test -f configure.sh; then cp -p configure.sh configure.sh.old; else touch configure.sh.old; fi
|
||||
@@ -170,6 +190,7 @@ configure.sh config.h.in: configure.ac aclocal.m4
|
||||
fi \
|
||||
fi
|
||||
|
||||
.PHONY: reconfigure
|
||||
reconfigure: configure.sh
|
||||
./config.status --recheck
|
||||
./config.status
|
||||
@@ -189,52 +210,46 @@ Makefile: Makefile.in config.status configure.sh config.h.in
|
||||
fi \
|
||||
fi
|
||||
|
||||
rsync-ssl: $(srcdir)/rsync-ssl.in Makefile
|
||||
sed 's;\@bindir\@;$(bindir);g' <$(srcdir)/rsync-ssl.in >rsync-ssl
|
||||
@chmod +x rsync-ssl
|
||||
|
||||
stunnel-rsync: $(srcdir)/stunnel-rsync.in Makefile
|
||||
sed 's;\@stunnel4\@;$(stunnel4);g' <$(srcdir)/stunnel-rsync.in >stunnel-rsync
|
||||
@chmod +x stunnel-rsync
|
||||
|
||||
stunnel-rsyncd.conf: $(srcdir)/stunnel-rsyncd.conf.in Makefile
|
||||
sed 's;\@bindir\@;$(bindir);g' <$(srcdir)/stunnel-rsyncd.conf.in >stunnel-rsyncd.conf
|
||||
|
||||
.PHONY: proto
|
||||
proto: proto.h-tstamp
|
||||
|
||||
proto.h: proto.h-tstamp
|
||||
@if test -f proto.h; then :; else cp -p $(srcdir)/proto.h .; fi
|
||||
|
||||
proto.h-tstamp: $(srcdir)/*.c $(srcdir)/lib/compat.c config.h
|
||||
perl $(srcdir)/mkproto.pl $(srcdir)/*.c $(srcdir)/lib/compat.c
|
||||
awk -f $(srcdir)/mkproto.awk $(srcdir)/*.c $(srcdir)/lib/compat.c
|
||||
|
||||
man: rsync.1 rsyncd.conf.5 man-copy
|
||||
.PHONY: man
|
||||
man: rsync.1 rsync-ssl.1 rsyncd.conf.5
|
||||
|
||||
man-copy:
|
||||
@-if test -f rsync.1; then :; else echo 'Copying srcdir rsync.1'; cp -p $(srcdir)/rsync.1 .; fi
|
||||
@-if test -f rsyncd.conf.5; then :; else echo 'Copying srcdir rsyncd.conf.5'; cp -p $(srcdir)/rsyncd.conf.5 .; fi
|
||||
rsync.1: rsync.1.md md2man NEWS.md Makefile
|
||||
@$(srcdir)/maybe-make-man $(srcdir) rsync.1.md
|
||||
|
||||
rsync.1: rsync.yo
|
||||
yodl2man -o rsync.1 $(srcdir)/rsync.yo
|
||||
-$(srcdir)/tweak_manpage rsync.1
|
||||
rsync-ssl.1: rsync-ssl.1.md md2man NEWS.md Makefile
|
||||
@$(srcdir)/maybe-make-man $(srcdir) rsync-ssl.1.md
|
||||
|
||||
rsyncd.conf.5: rsyncd.conf.yo
|
||||
yodl2man -o rsyncd.conf.5 $(srcdir)/rsyncd.conf.yo
|
||||
-$(srcdir)/tweak_manpage rsyncd.conf.5
|
||||
rsyncd.conf.5: rsyncd.conf.5.md md2man NEWS.md Makefile
|
||||
@$(srcdir)/maybe-make-man $(srcdir) rsyncd.conf.5.md
|
||||
|
||||
.PHONY: clean
|
||||
clean: cleantests
|
||||
rm -f *~ $(OBJS) $(CHECK_PROGS) $(CHECK_OBJS) $(CHECK_SYMLINKS) \
|
||||
rounding rounding.h *.old
|
||||
rounding rounding.h *.old rsync*.1 rsync*.5 rsync*.html
|
||||
|
||||
.PHONY: cleantests
|
||||
cleantests:
|
||||
rm -rf ./testtmp*
|
||||
|
||||
# We try to delete built files from both the source and build
|
||||
# directories, just in case somebody previously configured things in
|
||||
# the source directory.
|
||||
.PHONY: distclean
|
||||
distclean: clean
|
||||
rm -f Makefile config.h config.status
|
||||
rm -f rsync-ssl stunnel-rsync stunnel-rsyncd.conf
|
||||
rm -f stunnel-rsyncd.conf
|
||||
rm -f lib/dummy popt/dummy zlib/dummy
|
||||
rm -f $(srcdir)/Makefile $(srcdir)/config.h $(srcdir)/config.status
|
||||
rm -f $(srcdir)/lib/dummy $(srcdir)/popt/dummy $(srcdir)/zlib/dummy
|
||||
@@ -247,14 +262,14 @@ distclean: clean
|
||||
# this target is really just for my use. It only works on a limited
|
||||
# range of machines and is used to produce a list of potentially
|
||||
# dead (ie. unused) functions in the code. (tridge)
|
||||
.PHONY: finddead
|
||||
finddead:
|
||||
nm *.o */*.o |grep 'U ' | awk '{print $$2}' | sort -u > nmused.txt
|
||||
nm *.o */*.o |grep 'T ' | awk '{print $$3}' | sort -u > nmfns.txt
|
||||
comm -13 nmused.txt nmfns.txt
|
||||
|
||||
# 'check' is the GNU name, 'test' is the name for everybody else :-)
|
||||
.PHONY: check test
|
||||
|
||||
.PHONY: test
|
||||
test: check
|
||||
|
||||
# There seems to be no standard way to specify some variables as
|
||||
@@ -267,16 +282,19 @@ test: check
|
||||
# catch Bash-isms earlier even if we're running on GNU. Of course, we
|
||||
# might lose in the future where POSIX diverges from old sh.
|
||||
|
||||
.PHONY: check
|
||||
check: all $(CHECK_PROGS) $(CHECK_SYMLINKS)
|
||||
rsync_bin=`pwd`/rsync$(EXEEXT) $(srcdir)/runtests.sh
|
||||
|
||||
.PHONY: check29
|
||||
check29: all $(CHECK_PROGS) $(CHECK_SYMLINKS)
|
||||
rsync_bin=`pwd`/rsync$(EXEEXT) $(srcdir)/runtests.sh --protocol=29
|
||||
|
||||
.PHONY: check30
|
||||
check30: all $(CHECK_PROGS) $(CHECK_SYMLINKS)
|
||||
rsync_bin=`pwd`/rsync$(EXEEXT) $(srcdir)/runtests.sh --protocol=30
|
||||
|
||||
wildtest.o: wildtest.c lib/wildmatch.c rsync.h config.h
|
||||
wildtest.o: wildtest.c t_stub.o lib/wildmatch.c rsync.h config.h
|
||||
wildtest$(EXEEXT): wildtest.o lib/compat.o lib/snprintf.o @BUILD_POPT@
|
||||
$(CC) $(CFLAGS) $(LDFLAGS) -o $@ wildtest.o lib/compat.o lib/snprintf.o @BUILD_POPT@ $(LIBS)
|
||||
|
||||
@@ -293,6 +311,7 @@ testsuite/xattrs-hlink.test:
|
||||
# check a version installed from a binary or some other source tree,
|
||||
# if you want.
|
||||
|
||||
.PHONY: installcheck
|
||||
installcheck: $(CHECK_PROGS) $(CHECK_SYMLINKS)
|
||||
POSIXLY_CORRECT=1 TOOLDIR=`pwd` rsync_bin="$(bindir)/rsync$(EXEEXT)" srcdir="$(srcdir)" $(srcdir)/runtests.sh
|
||||
|
||||
@@ -303,21 +322,12 @@ installcheck: $(CHECK_PROGS) $(CHECK_SYMLINKS)
|
||||
splint:
|
||||
splint +unixlib +gnuextensions -weak rsync.c
|
||||
|
||||
|
||||
rsync.dvi: doc/rsync.texinfo
|
||||
texi2dvi -o $@ $<
|
||||
|
||||
rsync.ps: rsync.dvi
|
||||
dvips -ta4 -o $@ $<
|
||||
|
||||
rsync.pdf: doc/rsync.texinfo
|
||||
texi2dvi -o $@ --pdf $<
|
||||
|
||||
|
||||
.PHONY: doxygen
|
||||
doxygen:
|
||||
cd $(srcdir) && rm dox/html/* && doxygen
|
||||
|
||||
# for maintainers only
|
||||
.PHONY: doxygen-upload
|
||||
doxygen-upload:
|
||||
rsync -avzv $(srcdir)/dox/html/ --delete \
|
||||
samba.org:/home/httpd/html/rsync/doxygen/head/
|
||||
$${SAMBA_HOST-samba.org}:/home/httpd/html/rsync/doxygen/head/
|
||||
|
||||
105
NEWS
105
NEWS
@@ -1,105 +0,0 @@
|
||||
NEWS for rsync 3.1.1 (UNRELEASED)
|
||||
Protocol: 31 (unchanged)
|
||||
Changes since 3.1.0:
|
||||
|
||||
BUG FIXES:
|
||||
|
||||
- If the receiver gets bogus filenames from the sender (an unexpected
|
||||
leading slash or a ".." infix dir), exit with an error. This prevents a
|
||||
malicious sender from trying to inject filenames that would affect an
|
||||
area outside the destination directories.
|
||||
|
||||
- Fixed a failure to remove the partial-transfer temp file when interrupted
|
||||
(and rsync is not saving the partial files).
|
||||
|
||||
- Changed the chown/group/xattr-set order to avoid losing some security-
|
||||
related xattr info (that would get cleared by a chown).
|
||||
|
||||
- Fixed a bug in the xattr-finding code that could make a non-root-run
|
||||
receiver not able to find some xattr numbers.
|
||||
|
||||
- Fixed a bug in the early daemon protocol where a timeout failed to be
|
||||
honored (e.g. if the remote side fails to send us the initial protocol
|
||||
greeting).
|
||||
|
||||
- Fixed unintended inclusion of commas in file numbers in the daemon log.
|
||||
|
||||
- We once again send the 'f' sub-flag (of -e) to the server side so it
|
||||
knows that we can handle incremental-recursion directory errors properly
|
||||
in older protocols.
|
||||
|
||||
- Fixed an issue with too-aggressive keep-alive messages causing a problem
|
||||
for older rsync versions early in the transfer.
|
||||
|
||||
- Fixed an incorrect message about backup-directory-creation when using
|
||||
--dry-run and the backup dir is not an absolute path.
|
||||
|
||||
- Fixed a bug where a failed deletion and/or a failed sender-side removal
|
||||
would not affect the exit code.
|
||||
|
||||
- Fixed a bug that caused a failure when combining --delete-missing-args
|
||||
with --xattrs and/or --acls.
|
||||
|
||||
- Fixed a strange dir_depth assertion error that was caused by empty-dir
|
||||
removals and/or duplicate files in the transfer.
|
||||
|
||||
- Fixed a problem with --info=progress2's output stats where rsync would
|
||||
only update the stats at the end of each file's transfer. It now uses
|
||||
the data that is flowing for the current file, making the stats more
|
||||
accurate and less jumpy.
|
||||
|
||||
- Fixed an itemize bug that affected the combo of --link-dest, -X, and -n.
|
||||
|
||||
- Fixed a problem with delete messages not appearing in the log file when
|
||||
the user didn't use --verbose.
|
||||
|
||||
- Improve chunked xattr reading for OS X.
|
||||
|
||||
- Removed an attempted hard-link xattr optimization that was causing a
|
||||
transfer failure. (If you need to interact with an rsync 3.1.0 using
|
||||
--hard-links & --xattrs, you can specify --protocol=30.)
|
||||
|
||||
- We now generate a better error if the buffer overflows in do_mknod().
|
||||
|
||||
- Fixed a problem reading more than 16 ACLs on some OSes.
|
||||
|
||||
- Fixed the reading of the secrets file to avoid an infinite wait when
|
||||
the username is missing.
|
||||
|
||||
- Fixed a parsing problem in the --usermap/--groupmap options when using
|
||||
MIN-MAX numbers.
|
||||
|
||||
- Switched Cygwin back to using socketpair "pipes" to try to speed it up.
|
||||
|
||||
- Added knowledge of a few new options to rrsync.
|
||||
|
||||
ENHANCEMENTS:
|
||||
|
||||
- Tweaked the temp-file naming when --temp-dir=DIR is used: the temp-file
|
||||
names will not get a '.' prepended.
|
||||
|
||||
- Added support for a new-compression idiom that does not compress all the
|
||||
matching data in a transfer. This can help rsync to use less cpu when a
|
||||
transfer has a lot of matching data, and also makes rsync compatible with
|
||||
a non-bundled zlib. See the --new-compress and --old-compress options in
|
||||
the manpage.
|
||||
|
||||
- Added the support/rsync-no-vanished wrapper script.
|
||||
|
||||
- Made configure more prominently mention when we failed to find yodl (in
|
||||
case the user wants to be able to generate manpages from *.yo files).
|
||||
|
||||
- Have manpage mention how a daemon's max-verbosity setting affects info
|
||||
and debug options. Also added more clarification on backslash removals
|
||||
for excludes that contain wildcards.
|
||||
|
||||
- Have configure check if for the attr lib (for getxattr) for those systems
|
||||
that need to link against it explicitly.
|
||||
|
||||
- Change the early dir-creation logic to only use that idiom in an
|
||||
inc-recursive copy that is preserving directory times. e.g. using
|
||||
--omit-dir-times will avoid these early directories being created.
|
||||
|
||||
DEVELOPER RELATED:
|
||||
|
||||
- We now include an example systemd file (in packaging/systemd).
|
||||
192
NEWS.md
Normal file
192
NEWS.md
Normal file
@@ -0,0 +1,192 @@
|
||||
# NEWS for rsync 3.2.0 (UNRELEASED)
|
||||
|
||||
Protocol: 31 (unchanged)
|
||||
|
||||
## Changes since 3.1.3:
|
||||
|
||||
### BUG FIXES:
|
||||
|
||||
- Avoid a potential out-of-bounds read in daemon mode if argc can be made to
|
||||
become 0.
|
||||
|
||||
- Fix the default list of skip-compress files for non-daemon transfers.
|
||||
|
||||
- Fix xattr filter rules losing an 'x' attribute in a non-local transfer.
|
||||
|
||||
- Avoid an error when a check for a potential fuzzy file happens to reference
|
||||
a directory.
|
||||
|
||||
- Make the atomic-rsync helper script have a more consistent error-exit.
|
||||
|
||||
- Make sure that a signal handler calls `_exit()` instead of exit().
|
||||
|
||||
- Various zlib fixes, including security fixes for CVE-2016-9843,
|
||||
CVE-2016-9842, CVE-2016-9841, and CVE-2016-9840.
|
||||
|
||||
- Fixed an issue with `--remove-source-files` not removing a source symlink
|
||||
when combined with `--copy-links`.
|
||||
|
||||
- Fixed a bug where the daemon would fail to write early fatal error messages
|
||||
to the client, such as refused or unknown command-line options.
|
||||
|
||||
- Fixed the block-size validation logic when dealing with older protocols.
|
||||
|
||||
- Some rrsync fixes and enhancements to handle the latest options.
|
||||
|
||||
- Fixed a problem with the `--link-dest`|`--copy-dest` code when `--xattrs`
|
||||
was specified along with multiple alternate-destination directories (it
|
||||
could possibly choose a bad file match while trying to find a better xattr
|
||||
match).
|
||||
|
||||
- Fixed a couple bugs in the handling of files with the `--sparse` option.
|
||||
|
||||
- Fixed a bug in the writing of the batch.sh file (w/--write-batch) when the
|
||||
source & destination args were not last on the command-line.
|
||||
|
||||
- Avoid a hang when an overabundance of messages clogs up all the I/O buffers.
|
||||
|
||||
- Fixed a mismatch in the RSYNC_PID values put into the environment of
|
||||
`pre-xfer exec` and a `post-xfer exec`.
|
||||
|
||||
- Fixed a crash in the `--iconv` code.
|
||||
|
||||
- Fixed a rare crash in the popt_unalias() code.
|
||||
|
||||
### ENHANCEMENTS:
|
||||
|
||||
- Various checksum enhancements, including the optional use of openssl's MD4 &
|
||||
MD5 checksum algorithms, some x86-64 optimizations for the rolling checksum,
|
||||
some x86-64 optimizations for the (non-openssl) MD5 checksum, the addition
|
||||
of xxhash checksum support, and a negotiation heuristic that ensures that it
|
||||
is easier to add new checksum algorithms in the future. The environment
|
||||
variable `RSYNC_CHECKSUM_LIST` can be used to customize the preference order
|
||||
of the negotiation, or use `--checksum-choice` (`--cc`) to force a choice.
|
||||
|
||||
- Various compression enhancements, including the addition of zstd and lz4
|
||||
compression algorithms and a negotiation heuristic that picks the best
|
||||
compression option supported by both sides. The environment variable
|
||||
`RSYNC_COMPRESS_LIST` can be used to customize the preference order of the
|
||||
negotiation, or use `--compress-choice` (`--zc`) to force a choice.
|
||||
|
||||
- Added a --debug=NSTR option that outputs details of the new negotiation
|
||||
strings (for checksums and compression). The first level just outputs the
|
||||
result of each negotiation on the client, level 2 outputs the values of the
|
||||
strings that were sent to and received from the server, and level 3 outputs
|
||||
all those values on the server side too (when given the debug option).
|
||||
|
||||
- The --debug=OPTS command-line option is no longer auto-forwarded to the
|
||||
remote rsync which allows for the client and server to have different levels
|
||||
of debug specified. This also allows for newer debug options to be
|
||||
specified, such as using --debug=NSTR to see the negotiated hash result,
|
||||
without having the command fail if the server version is too old to handle
|
||||
that debug item. Use -M--debug=OPTS to send the options to the remote side.
|
||||
|
||||
- Added the `--atimes` option based on the long-standing patch (just with some
|
||||
fixes that the patch has been needing).
|
||||
|
||||
- Added `--open-noatime` option to open files using `O_NOATIME`.
|
||||
|
||||
- Added the `--write-devices` option based on the long-standing patch.
|
||||
|
||||
- Added openssl & preliminary gnutls support to the rsync-ssl script, which is
|
||||
now installed by default. This was unified with the old stunnel-rsync
|
||||
helper script to simplify packaging. Note that the script accepts the use
|
||||
of --type=gnutls for gnutls testing, but does not look for gnutls-cli on the
|
||||
path yet. The use of type=gnutls will not work right until gnutls-cli no
|
||||
longer drops data.
|
||||
|
||||
- Rsync was enhanced to set the `RSYNC_PORT` environment variable when running
|
||||
a daemon-over-rsh script. Its value is the user-specified port number (set
|
||||
via `--port` or an rsync:// URL) or 0 if the user didn't override the port.
|
||||
|
||||
- Added the `proxy protocol` daemon parameter that allows your rsyncd to know
|
||||
the real remote IP when it is setup behind a proxy.
|
||||
|
||||
- Added negated matching to the daemon's `refuse options` setting by using
|
||||
match strings that start with a `!` (such as `!compress*`). This lets you
|
||||
refuse all options except for a particular approved list, for example.
|
||||
|
||||
- Added the `early exec` daemon parameter that runs a script before the
|
||||
transfer parameters are known, allowing some early setup based on module
|
||||
name.
|
||||
|
||||
- Added status output in response to a signal (via both SIGINFO & SIGVTALRM).
|
||||
|
||||
- Added `--copy-as=USER` option to give some extra security to root-run rsync
|
||||
commands into/from untrusted directories (such as backups and restores).
|
||||
|
||||
- When resuming the transfer of a file in the `--partial-dir`, rsync will now
|
||||
update that partial file in-place instead of creating yet another tmp file
|
||||
copy. This requires both sender & receiver to be at least v3.2.0.
|
||||
|
||||
- Added support for `RSYNC_SHELL` & `RSYNC_NO_XFER_EXEC` environment variables
|
||||
that affect the pre-xfer exec and post-xfer exec rsync daemon options.
|
||||
|
||||
- Optimize the `--fuzzy --fuzzy` heuristic to avoid the fuzzy directory scan
|
||||
until all other basis-file options are exhausted (such as `--link-dest`).
|
||||
|
||||
- Have the daemon log include the normal-exit sent/received stats when the
|
||||
transfer exited with an error when possible (i.e. if it is the sender).
|
||||
|
||||
- The daemon now locks its pid file (when configured to use one) so that it
|
||||
will not fail to start when the file exists and it is unlocked.
|
||||
|
||||
- Various man page improvements, including some html representations (that
|
||||
aren't installed by default).
|
||||
|
||||
- Made -V the short option for --version and improved its information.
|
||||
|
||||
- Forward -4 or -6 to the ssh command, making it easier to type than
|
||||
`--rsh='ssh -4'` (or -6).
|
||||
|
||||
### PACKAGING RELATED:
|
||||
|
||||
- Add installed binary: /usr/bin/rsync-sll
|
||||
|
||||
- Add installed man page: /usr/man/man1/rsync-ssl.1
|
||||
|
||||
- Tweak auxilliary doc file names, such as: README.md, INSTALL.md, NEWS.md, &
|
||||
OLDNEWS.md.
|
||||
|
||||
- The rsync-ssl script wants to run openssl or stunnel4, so consider adding a
|
||||
dependency for one of those options (though it's probably fine to just let
|
||||
it complain about being unable to find the program and let the user decide
|
||||
if they want to install one or the other).
|
||||
|
||||
- If you packaged rsync + rsync-ssl + rsync-ssl-daemon as separate packages,
|
||||
the rsync-ssl package is now gone (rsync-ssl should be considered to be
|
||||
mainstream now that Samba requires SSL for its rsync daemon).
|
||||
|
||||
- Add _build_ dependency for liblz4-dev, libxxhash-dev, libzstd-dev, and
|
||||
libssl-dev. These development libraries will give rsync extra compression
|
||||
algorithms, extra checksum algorithms, and allow use of openssl's crypto
|
||||
lib for (potentially) faster MD4/MD5 checksums.
|
||||
|
||||
- Add _build_ dependency for g++ to enable the SIMD checksum optimizations.
|
||||
|
||||
- Add _build_ dependency for _either_ python3-cmarkcfm or python3-commonmark
|
||||
to allow for patching of man pages or building a git release. Note that
|
||||
cmarkcfm is faster than commonmark, but they generate the same data.
|
||||
|
||||
- Remove yodl _build_ dependency (if it was even listed before).
|
||||
|
||||
### DEVELOPER RELATED:
|
||||
|
||||
- Silenced some annoying warnings about major() & minor() by improving an
|
||||
autoconf include-file check.
|
||||
|
||||
- Converted the man pages from yodl to markdown. They are now processed via a
|
||||
simple python3 script using the cmarkgfm **or** commonmark library. This
|
||||
should make it easier to package rsync, since yodl has gotten obscure.
|
||||
|
||||
- Improved some configure checks to work better with strict C99 compilers.
|
||||
|
||||
- Some perl building/packaging scripts were recoded into awk and python3.
|
||||
|
||||
- Some defines in byteorder.h were changed into static inline functions that
|
||||
will help to ensure that the args don't get evaluated multiple times on
|
||||
"careful alignment" hosts.
|
||||
|
||||
- Some code typos were fixed (as pointed out by a Fossies run).
|
||||
|
||||
------------------------------------------------------------------------------
|
||||
3863
OLDNEWS.md
Normal file
3863
OLDNEWS.md
Normal file
File diff suppressed because it is too large
Load Diff
@@ -65,7 +65,7 @@ WEB SITE
|
||||
|
||||
The main rsync web site is here:
|
||||
|
||||
http://rsync.samba.org/
|
||||
> http://rsync.samba.org/
|
||||
|
||||
You'll find a FAQ list, downloads, resources, HTML versions of the
|
||||
manpages, etc.
|
||||
@@ -80,7 +80,7 @@ list, and there is also an announcement-only mailing list for those that
|
||||
want official announcements. See the mailing-list page for full
|
||||
details:
|
||||
|
||||
http://rsync.samba.org/lists.html
|
||||
> http://rsync.samba.org/lists.html
|
||||
|
||||
|
||||
BUG REPORTS
|
||||
@@ -88,34 +88,38 @@ BUG REPORTS
|
||||
|
||||
To visit this web page for full the details on bug reporting:
|
||||
|
||||
http://rsync.samba.org/bugzilla.html
|
||||
> http://rsync.samba.org/bugzilla.html
|
||||
|
||||
That page contains links to the current bug list, and information on how
|
||||
to report a bug well. You might also like to try searching the Internet
|
||||
for the error message you've received, or looking in the mailing list
|
||||
archives at:
|
||||
|
||||
http://mail-archive.com/rsync@lists.samba.org/
|
||||
> http://mail-archive.com/rsync@lists.samba.org/
|
||||
|
||||
To send a bug report, follow the instructions on the bug-tracking
|
||||
page of the web site.
|
||||
|
||||
Alternately, email your bug report to rsync@lists.samba.org .
|
||||
Alternately, email your bug report to <rsync@lists.samba.org>.
|
||||
|
||||
|
||||
GIT REPOSITORY
|
||||
--------------
|
||||
|
||||
If you want to get the very latest version of rsync direct from the
|
||||
source code repository then you can use git:
|
||||
source code repository, then you will need to use git. The git repo
|
||||
is hosted on github and on samba's site. Feel free to access it here:
|
||||
|
||||
git clone git://git.samba.org/rsync.git
|
||||
> https://github.com/WayneD/rsync
|
||||
|
||||
or clone it from its samba repo:
|
||||
|
||||
> git clone git://git.samba.org/rsync.git
|
||||
|
||||
See the download page for full details on all the ways to grab the
|
||||
source, including nightly tar files, web-browsing of the git repository,
|
||||
etc.:
|
||||
source:
|
||||
|
||||
http://rsync.samba.org/download.html
|
||||
> http://rsync.samba.org/download.html
|
||||
|
||||
|
||||
COPYRIGHT
|
||||
@@ -129,12 +133,17 @@ Rsync may be used, modified and redistributed only under the terms of
|
||||
the GNU General Public License, found in the file COPYING in this
|
||||
distribution, or at:
|
||||
|
||||
http://www.fsf.org/licenses/gpl.html
|
||||
> http://www.fsf.org/licenses/gpl.html
|
||||
|
||||
|
||||
AVAILABILITY
|
||||
------------
|
||||
|
||||
The main web site for rsync is http://rsync.samba.org/
|
||||
|
||||
The main ftp site is ftp://rsync.samba.org/pub/rsync/
|
||||
This is also available as rsync://rsync.samba.org/rsyncftp/
|
||||
|
||||
This is also available as rsync://download.samba.org/rsyncftp/ if you
|
||||
connect via ssl. Use the `rsync-ssl` script if you have it, otherwise
|
||||
connect to the rsync server via a normal rsync command and it will
|
||||
output some instructions for how to connect.
|
||||
4
TODO
4
TODO
@@ -94,7 +94,7 @@ Handling IPv6 on old machines
|
||||
platforms that have a half-working implementation, so redefining
|
||||
these functions clashes with system headers, and leaving them out
|
||||
breaks. This affects at least OSF/1, RedHat 5, and Cobalt, which
|
||||
are moderately improtant.
|
||||
are moderately important.
|
||||
|
||||
Perhaps the simplest solution would be to have two different files
|
||||
implementing the same interface, and choose either the new or the
|
||||
@@ -236,7 +236,7 @@ Memory accounting
|
||||
|
||||
At exit, show how much memory was used for the file list, etc.
|
||||
|
||||
Also we do a wierd exponential-growth allocation in flist.c. I'm
|
||||
We also do a weird exponential-growth allocation in flist.c. I'm
|
||||
not sure this makes sense with modern mallocs. At any rate it will
|
||||
make us allocate a huge amount of memory for large file lists.
|
||||
|
||||
|
||||
16
access.c
16
access.c
@@ -2,7 +2,7 @@
|
||||
* Routines to authenticate access to a daemon (hosts allow/deny).
|
||||
*
|
||||
* Copyright (C) 1998 Andrew Tridgell
|
||||
* Copyright (C) 2004-2014 Wayne Davison
|
||||
* Copyright (C) 2004-2020 Wayne Davison
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
@@ -158,8 +158,7 @@ static int match_address(const char *addr, const char *tok)
|
||||
break;
|
||||
|
||||
#ifdef INET6
|
||||
case PF_INET6:
|
||||
{
|
||||
case PF_INET6: {
|
||||
struct sockaddr_in6 *sin6a, *sin6t;
|
||||
|
||||
sin6a = (struct sockaddr_in6 *)resa->ai_addr;
|
||||
@@ -171,20 +170,19 @@ static int match_address(const char *addr, const char *tok)
|
||||
addrlen = 16;
|
||||
|
||||
#ifdef HAVE_SOCKADDR_IN6_SCOPE_ID
|
||||
if (sin6t->sin6_scope_id &&
|
||||
sin6a->sin6_scope_id != sin6t->sin6_scope_id) {
|
||||
if (sin6t->sin6_scope_id && sin6a->sin6_scope_id != sin6t->sin6_scope_id) {
|
||||
ret = 0;
|
||||
goto out;
|
||||
}
|
||||
#endif
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
default:
|
||||
rprintf(FLOG, "unknown family %u\n", rest->ai_family);
|
||||
ret = 0;
|
||||
goto out;
|
||||
rprintf(FLOG, "unknown family %u\n", rest->ai_family);
|
||||
ret = 0;
|
||||
goto out;
|
||||
}
|
||||
|
||||
bits = -1;
|
||||
|
||||
92
aclocal.m4
vendored
92
aclocal.m4
vendored
@@ -1,92 +0,0 @@
|
||||
dnl AC_VALIDATE_CACHE_SYSTEM_TYPE[(cmd)]
|
||||
dnl if the cache file is inconsistent with the current host,
|
||||
dnl target and build system types, execute CMD or print a default
|
||||
dnl error message.
|
||||
AC_DEFUN(AC_VALIDATE_CACHE_SYSTEM_TYPE, [
|
||||
AC_REQUIRE([AC_CANONICAL_SYSTEM])
|
||||
AC_MSG_CHECKING([config.cache system type])
|
||||
if { test x"${ac_cv_host_system_type+set}" = x"set" &&
|
||||
test x"$ac_cv_host_system_type" != x"$host"; } ||
|
||||
{ test x"${ac_cv_build_system_type+set}" = x"set" &&
|
||||
test x"$ac_cv_build_system_type" != x"$build"; } ||
|
||||
{ test x"${ac_cv_target_system_type+set}" = x"set" &&
|
||||
test x"$ac_cv_target_system_type" != x"$target"; }; then
|
||||
AC_MSG_RESULT([different])
|
||||
ifelse($#, 1, [$1],
|
||||
[AC_MSG_ERROR(["you must remove config.cache and restart configure"])])
|
||||
else
|
||||
AC_MSG_RESULT([same])
|
||||
fi
|
||||
ac_cv_host_system_type="$host"
|
||||
ac_cv_build_system_type="$build"
|
||||
ac_cv_target_system_type="$target"
|
||||
])
|
||||
|
||||
dnl Check for socklen_t: historically on BSD it is an int, and in
|
||||
dnl POSIX 1g it is a type of its own, but some platforms use different
|
||||
dnl types for the argument to getsockopt, getpeername, etc. So we
|
||||
dnl have to test to find something that will work.
|
||||
|
||||
dnl This is no good, because passing the wrong pointer on C compilers is
|
||||
dnl likely to only generate a warning, not an error. We don't call this at
|
||||
dnl the moment.
|
||||
|
||||
AC_DEFUN([TYPE_SOCKLEN_T],
|
||||
[
|
||||
AC_CHECK_TYPE([socklen_t], ,[
|
||||
AC_MSG_CHECKING([for socklen_t equivalent])
|
||||
AC_CACHE_VAL([rsync_cv_socklen_t_equiv],
|
||||
[
|
||||
# Systems have either "struct sockaddr *" or
|
||||
# "void *" as the second argument to getpeername
|
||||
rsync_cv_socklen_t_equiv=
|
||||
for arg2 in "struct sockaddr" void; do
|
||||
for t in int size_t unsigned long "unsigned long"; do
|
||||
AC_TRY_COMPILE([
|
||||
#include <sys/types.h>
|
||||
#include <sys/socket.h>
|
||||
|
||||
int getpeername (int, $arg2 *, $t *);
|
||||
],[
|
||||
$t len;
|
||||
getpeername(0,0,&len);
|
||||
],[
|
||||
rsync_cv_socklen_t_equiv="$t"
|
||||
break
|
||||
])
|
||||
done
|
||||
done
|
||||
|
||||
if test "x$rsync_cv_socklen_t_equiv" = x; then
|
||||
AC_MSG_ERROR([Cannot find a type to use in place of socklen_t])
|
||||
fi
|
||||
])
|
||||
AC_MSG_RESULT($rsync_cv_socklen_t_equiv)
|
||||
AC_DEFINE_UNQUOTED(socklen_t, $rsync_cv_socklen_t_equiv,
|
||||
[type to use in place of socklen_t if not defined])],
|
||||
[#include <sys/types.h>
|
||||
#include <sys/socket.h>])
|
||||
])
|
||||
|
||||
dnl AC_HAVE_TYPE(TYPE,INCLUDES)
|
||||
AC_DEFUN([AC_HAVE_TYPE], [
|
||||
AC_REQUIRE([AC_HEADER_STDC])
|
||||
cv=`echo "$1" | sed 'y%./+- %__p__%'`
|
||||
AC_MSG_CHECKING(for $1)
|
||||
AC_CACHE_VAL([ac_cv_type_$cv],
|
||||
AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[
|
||||
AC_INCLUDES_DEFAULT
|
||||
$2]],
|
||||
[[$1 foo;]])],
|
||||
[eval "ac_cv_type_$cv=yes"],
|
||||
[eval "ac_cv_type_$cv=no"]))dnl
|
||||
ac_foo=`eval echo \\$ac_cv_type_$cv`
|
||||
AC_MSG_RESULT($ac_foo)
|
||||
if test "$ac_foo" = yes; then
|
||||
ac_tr_hdr=HAVE_`echo $1 | sed 'y%abcdefghijklmnopqrstuvwxyz./- %ABCDEFGHIJKLMNOPQRSTUVWXYZ____%'`
|
||||
if false; then
|
||||
AC_CHECK_TYPES($1)
|
||||
fi
|
||||
AC_DEFINE_UNQUOTED($ac_tr_hdr, 1, [Define if you have type `$1'])
|
||||
fi
|
||||
])
|
||||
25
acls.c
25
acls.c
@@ -3,7 +3,7 @@
|
||||
*
|
||||
* Copyright (C) 1996 Andrew Tridgell
|
||||
* Copyright (C) 1996 Paul Mackerras
|
||||
* Copyright (C) 2006-2014 Wayne Davison
|
||||
* Copyright (C) 2006-2020 Wayne Davison
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
@@ -48,7 +48,7 @@ extern int preserve_specials;
|
||||
/* When we send the access bits over the wire, we shift them 2 bits to the
|
||||
* left and use the lower 2 bits as flags (relevant only to a name entry).
|
||||
* This makes the protocol more efficient than sending a value that would
|
||||
* be likely to have its hightest bits set. */
|
||||
* be likely to have its highest bits set. */
|
||||
#define XFLAG_NAME_FOLLOWS 0x0001u
|
||||
#define XFLAG_NAME_IS_USER 0x0002u
|
||||
|
||||
@@ -332,14 +332,12 @@ static BOOL unpack_smb_acl(SMB_ACL_T sacl, rsync_acl *racl)
|
||||
if (temp_ida_list.count) {
|
||||
#ifdef SMB_ACL_NEED_SORT
|
||||
if (temp_ida_list.count > 1) {
|
||||
qsort(temp_ida_list.items, temp_ida_list.count,
|
||||
sizeof (id_access), id_access_sorter);
|
||||
qsort(temp_ida_list.items, temp_ida_list.count, sizeof (id_access), id_access_sorter);
|
||||
}
|
||||
#endif
|
||||
if (!(racl->names.idas = new_array(id_access, temp_ida_list.count)))
|
||||
out_of_memory("unpack_smb_acl");
|
||||
memcpy(racl->names.idas, temp_ida_list.items,
|
||||
temp_ida_list.count * sizeof (id_access));
|
||||
memcpy(racl->names.idas, temp_ida_list.items, temp_ida_list.count * sizeof (id_access));
|
||||
} else
|
||||
racl->names.idas = NULL;
|
||||
|
||||
@@ -825,14 +823,12 @@ void cache_tmp_acl(struct file_struct *file, stat_x *sxp)
|
||||
if (prior_access_count == (size_t)-1)
|
||||
prior_access_count = access_acl_list.count;
|
||||
|
||||
F_ACL(file) = cache_rsync_acl(sxp->acc_acl,
|
||||
SMB_ACL_TYPE_ACCESS, &access_acl_list);
|
||||
F_ACL(file) = cache_rsync_acl(sxp->acc_acl, SMB_ACL_TYPE_ACCESS, &access_acl_list);
|
||||
|
||||
if (S_ISDIR(sxp->st.st_mode)) {
|
||||
if (prior_default_count == (size_t)-1)
|
||||
prior_default_count = default_acl_list.count;
|
||||
F_DIR_DEFACL(file) = cache_rsync_acl(sxp->def_acl,
|
||||
SMB_ACL_TYPE_DEFAULT, &default_acl_list);
|
||||
F_DIR_DEFACL(file) = cache_rsync_acl(sxp->def_acl, SMB_ACL_TYPE_DEFAULT, &default_acl_list);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -996,8 +992,7 @@ static int set_rsync_acl(const char *fname, acl_duo *duo_item,
|
||||
mode = 0; /* eliminate compiler warning */
|
||||
#else
|
||||
if (type == SMB_ACL_TYPE_ACCESS) {
|
||||
cur_mode = change_sacl_perms(duo_item->sacl, &duo_item->racl,
|
||||
cur_mode, mode);
|
||||
cur_mode = change_sacl_perms(duo_item->sacl, &duo_item->racl, cur_mode, mode);
|
||||
if (cur_mode == (mode_t)-1)
|
||||
return 0;
|
||||
}
|
||||
@@ -1117,14 +1112,12 @@ int default_perms_for_dir(const char *dir)
|
||||
case ENOSYS:
|
||||
/* No ACLs are available. */
|
||||
break;
|
||||
case ENOENT:
|
||||
if (dry_run) {
|
||||
default:
|
||||
if (dry_run && errno == ENOENT) {
|
||||
/* We're doing a dry run, so the containing directory
|
||||
* wasn't actually created. Don't worry about it. */
|
||||
break;
|
||||
}
|
||||
/* Otherwise fall through. */
|
||||
default:
|
||||
rprintf(FWARNING,
|
||||
"default_perms_for_dir: sys_acl_get_file(%s, %s): %s, falling back on umask\n",
|
||||
dir, str_acl_type(SMB_ACL_TYPE_DEFAULT), strerror(errno));
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
* Support rsync daemon authentication.
|
||||
*
|
||||
* Copyright (C) 1998-2000 Andrew Tridgell
|
||||
* Copyright (C) 2002-2014 Wayne Davison
|
||||
* Copyright (C) 2002-2020 Wayne Davison
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
@@ -71,7 +71,7 @@ static void gen_challenge(const char *addr, char *challenge)
|
||||
SIVAL(input, 20, tv.tv_usec);
|
||||
SIVAL(input, 24, getpid());
|
||||
|
||||
sum_init(0);
|
||||
sum_init(-1, 0);
|
||||
sum_update(input, sizeof input);
|
||||
len = sum_end(digest);
|
||||
|
||||
@@ -85,7 +85,7 @@ static void generate_hash(const char *in, const char *challenge, char *out)
|
||||
char buf[MAX_DIGEST_LEN];
|
||||
int len;
|
||||
|
||||
sum_init(0);
|
||||
sum_init(-1, 0);
|
||||
sum_update(in, strlen(in));
|
||||
sum_update(challenge, strlen(challenge));
|
||||
len = sum_end(buf);
|
||||
@@ -162,8 +162,8 @@ static const char *check_secret(int module, const char *user, const char *group,
|
||||
|
||||
fclose(fh);
|
||||
|
||||
memset(line, 0, sizeof line);
|
||||
memset(pass2, 0, sizeof pass2);
|
||||
force_memzero(line, sizeof line);
|
||||
force_memzero(pass2, sizeof pass2);
|
||||
|
||||
return err;
|
||||
}
|
||||
@@ -279,17 +279,18 @@ char *auth_server(int f_in, int f_out, int module, const char *host,
|
||||
/* See if authorizing user is a real user, and if so, see
|
||||
* if it is in a group that matches tok+1 wildmat. */
|
||||
if (auth_uid_groups_cnt < 0) {
|
||||
gid_t gid_list[64];
|
||||
item_list gid_list = EMPTY_ITEM_LIST;
|
||||
uid_t auth_uid;
|
||||
auth_uid_groups_cnt = sizeof gid_list / sizeof (gid_t);
|
||||
if (!user_to_uid(line, &auth_uid, False)
|
||||
|| getallgroups(auth_uid, gid_list, &auth_uid_groups_cnt) != NULL)
|
||||
|| getallgroups(auth_uid, &gid_list) != NULL)
|
||||
auth_uid_groups_cnt = 0;
|
||||
else {
|
||||
gid_t *gid_array = gid_list.items;
|
||||
auth_uid_groups_cnt = gid_list.count;
|
||||
if ((auth_uid_groups = new_array(char *, auth_uid_groups_cnt)) == NULL)
|
||||
out_of_memory("auth_server");
|
||||
for (j = 0; j < auth_uid_groups_cnt; j++)
|
||||
auth_uid_groups[j] = gid_to_group(gid_list[j]);
|
||||
auth_uid_groups[j] = gid_to_group(gid_array[j]);
|
||||
}
|
||||
}
|
||||
for (j = 0; j < auth_uid_groups_cnt; j++) {
|
||||
@@ -317,8 +318,8 @@ char *auth_server(int f_in, int f_out, int module, const char *host,
|
||||
err = check_secret(module, line, group, challenge, pass);
|
||||
}
|
||||
|
||||
memset(challenge, 0, sizeof challenge);
|
||||
memset(pass, 0, strlen(pass));
|
||||
force_memzero(challenge, sizeof challenge);
|
||||
force_memzero(pass, strlen(pass));
|
||||
|
||||
if (auth_uid_groups) {
|
||||
int j;
|
||||
@@ -356,12 +357,12 @@ void auth_client(int fd, const char *user, const char *challenge)
|
||||
/* XXX: cyeoh says that getpass is deprecated, because
|
||||
* it may return a truncated password on some systems,
|
||||
* and it is not in the LSB.
|
||||
*
|
||||
* Andrew Klein says that getpassphrase() is present
|
||||
* on Solaris and reads up to 256 characters.
|
||||
*
|
||||
* OpenBSD has a readpassphrase() that might be more suitable.
|
||||
*/
|
||||
*
|
||||
* Andrew Klein says that getpassphrase() is present
|
||||
* on Solaris and reads up to 256 characters.
|
||||
*
|
||||
* OpenBSD has a readpassphrase() that might be more suitable.
|
||||
*/
|
||||
pass = getpass("Password: ");
|
||||
}
|
||||
|
||||
|
||||
35
backup.c
35
backup.c
@@ -2,7 +2,7 @@
|
||||
* Backup handling code.
|
||||
*
|
||||
* Copyright (C) 1999 Andrew Tridgell
|
||||
* Copyright (C) 2003-2014 Wayne Davison
|
||||
* Copyright (C) 2003-2020 Wayne Davison
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
@@ -157,6 +157,18 @@ static BOOL copy_valid_path(const char *fname)
|
||||
char *get_backup_name(const char *fname)
|
||||
{
|
||||
if (backup_dir) {
|
||||
static int initialized = 0;
|
||||
if (!initialized) {
|
||||
int ret;
|
||||
if (backup_dir_len > 1)
|
||||
backup_dir_buf[backup_dir_len-1] = '\0';
|
||||
ret = make_path(backup_dir_buf, 0);
|
||||
if (backup_dir_len > 1)
|
||||
backup_dir_buf[backup_dir_len-1] = '/';
|
||||
if (ret < 0)
|
||||
return NULL;
|
||||
initialized = 1;
|
||||
}
|
||||
/* copy fname into backup_dir_buf while validating the dirs. */
|
||||
if (copy_valid_path(fname))
|
||||
return backup_dir_buf;
|
||||
@@ -208,23 +220,24 @@ static inline int link_or_rename(const char *from, const char *to,
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Hard-link, rename, or copy an item to the backup name. Returns 2 if item
|
||||
* was duplicated into backup area, 1 if item was moved, or 0 for failure.*/
|
||||
/* Hard-link, rename, or copy an item to the backup name. Returns 0 for
|
||||
* failure, 1 if item was moved, 2 if item was duplicated or hard linked
|
||||
* into backup area, or 3 if item doesn't exist or isn't a regular file. */
|
||||
int make_backup(const char *fname, BOOL prefer_rename)
|
||||
{
|
||||
stat_x sx;
|
||||
struct file_struct *file;
|
||||
int save_preserve_xattrs;
|
||||
char *buf = get_backup_name(fname);
|
||||
char *buf;
|
||||
int ret = 0;
|
||||
|
||||
if (!buf)
|
||||
return 0;
|
||||
|
||||
init_stat_x(&sx);
|
||||
/* Return success if no file to keep. */
|
||||
if (x_lstat(fname, &sx.st, NULL) < 0)
|
||||
return 1;
|
||||
return 3;
|
||||
|
||||
if (!(buf = get_backup_name(fname)))
|
||||
return 0;
|
||||
|
||||
/* Try a hard-link or a rename first. Using rename is not atomic, but
|
||||
* is more efficient than forcing a copy for larger files when no hard-
|
||||
@@ -244,7 +257,7 @@ int make_backup(const char *fname, BOOL prefer_rename)
|
||||
|
||||
/* Fall back to making a copy. */
|
||||
if (!(file = make_file(fname, NULL, &sx.st, 0, NO_FILTERS)))
|
||||
return 1; /* the file could have disappeared */
|
||||
return 3; /* the file could have disappeared */
|
||||
|
||||
#ifdef SUPPORT_ACLS
|
||||
if (preserve_acls && !S_ISLNK(file->mode)) {
|
||||
@@ -299,7 +312,7 @@ int make_backup(const char *fname, BOOL prefer_rename)
|
||||
#ifdef SUPPORT_XATTRS
|
||||
uncache_tmp_xattrs();
|
||||
#endif
|
||||
return 2;
|
||||
return 3;
|
||||
}
|
||||
|
||||
/* Copy to backup tree if a file. */
|
||||
@@ -323,7 +336,7 @@ int make_backup(const char *fname, BOOL prefer_rename)
|
||||
|
||||
save_preserve_xattrs = preserve_xattrs;
|
||||
preserve_xattrs = 0;
|
||||
set_file_attrs(buf, file, NULL, fname, 0);
|
||||
set_file_attrs(buf, file, NULL, fname, ATTRS_ACCURATE_TIME);
|
||||
preserve_xattrs = save_preserve_xattrs;
|
||||
|
||||
unmake_file(file);
|
||||
|
||||
166
batch.c
166
batch.c
@@ -3,7 +3,7 @@
|
||||
*
|
||||
* Copyright (C) 1999 Weiss
|
||||
* Copyright (C) 2004 Chris Shoemaker
|
||||
* Copyright (C) 2004-2014 Wayne Davison
|
||||
* Copyright (C) 2004-2020 Wayne Davison
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
@@ -37,14 +37,22 @@ extern int always_checksum;
|
||||
extern int do_compression;
|
||||
extern int inplace;
|
||||
extern int append_mode;
|
||||
extern int write_batch;
|
||||
extern int xfersum_type;
|
||||
extern int protocol_version;
|
||||
extern int raw_argc, cooked_argc;
|
||||
extern char **raw_argv, **cooked_argv;
|
||||
extern char *batch_name;
|
||||
extern const char *checksum_choice;
|
||||
extern const char *compress_choice;
|
||||
#ifdef ICONV_OPTION
|
||||
extern char *iconv_opt;
|
||||
#endif
|
||||
|
||||
extern filter_rule_list filter_list;
|
||||
|
||||
int batch_fd = -1;
|
||||
int batch_sh_fd = -1;
|
||||
int batch_stream_flags;
|
||||
|
||||
static int tweaked_append;
|
||||
@@ -156,37 +164,45 @@ void check_batch_flags(void)
|
||||
append_mode = 2;
|
||||
}
|
||||
|
||||
static int write_arg(int fd, char *arg)
|
||||
static int write_arg(const char *arg)
|
||||
{
|
||||
char *x, *s;
|
||||
int len, ret = 0;
|
||||
const char *x, *s;
|
||||
int len, err = 0;
|
||||
|
||||
if (*arg == '-' && (x = strchr(arg, '=')) != NULL) {
|
||||
if (write(fd, arg, x - arg + 1) != x - arg + 1)
|
||||
ret = -1;
|
||||
err |= write(batch_sh_fd, arg, x - arg + 1) != x - arg + 1;
|
||||
arg += x - arg + 1;
|
||||
}
|
||||
|
||||
if (strpbrk(arg, " \"'&;|[]()$#!*?^\\") != NULL) {
|
||||
if (write(fd, "'", 1) != 1)
|
||||
ret = -1;
|
||||
err |= write(batch_sh_fd, "'", 1) != 1;
|
||||
for (s = arg; (x = strchr(s, '\'')) != NULL; s = x + 1) {
|
||||
if (write(fd, s, x - s + 1) != x - s + 1
|
||||
|| write(fd, "'", 1) != 1)
|
||||
ret = -1;
|
||||
err |= write(batch_sh_fd, s, x - s + 1) != x - s + 1;
|
||||
err |= write(batch_sh_fd, "'", 1) != 1;
|
||||
}
|
||||
len = strlen(s);
|
||||
if (write(fd, s, len) != len
|
||||
|| write(fd, "'", 1) != 1)
|
||||
ret = -1;
|
||||
return ret;
|
||||
err |= write(batch_sh_fd, s, len) != len;
|
||||
err |= write(batch_sh_fd, "'", 1) != 1;
|
||||
return err;
|
||||
}
|
||||
|
||||
len = strlen(arg);
|
||||
if (write(fd, arg, len) != len)
|
||||
ret = -1;
|
||||
err |= write(batch_sh_fd, arg, len) != len;
|
||||
|
||||
return ret;
|
||||
return err;
|
||||
}
|
||||
|
||||
/* Writes out a space and then an option (or other string) with an optional "=" + arg suffix. */
|
||||
static int write_opt(const char *opt, const char *arg)
|
||||
{
|
||||
int len = strlen(opt);
|
||||
int err = write(batch_sh_fd, " ", 1) != 1;
|
||||
err = write(batch_sh_fd, opt, len) != len ? 1 : 0;
|
||||
if (arg) {
|
||||
err |= write(batch_sh_fd, "=", 1) != 1;
|
||||
err |= write_arg(arg);
|
||||
}
|
||||
return err;
|
||||
}
|
||||
|
||||
static void write_filter_rules(int fd)
|
||||
@@ -208,41 +224,74 @@ static void write_filter_rules(int fd)
|
||||
write_sbuf(fd, "#E#");
|
||||
}
|
||||
|
||||
/* This sets batch_fd and (for --write-batch) batch_sh_fd. */
|
||||
void open_batch_files(void)
|
||||
{
|
||||
if (write_batch) {
|
||||
char filename[MAXPATHLEN];
|
||||
|
||||
stringjoin(filename, sizeof filename, batch_name, ".sh", NULL);
|
||||
|
||||
batch_sh_fd = do_open(filename, O_WRONLY | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR | S_IXUSR);
|
||||
if (batch_sh_fd < 0) {
|
||||
rsyserr(FERROR, errno, "Batch file %s open error", full_fname(filename));
|
||||
exit_cleanup(RERR_FILESELECT);
|
||||
}
|
||||
|
||||
batch_fd = do_open(batch_name, O_WRONLY | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR);
|
||||
} else if (strcmp(batch_name, "-") == 0)
|
||||
batch_fd = STDIN_FILENO;
|
||||
else
|
||||
batch_fd = do_open(batch_name, O_RDONLY, S_IRUSR | S_IWUSR);
|
||||
|
||||
if (batch_fd < 0) {
|
||||
rsyserr(FERROR, errno, "Batch file %s open error", full_fname(batch_name));
|
||||
exit_cleanup(RERR_FILEIO);
|
||||
}
|
||||
}
|
||||
|
||||
/* This routine tries to write out an equivalent --read-batch command
|
||||
* given the user's --write-batch args. However, it doesn't really
|
||||
* understand most of the options, so it uses some overly simple
|
||||
* heuristics to munge the command line into something that will
|
||||
* (hopefully) work. */
|
||||
void write_batch_shell_file(int argc, char *argv[], int file_arg_cnt)
|
||||
void write_batch_shell_file(void)
|
||||
{
|
||||
int fd, i, len, err = 0;
|
||||
char *p, filename[MAXPATHLEN];
|
||||
|
||||
stringjoin(filename, sizeof filename,
|
||||
batch_name, ".sh", NULL);
|
||||
fd = do_open(filename, O_WRONLY | O_CREAT | O_TRUNC,
|
||||
S_IRUSR | S_IWUSR | S_IXUSR);
|
||||
if (fd < 0) {
|
||||
rsyserr(FERROR, errno, "Batch file %s open error",
|
||||
filename);
|
||||
exit_cleanup(RERR_FILESELECT);
|
||||
}
|
||||
int i, j, len, err = 0;
|
||||
char *p, *p2;
|
||||
|
||||
/* Write argvs info to BATCH.sh file */
|
||||
if (write_arg(fd, argv[0]) < 0)
|
||||
err = 1;
|
||||
err |= write_arg(raw_argv[0]);
|
||||
if (filter_list.head) {
|
||||
if (protocol_version >= 29)
|
||||
write_sbuf(fd, " --filter=._-");
|
||||
err |= write_opt("--filter", "._-");
|
||||
else
|
||||
write_sbuf(fd, " --exclude-from=-");
|
||||
err |= write_opt("--exclude-from", "-");
|
||||
}
|
||||
for (i = 1; i < argc - file_arg_cnt; i++) {
|
||||
p = argv[i];
|
||||
|
||||
/* We need to make sure that any protocol-based or negotiated choices get accurately
|
||||
* reflected in the options we save AND that we avoid any need for --read-batch to
|
||||
* do a string-based negotation (since we don't write them into the file). */
|
||||
if (do_compression)
|
||||
err |= write_opt("--compress-choice", compress_choice);
|
||||
if (strchr(checksum_choice, ',') || xfersum_type != parse_csum_name(NULL, -1))
|
||||
err |= write_opt("--checksum-choice", checksum_choice);
|
||||
|
||||
/* Elide the filename args from the option list, but scan for them in reverse. */
|
||||
for (i = raw_argc-1, j = cooked_argc-1; i > 0 && j >= 0; i--) {
|
||||
if (strcmp(raw_argv[i], cooked_argv[j]) == 0) {
|
||||
raw_argv[i] = NULL;
|
||||
j--;
|
||||
}
|
||||
}
|
||||
|
||||
for (i = 1; i < raw_argc; i++) {
|
||||
if (!(p = raw_argv[i]))
|
||||
continue;
|
||||
if (strncmp(p, "--files-from", 12) == 0
|
||||
|| strncmp(p, "--filter", 8) == 0
|
||||
|| strncmp(p, "--include", 9) == 0
|
||||
|| strncmp(p, "--exclude", 9) == 0) {
|
||||
|| strncmp(p, "--filter", 8) == 0
|
||||
|| strncmp(p, "--include", 9) == 0
|
||||
|| strncmp(p, "--exclude", 9) == 0) {
|
||||
if (strchr(p, '=') == NULL)
|
||||
i++;
|
||||
continue;
|
||||
@@ -251,33 +300,24 @@ void write_batch_shell_file(int argc, char *argv[], int file_arg_cnt)
|
||||
i++;
|
||||
continue;
|
||||
}
|
||||
if (write(fd, " ", 1) != 1)
|
||||
err = 1;
|
||||
if (strncmp(p, "--write-batch", len = 13) == 0
|
||||
|| strncmp(p, "--only-write-batch", len = 18) == 0) {
|
||||
if (write(fd, "--read-batch", 12) != 12)
|
||||
err = 1;
|
||||
if (p[len] == '=') {
|
||||
if (write(fd, "=", 1) != 1
|
||||
|| write_arg(fd, p + len + 1) < 0)
|
||||
err = 1;
|
||||
}
|
||||
} else {
|
||||
if (write_arg(fd, p) < 0)
|
||||
err = 1;
|
||||
|| strncmp(p, "--only-write-batch", len = 18) == 0)
|
||||
err |= write_opt("--read-batch", p[len] == '=' ? p + len + 1 : NULL);
|
||||
else {
|
||||
err |= write(batch_sh_fd, " ", 1) != 1;
|
||||
err |= write_arg(p);
|
||||
}
|
||||
}
|
||||
if (!(p = check_for_hostspec(argv[argc - 1], &p, &i)))
|
||||
p = argv[argc - 1];
|
||||
if (write(fd, " ${1:-", 6) != 6
|
||||
|| write_arg(fd, p) < 0)
|
||||
err = 1;
|
||||
write_byte(fd, '}');
|
||||
if (!(p = check_for_hostspec(cooked_argv[cooked_argc - 1], &p2, &i)))
|
||||
p = cooked_argv[cooked_argc - 1];
|
||||
err |= write_opt("${1:-", NULL);
|
||||
err |= write_arg(p);
|
||||
err |= write(batch_sh_fd, "}", 1) != 1;
|
||||
if (filter_list.head)
|
||||
write_filter_rules(fd);
|
||||
if (write(fd, "\n", 1) != 1 || close(fd) < 0 || err) {
|
||||
rsyserr(FERROR, errno, "Batch file %s write error",
|
||||
filename);
|
||||
write_filter_rules(batch_sh_fd);
|
||||
if (write(batch_sh_fd, "\n", 1) != 1 || close(batch_sh_fd) < 0 || err) {
|
||||
rsyserr(FERROR, errno, "Batch file %s.sh write error", batch_name);
|
||||
exit_cleanup(RERR_FILEIO);
|
||||
}
|
||||
batch_sh_fd = -1;
|
||||
}
|
||||
|
||||
78
byteorder.h
78
byteorder.h
@@ -2,7 +2,7 @@
|
||||
* Simple byteorder handling.
|
||||
*
|
||||
* Copyright (C) 1992-1995 Andrew Tridgell
|
||||
* Copyright (C) 2007-2014 Wayne Davison
|
||||
* Copyright (C) 2007-2020 Wayne Davison
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
@@ -19,7 +19,6 @@
|
||||
*/
|
||||
|
||||
#undef CAREFUL_ALIGNMENT
|
||||
#undef AVOID_BYTEORDER_INLINE
|
||||
|
||||
/* We know that the x86 can handle misalignment and has the same
|
||||
* byte order (LSB-first) as the 32-bit numbers we transmit. */
|
||||
@@ -36,16 +35,36 @@
|
||||
|
||||
#if CAREFUL_ALIGNMENT
|
||||
|
||||
#define PVAL(buf,pos) (UVAL(buf,pos)|UVAL(buf,(pos)+1)<<8)
|
||||
#define IVAL(buf,pos) (PVAL(buf,pos)|PVAL(buf,(pos)+2)<<16)
|
||||
#define IVAL64(buf,pos) (IVAL(buf,pos)|(int64)IVAL(buf,(pos)+4)<<32)
|
||||
#define SSVALX(buf,pos,val) (CVAL(buf,pos)=(val)&0xFF,CVAL(buf,pos+1)=(val)>>8)
|
||||
#define SIVALX(buf,pos,val) (SSVALX(buf,pos,val&0xFFFF),SSVALX(buf,pos+2,val>>16))
|
||||
#define SIVAL(buf,pos,val) SIVALX(buf,pos,(uint32)(val))
|
||||
#define SIVAL64(buf,pos,val) (SIVAL(buf,pos,val),SIVAL(buf,(pos)+4,(val)>>32))
|
||||
static inline uint32
|
||||
IVALu(const uchar *buf, int pos)
|
||||
{
|
||||
return UVAL(buf, pos)
|
||||
| UVAL(buf, pos + 1) << 8
|
||||
| UVAL(buf, pos + 2) << 16
|
||||
| UVAL(buf, pos + 3) << 24;
|
||||
}
|
||||
|
||||
#define IVALu(buf,pos) IVAL(buf,pos)
|
||||
#define SIVALu(buf,pos,val) SIVAL(buf,pos,val)
|
||||
static inline void
|
||||
SIVALu(uchar *buf, int pos, uint32 val)
|
||||
{
|
||||
CVAL(buf, pos) = val;
|
||||
CVAL(buf, pos + 1) = val >> 8;
|
||||
CVAL(buf, pos + 2) = val >> 16;
|
||||
CVAL(buf, pos + 3) = val >> 24;
|
||||
}
|
||||
|
||||
static inline int64
|
||||
IVAL64(const char *buf, int pos)
|
||||
{
|
||||
return IVALu((uchar*)buf, pos) | (int64)IVALu((uchar*)buf, pos + 4) << 32;
|
||||
}
|
||||
|
||||
static inline void
|
||||
SIVAL64(char *buf, int pos, int64 val)
|
||||
{
|
||||
SIVALu((uchar*)buf, pos, val);
|
||||
SIVALu((uchar*)buf, pos + 4, val >> 32);
|
||||
}
|
||||
|
||||
#else /* !CAREFUL_ALIGNMENT */
|
||||
|
||||
@@ -53,16 +72,6 @@
|
||||
* WARNING: This section is dependent on the length of an int32 (and thus a uint32)
|
||||
* being correct (4 bytes)! Set CAREFUL_ALIGNMENT if it is not. */
|
||||
|
||||
# ifdef AVOID_BYTEORDER_INLINE
|
||||
|
||||
#define IVAL(buf,pos) (*(uint32 *)((char *)(buf) + (pos)))
|
||||
#define SIVAL(buf,pos,val) IVAL(buf,pos)=((uint32)(val))
|
||||
|
||||
#define IVALu(buf,pos) IVAL(buf,pos)
|
||||
#define SIVALu(buf,pos,val) SIVAL(buf,pos,val)
|
||||
|
||||
# else /* !AVOID_BYTEORDER_INLINE */
|
||||
|
||||
static inline uint32
|
||||
IVALu(const uchar *buf, int pos)
|
||||
{
|
||||
@@ -85,18 +94,6 @@ SIVALu(uchar *buf, int pos, uint32 val)
|
||||
*u.num = val;
|
||||
}
|
||||
|
||||
static inline uint32
|
||||
IVAL(const char *buf, int pos)
|
||||
{
|
||||
return IVALu((uchar*)buf, pos);
|
||||
}
|
||||
|
||||
static inline void
|
||||
SIVAL(char *buf, int pos, uint32 val)
|
||||
{
|
||||
SIVALu((uchar*)buf, pos, val);
|
||||
}
|
||||
|
||||
static inline int64
|
||||
IVAL64(const char *buf, int pos)
|
||||
{
|
||||
@@ -119,6 +116,17 @@ SIVAL64(char *buf, int pos, int64 val)
|
||||
*u.num = val;
|
||||
}
|
||||
|
||||
# endif /* !AVOID_BYTEORDER_INLINE */
|
||||
|
||||
#endif /* !CAREFUL_ALIGNMENT */
|
||||
|
||||
static inline uint32
|
||||
IVAL(const char *buf, int pos)
|
||||
{
|
||||
return IVALu((uchar*)buf, pos);
|
||||
}
|
||||
|
||||
static inline void
|
||||
SIVAL(char *buf, int pos, uint32 val)
|
||||
{
|
||||
SIVALu((uchar*)buf, pos, val);
|
||||
}
|
||||
|
||||
|
||||
20
case_N.h
20
case_N.h
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* Allow an arbitrary sequence of case labels.
|
||||
*
|
||||
* Copyright (C) 2006-2014 Wayne Davison
|
||||
* Copyright (C) 2006-2020 Wayne Davison
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
@@ -17,7 +17,7 @@
|
||||
* with this program; if not, visit the http://fsf.org website.
|
||||
*/
|
||||
|
||||
/* This is included multiple times, once for every segement in a switch statement.
|
||||
/* This is included multiple times, once for every segment in a switch statement.
|
||||
* This produces the next "case N:" statement in sequence. */
|
||||
|
||||
#if !defined CASE_N_STATE_0
|
||||
@@ -25,51 +25,67 @@
|
||||
case 0:
|
||||
#elif !defined CASE_N_STATE_1
|
||||
#define CASE_N_STATE_1
|
||||
/* FALLTHROUGH */
|
||||
case 1:
|
||||
#elif !defined CASE_N_STATE_2
|
||||
#define CASE_N_STATE_2
|
||||
/* FALLTHROUGH */
|
||||
case 2:
|
||||
#elif !defined CASE_N_STATE_3
|
||||
#define CASE_N_STATE_3
|
||||
/* FALLTHROUGH */
|
||||
case 3:
|
||||
#elif !defined CASE_N_STATE_4
|
||||
#define CASE_N_STATE_4
|
||||
/* FALLTHROUGH */
|
||||
case 4:
|
||||
#elif !defined CASE_N_STATE_5
|
||||
#define CASE_N_STATE_5
|
||||
/* FALLTHROUGH */
|
||||
case 5:
|
||||
#elif !defined CASE_N_STATE_6
|
||||
#define CASE_N_STATE_6
|
||||
/* FALLTHROUGH */
|
||||
case 6:
|
||||
#elif !defined CASE_N_STATE_7
|
||||
#define CASE_N_STATE_7
|
||||
/* FALLTHROUGH */
|
||||
case 7:
|
||||
#elif !defined CASE_N_STATE_8
|
||||
#define CASE_N_STATE_8
|
||||
/* FALLTHROUGH */
|
||||
case 8:
|
||||
#elif !defined CASE_N_STATE_9
|
||||
#define CASE_N_STATE_9
|
||||
/* FALLTHROUGH */
|
||||
case 9:
|
||||
#elif !defined CASE_N_STATE_10
|
||||
#define CASE_N_STATE_10
|
||||
/* FALLTHROUGH */
|
||||
case 10:
|
||||
#elif !defined CASE_N_STATE_11
|
||||
#define CASE_N_STATE_11
|
||||
/* FALLTHROUGH */
|
||||
case 11:
|
||||
#elif !defined CASE_N_STATE_12
|
||||
#define CASE_N_STATE_12
|
||||
/* FALLTHROUGH */
|
||||
case 12:
|
||||
#elif !defined CASE_N_STATE_13
|
||||
#define CASE_N_STATE_13
|
||||
/* FALLTHROUGH */
|
||||
case 13:
|
||||
#elif !defined CASE_N_STATE_14
|
||||
#define CASE_N_STATE_14
|
||||
/* FALLTHROUGH */
|
||||
case 14:
|
||||
#elif !defined CASE_N_STATE_15
|
||||
#define CASE_N_STATE_15
|
||||
/* FALLTHROUGH */
|
||||
case 15:
|
||||
#elif !defined CASE_N_STATE_16
|
||||
#define CASE_N_STATE_16
|
||||
/* FALLTHROUGH */
|
||||
case 16:
|
||||
#else
|
||||
#error Need to add more case statements!
|
||||
|
||||
473
checksum.c
473
checksum.c
@@ -3,13 +3,20 @@
|
||||
*
|
||||
* Copyright (C) 1996 Andrew Tridgell
|
||||
* Copyright (C) 1996 Paul Mackerras
|
||||
* Copyright (C) 2004-2014 Wayne Davison
|
||||
* Copyright (C) 2004-2020 Wayne Davison
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* In addition, as a special exception, the copyright holders give
|
||||
* permission to dynamically link rsync with the OpenSSL and xxhash
|
||||
* libraries when those libraries are being distributed in compliance
|
||||
* with their license terms, and to distribute a dynamically linked
|
||||
* combination of rsync and these libraries. This is also considered
|
||||
* to be covered under the GPL's System Libraries exception.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
@@ -20,47 +27,217 @@
|
||||
*/
|
||||
|
||||
#include "rsync.h"
|
||||
#ifdef SUPPORT_XXHASH
|
||||
#include "xxhash.h"
|
||||
#endif
|
||||
|
||||
extern int am_server;
|
||||
extern int whole_file;
|
||||
extern int checksum_seed;
|
||||
extern int protocol_version;
|
||||
extern int proper_seed_order;
|
||||
extern const char *checksum_choice;
|
||||
|
||||
struct name_num_obj valid_checksums = {
|
||||
"checksum", NULL, NULL, 0, 0, {
|
||||
#ifdef SUPPORT_XXHASH
|
||||
{ CSUM_XXH64, "xxh64", NULL },
|
||||
{ CSUM_XXH64, "xxhash", NULL },
|
||||
#endif
|
||||
{ CSUM_MD5, "md5", NULL },
|
||||
{ CSUM_MD4, "md4", NULL },
|
||||
{ CSUM_NONE, "none", NULL },
|
||||
{ 0, NULL, NULL }
|
||||
}
|
||||
};
|
||||
|
||||
int xfersum_type = 0; /* used for the file transfer checksums */
|
||||
int checksum_type = 0; /* used for the pre-transfer (--checksum) checksums */
|
||||
|
||||
int parse_csum_name(const char *name, int len)
|
||||
{
|
||||
struct name_num_item *nni;
|
||||
|
||||
if (len < 0 && name)
|
||||
len = strlen(name);
|
||||
|
||||
if (!name || (len == 4 && strncasecmp(name, "auto", 4) == 0)) {
|
||||
if (protocol_version >= 30)
|
||||
return CSUM_MD5;
|
||||
if (protocol_version >= 27)
|
||||
return CSUM_MD4_OLD;
|
||||
if (protocol_version >= 21)
|
||||
return CSUM_MD4_BUSTED;
|
||||
return CSUM_MD4_ARCHAIC;
|
||||
}
|
||||
|
||||
nni = get_nni_by_name(&valid_checksums, name, len);
|
||||
|
||||
if (!nni) {
|
||||
rprintf(FERROR, "unknown checksum name: %s\n", name);
|
||||
exit_cleanup(RERR_UNSUPPORTED);
|
||||
}
|
||||
|
||||
return nni->num;
|
||||
}
|
||||
|
||||
static const char *checksum_name(int num)
|
||||
{
|
||||
struct name_num_item *nni = get_nni_by_num(&valid_checksums, num);
|
||||
|
||||
return nni ? nni->name : num < CSUM_MD4 ? "MD4" : "UNKNOWN";
|
||||
}
|
||||
|
||||
void parse_checksum_choice(int final_call)
|
||||
{
|
||||
if (valid_checksums.negotiated_name)
|
||||
xfersum_type = checksum_type = valid_checksums.negotiated_num;
|
||||
else {
|
||||
char *cp = checksum_choice ? strchr(checksum_choice, ',') : NULL;
|
||||
if (cp) {
|
||||
xfersum_type = parse_csum_name(checksum_choice, cp - checksum_choice);
|
||||
checksum_type = parse_csum_name(cp+1, -1);
|
||||
} else
|
||||
xfersum_type = checksum_type = parse_csum_name(checksum_choice, -1);
|
||||
}
|
||||
|
||||
if (xfersum_type == CSUM_NONE)
|
||||
whole_file = 1;
|
||||
|
||||
/* Snag the checksum name for both write_batch's option output & the following debug output. */
|
||||
if (valid_checksums.negotiated_name)
|
||||
checksum_choice = valid_checksums.negotiated_name;
|
||||
else if (checksum_choice == NULL)
|
||||
checksum_choice = checksum_name(xfersum_type);
|
||||
|
||||
if (final_call && DEBUG_GTE(NSTR, am_server ? 3 : 1)) {
|
||||
rprintf(FINFO, "%s%s checksum: %s\n",
|
||||
am_server ? "Server" : "Client",
|
||||
valid_checksums.negotiated_name ? " negotiated" : "",
|
||||
checksum_choice);
|
||||
}
|
||||
}
|
||||
|
||||
int csum_len_for_type(int cst, BOOL flist_csum)
|
||||
{
|
||||
switch (cst) {
|
||||
case CSUM_NONE:
|
||||
return 1;
|
||||
case CSUM_MD4_ARCHAIC:
|
||||
/* The oldest checksum code is rather weird: the file-list code only sent
|
||||
* 2-byte checksums, but all other checksums were full MD4 length. */
|
||||
return flist_csum ? 2 : MD4_DIGEST_LEN;
|
||||
case CSUM_MD4:
|
||||
case CSUM_MD4_OLD:
|
||||
case CSUM_MD4_BUSTED:
|
||||
return MD4_DIGEST_LEN;
|
||||
case CSUM_MD5:
|
||||
return MD5_DIGEST_LEN;
|
||||
#ifdef SUPPORT_XXHASH
|
||||
case CSUM_XXH64:
|
||||
return 64/8;
|
||||
#endif
|
||||
default: /* paranoia to prevent missing case values */
|
||||
exit_cleanup(RERR_UNSUPPORTED);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Returns 0 if the checksum is not canonical (i.e. it includes a seed value).
|
||||
* Returns 1 if the public sum order matches our internal sum order.
|
||||
* Returns -1 if the public sum order is the reverse of our internal sum order.
|
||||
*/
|
||||
int canonical_checksum(int csum_type)
|
||||
{
|
||||
switch (csum_type) {
|
||||
case CSUM_NONE:
|
||||
case CSUM_MD4_ARCHAIC:
|
||||
case CSUM_MD4_OLD:
|
||||
case CSUM_MD4_BUSTED:
|
||||
break;
|
||||
case CSUM_MD4:
|
||||
case CSUM_MD5:
|
||||
return -1;
|
||||
#ifdef SUPPORT_XXHASH
|
||||
case CSUM_XXH64:
|
||||
return 1;
|
||||
#endif
|
||||
default: /* paranoia to prevent missing case values */
|
||||
exit_cleanup(RERR_UNSUPPORTED);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifndef HAVE_SIMD /* See simd-checksum-*.cpp. */
|
||||
/*
|
||||
a simple 32 bit checksum that can be upadted from either end
|
||||
a simple 32 bit checksum that can be updated from either end
|
||||
(inspired by Mark Adler's Adler-32 checksum)
|
||||
*/
|
||||
uint32 get_checksum1(char *buf1, int32 len)
|
||||
{
|
||||
int32 i;
|
||||
uint32 s1, s2;
|
||||
schar *buf = (schar *)buf1;
|
||||
int32 i;
|
||||
uint32 s1, s2;
|
||||
schar *buf = (schar *)buf1;
|
||||
|
||||
s1 = s2 = 0;
|
||||
for (i = 0; i < (len-4); i+=4) {
|
||||
s2 += 4*(s1 + buf[i]) + 3*buf[i+1] + 2*buf[i+2] + buf[i+3] +
|
||||
10*CHAR_OFFSET;
|
||||
s1 += (buf[i+0] + buf[i+1] + buf[i+2] + buf[i+3] + 4*CHAR_OFFSET);
|
||||
}
|
||||
for (; i < len; i++) {
|
||||
s1 += (buf[i]+CHAR_OFFSET); s2 += s1;
|
||||
}
|
||||
return (s1 & 0xffff) + (s2 << 16);
|
||||
s1 = s2 = 0;
|
||||
for (i = 0; i < (len-4); i+=4) {
|
||||
s2 += 4*(s1 + buf[i]) + 3*buf[i+1] + 2*buf[i+2] + buf[i+3] + 10*CHAR_OFFSET;
|
||||
s1 += (buf[i+0] + buf[i+1] + buf[i+2] + buf[i+3] + 4*CHAR_OFFSET);
|
||||
}
|
||||
for (; i < len; i++) {
|
||||
s1 += (buf[i]+CHAR_OFFSET); s2 += s1;
|
||||
}
|
||||
return (s1 & 0xffff) + (s2 << 16);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
void get_checksum2(char *buf, int32 len, char *sum)
|
||||
{
|
||||
md_context m;
|
||||
|
||||
if (protocol_version >= 30) {
|
||||
switch (xfersum_type) {
|
||||
#ifdef SUPPORT_XXHASH
|
||||
case CSUM_XXH64:
|
||||
SIVAL64(sum, 0, XXH64(buf, len, checksum_seed));
|
||||
break;
|
||||
#endif
|
||||
case CSUM_MD5: {
|
||||
MD5_CTX m5;
|
||||
uchar seedbuf[4];
|
||||
md5_begin(&m);
|
||||
md5_update(&m, (uchar *)buf, len);
|
||||
if (checksum_seed) {
|
||||
SIVALu(seedbuf, 0, checksum_seed);
|
||||
md5_update(&m, seedbuf, 4);
|
||||
MD5_Init(&m5);
|
||||
if (proper_seed_order) {
|
||||
if (checksum_seed) {
|
||||
SIVALu(seedbuf, 0, checksum_seed);
|
||||
MD5_Update(&m5, seedbuf, 4);
|
||||
}
|
||||
MD5_Update(&m5, (uchar *)buf, len);
|
||||
} else {
|
||||
MD5_Update(&m5, (uchar *)buf, len);
|
||||
if (checksum_seed) {
|
||||
SIVALu(seedbuf, 0, checksum_seed);
|
||||
MD5_Update(&m5, seedbuf, 4);
|
||||
}
|
||||
}
|
||||
md5_result(&m, (uchar *)sum);
|
||||
} else {
|
||||
MD5_Final((uchar *)sum, &m5);
|
||||
break;
|
||||
}
|
||||
case CSUM_MD4:
|
||||
#ifdef USE_OPENSSL
|
||||
{
|
||||
MD4_CTX m4;
|
||||
MD4_Init(&m4);
|
||||
MD4_Update(&m4, (uchar *)buf, len);
|
||||
if (checksum_seed) {
|
||||
uchar seedbuf[4];
|
||||
SIVALu(seedbuf, 0, checksum_seed);
|
||||
MD4_Update(&m4, seedbuf, 4);
|
||||
}
|
||||
MD4_Final((uchar *)sum, &m4);
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
case CSUM_MD4_OLD:
|
||||
case CSUM_MD4_BUSTED:
|
||||
case CSUM_MD4_ARCHAIC: {
|
||||
md_context m;
|
||||
int32 i;
|
||||
static char *buf1;
|
||||
static int32 len1;
|
||||
@@ -91,10 +268,14 @@ void get_checksum2(char *buf, int32 len, char *sum)
|
||||
* are multiples of 64. This is fixed by calling mdfour_update()
|
||||
* even when there are no more bytes.
|
||||
*/
|
||||
if (len - i > 0 || protocol_version >= 27)
|
||||
if (len - i > 0 || xfersum_type > CSUM_MD4_BUSTED)
|
||||
mdfour_update(&m, (uchar *)(buf1+i), len-i);
|
||||
|
||||
mdfour_result(&m, (uchar *)sum);
|
||||
break;
|
||||
}
|
||||
default: /* paranoia to prevent missing case values */
|
||||
exit_cleanup(RERR_UNSUPPORTED);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -102,7 +283,6 @@ void file_checksum(const char *fname, const STRUCT_STAT *st_p, char *sum)
|
||||
{
|
||||
struct map_struct *buf;
|
||||
OFF_T i, len = st_p->st_size;
|
||||
md_context m;
|
||||
int32 remainder;
|
||||
int fd;
|
||||
|
||||
@@ -112,38 +292,86 @@ void file_checksum(const char *fname, const STRUCT_STAT *st_p, char *sum)
|
||||
if (fd == -1)
|
||||
return;
|
||||
|
||||
buf = map_file(fd, len, MAX_MAP_SIZE, CSUM_CHUNK);
|
||||
buf = map_file(fd, len, MAX_MAP_SIZE, CHUNK_SIZE);
|
||||
|
||||
if (protocol_version >= 30) {
|
||||
md5_begin(&m);
|
||||
switch (checksum_type) {
|
||||
#ifdef SUPPORT_XXHASH
|
||||
case CSUM_XXH64: {
|
||||
static XXH64_state_t* state = NULL;
|
||||
if (!state && !(state = XXH64_createState()))
|
||||
out_of_memory("file_checksum");
|
||||
|
||||
for (i = 0; i + CSUM_CHUNK <= len; i += CSUM_CHUNK) {
|
||||
md5_update(&m, (uchar *)map_ptr(buf, i, CSUM_CHUNK),
|
||||
CSUM_CHUNK);
|
||||
}
|
||||
XXH64_reset(state, 0);
|
||||
|
||||
for (i = 0; i + CHUNK_SIZE <= len; i += CHUNK_SIZE)
|
||||
XXH64_update(state, (uchar *)map_ptr(buf, i, CHUNK_SIZE), CHUNK_SIZE);
|
||||
|
||||
remainder = (int32)(len - i);
|
||||
if (remainder > 0)
|
||||
md5_update(&m, (uchar *)map_ptr(buf, i, remainder), remainder);
|
||||
XXH64_update(state, (uchar *)map_ptr(buf, i, remainder), remainder);
|
||||
|
||||
SIVAL64(sum, 0, XXH64_digest(state));
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
case CSUM_MD5: {
|
||||
MD5_CTX m5;
|
||||
|
||||
MD5_Init(&m5);
|
||||
|
||||
for (i = 0; i + CHUNK_SIZE <= len; i += CHUNK_SIZE)
|
||||
MD5_Update(&m5, (uchar *)map_ptr(buf, i, CHUNK_SIZE), CHUNK_SIZE);
|
||||
|
||||
remainder = (int32)(len - i);
|
||||
if (remainder > 0)
|
||||
MD5_Update(&m5, (uchar *)map_ptr(buf, i, remainder), remainder);
|
||||
|
||||
MD5_Final((uchar *)sum, &m5);
|
||||
break;
|
||||
}
|
||||
case CSUM_MD4:
|
||||
#ifdef USE_OPENSSL
|
||||
{
|
||||
MD4_CTX m4;
|
||||
|
||||
MD4_Init(&m4);
|
||||
|
||||
for (i = 0; i + CHUNK_SIZE <= len; i += CHUNK_SIZE)
|
||||
MD4_Update(&m4, (uchar *)map_ptr(buf, i, CHUNK_SIZE), CHUNK_SIZE);
|
||||
|
||||
remainder = (int32)(len - i);
|
||||
if (remainder > 0)
|
||||
MD4_Update(&m4, (uchar *)map_ptr(buf, i, remainder), remainder);
|
||||
|
||||
MD4_Final((uchar *)sum, &m4);
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
case CSUM_MD4_OLD:
|
||||
case CSUM_MD4_BUSTED:
|
||||
case CSUM_MD4_ARCHAIC: {
|
||||
md_context m;
|
||||
|
||||
md5_result(&m, (uchar *)sum);
|
||||
} else {
|
||||
mdfour_begin(&m);
|
||||
|
||||
for (i = 0; i + CSUM_CHUNK <= len; i += CSUM_CHUNK) {
|
||||
mdfour_update(&m, (uchar *)map_ptr(buf, i, CSUM_CHUNK),
|
||||
CSUM_CHUNK);
|
||||
}
|
||||
for (i = 0; i + CHUNK_SIZE <= len; i += CHUNK_SIZE)
|
||||
mdfour_update(&m, (uchar *)map_ptr(buf, i, CHUNK_SIZE), CHUNK_SIZE);
|
||||
|
||||
/* Prior to version 27 an incorrect MD4 checksum was computed
|
||||
* by failing to call mdfour_tail() for block sizes that
|
||||
* are multiples of 64. This is fixed by calling mdfour_update()
|
||||
* even when there are no more bytes. */
|
||||
remainder = (int32)(len - i);
|
||||
if (remainder > 0 || protocol_version >= 27)
|
||||
if (remainder > 0 || checksum_type > CSUM_MD4_BUSTED)
|
||||
mdfour_update(&m, (uchar *)map_ptr(buf, i, remainder), remainder);
|
||||
|
||||
mdfour_result(&m, (uchar *)sum);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
rprintf(FERROR, "Invalid checksum-choice for --checksum: %s (%d)\n",
|
||||
checksum_name(checksum_type), checksum_type);
|
||||
exit_cleanup(RERR_UNSUPPORTED);
|
||||
}
|
||||
|
||||
close(fd);
|
||||
@@ -151,19 +379,57 @@ void file_checksum(const char *fname, const STRUCT_STAT *st_p, char *sum)
|
||||
}
|
||||
|
||||
static int32 sumresidue;
|
||||
static md_context md;
|
||||
static union {
|
||||
md_context md;
|
||||
#ifdef USE_OPENSSL
|
||||
MD4_CTX m4;
|
||||
#endif
|
||||
MD5_CTX m5;
|
||||
} ctx;
|
||||
#ifdef SUPPORT_XXHASH
|
||||
static XXH64_state_t* xxh64_state;
|
||||
#endif
|
||||
static int cursum_type;
|
||||
|
||||
void sum_init(int seed)
|
||||
void sum_init(int csum_type, int seed)
|
||||
{
|
||||
char s[4];
|
||||
|
||||
if (protocol_version >= 30)
|
||||
md5_begin(&md);
|
||||
else {
|
||||
mdfour_begin(&md);
|
||||
if (csum_type < 0)
|
||||
csum_type = parse_csum_name(NULL, 0);
|
||||
cursum_type = csum_type;
|
||||
|
||||
switch (csum_type) {
|
||||
#ifdef SUPPORT_XXHASH
|
||||
case CSUM_XXH64:
|
||||
if (!xxh64_state && !(xxh64_state = XXH64_createState()))
|
||||
out_of_memory("sum_init");
|
||||
XXH64_reset(xxh64_state, 0);
|
||||
break;
|
||||
#endif
|
||||
case CSUM_MD5:
|
||||
MD5_Init(&ctx.m5);
|
||||
break;
|
||||
case CSUM_MD4:
|
||||
#ifdef USE_OPENSSL
|
||||
MD4_Init(&ctx.m4);
|
||||
#else
|
||||
mdfour_begin(&ctx.md);
|
||||
sumresidue = 0;
|
||||
#endif
|
||||
break;
|
||||
case CSUM_MD4_OLD:
|
||||
case CSUM_MD4_BUSTED:
|
||||
case CSUM_MD4_ARCHAIC:
|
||||
mdfour_begin(&ctx.md);
|
||||
sumresidue = 0;
|
||||
SIVAL(s, 0, seed);
|
||||
sum_update(s, 4);
|
||||
break;
|
||||
case CSUM_NONE:
|
||||
break;
|
||||
default: /* paranoia to prevent missing case values */
|
||||
exit_cleanup(RERR_UNSUPPORTED);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -177,47 +443,90 @@ void sum_init(int seed)
|
||||
**/
|
||||
void sum_update(const char *p, int32 len)
|
||||
{
|
||||
if (protocol_version >= 30) {
|
||||
md5_update(&md, (uchar *)p, len);
|
||||
return;
|
||||
}
|
||||
switch (cursum_type) {
|
||||
#ifdef SUPPORT_XXHASH
|
||||
case CSUM_XXH64:
|
||||
XXH64_update(xxh64_state, p, len);
|
||||
break;
|
||||
#endif
|
||||
case CSUM_MD5:
|
||||
MD5_Update(&ctx.m5, (uchar *)p, len);
|
||||
break;
|
||||
case CSUM_MD4:
|
||||
#ifdef USE_OPENSSL
|
||||
MD4_Update(&ctx.m4, (uchar *)p, len);
|
||||
break;
|
||||
#endif
|
||||
case CSUM_MD4_OLD:
|
||||
case CSUM_MD4_BUSTED:
|
||||
case CSUM_MD4_ARCHAIC:
|
||||
if (len + sumresidue < CSUM_CHUNK) {
|
||||
memcpy(ctx.md.buffer + sumresidue, p, len);
|
||||
sumresidue += len;
|
||||
break;
|
||||
}
|
||||
|
||||
if (len + sumresidue < CSUM_CHUNK) {
|
||||
memcpy(md.buffer + sumresidue, p, len);
|
||||
sumresidue += len;
|
||||
return;
|
||||
}
|
||||
if (sumresidue) {
|
||||
int32 i = CSUM_CHUNK - sumresidue;
|
||||
memcpy(ctx.md.buffer + sumresidue, p, i);
|
||||
mdfour_update(&ctx.md, (uchar *)ctx.md.buffer, CSUM_CHUNK);
|
||||
len -= i;
|
||||
p += i;
|
||||
}
|
||||
|
||||
if (sumresidue) {
|
||||
int32 i = CSUM_CHUNK - sumresidue;
|
||||
memcpy(md.buffer + sumresidue, p, i);
|
||||
mdfour_update(&md, (uchar *)md.buffer, CSUM_CHUNK);
|
||||
len -= i;
|
||||
p += i;
|
||||
}
|
||||
while (len >= CSUM_CHUNK) {
|
||||
mdfour_update(&ctx.md, (uchar *)p, CSUM_CHUNK);
|
||||
len -= CSUM_CHUNK;
|
||||
p += CSUM_CHUNK;
|
||||
}
|
||||
|
||||
while (len >= CSUM_CHUNK) {
|
||||
mdfour_update(&md, (uchar *)p, CSUM_CHUNK);
|
||||
len -= CSUM_CHUNK;
|
||||
p += CSUM_CHUNK;
|
||||
sumresidue = len;
|
||||
if (sumresidue)
|
||||
memcpy(ctx.md.buffer, p, sumresidue);
|
||||
break;
|
||||
case CSUM_NONE:
|
||||
break;
|
||||
default: /* paranoia to prevent missing case values */
|
||||
exit_cleanup(RERR_UNSUPPORTED);
|
||||
}
|
||||
|
||||
sumresidue = len;
|
||||
if (sumresidue)
|
||||
memcpy(md.buffer, p, sumresidue);
|
||||
}
|
||||
|
||||
/* NOTE: all the callers of sum_end() pass in a pointer to a buffer that is
|
||||
* MAX_DIGEST_LEN in size, so even if the csum-len is shorter that that (i.e.
|
||||
* CSUM_MD4_ARCHAIC), we don't have to worry about limiting the data we write
|
||||
* into the "sum" buffer. */
|
||||
int sum_end(char *sum)
|
||||
{
|
||||
if (protocol_version >= 30) {
|
||||
md5_result(&md, (uchar *)sum);
|
||||
return MD5_DIGEST_LEN;
|
||||
switch (cursum_type) {
|
||||
#ifdef SUPPORT_XXHASH
|
||||
case CSUM_XXH64:
|
||||
SIVAL64(sum, 0, XXH64_digest(xxh64_state));
|
||||
break;
|
||||
#endif
|
||||
case CSUM_MD5:
|
||||
MD5_Final((uchar *)sum, &ctx.m5);
|
||||
break;
|
||||
case CSUM_MD4:
|
||||
#ifdef USE_OPENSSL
|
||||
MD4_Final((uchar *)sum, &ctx.m4);
|
||||
break;
|
||||
#endif
|
||||
case CSUM_MD4_OLD:
|
||||
mdfour_update(&ctx.md, (uchar *)ctx.md.buffer, sumresidue);
|
||||
mdfour_result(&ctx.md, (uchar *)sum);
|
||||
break;
|
||||
case CSUM_MD4_BUSTED:
|
||||
case CSUM_MD4_ARCHAIC:
|
||||
if (sumresidue)
|
||||
mdfour_update(&ctx.md, (uchar *)ctx.md.buffer, sumresidue);
|
||||
mdfour_result(&ctx.md, (uchar *)sum);
|
||||
break;
|
||||
case CSUM_NONE:
|
||||
*sum = '\0';
|
||||
break;
|
||||
default: /* paranoia to prevent missing case values */
|
||||
exit_cleanup(RERR_UNSUPPORTED);
|
||||
}
|
||||
|
||||
if (sumresidue || protocol_version >= 27)
|
||||
mdfour_update(&md, (uchar *)md.buffer, sumresidue);
|
||||
|
||||
mdfour_result(&md, (uchar *)sum);
|
||||
|
||||
return MD4_DIGEST_LEN;
|
||||
return csum_len_for_type(cursum_type, 0);
|
||||
}
|
||||
|
||||
4
chmod.c
4
chmod.c
@@ -2,7 +2,7 @@
|
||||
* Implement the core of the --chmod option.
|
||||
*
|
||||
* Copyright (C) 2002 Scott Howard
|
||||
* Copyright (C) 2005-2014 Wayne Davison
|
||||
* Copyright (C) 2005-2020 Wayne Davison
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
@@ -44,7 +44,7 @@ struct chmod_mode_struct {
|
||||
#define STATE_OCTAL_NUM 3
|
||||
|
||||
/* Parse a chmod-style argument, and break it down into one or more AND/OR
|
||||
* pairs in a linked list. We return a pointer to new items on succcess
|
||||
* pairs in a linked list. We return a pointer to new items on success
|
||||
* (appending the items to the specified list), or NULL on error. */
|
||||
struct chmod_mode_struct *parse_chmod(const char *modestr,
|
||||
struct chmod_mode_struct **root_mode_ptr)
|
||||
|
||||
49
cleanup.c
49
cleanup.c
@@ -4,7 +4,7 @@
|
||||
* Copyright (C) 1996-2000 Andrew Tridgell
|
||||
* Copyright (C) 1996 Paul Mackerras
|
||||
* Copyright (C) 2002 Martin Pool
|
||||
* Copyright (C) 2003-2014 Wayne Davison
|
||||
* Copyright (C) 2003-2020 Wayne Davison
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
@@ -22,9 +22,11 @@
|
||||
|
||||
#include "rsync.h"
|
||||
|
||||
extern int dry_run;
|
||||
extern int am_server;
|
||||
extern int am_daemon;
|
||||
extern int am_receiver;
|
||||
extern int am_sender;
|
||||
extern int io_error;
|
||||
extern int keep_partial;
|
||||
extern int got_xfer_error;
|
||||
@@ -33,6 +35,7 @@ extern int output_needs_newline;
|
||||
extern char *partial_dir;
|
||||
extern char *logfile_name;
|
||||
|
||||
int called_from_signal_handler = 0;
|
||||
BOOL shutting_down = False;
|
||||
BOOL flush_ok_after_signal = False;
|
||||
|
||||
@@ -137,7 +140,6 @@ NORETURN void _exit_cleanup(int code, const char *file, int line)
|
||||
who_am_i(), code, file, line);
|
||||
}
|
||||
|
||||
/* FALLTHROUGH */
|
||||
#include "case_N.h"
|
||||
switch_step++;
|
||||
|
||||
@@ -151,7 +153,6 @@ NORETURN void _exit_cleanup(int code, const char *file, int line)
|
||||
}
|
||||
}
|
||||
|
||||
/* FALLTHROUGH */
|
||||
#include "case_N.h"
|
||||
switch_step++;
|
||||
|
||||
@@ -171,18 +172,17 @@ NORETURN void _exit_cleanup(int code, const char *file, int line)
|
||||
const char *fname = cleanup_fname;
|
||||
cleanup_fname = NULL;
|
||||
if (!partial_dir) {
|
||||
/* We don't want to leave a partial file with a modern time or it
|
||||
* could be skipped via --update. Setting the time to something
|
||||
* really old also helps it to stand out as unfinished in an ls. */
|
||||
tweak_modtime = 1;
|
||||
cleanup_file->modtime = 0;
|
||||
/* We don't want to leave a partial file with a modern time or it
|
||||
* could be skipped via --update. Setting the time to something
|
||||
* really old also helps it to stand out as unfinished in an ls. */
|
||||
tweak_modtime = 1;
|
||||
cleanup_file->modtime = 0;
|
||||
}
|
||||
finish_transfer(cleanup_new_fname, fname, NULL, NULL,
|
||||
cleanup_file, tweak_modtime, !partial_dir);
|
||||
}
|
||||
}
|
||||
|
||||
/* FALLTHROUGH */
|
||||
#include "case_N.h"
|
||||
switch_step++;
|
||||
|
||||
@@ -194,7 +194,6 @@ NORETURN void _exit_cleanup(int code, const char *file, int line)
|
||||
if (!exit_code && !code)
|
||||
io_flush(FULL_FLUSH);
|
||||
|
||||
/* FALLTHROUGH */
|
||||
#include "case_N.h"
|
||||
switch_step++;
|
||||
|
||||
@@ -225,34 +224,38 @@ NORETURN void _exit_cleanup(int code, const char *file, int line)
|
||||
|| am_daemon || (logfile_name && (am_server || !INFO_GTE(STATS, 1))))
|
||||
log_exit(exit_code, exit_file, exit_line);
|
||||
|
||||
/* FALLTHROUGH */
|
||||
#include "case_N.h"
|
||||
switch_step++;
|
||||
|
||||
if (DEBUG_GTE(EXIT, 1)) {
|
||||
rprintf(FINFO,
|
||||
"[%s] _exit_cleanup(code=%d, file=%s, line=%d): "
|
||||
"about to call exit(%d)\n",
|
||||
who_am_i(), first_code, exit_file, exit_line, exit_code);
|
||||
"about to call exit(%d)%s\n",
|
||||
who_am_i(), first_code, exit_file, exit_line, exit_code,
|
||||
dry_run ? " (DRY RUN)" : "");
|
||||
}
|
||||
|
||||
/* FALLTHROUGH */
|
||||
#include "case_N.h"
|
||||
switch_step++;
|
||||
|
||||
if (exit_code && exit_code != RERR_SOCKETIO && exit_code != RERR_STREAMIO && exit_code != RERR_SIGNAL1
|
||||
&& exit_code != RERR_TIMEOUT && !shutting_down && (protocol_version >= 31 || am_receiver)) {
|
||||
if (line > 0) {
|
||||
if (DEBUG_GTE(EXIT, 3)) {
|
||||
rprintf(FINFO, "[%s] sending MSG_ERROR_EXIT with exit_code %d\n",
|
||||
who_am_i(), exit_code);
|
||||
&& exit_code != RERR_TIMEOUT && !shutting_down) {
|
||||
if (protocol_version >= 31 || am_receiver) {
|
||||
if (line > 0) {
|
||||
if (DEBUG_GTE(EXIT, 3)) {
|
||||
rprintf(FINFO, "[%s] sending MSG_ERROR_EXIT with exit_code %d\n",
|
||||
who_am_i(), exit_code);
|
||||
}
|
||||
send_msg_int(MSG_ERROR_EXIT, exit_code);
|
||||
}
|
||||
send_msg_int(MSG_ERROR_EXIT, exit_code);
|
||||
if (!am_sender)
|
||||
io_flush(MSG_FLUSH); /* Be sure to send all messages */
|
||||
noop_io_until_death();
|
||||
}
|
||||
noop_io_until_death();
|
||||
else if (!am_sender)
|
||||
io_flush(MSG_FLUSH); /* Be sure to send all messages */
|
||||
}
|
||||
|
||||
/* FALLTHROUGH */
|
||||
#include "case_N.h"
|
||||
switch_step++;
|
||||
|
||||
@@ -265,6 +268,8 @@ NORETURN void _exit_cleanup(int code, const char *file, int line)
|
||||
break;
|
||||
}
|
||||
|
||||
if (called_from_signal_handler)
|
||||
_exit(exit_code);
|
||||
exit(exit_code);
|
||||
}
|
||||
|
||||
|
||||
414
clientname.c
414
clientname.c
@@ -3,7 +3,7 @@
|
||||
*
|
||||
* Copyright (C) 1992-2001 Andrew Tridgell <tridge@samba.org>
|
||||
* Copyright (C) 2001, 2002 Martin Pool <mbp@samba.org>
|
||||
* Copyright (C) 2002-2014 Wayne Davison
|
||||
* Copyright (C) 2002-2020 Wayne Davison
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
@@ -27,52 +27,60 @@
|
||||
*/
|
||||
|
||||
#include "rsync.h"
|
||||
#include "itypes.h"
|
||||
|
||||
extern int am_daemon;
|
||||
|
||||
static const char default_name[] = "UNKNOWN";
|
||||
extern int am_server;
|
||||
static const char proxyv2sig[] = "\r\n\r\n\0\r\nQUIT\n";
|
||||
|
||||
static char ipaddr_buf[100];
|
||||
|
||||
/**
|
||||
* Return the IP addr of the client as a string
|
||||
**/
|
||||
#define PROXY_V2_SIG_SIZE ((int)sizeof proxyv2sig - 1)
|
||||
#define PROXY_V2_HEADER_SIZE (PROXY_V2_SIG_SIZE + 1 + 1 + 2)
|
||||
|
||||
#define CMD_LOCAL 0
|
||||
#define CMD_PROXY 1
|
||||
|
||||
#define PROXY_FAM_TCPv4 0x11
|
||||
#define PROXY_FAM_TCPv6 0x21
|
||||
|
||||
#define GET_SOCKADDR_FAMILY(ss) ((struct sockaddr*)ss)->sa_family
|
||||
|
||||
static void client_sockaddr(int fd, struct sockaddr_storage *ss, socklen_t *ss_len);
|
||||
static int check_name(const char *ipaddr, const struct sockaddr_storage *ss, char *name_buf, size_t name_buf_size);
|
||||
static int valid_ipaddr(const char *s);
|
||||
|
||||
/* Return the IP addr of the client as a string. */
|
||||
char *client_addr(int fd)
|
||||
{
|
||||
static char addr_buf[100];
|
||||
static int initialised;
|
||||
struct sockaddr_storage ss;
|
||||
socklen_t length = sizeof ss;
|
||||
|
||||
if (initialised)
|
||||
return addr_buf;
|
||||
if (*ipaddr_buf)
|
||||
return ipaddr_buf;
|
||||
|
||||
initialised = 1;
|
||||
|
||||
if (am_server) { /* daemon over --rsh mode */
|
||||
if (am_daemon < 0) { /* daemon over --rsh mode */
|
||||
char *env_str;
|
||||
strlcpy(addr_buf, "0.0.0.0", sizeof addr_buf);
|
||||
strlcpy(ipaddr_buf, "0.0.0.0", sizeof ipaddr_buf);
|
||||
if ((env_str = getenv("REMOTE_HOST")) != NULL
|
||||
|| (env_str = getenv("SSH_CONNECTION")) != NULL
|
||||
|| (env_str = getenv("SSH_CLIENT")) != NULL
|
||||
|| (env_str = getenv("SSH2_CLIENT")) != NULL) {
|
||||
char *p;
|
||||
strlcpy(addr_buf, env_str, sizeof addr_buf);
|
||||
strlcpy(ipaddr_buf, env_str, sizeof ipaddr_buf);
|
||||
/* Truncate the value to just the IP address. */
|
||||
if ((p = strchr(addr_buf, ' ')) != NULL)
|
||||
if ((p = strchr(ipaddr_buf, ' ')) != NULL)
|
||||
*p = '\0';
|
||||
}
|
||||
} else {
|
||||
client_sockaddr(fd, &ss, &length);
|
||||
getnameinfo((struct sockaddr *)&ss, length,
|
||||
addr_buf, sizeof addr_buf, NULL, 0, NI_NUMERICHOST);
|
||||
if (valid_ipaddr(ipaddr_buf))
|
||||
return ipaddr_buf;
|
||||
}
|
||||
|
||||
return addr_buf;
|
||||
}
|
||||
client_sockaddr(fd, &ss, &length);
|
||||
getnameinfo((struct sockaddr *)&ss, length, ipaddr_buf, sizeof ipaddr_buf, NULL, 0, NI_NUMERICHOST);
|
||||
|
||||
|
||||
static int get_sockaddr_family(const struct sockaddr_storage *ss)
|
||||
{
|
||||
return ((struct sockaddr *) ss)->sa_family;
|
||||
return ipaddr_buf;
|
||||
}
|
||||
|
||||
|
||||
@@ -89,71 +97,216 @@ static int get_sockaddr_family(const struct sockaddr_storage *ss)
|
||||
* After translation from sockaddr to name we do a forward lookup to
|
||||
* make sure nobody is spoofing PTR records.
|
||||
**/
|
||||
char *client_name(int fd)
|
||||
char *client_name(const char *ipaddr)
|
||||
{
|
||||
static char name_buf[100];
|
||||
static char port_buf[100];
|
||||
static int initialised;
|
||||
char port_buf[100];
|
||||
struct sockaddr_storage ss;
|
||||
socklen_t ss_len;
|
||||
struct addrinfo hint, *answer;
|
||||
int err;
|
||||
|
||||
if (initialised)
|
||||
if (*name_buf)
|
||||
return name_buf;
|
||||
|
||||
strlcpy(name_buf, default_name, sizeof name_buf);
|
||||
initialised = 1;
|
||||
|
||||
if (strcmp(ipaddr, "0.0.0.0") == 0)
|
||||
return name_buf;
|
||||
|
||||
memset(&ss, 0, sizeof ss);
|
||||
|
||||
if (am_server) { /* daemon over --rsh mode */
|
||||
char *addr = client_addr(fd);
|
||||
struct addrinfo hint, *answer;
|
||||
int err;
|
||||
|
||||
if (strcmp(addr, "0.0.0.0") == 0)
|
||||
return name_buf;
|
||||
|
||||
memset(&hint, 0, sizeof hint);
|
||||
memset(&hint, 0, sizeof hint);
|
||||
|
||||
#ifdef AI_NUMERICHOST
|
||||
hint.ai_flags = AI_NUMERICHOST;
|
||||
hint.ai_flags = AI_NUMERICHOST;
|
||||
#endif
|
||||
hint.ai_socktype = SOCK_STREAM;
|
||||
hint.ai_socktype = SOCK_STREAM;
|
||||
|
||||
if ((err = getaddrinfo(addr, NULL, &hint, &answer)) != 0) {
|
||||
rprintf(FLOG, "malformed address %s: %s\n",
|
||||
addr, gai_strerror(err));
|
||||
return name_buf;
|
||||
}
|
||||
|
||||
switch (answer->ai_family) {
|
||||
case AF_INET:
|
||||
ss_len = sizeof (struct sockaddr_in);
|
||||
memcpy(&ss, answer->ai_addr, ss_len);
|
||||
break;
|
||||
#ifdef INET6
|
||||
case AF_INET6:
|
||||
ss_len = sizeof (struct sockaddr_in6);
|
||||
memcpy(&ss, answer->ai_addr, ss_len);
|
||||
break;
|
||||
#endif
|
||||
default:
|
||||
exit_cleanup(RERR_SOCKETIO);
|
||||
}
|
||||
freeaddrinfo(answer);
|
||||
} else {
|
||||
ss_len = sizeof ss;
|
||||
client_sockaddr(fd, &ss, &ss_len);
|
||||
if ((err = getaddrinfo(ipaddr, NULL, &hint, &answer)) != 0) {
|
||||
rprintf(FLOG, "malformed address %s: %s\n", ipaddr, gai_strerror(err));
|
||||
return name_buf;
|
||||
}
|
||||
|
||||
if (lookup_name(fd, &ss, ss_len, name_buf, sizeof name_buf,
|
||||
port_buf, sizeof port_buf) == 0)
|
||||
check_name(fd, &ss, name_buf, sizeof name_buf);
|
||||
switch (answer->ai_family) {
|
||||
case AF_INET:
|
||||
ss_len = sizeof (struct sockaddr_in);
|
||||
memcpy(&ss, answer->ai_addr, ss_len);
|
||||
break;
|
||||
#ifdef INET6
|
||||
case AF_INET6:
|
||||
ss_len = sizeof (struct sockaddr_in6);
|
||||
memcpy(&ss, answer->ai_addr, ss_len);
|
||||
break;
|
||||
#endif
|
||||
default:
|
||||
assert(0);
|
||||
}
|
||||
freeaddrinfo(answer);
|
||||
|
||||
/* reverse lookup */
|
||||
err = getnameinfo((struct sockaddr*)&ss, ss_len, name_buf, sizeof name_buf,
|
||||
port_buf, sizeof port_buf, NI_NAMEREQD | NI_NUMERICSERV);
|
||||
if (err) {
|
||||
strlcpy(name_buf, default_name, sizeof name_buf);
|
||||
rprintf(FLOG, "name lookup failed for %s: %s\n", ipaddr, gai_strerror(err));
|
||||
} else
|
||||
check_name(ipaddr, &ss, name_buf, sizeof name_buf);
|
||||
|
||||
return name_buf;
|
||||
}
|
||||
|
||||
|
||||
/* Try to read an proxy protocol header (V1 or V2). Returns 1 on success or 0 on failure. */
|
||||
int read_proxy_protocol_header(int fd)
|
||||
{
|
||||
union {
|
||||
struct {
|
||||
char line[108];
|
||||
} v1;
|
||||
struct {
|
||||
char sig[PROXY_V2_SIG_SIZE];
|
||||
char ver_cmd;
|
||||
char fam;
|
||||
char len[2];
|
||||
union {
|
||||
struct {
|
||||
char src_addr[4];
|
||||
char dst_addr[4];
|
||||
char src_port[2];
|
||||
char dst_port[2];
|
||||
} ip4;
|
||||
struct {
|
||||
char src_addr[16];
|
||||
char dst_addr[16];
|
||||
char src_port[2];
|
||||
char dst_port[2];
|
||||
} ip6;
|
||||
struct {
|
||||
char src_addr[108];
|
||||
char dst_addr[108];
|
||||
} unx;
|
||||
} addr;
|
||||
} v2;
|
||||
} hdr;
|
||||
|
||||
read_buf(fd, (char*)&hdr, PROXY_V2_SIG_SIZE);
|
||||
|
||||
if (memcmp(hdr.v2.sig, proxyv2sig, PROXY_V2_SIG_SIZE) == 0) { /* Proxy V2 */
|
||||
int ver, cmd, size;
|
||||
|
||||
read_buf(fd, (char*)&hdr + PROXY_V2_SIG_SIZE, PROXY_V2_HEADER_SIZE - PROXY_V2_SIG_SIZE);
|
||||
|
||||
ver = (hdr.v2.ver_cmd & 0xf0) >> 4;
|
||||
cmd = (hdr.v2.ver_cmd & 0x0f);
|
||||
size = (hdr.v2.len[0] << 8) + hdr.v2.len[1];
|
||||
|
||||
if (ver != 2 || size + PROXY_V2_HEADER_SIZE > (int)sizeof hdr)
|
||||
return 0;
|
||||
|
||||
/* Grab all the remaining data in the binary request. */
|
||||
read_buf(fd, (char*)&hdr + PROXY_V2_HEADER_SIZE, size);
|
||||
|
||||
switch (cmd) {
|
||||
case CMD_PROXY:
|
||||
switch (hdr.v2.fam) {
|
||||
case PROXY_FAM_TCPv4:
|
||||
if (size != sizeof hdr.v2.addr.ip4)
|
||||
return 0;
|
||||
inet_ntop(AF_INET, hdr.v2.addr.ip4.src_addr, ipaddr_buf, sizeof ipaddr_buf);
|
||||
return valid_ipaddr(ipaddr_buf);
|
||||
case PROXY_FAM_TCPv6:
|
||||
if (size != sizeof hdr.v2.addr.ip6)
|
||||
return 0;
|
||||
inet_ntop(AF_INET6, hdr.v2.addr.ip6.src_addr, ipaddr_buf, sizeof ipaddr_buf);
|
||||
return valid_ipaddr(ipaddr_buf);
|
||||
default:
|
||||
break;
|
||||
}
|
||||
/* For an unsupported protocol we'll ignore the proxy data (leaving ipaddr_buf unset)
|
||||
* and accept the connection, which will get handled as a normal socket addr. */
|
||||
return 1;
|
||||
case CMD_LOCAL:
|
||||
return 1;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (memcmp(hdr.v1.line, "PROXY", 5) == 0) { /* Proxy V1 */
|
||||
char *endc, *sp, *p = hdr.v1.line + PROXY_V2_SIG_SIZE;
|
||||
int port_chk;
|
||||
|
||||
*p = '\0';
|
||||
if (!strchr(hdr.v1.line, '\n')) {
|
||||
while (1) {
|
||||
read_buf(fd, p, 1);
|
||||
if (*p++ == '\n')
|
||||
break;
|
||||
if (p - hdr.v1.line >= (int)sizeof hdr.v1.line - 1)
|
||||
return 0;
|
||||
}
|
||||
*p = '\0';
|
||||
}
|
||||
|
||||
endc = strchr(hdr.v1.line, '\r');
|
||||
if (!endc || endc[1] != '\n' || endc[2])
|
||||
return 0;
|
||||
*endc = '\0';
|
||||
|
||||
p = hdr.v1.line + 5;
|
||||
|
||||
if (!isSpace(p++))
|
||||
return 0;
|
||||
if (strncmp(p, "TCP4", 4) == 0)
|
||||
p += 4;
|
||||
else if (strncmp(p, "TCP6", 4) == 0)
|
||||
p += 4;
|
||||
else if (strncmp(p, "UNKNOWN", 7) == 0)
|
||||
return 1;
|
||||
else
|
||||
return 0;
|
||||
|
||||
if (!isSpace(p++))
|
||||
return 0;
|
||||
|
||||
if ((sp = strchr(p, ' ')) == NULL)
|
||||
return 0;
|
||||
*sp = '\0';
|
||||
if (!valid_ipaddr(p))
|
||||
return 0;
|
||||
strlcpy(ipaddr_buf, p, sizeof ipaddr_buf); /* It will always fit when valid. */
|
||||
|
||||
p = sp + 1;
|
||||
if ((sp = strchr(p, ' ')) == NULL)
|
||||
return 0;
|
||||
*sp = '\0';
|
||||
if (!valid_ipaddr(p))
|
||||
return 0;
|
||||
/* Ignore destination address. */
|
||||
|
||||
p = sp + 1;
|
||||
if ((sp = strchr(p, ' ')) == NULL)
|
||||
return 0;
|
||||
*sp = '\0';
|
||||
port_chk = strtol(p, &endc, 10);
|
||||
if (*endc || port_chk == 0)
|
||||
return 0;
|
||||
/* Ignore source port. */
|
||||
|
||||
p = sp + 1;
|
||||
port_chk = strtol(p, &endc, 10);
|
||||
if (*endc || port_chk == 0)
|
||||
return 0;
|
||||
/* Ignore destination port. */
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Get the sockaddr for the client.
|
||||
@@ -161,9 +314,7 @@ char *client_name(int fd)
|
||||
* If it comes in as an ipv4 address mapped into IPv6 format then we
|
||||
* convert it back to a regular IPv4.
|
||||
**/
|
||||
void client_sockaddr(int fd,
|
||||
struct sockaddr_storage *ss,
|
||||
socklen_t *ss_len)
|
||||
static void client_sockaddr(int fd, struct sockaddr_storage *ss, socklen_t *ss_len)
|
||||
{
|
||||
memset(ss, 0, sizeof *ss);
|
||||
|
||||
@@ -174,8 +325,8 @@ void client_sockaddr(int fd,
|
||||
}
|
||||
|
||||
#ifdef INET6
|
||||
if (get_sockaddr_family(ss) == AF_INET6 &&
|
||||
IN6_IS_ADDR_V4MAPPED(&((struct sockaddr_in6 *)ss)->sin6_addr)) {
|
||||
if (GET_SOCKADDR_FAMILY(ss) == AF_INET6
|
||||
&& IN6_IS_ADDR_V4MAPPED(&((struct sockaddr_in6 *)ss)->sin6_addr)) {
|
||||
/* OK, so ss is in the IPv6 family, but it is really
|
||||
* an IPv4 address: something like
|
||||
* "::ffff:10.130.1.2". If we use it as-is, then the
|
||||
@@ -198,51 +349,20 @@ void client_sockaddr(int fd,
|
||||
/* There is a macro to extract the mapped part
|
||||
* (IN6_V4MAPPED_TO_SINADDR ?), but it does not seem
|
||||
* to be present in the Linux headers. */
|
||||
memcpy(&sin->sin_addr, &sin6.sin6_addr.s6_addr[12],
|
||||
sizeof sin->sin_addr);
|
||||
memcpy(&sin->sin_addr, &sin6.sin6_addr.s6_addr[12], sizeof sin->sin_addr);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Look up a name from @p ss into @p name_buf.
|
||||
*
|
||||
* @param fd file descriptor for client socket.
|
||||
**/
|
||||
int lookup_name(int fd, const struct sockaddr_storage *ss,
|
||||
socklen_t ss_len,
|
||||
char *name_buf, size_t name_buf_size,
|
||||
char *port_buf, size_t port_buf_size)
|
||||
{
|
||||
int name_err;
|
||||
|
||||
/* reverse lookup */
|
||||
name_err = getnameinfo((struct sockaddr *) ss, ss_len,
|
||||
name_buf, name_buf_size,
|
||||
port_buf, port_buf_size,
|
||||
NI_NAMEREQD | NI_NUMERICSERV);
|
||||
if (name_err != 0) {
|
||||
strlcpy(name_buf, default_name, name_buf_size);
|
||||
rprintf(FLOG, "name lookup failed for %s: %s\n",
|
||||
client_addr(fd), gai_strerror(name_err));
|
||||
return name_err;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Compare an addrinfo from the resolver to a sockinfo.
|
||||
*
|
||||
* Like strcmp, returns 0 for identical.
|
||||
**/
|
||||
int compare_addrinfo_sockaddr(const struct addrinfo *ai,
|
||||
const struct sockaddr_storage *ss)
|
||||
static int compare_addrinfo_sockaddr(const struct addrinfo *ai, const struct sockaddr_storage *ss)
|
||||
{
|
||||
int ss_family = get_sockaddr_family(ss);
|
||||
int ss_family = GET_SOCKADDR_FAMILY(ss);
|
||||
const char fn[] = "compare_addrinfo_sockaddr";
|
||||
|
||||
if (ai->ai_family != ss_family) {
|
||||
@@ -258,8 +378,7 @@ int compare_addrinfo_sockaddr(const struct addrinfo *ai,
|
||||
sin1 = (const struct sockaddr_in *) ss;
|
||||
sin2 = (const struct sockaddr_in *) ai->ai_addr;
|
||||
|
||||
return memcmp(&sin1->sin_addr, &sin2->sin_addr,
|
||||
sizeof sin1->sin_addr);
|
||||
return memcmp(&sin1->sin_addr, &sin2->sin_addr, sizeof sin1->sin_addr);
|
||||
}
|
||||
|
||||
#ifdef INET6
|
||||
@@ -275,8 +394,7 @@ int compare_addrinfo_sockaddr(const struct addrinfo *ai,
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (memcmp(&sin1->sin6_addr, &sin2->sin6_addr,
|
||||
sizeof sin1->sin6_addr))
|
||||
if (memcmp(&sin1->sin6_addr, &sin2->sin6_addr, sizeof sin1->sin6_addr))
|
||||
return 1;
|
||||
|
||||
#ifdef HAVE_SOCKADDR_IN6_SCOPE_ID
|
||||
@@ -302,13 +420,11 @@ int compare_addrinfo_sockaddr(const struct addrinfo *ai,
|
||||
* because it doesn't seem that it could be spoofed in any way, and
|
||||
* getaddrinfo on random service names seems to cause problems on AIX.
|
||||
**/
|
||||
int check_name(int fd,
|
||||
const struct sockaddr_storage *ss,
|
||||
char *name_buf, size_t name_buf_size)
|
||||
static int check_name(const char *ipaddr, const struct sockaddr_storage *ss, char *name_buf, size_t name_buf_size)
|
||||
{
|
||||
struct addrinfo hints, *res, *res0;
|
||||
int error;
|
||||
int ss_family = get_sockaddr_family(ss);
|
||||
int ss_family = GET_SOCKADDR_FAMILY(ss);
|
||||
|
||||
memset(&hints, 0, sizeof hints);
|
||||
hints.ai_family = ss_family;
|
||||
@@ -339,10 +455,74 @@ int check_name(int fd,
|
||||
/* We hit the end of the list without finding an
|
||||
* address that was the same as ss. */
|
||||
rprintf(FLOG, "%s is not a known address for \"%s\": "
|
||||
"spoofed address?\n", client_addr(fd), name_buf);
|
||||
"spoofed address?\n", ipaddr, name_buf);
|
||||
strlcpy(name_buf, default_name, name_buf_size);
|
||||
}
|
||||
|
||||
freeaddrinfo(res0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Returns 1 for a valid IPv4 or IPv6 addr, or 0 for a bad one. */
|
||||
static int valid_ipaddr(const char *s)
|
||||
{
|
||||
int i;
|
||||
|
||||
if (strchr(s, ':') != NULL) { /* Only IPv6 has a colon. */
|
||||
int count, saw_double_colon = 0;
|
||||
int ipv4_at_end = 0;
|
||||
|
||||
if (*s == ':') { /* A colon at the start must be a :: */
|
||||
if (*++s != ':')
|
||||
return 0;
|
||||
saw_double_colon = 1;
|
||||
s++;
|
||||
}
|
||||
|
||||
for (count = 0; count < 8; count++) {
|
||||
if (!*s)
|
||||
return saw_double_colon && count < 7;
|
||||
|
||||
if (strchr(s, ':') == NULL && strchr(s, '.') != NULL) {
|
||||
if ((!saw_double_colon && count != 6) || (saw_double_colon && count > 6))
|
||||
return 0;
|
||||
ipv4_at_end = 1;
|
||||
break;
|
||||
}
|
||||
|
||||
if (!isHexDigit(s++)) /* Need 1-4 hex digits */
|
||||
return 0;
|
||||
if (isHexDigit(s) && isHexDigit(++s) && isHexDigit(++s) && isHexDigit(++s))
|
||||
return 0;
|
||||
|
||||
if (*s == ':') {
|
||||
if (!*++s)
|
||||
return 0;
|
||||
if (*s == ':') {
|
||||
if (saw_double_colon)
|
||||
return 0;
|
||||
saw_double_colon = 1;
|
||||
s++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!ipv4_at_end)
|
||||
return !*s;
|
||||
}
|
||||
|
||||
/* IPv4 */
|
||||
for (i = 0; i < 4; i++) {
|
||||
long n;
|
||||
char *end;
|
||||
|
||||
if (i && *s++ != '.')
|
||||
return 0;
|
||||
n = strtol(s, &end, 10);
|
||||
if (n > 255 || n < 0 || end <= s || end > s+3)
|
||||
return 0;
|
||||
s = end;
|
||||
}
|
||||
|
||||
return !*s;
|
||||
}
|
||||
|
||||
554
clientserver.c
554
clientserver.c
@@ -3,7 +3,7 @@
|
||||
*
|
||||
* Copyright (C) 1998-2001 Andrew Tridgell <tridge@samba.org>
|
||||
* Copyright (C) 2001-2002 Martin Pool <mbp@samba.org>
|
||||
* Copyright (C) 2002-2014 Wayne Davison
|
||||
* Copyright (C) 2002-2020 Wayne Davison
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
@@ -30,6 +30,7 @@ extern int am_sender;
|
||||
extern int am_server;
|
||||
extern int am_daemon;
|
||||
extern int am_root;
|
||||
extern int msgs2stderr;
|
||||
extern int rsync_port;
|
||||
extern int protect_args;
|
||||
extern int ignore_errors;
|
||||
@@ -59,12 +60,13 @@ extern filter_rule_list daemon_filter_list;
|
||||
extern char *iconv_opt;
|
||||
extern iconv_t ic_send, ic_recv;
|
||||
#endif
|
||||
|
||||
#define MAX_GID_LIST 32
|
||||
extern uid_t our_uid;
|
||||
extern gid_t our_gid;
|
||||
|
||||
char *auth_user;
|
||||
int read_only = 0;
|
||||
int module_id = -1;
|
||||
int pid_file_fd = -1;
|
||||
struct chmod_mode_struct *daemon_chmod_modes;
|
||||
|
||||
/* module_dirlen is the length of the module_dir string when in daemon
|
||||
@@ -81,8 +83,7 @@ static int rl_nulls = 0;
|
||||
static struct sigaction sigact;
|
||||
#endif
|
||||
|
||||
static gid_t gid_list[MAX_GID_LIST];
|
||||
static int gid_count = 0;
|
||||
static item_list gid_list = EMPTY_ITEM_LIST;
|
||||
|
||||
/* Used when "reverse lookup" is off. */
|
||||
const char undetermined_hostname[] = "UNDETERMINED";
|
||||
@@ -122,8 +123,7 @@ int start_socket_client(char *host, int remote_argc, char *remote_argv[],
|
||||
*p = '\0';
|
||||
}
|
||||
|
||||
fd = open_socket_out_wrapped(host, rsync_port, bind_address,
|
||||
default_af_hint);
|
||||
fd = open_socket_out_wrapped(host, rsync_port, bind_address, default_af_hint);
|
||||
if (fd == -1)
|
||||
exit_cleanup(RERR_SOCKETIO);
|
||||
|
||||
@@ -348,61 +348,6 @@ int start_inband_exchange(int f_in, int f_out, const char *user, int argc, char
|
||||
return 0;
|
||||
}
|
||||
|
||||
static char *finish_pre_exec(pid_t pid, int write_fd, int read_fd, char *request,
|
||||
char **early_argv, char **argv)
|
||||
{
|
||||
char buf[BIGPATHBUFLEN], *bp;
|
||||
int j = 0, status = -1, msglen = sizeof buf - 1;
|
||||
|
||||
if (!request)
|
||||
request = "(NONE)";
|
||||
|
||||
write_buf(write_fd, request, strlen(request)+1);
|
||||
if (early_argv) {
|
||||
for ( ; *early_argv; early_argv++)
|
||||
write_buf(write_fd, *early_argv, strlen(*early_argv)+1);
|
||||
j = 1; /* Skip arg0 name in argv. */
|
||||
}
|
||||
for ( ; argv[j]; j++)
|
||||
write_buf(write_fd, argv[j], strlen(argv[j])+1);
|
||||
write_byte(write_fd, 0);
|
||||
|
||||
close(write_fd);
|
||||
|
||||
/* Read the stdout from the pre-xfer exec program. This it is only
|
||||
* displayed to the user if the script also returns an error status. */
|
||||
for (bp = buf; msglen > 0; msglen -= j) {
|
||||
if ((j = read(read_fd, bp, msglen)) <= 0) {
|
||||
if (j == 0)
|
||||
break;
|
||||
if (errno == EINTR)
|
||||
continue;
|
||||
break; /* Just ignore the read error for now... */
|
||||
}
|
||||
bp += j;
|
||||
if (j > 1 && bp[-1] == '\n' && bp[-2] == '\r') {
|
||||
bp--;
|
||||
j--;
|
||||
bp[-1] = '\n';
|
||||
}
|
||||
}
|
||||
*bp = '\0';
|
||||
|
||||
close(read_fd);
|
||||
|
||||
if (wait_process(pid, &status, 0) < 0
|
||||
|| !WIFEXITED(status) || WEXITSTATUS(status) != 0) {
|
||||
char *e;
|
||||
if (asprintf(&e, "pre-xfer exec returned failure (%d)%s%s%s\n%s",
|
||||
status, status < 0 ? ": " : "",
|
||||
status < 0 ? strerror(errno) : "",
|
||||
*buf ? ":" : "", buf) < 0)
|
||||
return "out_of_memory in finish_pre_exec\n";
|
||||
return e;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
#ifdef HAVE_PUTENV
|
||||
static int read_arg_from_pipe(int fd, char *buf, int limit)
|
||||
{
|
||||
@@ -426,61 +371,6 @@ static int read_arg_from_pipe(int fd, char *buf, int limit)
|
||||
}
|
||||
#endif
|
||||
|
||||
static int path_failure(int f_out, const char *dir, BOOL was_chdir)
|
||||
{
|
||||
if (was_chdir)
|
||||
rsyserr(FLOG, errno, "chdir %s failed\n", dir);
|
||||
else
|
||||
rprintf(FLOG, "normalize_path(%s) failed\n", dir);
|
||||
io_printf(f_out, "@ERROR: chdir failed\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int add_a_group(int f_out, const char *gname)
|
||||
{
|
||||
gid_t gid;
|
||||
if (!group_to_gid(gname, &gid, True)) {
|
||||
rprintf(FLOG, "Invalid gid %s\n", gname);
|
||||
io_printf(f_out, "@ERROR: invalid gid %s\n", gname);
|
||||
return -1;
|
||||
}
|
||||
if (gid_count == MAX_GID_LIST) {
|
||||
rprintf(FLOG, "Too many groups specified via gid parameter.\n");
|
||||
io_printf(f_out, "@ERROR: too many groups\n");
|
||||
return -1;
|
||||
}
|
||||
gid_list[gid_count++] = gid;
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef HAVE_GETGROUPLIST
|
||||
static int want_all_groups(int f_out, uid_t uid)
|
||||
{
|
||||
const char *err;
|
||||
gid_count = MAX_GID_LIST;
|
||||
if ((err = getallgroups(uid, gid_list, &gid_count)) != NULL) {
|
||||
rsyserr(FLOG, errno, "%s", err);
|
||||
io_printf(f_out, "@ERROR: %s\n", err);
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
#elif defined HAVE_INITGROUPS
|
||||
static struct passwd *want_all_groups(int f_out, uid_t uid)
|
||||
{
|
||||
struct passwd *pw;
|
||||
if ((pw = getpwuid(uid)) == NULL) {
|
||||
rsyserr(FLOG, errno, "getpwuid failed");
|
||||
io_printf(f_out, "@ERROR: getpwuid failed\n");
|
||||
return NULL;
|
||||
}
|
||||
/* Start with the default group and initgroups() will add the reset. */
|
||||
gid_count = 1;
|
||||
gid_list[0] = pw->pw_gid;
|
||||
return pw;
|
||||
}
|
||||
#endif
|
||||
|
||||
static void set_env_str(const char *var, const char *str)
|
||||
{
|
||||
#ifdef HAVE_PUTENV
|
||||
@@ -492,7 +382,7 @@ static void set_env_str(const char *var, const char *str)
|
||||
}
|
||||
|
||||
#ifdef HAVE_PUTENV
|
||||
static void set_env_num(const char *var, long num)
|
||||
void set_env_num(const char *var, long num)
|
||||
{
|
||||
char *mem;
|
||||
if (asprintf(&mem, "%s=%ld", var, num) < 0)
|
||||
@@ -501,6 +391,199 @@ static void set_env_num(const char *var, long num)
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Used for both early exec & pre-xfer exec */
|
||||
static pid_t start_pre_exec(const char *cmd, int *arg_fd_ptr, int *error_fd_ptr)
|
||||
{
|
||||
int arg_fds[2], error_fds[2], arg_fd, error_fd;
|
||||
pid_t pid;
|
||||
|
||||
if ((error_fd_ptr && pipe(error_fds) < 0) || (arg_fd_ptr && pipe(arg_fds) < 0) || (pid = fork()) < 0)
|
||||
return (pid_t)-1;
|
||||
|
||||
if (pid == 0) {
|
||||
char buf[BIGPATHBUFLEN];
|
||||
int j, len, status;
|
||||
|
||||
if (error_fd_ptr) {
|
||||
close(error_fds[0]);
|
||||
error_fd = error_fds[1];
|
||||
set_blocking(error_fd);
|
||||
}
|
||||
|
||||
if (arg_fd_ptr) {
|
||||
close(arg_fds[1]);
|
||||
arg_fd = arg_fds[0];
|
||||
set_blocking(arg_fd);
|
||||
|
||||
len = read_arg_from_pipe(arg_fd, buf, BIGPATHBUFLEN);
|
||||
if (len <= 0)
|
||||
_exit(1);
|
||||
set_env_str("RSYNC_REQUEST", buf);
|
||||
|
||||
for (j = 0; ; j++) {
|
||||
char *p;
|
||||
len = read_arg_from_pipe(arg_fd, buf, BIGPATHBUFLEN);
|
||||
if (len <= 0) {
|
||||
if (!len)
|
||||
break;
|
||||
_exit(1);
|
||||
}
|
||||
if (asprintf(&p, "RSYNC_ARG%d=%s", j, buf) >= 0)
|
||||
putenv(p);
|
||||
}
|
||||
close(arg_fd);
|
||||
}
|
||||
|
||||
if (error_fd_ptr) {
|
||||
close(STDIN_FILENO);
|
||||
dup2(error_fd, STDOUT_FILENO);
|
||||
close(error_fd);
|
||||
}
|
||||
|
||||
status = shell_exec(cmd);
|
||||
|
||||
if (!WIFEXITED(status))
|
||||
_exit(1);
|
||||
_exit(WEXITSTATUS(status));
|
||||
}
|
||||
|
||||
if (error_fd_ptr) {
|
||||
close(error_fds[1]);
|
||||
error_fd = *error_fd_ptr = error_fds[0];
|
||||
set_blocking(error_fd);
|
||||
}
|
||||
|
||||
if (arg_fd_ptr) {
|
||||
close(arg_fds[0]);
|
||||
arg_fd = *arg_fd_ptr = arg_fds[1];
|
||||
set_blocking(arg_fd);
|
||||
}
|
||||
|
||||
return pid;
|
||||
}
|
||||
|
||||
static void write_pre_exec_args(int write_fd, char *request, char **early_argv, char **argv)
|
||||
{
|
||||
int j = 0;
|
||||
|
||||
if (!request)
|
||||
request = "(NONE)";
|
||||
|
||||
write_buf(write_fd, request, strlen(request)+1);
|
||||
if (early_argv) {
|
||||
for ( ; *early_argv; early_argv++)
|
||||
write_buf(write_fd, *early_argv, strlen(*early_argv)+1);
|
||||
j = 1; /* Skip arg0 name in argv. */
|
||||
}
|
||||
for ( ; argv[j]; j++)
|
||||
write_buf(write_fd, argv[j], strlen(argv[j])+1);
|
||||
write_byte(write_fd, 0);
|
||||
|
||||
close(write_fd);
|
||||
}
|
||||
|
||||
static char *finish_pre_exec(const char *desc, pid_t pid, int read_fd)
|
||||
{
|
||||
char buf[BIGPATHBUFLEN], *bp, *cr;
|
||||
int j, status = -1, msglen = sizeof buf - 1;
|
||||
|
||||
if (read_fd >= 0) {
|
||||
/* Read the stdout from the program. This it is only displayed
|
||||
* to the user if the script also returns an error status. */
|
||||
for (bp = buf, cr = buf; msglen > 0; msglen -= j) {
|
||||
if ((j = read(read_fd, bp, msglen)) <= 0) {
|
||||
if (j == 0)
|
||||
break;
|
||||
if (errno == EINTR)
|
||||
continue;
|
||||
break; /* Just ignore the read error for now... */
|
||||
}
|
||||
bp[j] = '\0';
|
||||
while (1) {
|
||||
if ((cr = strchr(cr, '\r')) == NULL) {
|
||||
cr = bp + j;
|
||||
break;
|
||||
}
|
||||
if (!cr[1])
|
||||
break; /* wait for more data before we decide what to do */
|
||||
if (cr[1] == '\n') {
|
||||
memmove(cr, cr+1, j - (cr - bp));
|
||||
j--;
|
||||
} else
|
||||
cr++;
|
||||
}
|
||||
bp += j;
|
||||
}
|
||||
*bp = '\0';
|
||||
|
||||
close(read_fd);
|
||||
} else
|
||||
*buf = '\0';
|
||||
|
||||
if (wait_process(pid, &status, 0) < 0
|
||||
|| !WIFEXITED(status) || WEXITSTATUS(status) != 0) {
|
||||
char *e;
|
||||
if (asprintf(&e, "%s returned failure (%d)%s%s%s\n%s",
|
||||
desc, status, status < 0 ? ": " : "",
|
||||
status < 0 ? strerror(errno) : "",
|
||||
*buf ? ":" : "", buf) < 0)
|
||||
return "out_of_memory in finish_pre_exec\n";
|
||||
return e;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static int path_failure(int f_out, const char *dir, BOOL was_chdir)
|
||||
{
|
||||
if (was_chdir)
|
||||
rsyserr(FLOG, errno, "chdir %s failed", dir);
|
||||
else
|
||||
rprintf(FLOG, "normalize_path(%s) failed\n", dir);
|
||||
io_printf(f_out, "@ERROR: chdir failed\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int add_a_group(int f_out, const char *gname)
|
||||
{
|
||||
gid_t gid, *gid_p;
|
||||
if (!group_to_gid(gname, &gid, True)) {
|
||||
rprintf(FLOG, "Invalid gid %s\n", gname);
|
||||
io_printf(f_out, "@ERROR: invalid gid %s\n", gname);
|
||||
return -1;
|
||||
}
|
||||
gid_p = EXPAND_ITEM_LIST(&gid_list, gid_t, -32);
|
||||
*gid_p = gid;
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef HAVE_GETGROUPLIST
|
||||
static int want_all_groups(int f_out, uid_t uid)
|
||||
{
|
||||
const char *err;
|
||||
if ((err = getallgroups(uid, &gid_list)) != NULL) {
|
||||
rsyserr(FLOG, errno, "%s", err);
|
||||
io_printf(f_out, "@ERROR: %s\n", err);
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
#elif defined HAVE_INITGROUPS
|
||||
static struct passwd *want_all_groups(int f_out, uid_t uid)
|
||||
{
|
||||
struct passwd *pw;
|
||||
gid_t *gid_p;
|
||||
if ((pw = getpwuid(uid)) == NULL) {
|
||||
rsyserr(FLOG, errno, "getpwuid failed");
|
||||
io_printf(f_out, "@ERROR: getpwuid failed\n");
|
||||
return NULL;
|
||||
}
|
||||
/* Start with the default group and initgroups() will add the rest. */
|
||||
gid_p = EXPAND_ITEM_LIST(&gid_list, gid_t, -32);
|
||||
*gid_p = pw->pw_gid;
|
||||
return pw;
|
||||
}
|
||||
#endif
|
||||
|
||||
static int rsync_module(int f_in, int f_out, int i, const char *addr, const char *host)
|
||||
{
|
||||
int argc;
|
||||
@@ -531,7 +614,7 @@ static int rsync_module(int f_in, int f_out, int i, const char *addr, const char
|
||||
/* If reverse lookup is disabled globally but enabled for this module,
|
||||
* we need to do it now before the access check. */
|
||||
if (host == undetermined_hostname && lp_reverse_lookup(i))
|
||||
host = client_name(f_in);
|
||||
host = client_name(client_addr(f_in));
|
||||
set_env_str("RSYNC_HOST_NAME", host);
|
||||
set_env_str("RSYNC_HOST_ADDR", addr);
|
||||
|
||||
@@ -548,7 +631,7 @@ static int rsync_module(int f_in, int f_out, int i, const char *addr, const char
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (am_daemon && am_server) {
|
||||
if (am_daemon > 0) {
|
||||
rprintf(FLOG, "rsync allowed access on module %s from %s (%s)\n",
|
||||
name, host, addr);
|
||||
}
|
||||
@@ -599,7 +682,7 @@ static int rsync_module(int f_in, int f_out, int i, const char *addr, const char
|
||||
} else
|
||||
set_uid = 0;
|
||||
|
||||
p = *lp_gid(i) ? strtok(lp_gid(i), ", ") : NULL;
|
||||
p = *lp_gid(i) ? conf_strtok(lp_gid(i)) : NULL;
|
||||
if (p) {
|
||||
/* The "*" gid must be the first item in the list. */
|
||||
if (strcmp(p, "*") == 0) {
|
||||
@@ -616,7 +699,7 @@ static int rsync_module(int f_in, int f_out, int i, const char *addr, const char
|
||||
#endif
|
||||
} else if (add_a_group(f_out, p) < 0)
|
||||
return -1;
|
||||
while ((p = strtok(NULL, ", ")) != NULL) {
|
||||
while ((p = conf_strtok(NULL)) != NULL) {
|
||||
#if defined HAVE_INITGROUPS && !defined HAVE_GETGROUPLIST
|
||||
if (pw) {
|
||||
rprintf(FLOG, "This rsync cannot add groups after \"*\".\n");
|
||||
@@ -671,30 +754,31 @@ static int rsync_module(int f_in, int f_out, int i, const char *addr, const char
|
||||
|
||||
p = lp_filter(i);
|
||||
parse_filter_str(&daemon_filter_list, p, rule_template(FILTRULE_WORD_SPLIT),
|
||||
XFLG_ABS_IF_SLASH | XFLG_DIR2WILD3);
|
||||
XFLG_ABS_IF_SLASH | XFLG_DIR2WILD3);
|
||||
|
||||
p = lp_include_from(i);
|
||||
parse_filter_file(&daemon_filter_list, p, rule_template(FILTRULE_INCLUDE),
|
||||
XFLG_ABS_IF_SLASH | XFLG_DIR2WILD3 | XFLG_OLD_PREFIXES | XFLG_FATAL_ERRORS);
|
||||
XFLG_ABS_IF_SLASH | XFLG_DIR2WILD3 | XFLG_OLD_PREFIXES | XFLG_FATAL_ERRORS);
|
||||
|
||||
p = lp_include(i);
|
||||
parse_filter_str(&daemon_filter_list, p,
|
||||
rule_template(FILTRULE_INCLUDE | FILTRULE_WORD_SPLIT),
|
||||
XFLG_ABS_IF_SLASH | XFLG_DIR2WILD3 | XFLG_OLD_PREFIXES);
|
||||
rule_template(FILTRULE_INCLUDE | FILTRULE_WORD_SPLIT),
|
||||
XFLG_ABS_IF_SLASH | XFLG_DIR2WILD3 | XFLG_OLD_PREFIXES);
|
||||
|
||||
p = lp_exclude_from(i);
|
||||
parse_filter_file(&daemon_filter_list, p, rule_template(0),
|
||||
XFLG_ABS_IF_SLASH | XFLG_DIR2WILD3 | XFLG_OLD_PREFIXES | XFLG_FATAL_ERRORS);
|
||||
XFLG_ABS_IF_SLASH | XFLG_DIR2WILD3 | XFLG_OLD_PREFIXES | XFLG_FATAL_ERRORS);
|
||||
|
||||
p = lp_exclude(i);
|
||||
parse_filter_str(&daemon_filter_list, p, rule_template(FILTRULE_WORD_SPLIT),
|
||||
XFLG_ABS_IF_SLASH | XFLG_DIR2WILD3 | XFLG_OLD_PREFIXES);
|
||||
XFLG_ABS_IF_SLASH | XFLG_DIR2WILD3 | XFLG_OLD_PREFIXES);
|
||||
|
||||
log_init(1);
|
||||
|
||||
#ifdef HAVE_PUTENV
|
||||
if (*lp_prexfer_exec(i) || *lp_postxfer_exec(i)) {
|
||||
int status;
|
||||
if ((*lp_early_exec(i) || *lp_prexfer_exec(i) || *lp_postxfer_exec(i))
|
||||
&& !getenv("RSYNC_NO_XFER_EXEC")) {
|
||||
set_env_num("RSYNC_PID", (long)getpid());
|
||||
|
||||
/* For post-xfer exec, fork a new process to run the rsync
|
||||
* daemon while this process waits for the exit status and
|
||||
@@ -707,10 +791,10 @@ static int rsync_module(int f_in, int f_out, int i, const char *addr, const char
|
||||
return -1;
|
||||
}
|
||||
if (pid) {
|
||||
int status;
|
||||
close(f_in);
|
||||
if (f_out != f_in)
|
||||
close(f_out);
|
||||
set_env_num("RSYNC_PID", (long)pid);
|
||||
if (wait_process(pid, &status, 0) < 0)
|
||||
status = -1;
|
||||
set_env_num("RSYNC_RAW_STATUS", status);
|
||||
@@ -719,61 +803,38 @@ static int rsync_module(int f_in, int f_out, int i, const char *addr, const char
|
||||
else
|
||||
status = -1;
|
||||
set_env_num("RSYNC_EXIT_STATUS", status);
|
||||
if (system(lp_postxfer_exec(i)) < 0)
|
||||
if (shell_exec(lp_postxfer_exec(i)) < 0)
|
||||
status = -1;
|
||||
_exit(status);
|
||||
}
|
||||
}
|
||||
|
||||
/* For early exec, fork a child process to run the indicated
|
||||
* command and wait for it to exit. */
|
||||
if (*lp_early_exec(i)) {
|
||||
pid_t pid = start_pre_exec(lp_early_exec(i), NULL, NULL);
|
||||
if (pid == (pid_t)-1) {
|
||||
rsyserr(FLOG, errno, "early exec preparation failed");
|
||||
io_printf(f_out, "@ERROR: early exec preparation failed\n");
|
||||
return -1;
|
||||
}
|
||||
if (finish_pre_exec("early exec", pid, -1) != NULL) {
|
||||
rsyserr(FLOG, errno, "early exec failed");
|
||||
io_printf(f_out, "@ERROR: early exec failed\n");
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
/* For pre-xfer exec, fork a child process to run the indicated
|
||||
* command, though it first waits for the parent process to
|
||||
* send us the user's request via a pipe. */
|
||||
if (*lp_prexfer_exec(i)) {
|
||||
int arg_fds[2], error_fds[2];
|
||||
set_env_num("RSYNC_PID", (long)getpid());
|
||||
if (pipe(arg_fds) < 0 || pipe(error_fds) < 0 || (pre_exec_pid = fork()) < 0) {
|
||||
pre_exec_pid = start_pre_exec(lp_prexfer_exec(i), &pre_exec_arg_fd, &pre_exec_error_fd);
|
||||
if (pre_exec_pid == (pid_t)-1) {
|
||||
rsyserr(FLOG, errno, "pre-xfer exec preparation failed");
|
||||
io_printf(f_out, "@ERROR: pre-xfer exec preparation failed\n");
|
||||
return -1;
|
||||
}
|
||||
if (pre_exec_pid == 0) {
|
||||
char buf[BIGPATHBUFLEN];
|
||||
int j, len;
|
||||
close(arg_fds[1]);
|
||||
close(error_fds[0]);
|
||||
pre_exec_arg_fd = arg_fds[0];
|
||||
pre_exec_error_fd = error_fds[1];
|
||||
set_blocking(pre_exec_arg_fd);
|
||||
set_blocking(pre_exec_error_fd);
|
||||
len = read_arg_from_pipe(pre_exec_arg_fd, buf, BIGPATHBUFLEN);
|
||||
if (len <= 0)
|
||||
_exit(1);
|
||||
set_env_str("RSYNC_REQUEST", buf);
|
||||
for (j = 0; ; j++) {
|
||||
len = read_arg_from_pipe(pre_exec_arg_fd, buf,
|
||||
BIGPATHBUFLEN);
|
||||
if (len <= 0) {
|
||||
if (!len)
|
||||
break;
|
||||
_exit(1);
|
||||
}
|
||||
if (asprintf(&p, "RSYNC_ARG%d=%s", j, buf) >= 0)
|
||||
putenv(p);
|
||||
}
|
||||
close(pre_exec_arg_fd);
|
||||
close(STDIN_FILENO);
|
||||
dup2(pre_exec_error_fd, STDOUT_FILENO);
|
||||
close(pre_exec_error_fd);
|
||||
status = system(lp_prexfer_exec(i));
|
||||
if (!WIFEXITED(status))
|
||||
_exit(1);
|
||||
_exit(WEXITSTATUS(status));
|
||||
}
|
||||
close(arg_fds[0]);
|
||||
close(error_fds[1]);
|
||||
pre_exec_arg_fd = arg_fds[1];
|
||||
pre_exec_error_fd = error_fds[0];
|
||||
set_blocking(pre_exec_arg_fd);
|
||||
set_blocking(pre_exec_error_fd);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
@@ -801,7 +862,7 @@ static int rsync_module(int f_in, int f_out, int i, const char *addr, const char
|
||||
|
||||
if (!change_dir(module_chdir, CD_NORMAL))
|
||||
return path_failure(f_out, module_chdir, True);
|
||||
if (module_dirlen || !use_chroot)
|
||||
if (module_dirlen || (!use_chroot && !*lp_daemon_chroot()))
|
||||
sanitize_paths = 1;
|
||||
|
||||
if ((munge_symlinks = lp_munge_symlinks(i)) < 0)
|
||||
@@ -818,15 +879,16 @@ static int rsync_module(int f_in, int f_out, int i, const char *addr, const char
|
||||
}
|
||||
}
|
||||
|
||||
if (gid_count) {
|
||||
if (setgid(gid_list[0])) {
|
||||
rsyserr(FLOG, errno, "setgid %ld failed", (long)gid_list[0]);
|
||||
if (gid_list.count) {
|
||||
gid_t *gid_array = gid_list.items;
|
||||
if (setgid(gid_array[0])) {
|
||||
rsyserr(FLOG, errno, "setgid %ld failed", (long)gid_array[0]);
|
||||
io_printf(f_out, "@ERROR: setgid failed\n");
|
||||
return -1;
|
||||
}
|
||||
#ifdef HAVE_SETGROUPS
|
||||
/* Set the group(s) we want to be active. */
|
||||
if (setgroups(gid_count, gid_list)) {
|
||||
if (setgroups(gid_list.count, gid_array)) {
|
||||
rsyserr(FLOG, errno, "setgroups failed");
|
||||
io_printf(f_out, "@ERROR: setgroups failed\n");
|
||||
return -1;
|
||||
@@ -840,6 +902,7 @@ static int rsync_module(int f_in, int f_out, int i, const char *addr, const char
|
||||
return -1;
|
||||
}
|
||||
#endif
|
||||
our_gid = MY_GID();
|
||||
}
|
||||
|
||||
if (set_uid) {
|
||||
@@ -853,7 +916,8 @@ static int rsync_module(int f_in, int f_out, int i, const char *addr, const char
|
||||
return -1;
|
||||
}
|
||||
|
||||
am_root = (MY_UID() == 0);
|
||||
our_uid = MY_UID();
|
||||
am_root = (our_uid == 0);
|
||||
}
|
||||
|
||||
if (lp_temp_dir(i) && *lp_temp_dir(i)) {
|
||||
@@ -885,10 +949,12 @@ static int rsync_module(int f_in, int f_out, int i, const char *addr, const char
|
||||
orig_early_argv = NULL;
|
||||
|
||||
munge_symlinks = save_munge_symlinks; /* The client mustn't control this. */
|
||||
if (am_daemon > 0)
|
||||
msgs2stderr = 0; /* A non-rsh-run daemon doesn't have stderr for msgs. */
|
||||
|
||||
if (pre_exec_pid) {
|
||||
err_msg = finish_pre_exec(pre_exec_pid, pre_exec_arg_fd, pre_exec_error_fd,
|
||||
request, orig_early_argv, orig_argv);
|
||||
write_pre_exec_args(pre_exec_arg_fd, request, orig_early_argv, orig_argv);
|
||||
err_msg = finish_pre_exec("pre-xfer exec", pre_exec_pid, pre_exec_error_fd);
|
||||
}
|
||||
|
||||
if (orig_early_argv)
|
||||
@@ -929,8 +995,7 @@ static int rsync_module(int f_in, int f_out, int i, const char *addr, const char
|
||||
limit_output_verbosity(lp_max_verbosity(i));
|
||||
#endif
|
||||
|
||||
if (protocol_version < 23
|
||||
&& (protocol_version == 22 || am_sender))
|
||||
if (protocol_version < 23 && (protocol_version == 22 || am_sender))
|
||||
io_start_multiplex_out(f_out);
|
||||
else if (!ret || err_msg) {
|
||||
/* We have to get I/O multiplexing started so that we can
|
||||
@@ -967,6 +1032,7 @@ static int rsync_module(int f_in, int f_out, int i, const char *addr, const char
|
||||
}
|
||||
if (*err_msg)
|
||||
rprintf(FERROR, "%s\n", err_msg);
|
||||
io_flush(MSG_FLUSH);
|
||||
} else
|
||||
option_error();
|
||||
msleep(400);
|
||||
@@ -1030,7 +1096,7 @@ static void send_listing(int fd)
|
||||
static int load_config(int globals_only)
|
||||
{
|
||||
if (!config_file) {
|
||||
if (am_server && am_root <= 0)
|
||||
if (am_daemon < 0 && am_root <= 0)
|
||||
config_file = RSYNCD_USERCONF;
|
||||
else
|
||||
config_file = RSYNCD_SYSCONF;
|
||||
@@ -1045,8 +1111,16 @@ int start_daemon(int f_in, int f_out)
|
||||
{
|
||||
char line[1024];
|
||||
const char *addr, *host;
|
||||
char *p;
|
||||
int i;
|
||||
|
||||
/* At this point, am_server is only set for a daemon started via rsh.
|
||||
* Because am_server gets forced on soon, we'll set am_daemon to -1 as
|
||||
* a flag that can be checked later on to distinguish a normal daemon
|
||||
* from an rsh-run daemon. */
|
||||
if (am_server)
|
||||
am_daemon = -1;
|
||||
|
||||
io_set_sock_fds(f_in, f_out);
|
||||
|
||||
/* We must load the config file before calling any function that
|
||||
@@ -1056,11 +1130,50 @@ int start_daemon(int f_in, int f_out)
|
||||
if (!load_config(0))
|
||||
exit_cleanup(RERR_SYNTAX);
|
||||
|
||||
if (lp_proxy_protocol() && !read_proxy_protocol_header(f_in))
|
||||
return -1;
|
||||
|
||||
p = lp_daemon_chroot();
|
||||
if (*p) {
|
||||
log_init(0); /* Make use we've initialized syslog before chrooting. */
|
||||
if (chroot(p) < 0 || chdir("/") < 0) {
|
||||
rsyserr(FLOG, errno, "daemon chroot %s failed", p);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
p = lp_daemon_gid();
|
||||
if (*p) {
|
||||
gid_t gid;
|
||||
if (!group_to_gid(p, &gid, True)) {
|
||||
rprintf(FLOG, "Invalid daemon gid: %s\n", p);
|
||||
return -1;
|
||||
}
|
||||
if (setgid(gid) < 0) {
|
||||
rsyserr(FLOG, errno, "Unable to set group to daemon gid %ld", (long)gid);
|
||||
return -1;
|
||||
}
|
||||
our_gid = MY_GID();
|
||||
}
|
||||
p = lp_daemon_uid();
|
||||
if (*p) {
|
||||
uid_t uid;
|
||||
if (!user_to_uid(p, &uid, True)) {
|
||||
rprintf(FLOG, "Invalid daemon uid: %s\n", p);
|
||||
return -1;
|
||||
}
|
||||
if (setuid(uid) < 0) {
|
||||
rsyserr(FLOG, errno, "Unable to set user to daemon uid %ld", (long)uid);
|
||||
return -1;
|
||||
}
|
||||
our_uid = MY_UID();
|
||||
am_root = (our_uid == 0);
|
||||
}
|
||||
|
||||
addr = client_addr(f_in);
|
||||
host = lp_reverse_lookup(-1) ? client_name(f_in) : undetermined_hostname;
|
||||
host = lp_reverse_lookup(-1) ? client_name(addr) : undetermined_hostname;
|
||||
rprintf(FLOG, "connect from %s (%s)\n", host, addr);
|
||||
|
||||
if (!am_server) {
|
||||
if (am_daemon > 0) {
|
||||
set_socket_options(f_in, "SO_KEEPALIVE");
|
||||
set_nonblocking(f_in);
|
||||
}
|
||||
@@ -1103,26 +1216,65 @@ int start_daemon(int f_in, int f_out)
|
||||
static void create_pid_file(void)
|
||||
{
|
||||
char *pid_file = lp_pid_file();
|
||||
char pidbuf[16];
|
||||
pid_t pid = getpid();
|
||||
int fd, len;
|
||||
char pidbuf[32];
|
||||
STRUCT_STAT st1, st2;
|
||||
char *fail = NULL;
|
||||
|
||||
if (!pid_file || !*pid_file)
|
||||
return;
|
||||
|
||||
cleanup_set_pid(pid);
|
||||
if ((fd = do_open(pid_file, O_WRONLY|O_CREAT|O_EXCL, 0666)) == -1) {
|
||||
failure:
|
||||
cleanup_set_pid(0);
|
||||
fprintf(stderr, "failed to create pid file %s: %s\n", pid_file, strerror(errno));
|
||||
rsyserr(FLOG, errno, "failed to create pid file %s", pid_file);
|
||||
#ifdef O_NOFOLLOW
|
||||
#define SAFE_OPEN_FLAGS (O_CREAT|O_NOFOLLOW)
|
||||
#else
|
||||
#define SAFE_OPEN_FLAGS (O_CREAT)
|
||||
#endif
|
||||
|
||||
/* These tests make sure that a temp-style lock dir is handled safely. */
|
||||
st1.st_mode = 0;
|
||||
if (do_lstat(pid_file, &st1) == 0 && !S_ISREG(st1.st_mode) && unlink(pid_file) < 0)
|
||||
fail = "unlink";
|
||||
else if ((pid_file_fd = do_open(pid_file, O_RDWR|SAFE_OPEN_FLAGS, 0664)) < 0)
|
||||
fail = S_ISREG(st1.st_mode) ? "open" : "create";
|
||||
else if (!lock_range(pid_file_fd, 0, 4))
|
||||
fail = "lock";
|
||||
else if (do_fstat(pid_file_fd, &st1) < 0)
|
||||
fail = "fstat opened";
|
||||
else if (st1.st_size > (int)sizeof pidbuf)
|
||||
fail = "find small";
|
||||
else if (do_lstat(pid_file, &st2) < 0)
|
||||
fail = "lstat";
|
||||
else if (!S_ISREG(st1.st_mode))
|
||||
fail = "avoid file overwrite race for";
|
||||
else if (st1.st_dev != st2.st_dev || st1.st_ino != st2.st_ino)
|
||||
fail = "verify stat info for";
|
||||
#ifdef HAVE_FTRUNCATE
|
||||
else if (do_ftruncate(pid_file_fd, 0) < 0)
|
||||
fail = "truncate";
|
||||
#endif
|
||||
else {
|
||||
pid_t pid = getpid();
|
||||
int len = snprintf(pidbuf, sizeof pidbuf, "%d\n", (int)pid);
|
||||
#ifndef HAVE_FTRUNCATE
|
||||
/* What can we do with a too-long file and no truncate? I guess we'll add extra newlines. */
|
||||
while (len < st1.st_size) /* We already verified that st_size chars fits in the buffer. */
|
||||
pidbuf[len++] = '\n';
|
||||
/* We don't need the buffer to end in a '\0' (and we may not have room to add it). */
|
||||
#endif
|
||||
if (write(pid_file_fd, pidbuf, len) != len)
|
||||
fail = "write";
|
||||
cleanup_set_pid(pid); /* Mark the file for removal on exit, even if the write failed. */
|
||||
}
|
||||
|
||||
if (fail) {
|
||||
char msg[1024];
|
||||
snprintf(msg, sizeof msg, "failed to %s pid file %s: %s\n",
|
||||
fail, pid_file, strerror(errno));
|
||||
fputs(msg, stderr);
|
||||
rprintf(FLOG, "%s", msg);
|
||||
exit_cleanup(RERR_FILEIO);
|
||||
}
|
||||
snprintf(pidbuf, sizeof pidbuf, "%d\n", (int)pid);
|
||||
len = strlen(pidbuf);
|
||||
if (write(fd, pidbuf, len) != len)
|
||||
goto failure;
|
||||
close(fd);
|
||||
|
||||
/* The file is left open so that the lock remains valid. It is closed in our forked child procs. */
|
||||
}
|
||||
|
||||
/* Become a daemon, discarding the controlling terminal. */
|
||||
|
||||
435
compat.c
435
compat.c
@@ -3,7 +3,7 @@
|
||||
*
|
||||
* Copyright (C) Andrew Tridgell 1996
|
||||
* Copyright (C) Paul Mackerras 1996
|
||||
* Copyright (C) 2004-2014 Wayne Davison
|
||||
* Copyright (C) 2004-2020 Wayne Davison
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
@@ -21,12 +21,6 @@
|
||||
|
||||
#include "rsync.h"
|
||||
|
||||
int remote_protocol = 0;
|
||||
int file_extra_cnt = 0; /* count of file-list extras that everyone gets */
|
||||
int inc_recurse = 0;
|
||||
int compat_flags = 0;
|
||||
int use_safe_inc_flist = 0;
|
||||
|
||||
extern int am_server;
|
||||
extern int am_sender;
|
||||
extern int local_server;
|
||||
@@ -38,6 +32,7 @@ extern int preallocate_files;
|
||||
extern int append_mode;
|
||||
extern int fuzzy_basis;
|
||||
extern int read_batch;
|
||||
extern int write_batch;
|
||||
extern int delay_updates;
|
||||
extern int checksum_seed;
|
||||
extern int basis_dir_cnt;
|
||||
@@ -46,24 +41,40 @@ extern int protocol_version;
|
||||
extern int protect_args;
|
||||
extern int preserve_uid;
|
||||
extern int preserve_gid;
|
||||
extern int preserve_atimes;
|
||||
extern int preserve_acls;
|
||||
extern int preserve_xattrs;
|
||||
extern int xfer_flags_as_varint;
|
||||
extern int need_messages_from_generator;
|
||||
extern int delete_mode, delete_before, delete_during, delete_after;
|
||||
extern int do_compression;
|
||||
extern int do_compression_level;
|
||||
extern char *shell_cmd;
|
||||
extern char *partial_dir;
|
||||
extern char *dest_option;
|
||||
extern char *files_from;
|
||||
extern char *filesfrom_host;
|
||||
extern const char *checksum_choice;
|
||||
extern const char *compress_choice;
|
||||
extern filter_rule_list filter_list;
|
||||
extern int need_unsorted_flist;
|
||||
#ifdef ICONV_OPTION
|
||||
extern iconv_t ic_send, ic_recv;
|
||||
extern char *iconv_opt;
|
||||
#endif
|
||||
extern struct name_num_obj valid_checksums;
|
||||
|
||||
int remote_protocol = 0;
|
||||
int file_extra_cnt = 0; /* count of file-list extras that everyone gets */
|
||||
int inc_recurse = 0;
|
||||
int compat_flags = 0;
|
||||
int use_safe_inc_flist = 0;
|
||||
int want_xattr_optim = 0;
|
||||
int proper_seed_order = 0;
|
||||
int inplace_partial = 0;
|
||||
int do_negotiated_strings = 0;
|
||||
|
||||
/* These index values are for the file-list's extra-attribute array. */
|
||||
int uid_ndx, gid_ndx, acls_ndx, xattrs_ndx, unsort_ndx;
|
||||
int pathname_ndx, depth_ndx, atimes_ndx, uid_ndx, gid_ndx, acls_ndx, xattrs_ndx, unsort_ndx;
|
||||
|
||||
int receiver_symlink_times = 0; /* receiver can set the time on a symlink */
|
||||
int sender_symlink_iconv = 0; /* sender should convert symlink content */
|
||||
@@ -72,10 +83,31 @@ int sender_symlink_iconv = 0; /* sender should convert symlink content */
|
||||
int filesfrom_convert = 0;
|
||||
#endif
|
||||
|
||||
#define MAX_NSTR_STRLEN 256
|
||||
|
||||
struct name_num_obj valid_compressions = {
|
||||
"compress", NULL, NULL, 0, 0, {
|
||||
#ifdef SUPPORT_ZSTD
|
||||
{ CPRES_ZSTD, "zstd", NULL },
|
||||
#endif
|
||||
#ifdef SUPPORT_LZ4
|
||||
{ CPRES_LZ4, "lz4", NULL },
|
||||
#endif
|
||||
{ CPRES_ZLIBX, "zlibx", NULL },
|
||||
{ CPRES_ZLIB, "zlib", NULL },
|
||||
{ CPRES_NONE, "none", NULL },
|
||||
{ 0, NULL, NULL }
|
||||
}
|
||||
};
|
||||
|
||||
#define CF_INC_RECURSE (1<<0)
|
||||
#define CF_SYMLINK_TIMES (1<<1)
|
||||
#define CF_SYMLINK_ICONV (1<<2)
|
||||
#define CF_SAFE_FLIST (1<<3)
|
||||
#define CF_AVOID_XATTR_OPTIM (1<<4)
|
||||
#define CF_CHKSUM_SEED_FIX (1<<5)
|
||||
#define CF_INPLACE_PARTIAL_DIR (1<<6)
|
||||
#define CF_VARINT_FLIST_FLAGS (1<<7)
|
||||
|
||||
static const char *client_info;
|
||||
|
||||
@@ -130,12 +162,308 @@ void set_allow_inc_recurse(void)
|
||||
allow_inc_recurse = 0;
|
||||
}
|
||||
|
||||
void parse_compress_choice(int final_call)
|
||||
{
|
||||
if (valid_compressions.negotiated_name)
|
||||
do_compression = valid_compressions.negotiated_num;
|
||||
else if (compress_choice) {
|
||||
struct name_num_item *nni = get_nni_by_name(&valid_compressions, compress_choice, -1);
|
||||
if (!nni) {
|
||||
rprintf(FERROR, "unknown compress name: %s\n", compress_choice);
|
||||
exit_cleanup(RERR_UNSUPPORTED);
|
||||
}
|
||||
do_compression = nni->num;
|
||||
} else if (do_compression)
|
||||
do_compression = CPRES_ZLIB;
|
||||
else
|
||||
do_compression = CPRES_NONE;
|
||||
|
||||
if (do_compression != CPRES_NONE && final_call)
|
||||
init_compression_level(); /* There's a chance this might turn compression off! */
|
||||
|
||||
if (do_compression == CPRES_NONE)
|
||||
compress_choice = NULL;
|
||||
|
||||
/* Snag the compression name for both write_batch's option output & the following debug output. */
|
||||
if (valid_compressions.negotiated_name)
|
||||
compress_choice = valid_compressions.negotiated_name;
|
||||
else if (compress_choice == NULL) {
|
||||
struct name_num_item *nni = get_nni_by_num(&valid_compressions, do_compression);
|
||||
compress_choice = nni ? nni->name : "UNKNOWN";
|
||||
}
|
||||
|
||||
if (final_call && DEBUG_GTE(NSTR, am_server ? 3 : 1)
|
||||
&& (do_compression != CPRES_NONE || do_compression_level != CLVL_NOT_SPECIFIED)) {
|
||||
rprintf(FINFO, "%s%s compress: %s (level %d)\n",
|
||||
am_server ? "Server" : "Client",
|
||||
valid_compressions.negotiated_name ? " negotiated" : "",
|
||||
compress_choice, do_compression_level);
|
||||
}
|
||||
}
|
||||
|
||||
struct name_num_item *get_nni_by_name(struct name_num_obj *nno, const char *name, int len)
|
||||
{
|
||||
struct name_num_item *nni;
|
||||
|
||||
if (len < 0)
|
||||
len = strlen(name);
|
||||
|
||||
for (nni = nno->list; nni->name; nni++) {
|
||||
if (strncasecmp(name, nni->name, len) == 0 && nni->name[len] == '\0')
|
||||
return nni;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
struct name_num_item *get_nni_by_num(struct name_num_obj *nno, int num)
|
||||
{
|
||||
struct name_num_item *nni;
|
||||
|
||||
for (nni = nno->list; nni->name; nni++) {
|
||||
if (num == nni->num)
|
||||
return nni;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void init_nno_saw(struct name_num_obj *nno, int val)
|
||||
{
|
||||
struct name_num_item *nni;
|
||||
int cnt;
|
||||
|
||||
if (!nno->saw_len) {
|
||||
for (nni = nno->list; nni->name; nni++) {
|
||||
if (nni->num >= nno->saw_len)
|
||||
nno->saw_len = nni->num + 1;
|
||||
}
|
||||
}
|
||||
|
||||
if (!nno->saw) {
|
||||
if (!(nno->saw = new_array0(uchar, nno->saw_len)))
|
||||
out_of_memory("init_nno_saw");
|
||||
|
||||
/* We'll take this opportunity to make sure that the main_name values are set right. */
|
||||
for (cnt = 1, nni = nno->list; nni->name; nni++, cnt++) {
|
||||
if (nno->saw[nni->num])
|
||||
nni->main_name = nno->list[nno->saw[nni->num]-1].name;
|
||||
else
|
||||
nno->saw[nni->num] = cnt;
|
||||
}
|
||||
}
|
||||
|
||||
memset(nno->saw, val, nno->saw_len);
|
||||
}
|
||||
|
||||
/* Simplify the user-provided string so that it contains valid names without any duplicates.
|
||||
* It also sets the "saw" flags to a 1-relative count of which name was seen first. */
|
||||
static int parse_nni_str(struct name_num_obj *nno, const char *from, char *tobuf, int tobuf_len)
|
||||
{
|
||||
char *to = tobuf, *tok = NULL;
|
||||
int cnt = 0;
|
||||
|
||||
while (1) {
|
||||
if (*from == ' ' || !*from) {
|
||||
if (tok) {
|
||||
struct name_num_item *nni = get_nni_by_name(nno, tok, to - tok);
|
||||
if (nni && !nno->saw[nni->num]) {
|
||||
nno->saw[nni->num] = ++cnt;
|
||||
if (nni->main_name) {
|
||||
to = tok + strlcpy(tok, nni->main_name, tobuf_len - (tok - tobuf));
|
||||
if (to - tobuf >= tobuf_len) {
|
||||
to = tok - 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else
|
||||
to = tok - (tok != tobuf);
|
||||
tok = NULL;
|
||||
}
|
||||
if (!*from++)
|
||||
break;
|
||||
continue;
|
||||
}
|
||||
if (!tok) {
|
||||
if (to != tobuf)
|
||||
*to++ = ' ';
|
||||
tok = to;
|
||||
}
|
||||
if (to - tobuf >= tobuf_len - 1) {
|
||||
to = tok - (tok != tobuf);
|
||||
break;
|
||||
}
|
||||
*to++ = *from++;
|
||||
}
|
||||
*to = '\0';
|
||||
|
||||
return to - tobuf;
|
||||
}
|
||||
|
||||
static void recv_negotiate_str(int f_in, struct name_num_obj *nno, char *tmpbuf, int len)
|
||||
{
|
||||
struct name_num_item *ret = NULL;
|
||||
|
||||
if (len < 0)
|
||||
len = read_vstring(f_in, tmpbuf, MAX_NSTR_STRLEN);
|
||||
|
||||
if (DEBUG_GTE(NSTR, am_server ? 3 : 2)) {
|
||||
if (am_server)
|
||||
rprintf(FINFO, "Client %s list (on server): %s\n", nno->type, tmpbuf);
|
||||
else
|
||||
rprintf(FINFO, "Server %s list (on client): %s\n", nno->type, tmpbuf);
|
||||
}
|
||||
|
||||
if (len > 0) {
|
||||
int best = nno->saw_len; /* We want best == 1 from the client list, so start with a big number. */
|
||||
char *tok;
|
||||
if (am_server)
|
||||
init_nno_saw(nno, 1); /* Since we're parsing client names, anything we parse first is #1. */
|
||||
for (tok = strtok(tmpbuf, " \t"); tok; tok = strtok(NULL, " \t")) {
|
||||
struct name_num_item *nni = get_nni_by_name(nno, tok, -1);
|
||||
if (!nni || !nno->saw[nni->num] || best <= nno->saw[nni->num])
|
||||
continue;
|
||||
ret = nni;
|
||||
best = nno->saw[nni->num];
|
||||
if (best == 1)
|
||||
break;
|
||||
}
|
||||
if (ret) {
|
||||
free(nno->saw);
|
||||
nno->saw = NULL;
|
||||
nno->negotiated_name = ret->main_name ? ret->main_name : ret->name;
|
||||
nno->negotiated_num = ret->num;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (!am_server)
|
||||
rprintf(FERROR, "Failed to negotiate a common %s\n", nno->type);
|
||||
exit_cleanup(RERR_UNSUPPORTED);
|
||||
}
|
||||
|
||||
/* The saw buffer is initialized and used to store ordinal values from 1 to N
|
||||
* for the order of the args in the array. If dup_markup == '\0', duplicates
|
||||
* are removed otherwise the char is prefixed to the duplicate term and, if it
|
||||
* is an opening paren/bracket/brace, the matching closing char is suffixed. */
|
||||
int get_default_nno_list(struct name_num_obj *nno, char *to_buf, int to_buf_len, char dup_markup)
|
||||
{
|
||||
struct name_num_item *nni;
|
||||
int len = 0, cnt = 0;
|
||||
char delim = '\0', post_delim;
|
||||
|
||||
switch (dup_markup) {
|
||||
case '(': post_delim = ')'; break;
|
||||
case '[': post_delim = ']'; break;
|
||||
case '{': post_delim = '}'; break;
|
||||
default: post_delim = '\0'; break;
|
||||
}
|
||||
|
||||
init_nno_saw(nno, 0);
|
||||
|
||||
for (nni = nno->list, len = 0; nni->name; nni++) {
|
||||
if (nni->main_name) {
|
||||
if (!dup_markup)
|
||||
continue;
|
||||
delim = dup_markup;
|
||||
}
|
||||
if (len)
|
||||
to_buf[len++]= ' ';
|
||||
if (delim) {
|
||||
to_buf[len++]= delim;
|
||||
delim = post_delim;
|
||||
}
|
||||
len += strlcpy(to_buf+len, nni->name, to_buf_len - len);
|
||||
if (len >= to_buf_len - 3)
|
||||
exit_cleanup(RERR_UNSUPPORTED); /* IMPOSSIBLE... */
|
||||
if (delim) {
|
||||
to_buf[len++]= delim;
|
||||
delim = '\0';
|
||||
}
|
||||
nno->saw[nni->num] = ++cnt;
|
||||
}
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
static void send_negotiate_str(int f_out, struct name_num_obj *nno, const char *env_name)
|
||||
{
|
||||
char tmpbuf[MAX_NSTR_STRLEN];
|
||||
const char *list_str = getenv(env_name);
|
||||
int len, fail_if_empty = list_str && strstr(list_str, "FAIL");
|
||||
|
||||
if (!do_negotiated_strings) {
|
||||
if (!am_server && fail_if_empty) {
|
||||
rprintf(FERROR, "Remote rsync is too old for %s negotation\n", nno->type);
|
||||
exit_cleanup(RERR_UNSUPPORTED);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (list_str && *list_str && (!am_server || local_server)) {
|
||||
init_nno_saw(nno, 0);
|
||||
len = parse_nni_str(nno, list_str, tmpbuf, MAX_NSTR_STRLEN);
|
||||
if (fail_if_empty && !len)
|
||||
len = strlcpy(tmpbuf, "FAIL", MAX_NSTR_STRLEN);
|
||||
list_str = tmpbuf;
|
||||
} else
|
||||
list_str = NULL;
|
||||
|
||||
if (!list_str || !*list_str)
|
||||
len = get_default_nno_list(nno, tmpbuf, MAX_NSTR_STRLEN, '\0');
|
||||
|
||||
if (DEBUG_GTE(NSTR, am_server ? 3 : 2)) {
|
||||
if (am_server)
|
||||
rprintf(FINFO, "Server %s list (on server): %s\n", nno->type, tmpbuf);
|
||||
else
|
||||
rprintf(FINFO, "Client %s list (on client): %s\n", nno->type, tmpbuf);
|
||||
}
|
||||
|
||||
if (local_server) {
|
||||
/* A local server doesn't bother to send/recv the strings, it just constructs
|
||||
* and parses the same string on both sides. */
|
||||
recv_negotiate_str(-1, nno, tmpbuf, len);
|
||||
} else {
|
||||
/* Each side sends their list of valid names to the other side and then both sides
|
||||
* pick the first name in the client's list that is also in the server's list. */
|
||||
write_vstring(f_out, tmpbuf, len);
|
||||
}
|
||||
}
|
||||
|
||||
static void negotiate_the_strings(int f_in, int f_out)
|
||||
{
|
||||
/* We send all the negotiation strings before we start to read them to help avoid a slow startup. */
|
||||
|
||||
if (!checksum_choice)
|
||||
send_negotiate_str(f_out, &valid_checksums, "RSYNC_CHECKSUM_LIST");
|
||||
|
||||
if (do_compression && !compress_choice)
|
||||
send_negotiate_str(f_out, &valid_compressions, "RSYNC_COMPRESS_LIST");
|
||||
|
||||
if (valid_checksums.saw) {
|
||||
char tmpbuf[MAX_NSTR_STRLEN];
|
||||
recv_negotiate_str(f_in, &valid_checksums, tmpbuf, -1);
|
||||
}
|
||||
|
||||
if (valid_compressions.saw) {
|
||||
char tmpbuf[MAX_NSTR_STRLEN];
|
||||
recv_negotiate_str(f_in, &valid_compressions, tmpbuf, -1);
|
||||
}
|
||||
}
|
||||
|
||||
void setup_protocol(int f_out,int f_in)
|
||||
{
|
||||
if (am_sender)
|
||||
file_extra_cnt += PTR_EXTRA_CNT;
|
||||
assert(file_extra_cnt == 0);
|
||||
assert(EXTRA64_CNT == 2 || EXTRA64_CNT == 1);
|
||||
|
||||
/* All int64 values must be set first so that they are guaranteed to be
|
||||
* aligned for direct int64-pointer memory access. */
|
||||
if (preserve_atimes)
|
||||
atimes_ndx = (file_extra_cnt += EXTRA64_CNT);
|
||||
if (am_sender) /* This is most likely in the in64 union as well. */
|
||||
pathname_ndx = (file_extra_cnt += PTR_EXTRA_CNT);
|
||||
else
|
||||
file_extra_cnt++;
|
||||
depth_ndx = ++file_extra_cnt;
|
||||
if (preserve_uid)
|
||||
uid_ndx = ++file_extra_cnt;
|
||||
if (preserve_gid)
|
||||
@@ -203,16 +531,16 @@ void setup_protocol(int f_out,int f_in)
|
||||
append_mode = 2;
|
||||
if (preserve_acls && !local_server) {
|
||||
rprintf(FERROR,
|
||||
"--acls requires protocol 30 or higher"
|
||||
" (negotiated %d).\n",
|
||||
protocol_version);
|
||||
"--acls requires protocol 30 or higher"
|
||||
" (negotiated %d).\n",
|
||||
protocol_version);
|
||||
exit_cleanup(RERR_PROTOCOL);
|
||||
}
|
||||
if (preserve_xattrs && !local_server) {
|
||||
rprintf(FERROR,
|
||||
"--xattrs requires protocol 30 or higher"
|
||||
" (negotiated %d).\n",
|
||||
protocol_version);
|
||||
"--xattrs requires protocol 30 or higher"
|
||||
" (negotiated %d).\n",
|
||||
protocol_version);
|
||||
exit_cleanup(RERR_PROTOCOL);
|
||||
}
|
||||
}
|
||||
@@ -227,33 +555,33 @@ void setup_protocol(int f_out,int f_in)
|
||||
if (protocol_version < 29) {
|
||||
if (fuzzy_basis) {
|
||||
rprintf(FERROR,
|
||||
"--fuzzy requires protocol 29 or higher"
|
||||
" (negotiated %d).\n",
|
||||
protocol_version);
|
||||
"--fuzzy requires protocol 29 or higher"
|
||||
" (negotiated %d).\n",
|
||||
protocol_version);
|
||||
exit_cleanup(RERR_PROTOCOL);
|
||||
}
|
||||
|
||||
if (basis_dir_cnt && inplace) {
|
||||
rprintf(FERROR,
|
||||
"%s with --inplace requires protocol 29 or higher"
|
||||
" (negotiated %d).\n",
|
||||
dest_option, protocol_version);
|
||||
"%s with --inplace requires protocol 29 or higher"
|
||||
" (negotiated %d).\n",
|
||||
alt_dest_opt(0), protocol_version);
|
||||
exit_cleanup(RERR_PROTOCOL);
|
||||
}
|
||||
|
||||
if (basis_dir_cnt > 1) {
|
||||
rprintf(FERROR,
|
||||
"Using more than one %s option requires protocol"
|
||||
" 29 or higher (negotiated %d).\n",
|
||||
dest_option, protocol_version);
|
||||
"Using more than one %s option requires protocol"
|
||||
" 29 or higher (negotiated %d).\n",
|
||||
alt_dest_opt(0), protocol_version);
|
||||
exit_cleanup(RERR_PROTOCOL);
|
||||
}
|
||||
|
||||
if (prune_empty_dirs) {
|
||||
rprintf(FERROR,
|
||||
"--prune-empty-dirs requires protocol 29 or higher"
|
||||
" (negotiated %d).\n",
|
||||
protocol_version);
|
||||
"--prune-empty-dirs requires protocol 29 or higher"
|
||||
" (negotiated %d).\n",
|
||||
protocol_version);
|
||||
exit_cleanup(RERR_PROTOCOL);
|
||||
}
|
||||
} else if (protocol_version >= 30) {
|
||||
@@ -267,11 +595,34 @@ void setup_protocol(int f_out,int f_in)
|
||||
#endif
|
||||
if (local_server || strchr(client_info, 'f') != NULL)
|
||||
compat_flags |= CF_SAFE_FLIST;
|
||||
write_byte(f_out, compat_flags);
|
||||
} else
|
||||
compat_flags = read_byte(f_in);
|
||||
if (local_server || strchr(client_info, 'x') != NULL)
|
||||
compat_flags |= CF_AVOID_XATTR_OPTIM;
|
||||
if (local_server || strchr(client_info, 'C') != NULL)
|
||||
compat_flags |= CF_CHKSUM_SEED_FIX;
|
||||
if (local_server || strchr(client_info, 'I') != NULL)
|
||||
compat_flags |= CF_INPLACE_PARTIAL_DIR;
|
||||
if (local_server || strchr(client_info, 'v') != NULL) {
|
||||
if (!write_batch || protocol_version >= 30) {
|
||||
do_negotiated_strings = 1;
|
||||
compat_flags |= CF_VARINT_FLIST_FLAGS;
|
||||
}
|
||||
}
|
||||
if (strchr(client_info, 'V') != NULL) { /* Support a pre-release 'V' that got superseded */
|
||||
if (!write_batch)
|
||||
compat_flags |= CF_VARINT_FLIST_FLAGS;
|
||||
write_byte(f_out, compat_flags);
|
||||
} else
|
||||
write_varint(f_out, compat_flags);
|
||||
} else { /* read_varint() is compatible with the older write_byte() when the 0x80 bit isn't on. */
|
||||
compat_flags = read_varint(f_in);
|
||||
if (compat_flags & CF_VARINT_FLIST_FLAGS)
|
||||
do_negotiated_strings = 1;
|
||||
}
|
||||
/* The inc_recurse var MUST be set to 0 or 1. */
|
||||
inc_recurse = compat_flags & CF_INC_RECURSE ? 1 : 0;
|
||||
want_xattr_optim = protocol_version >= 31 && !(compat_flags & CF_AVOID_XATTR_OPTIM);
|
||||
proper_seed_order = compat_flags & CF_CHKSUM_SEED_FIX ? 1 : 0;
|
||||
xfer_flags_as_varint = compat_flags & CF_VARINT_FLIST_FLAGS ? 1 : 0;
|
||||
if (am_sender) {
|
||||
receiver_symlink_times = am_server
|
||||
? strchr(client_info, 'L') != NULL
|
||||
@@ -289,12 +640,14 @@ void setup_protocol(int f_out,int f_in)
|
||||
if (inc_recurse && !allow_inc_recurse) {
|
||||
/* This should only be able to happen in a batch. */
|
||||
fprintf(stderr,
|
||||
"Incompatible options specified for inc-recursive %s.\n",
|
||||
read_batch ? "batch file" : "connection");
|
||||
"Incompatible options specified for inc-recursive %s.\n",
|
||||
read_batch ? "batch file" : "connection");
|
||||
exit_cleanup(RERR_SYNTAX);
|
||||
}
|
||||
use_safe_inc_flist = (compat_flags & CF_SAFE_FLIST) || protocol_version >= 31;
|
||||
need_messages_from_generator = 1;
|
||||
if (compat_flags & CF_INPLACE_PARTIAL_DIR)
|
||||
inplace_partial = 1;
|
||||
#ifdef CAN_SET_SYMLINK_TIMES
|
||||
} else if (!am_sender) {
|
||||
receiver_symlink_times = 1;
|
||||
@@ -321,11 +674,21 @@ void setup_protocol(int f_out,int f_in)
|
||||
}
|
||||
#endif
|
||||
|
||||
negotiate_the_strings(f_in, f_out);
|
||||
|
||||
if (am_server) {
|
||||
if (!checksum_seed)
|
||||
checksum_seed = time(NULL);
|
||||
checksum_seed = time(NULL) ^ (getpid() << 6);
|
||||
write_int(f_out, checksum_seed);
|
||||
} else {
|
||||
checksum_seed = read_int(f_in);
|
||||
}
|
||||
|
||||
parse_checksum_choice(1); /* Sets checksum_type & xfersum_type */
|
||||
parse_compress_choice(1); /* Sets do_compression */
|
||||
|
||||
if (write_batch && !am_server)
|
||||
write_batch_shell_file();
|
||||
|
||||
init_flist();
|
||||
}
|
||||
|
||||
405
configure.ac
405
configure.ac
@@ -1,20 +1,25 @@
|
||||
dnl Process this file with autoconf to produce a configure script.
|
||||
|
||||
AC_INIT()
|
||||
AC_INIT([rsync],[3.2.0pre2],[http://rsync.samba.org/bugzilla.html])
|
||||
|
||||
AC_CONFIG_MACRO_DIR([m4])
|
||||
AC_CONFIG_SRCDIR([byteorder.h])
|
||||
AC_CONFIG_HEADER(config.h)
|
||||
AC_PREREQ(2.60)
|
||||
AC_PREREQ([2.69])
|
||||
|
||||
RSYNC_VERSION=3.1.1pre2
|
||||
AC_SUBST(RSYNC_VERSION)
|
||||
AC_MSG_NOTICE([Configuring rsync $RSYNC_VERSION])
|
||||
AC_SUBST(RSYNC_VERSION, $PACKAGE_VERSION)
|
||||
AC_MSG_NOTICE([Configuring rsync $PACKAGE_VERSION])
|
||||
|
||||
AC_DEFINE_UNQUOTED(RSYNC_VERSION, ["$RSYNC_VERSION"], [rsync release version])
|
||||
AC_DEFINE_UNQUOTED(RSYNC_VERSION, ["$PACKAGE_VERSION"], [rsync release version])
|
||||
|
||||
LDFLAGS=${LDFLAGS-""}
|
||||
|
||||
AC_CANONICAL_HOST
|
||||
|
||||
dnl define the directory for replacement function since AC_LIBOBJ does not
|
||||
dnl officially support subdirs and fails with automake
|
||||
AC_CONFIG_LIBOBJ_DIR([lib])
|
||||
|
||||
# We must decide this before testing the compiler.
|
||||
|
||||
# Please allow this to default to yes, so that your users have more
|
||||
@@ -22,8 +27,7 @@ AC_CANONICAL_HOST
|
||||
|
||||
AC_MSG_CHECKING([whether to include debugging symbols])
|
||||
AC_ARG_ENABLE(debug,
|
||||
AC_HELP_STRING([--disable-debug],
|
||||
[disable debugging symbols and features]))
|
||||
AS_HELP_STRING([--disable-debug],[disable debugging symbols and features]))
|
||||
|
||||
if test x"$enable_debug" = x"no"; then
|
||||
AC_MSG_RESULT(no)
|
||||
@@ -37,11 +41,13 @@ fi
|
||||
dnl Checks for programs.
|
||||
AC_PROG_CC
|
||||
AC_PROG_CPP
|
||||
AC_PROG_CXX
|
||||
AC_PROG_EGREP
|
||||
AC_PROG_INSTALL
|
||||
AC_PROG_MKDIR_P
|
||||
AC_PROG_CC_STDC
|
||||
AC_SUBST(SHELL)
|
||||
AC_PATH_PROG([PERL], [perl])
|
||||
|
||||
AC_DEFINE([_GNU_SOURCE], 1,
|
||||
[Define _GNU_SOURCE so that we get all necessary prototypes])
|
||||
@@ -51,8 +57,7 @@ if test x"$ac_cv_prog_cc_stdc" = x"no"; then
|
||||
fi
|
||||
|
||||
AC_ARG_ENABLE(profile,
|
||||
AC_HELP_STRING([--enable-profile],
|
||||
[turn on CPU profiling]))
|
||||
AS_HELP_STRING([--enable-profile],[turn on CPU profiling]))
|
||||
if test x"$enable_profile" = x"yes"; then
|
||||
CFLAGS="$CFLAGS -pg"
|
||||
fi
|
||||
@@ -60,8 +65,7 @@ fi
|
||||
|
||||
# Specifically, this turns on panic_action handling.
|
||||
AC_ARG_ENABLE(maintainer-mode,
|
||||
AC_HELP_STRING([--enable-maintainer-mode],
|
||||
[turn on extra debug features]))
|
||||
AS_HELP_STRING([--enable-maintainer-mode],[turn on extra debug features]))
|
||||
if test x"$enable_maintainer_mode" = x"yes"; then
|
||||
CFLAGS="$CFLAGS -DMAINTAINER_MODE"
|
||||
fi
|
||||
@@ -77,26 +81,26 @@ if test x"$GCC" = x"yes"; then
|
||||
fi
|
||||
|
||||
AC_ARG_WITH(included-popt,
|
||||
AC_HELP_STRING([--with-included-popt], [use bundled popt library, not from system]))
|
||||
AS_HELP_STRING([--with-included-popt],[use bundled popt library, not from system]))
|
||||
|
||||
AC_ARG_WITH(included-zlib,
|
||||
AC_HELP_STRING([--with-included-zlib], [use bundled zlib library, not from system]))
|
||||
AS_HELP_STRING([--with-included-zlib],[use bundled zlib library, not from system]))
|
||||
|
||||
AC_ARG_WITH(protected-args,
|
||||
AC_HELP_STRING([--with-protected-args], [make --protected-args option the default]))
|
||||
AS_HELP_STRING([--with-protected-args],[make --protected-args option the default]))
|
||||
if test x"$with_protected_args" = x"yes"; then
|
||||
AC_DEFINE_UNQUOTED(RSYNC_USE_PROTECTED_ARGS, 1, [Define to 1 if --protected-args should be the default])
|
||||
fi
|
||||
|
||||
AC_ARG_WITH(rsync-path,
|
||||
AC_HELP_STRING([--with-rsync-path=PATH], [set default --rsync-path to PATH (default: rsync)]),
|
||||
AS_HELP_STRING([--with-rsync-path=PATH],[set default --rsync-path to PATH (default: rsync)]),
|
||||
[ RSYNC_PATH="$with_rsync_path" ],
|
||||
[ RSYNC_PATH="rsync" ])
|
||||
|
||||
AC_DEFINE_UNQUOTED(RSYNC_PATH, "$RSYNC_PATH", [location of rsync on remote machine])
|
||||
|
||||
AC_ARG_WITH(rsyncd-conf,
|
||||
AC_HELP_STRING([--with-rsyncd-conf=PATH], [set configuration file for rsync server to PATH (default: /etc/rsyncd.conf)]),
|
||||
AS_HELP_STRING([--with-rsyncd-conf=PATH],[set configuration file for rsync server to PATH (default: /etc/rsyncd.conf)]),
|
||||
[ if test ! -z "$with_rsyncd_conf" ; then
|
||||
case $with_rsyncd_conf in
|
||||
yes|no)
|
||||
@@ -117,7 +121,7 @@ AC_ARG_WITH(rsyncd-conf,
|
||||
AC_DEFINE_UNQUOTED(RSYNCD_SYSCONF, "$RSYNCD_SYSCONF", [location of configuration file for rsync server])
|
||||
|
||||
AC_ARG_WITH(rsh,
|
||||
AC_HELP_STRING([--with-rsh=CMD], [set remote shell command to CMD (default: ssh)]))
|
||||
AS_HELP_STRING([--with-rsh=CMD],[set remote shell command to CMD (default: ssh)]))
|
||||
|
||||
AC_CHECK_PROG(HAVE_REMSH, remsh, 1, 0)
|
||||
if test x$HAVE_REMSH = x1; then
|
||||
@@ -131,20 +135,12 @@ else
|
||||
fi
|
||||
AC_DEFINE_UNQUOTED(RSYNC_RSH, "$RSYNC_RSH", [default -e command])
|
||||
|
||||
AC_CHECK_PROG(HAVE_YODL2MAN, yodl2man, 1, 0)
|
||||
if test x$HAVE_YODL2MAN = x1; then
|
||||
MAKE_MAN=man
|
||||
else
|
||||
MAKE_MAN=man-copy
|
||||
fi
|
||||
|
||||
# Some programs on solaris are only found in /usr/xpg4/bin (or work better than others versions).
|
||||
AC_PATH_PROG(SHELL_PATH, sh, /bin/sh, [/usr/xpg4/bin$PATH_SEPARATOR$PATH])
|
||||
AC_PATH_PROG(FAKEROOT_PATH, fakeroot, /usr/bin/fakeroot, [/usr/xpg4/bin$PATH_SEPARATOR$PATH])
|
||||
|
||||
AC_ARG_WITH(nobody-group,
|
||||
AC_HELP_STRING([--with-nobody-group=GROUP],
|
||||
[set the default unprivileged group (default nobody or nogroup)]),
|
||||
AS_HELP_STRING([--with-nobody-group=GROUP],[set the default unprivileged group (default nobody or nogroup)]),
|
||||
[ NOBODY_GROUP="$with_nobody_group" ])
|
||||
|
||||
if test x"$with_nobody_group" = x; then
|
||||
@@ -162,15 +158,48 @@ fi
|
||||
AC_DEFINE_UNQUOTED(NOBODY_USER, "nobody", [unprivileged user--e.g. nobody])
|
||||
AC_DEFINE_UNQUOTED(NOBODY_GROUP, "$NOBODY_GROUP", [unprivileged group for unprivileged user])
|
||||
|
||||
# SIMD optimizations
|
||||
SIMD=
|
||||
|
||||
AC_MSG_CHECKING([whether to enable SIMD optimizations])
|
||||
AC_ARG_ENABLE(simd,
|
||||
AS_HELP_STRING([--disable-simd],[disable SIMD optimizations (requires g++)]))
|
||||
|
||||
if test x"$enable_simd" != x"no"; then
|
||||
# For x86-64 SIMD, g++ is also required
|
||||
if test x"$build_cpu" = x"x86_64" && test x"$CXX" = x"g++"; then
|
||||
SIMD="$SIMD x86_64"
|
||||
fi
|
||||
fi
|
||||
|
||||
if test x"$SIMD" != x""; then
|
||||
SIMD=`echo "$SIMD" | sed -e 's/^ *//'`
|
||||
AC_MSG_RESULT([yes ($SIMD)])
|
||||
AC_DEFINE(HAVE_SIMD, 1, [Define to 1 to enable SIMD optimizations])
|
||||
SIMD=`echo "$SIMD" | sed -e 's/[[^ ]]\+/$(SIMD_&)/g'`
|
||||
else
|
||||
AC_MSG_RESULT(no)
|
||||
fi
|
||||
|
||||
AC_SUBST(SIMD)
|
||||
|
||||
# We only use g++ for its target attribute dispatching, disable unneeded bulky features
|
||||
if test x"$CXXOBJ" != x""; then
|
||||
CXXFLAGS="$CXXFLAGS -fno-exceptions -fno-rtti"
|
||||
fi
|
||||
|
||||
# arrgh. libc in some old debian version screwed up the largefile
|
||||
# stuff, getting byte range locking wrong
|
||||
AC_CACHE_CHECK([for broken largefile support],rsync_cv_HAVE_BROKEN_LARGEFILE,[
|
||||
AC_TRY_RUN([
|
||||
AC_RUN_IFELSE([AC_LANG_SOURCE([[
|
||||
#define _FILE_OFFSET_BITS 64
|
||||
#include <stdio.h>
|
||||
#include <fcntl.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/wait.h>
|
||||
#if HAVE_UNISTD_H
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
|
||||
int main(void)
|
||||
{
|
||||
@@ -195,10 +224,9 @@ int main(void)
|
||||
}
|
||||
wait(&status);
|
||||
unlink(tpl);
|
||||
exit(WEXITSTATUS(status));
|
||||
return WEXITSTATUS(status);
|
||||
}
|
||||
],
|
||||
rsync_cv_HAVE_BROKEN_LARGEFILE=yes,rsync_cv_HAVE_BROKEN_LARGEFILE=no,rsync_cv_HAVE_BROKEN_LARGEFILE=cross)])
|
||||
]])],[rsync_cv_HAVE_BROKEN_LARGEFILE=yes],[rsync_cv_HAVE_BROKEN_LARGEFILE=no],[rsync_cv_HAVE_BROKEN_LARGEFILE=cross])])
|
||||
if test x"$rsync_cv_HAVE_BROKEN_LARGEFILE" != x"yes"; then
|
||||
AC_SYS_LARGEFILE
|
||||
fi
|
||||
@@ -208,8 +236,7 @@ ipv6lib=none
|
||||
ipv6trylibc=yes
|
||||
|
||||
AC_ARG_ENABLE(ipv6,
|
||||
AC_HELP_STRING([--disable-ipv6],
|
||||
[do not even try to use IPv6]))
|
||||
AS_HELP_STRING([--disable-ipv6],[turn off IPv6 support]))
|
||||
if test x"$enable_ipv6" != x"no"; then
|
||||
AC_MSG_CHECKING([ipv6 stack type])
|
||||
for i in inria kame linux-glibc linux-inet6 solaris toshiba v6d zeta cygwin; do
|
||||
@@ -320,8 +347,7 @@ fi
|
||||
|
||||
dnl Do you want to disable use of locale functions
|
||||
AC_ARG_ENABLE([locale],
|
||||
AC_HELP_STRING([--disable-locale],
|
||||
[disable locale features]))
|
||||
AS_HELP_STRING([--disable-locale],[disable locale features]))
|
||||
AH_TEMPLATE([CONFIG_LOCALE],
|
||||
[Undefine if you do not want locale features. By default this is defined.])
|
||||
if test x"$enable_locale" != x"no"; then
|
||||
@@ -348,11 +374,59 @@ AC_CHECK_HEADERS(sys/fcntl.h sys/select.h fcntl.h sys/time.h sys/unistd.h \
|
||||
netdb.h malloc.h float.h limits.h iconv.h libcharset.h langinfo.h \
|
||||
sys/acl.h acl/libacl.h attr/xattr.h sys/xattr.h sys/extattr.h \
|
||||
popt.h popt/popt.h linux/falloc.h netinet/in_systm.h netinet/ip.h \
|
||||
zlib.h)
|
||||
AC_HEADER_MAJOR
|
||||
zlib.h xxhash.h openssl/md4.h openssl/md5.h zstd.h lz4.h)
|
||||
AC_HEADER_MAJOR_FIXED
|
||||
|
||||
AC_MSG_CHECKING([whether to enable use of openssl crypto library])
|
||||
AC_ARG_ENABLE([openssl],
|
||||
AS_HELP_STRING([--disable-openssl],[disable openssl crypto library]))
|
||||
AH_TEMPLATE([USE_OPENSSL],
|
||||
[Undefine if you do not want to use openssl crypto library. By default this is defined.])
|
||||
if test x"$enable_openssl" != x"no" && test x"$ac_cv_header_openssl_md4_h" = x"yes" && test x"$ac_cv_header_openssl_md5_h" = x"yes"; then
|
||||
AC_MSG_RESULT(yes)
|
||||
AC_SEARCH_LIBS(MD5_Init, crypto, [AC_DEFINE(USE_OPENSSL)])
|
||||
else
|
||||
AC_MSG_RESULT(no)
|
||||
fi
|
||||
|
||||
AC_MSG_CHECKING([whether to enable xxhash checksum support])
|
||||
AC_ARG_ENABLE([xxhash],
|
||||
AS_HELP_STRING([--disable-xxhash],[disable xxhash checksums]))
|
||||
AH_TEMPLATE([SUPPORT_XXHASH],
|
||||
[Undefine if you do not want xxhash checksums. By default this is defined.])
|
||||
if test x"$enable_xxhash" != x"no" && test x"$ac_cv_header_xxhash_h" = x"yes"; then
|
||||
AC_MSG_RESULT(yes)
|
||||
AC_SEARCH_LIBS(XXH64_createState, xxhash, [AC_DEFINE(SUPPORT_XXHASH)])
|
||||
else
|
||||
AC_MSG_RESULT(no)
|
||||
fi
|
||||
|
||||
AC_MSG_CHECKING([whether to enable zstd compression])
|
||||
AC_ARG_ENABLE([zstd],
|
||||
AC_HELP_STRING([--disable-zstd], [disable zstd compression]))
|
||||
AH_TEMPLATE([SUPPORT_ZSTD],
|
||||
[Undefine if you do not want zstd compression. By default this is defined.])
|
||||
if test x"$enable_zstd" != x"no" && test x"$ac_cv_header_zstd_h" = x"yes"; then
|
||||
AC_MSG_RESULT(yes)
|
||||
AC_SEARCH_LIBS(ZSTD_minCLevel, zstd, [AC_DEFINE(SUPPORT_ZSTD)])
|
||||
else
|
||||
AC_MSG_RESULT(no)
|
||||
fi
|
||||
|
||||
AC_MSG_CHECKING([whether to enable LZ4 compression])
|
||||
AC_ARG_ENABLE([lz4],
|
||||
AC_HELP_STRING([--disable-lz4], [disable LZ4 compression]))
|
||||
AH_TEMPLATE([SUPPORT_LZ4],
|
||||
[Undefine if you do not want LZ4 compression. By default this is defined.])
|
||||
if test x"$enable_lz4" != x"no" && test x"$ac_cv_header_lz4_h" = x"yes"; then
|
||||
AC_MSG_RESULT(yes)
|
||||
AC_SEARCH_LIBS(LZ4_compress_default, lz4, [AC_DEFINE(SUPPORT_LZ4)])
|
||||
else
|
||||
AC_MSG_RESULT(no)
|
||||
fi
|
||||
|
||||
AC_CACHE_CHECK([if makedev takes 3 args],rsync_cv_MAKEDEV_TAKES_3_ARGS,[
|
||||
AC_TRY_RUN([
|
||||
AC_RUN_IFELSE([AC_LANG_SOURCE([[
|
||||
#include <sys/types.h>
|
||||
#ifdef MAJOR_IN_MKDEV
|
||||
#include <sys/mkdev.h>
|
||||
@@ -367,11 +441,10 @@ int main(void)
|
||||
{
|
||||
dev_t dev = makedev(0, 5, 7);
|
||||
if (major(dev) != 5 || minor(dev) != 7)
|
||||
exit(1);
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
],
|
||||
rsync_cv_MAKEDEV_TAKES_3_ARGS=yes,rsync_cv_MAKEDEV_TAKES_3_ARGS=no,rsync_cv_MAKEDEV_TAKES_3_ARGS=no)])
|
||||
]])],[rsync_cv_MAKEDEV_TAKES_3_ARGS=yes],[rsync_cv_MAKEDEV_TAKES_3_ARGS=no],[rsync_cv_MAKEDEV_TAKES_3_ARGS=no])])
|
||||
if test x"$rsync_cv_MAKEDEV_TAKES_3_ARGS" = x"yes"; then
|
||||
AC_DEFINE(MAKEDEV_TAKES_3_ARGS, 1, [Define to 1 if makedev() takes 3 args])
|
||||
fi
|
||||
@@ -388,16 +461,22 @@ AC_CHECK_SIZEOF(int64_t)
|
||||
AC_CHECK_SIZEOF(off_t)
|
||||
AC_CHECK_SIZEOF(off64_t)
|
||||
AC_CHECK_SIZEOF(time_t)
|
||||
AC_CHECK_SIZEOF(char*)
|
||||
|
||||
AC_C_INLINE
|
||||
AC_C_LONG_DOUBLE
|
||||
|
||||
AC_TYPE_SIGNAL
|
||||
AC_TYPE_LONG_DOUBLE_WIDER
|
||||
ac_cv_c_long_double=$ac_cv_type_long_double_wider
|
||||
if test $ac_cv_c_long_double = yes; then
|
||||
AC_DEFINE([HAVE_LONG_DOUBLE],[1],[Define to 1 if the type `long double' works and has more range or precision than `double'.])
|
||||
fi
|
||||
|
||||
AC_TYPE_UID_T
|
||||
AC_CHECK_TYPES([mode_t,off_t,size_t,pid_t,id_t])
|
||||
AC_TYPE_GETGROUPS
|
||||
AC_CHECK_MEMBERS([struct stat.st_rdev,
|
||||
struct stat.st_mtimensec,
|
||||
struct stat.st_mtimespec.tv_nsec,
|
||||
struct stat.st_mtim.tv_nsec],,,[
|
||||
#ifdef HAVE_SYS_TYPES_H
|
||||
#include <sys/types.h>
|
||||
@@ -412,8 +491,7 @@ AC_CHECK_MEMBERS([struct stat.st_rdev,
|
||||
TYPE_SOCKLEN_T
|
||||
|
||||
AC_CACHE_CHECK([for errno in errno.h],rsync_cv_errno, [
|
||||
AC_TRY_COMPILE([#include <errno.h>],[int i = errno],
|
||||
rsync_cv_errno=yes,rsync_cv_have_errno_decl=no)])
|
||||
AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[#include <errno.h>]], [[int i = errno]])],[rsync_cv_errno=yes],[rsync_cv_have_errno_decl=no])])
|
||||
if test x"$rsync_cv_errno" = x"yes"; then
|
||||
AC_DEFINE(HAVE_ERRNO_DECL, 1, [Define to 1 if errno is declared in errno.h])
|
||||
fi
|
||||
@@ -464,7 +542,7 @@ AC_SEARCH_LIBS(libiconv_open, iconv)
|
||||
|
||||
AC_MSG_CHECKING([for iconv declaration])
|
||||
AC_CACHE_VAL(am_cv_proto_iconv, [
|
||||
AC_TRY_COMPILE([
|
||||
AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[
|
||||
#include <stdlib.h>
|
||||
#include <iconv.h>
|
||||
extern
|
||||
@@ -476,7 +554,7 @@ size_t iconv (iconv_t cd, char * *inbuf, size_t *inbytesleft, char * *outbuf, si
|
||||
#else
|
||||
size_t iconv();
|
||||
#endif
|
||||
], [], am_cv_proto_iconv_arg1="", am_cv_proto_iconv_arg1="const")
|
||||
]], [[]])],[am_cv_proto_iconv_arg1=""],[am_cv_proto_iconv_arg1="const"])
|
||||
am_cv_proto_iconv="extern size_t iconv (iconv_t cd, $am_cv_proto_iconv_arg1 char * *inbuf, size_t *inbytesleft, char * *outbuf, size_t *outbytesleft);"])
|
||||
am_cv_proto_iconv=`echo "[$]am_cv_proto_iconv" | tr -s ' ' | sed -e 's/( /(/'`
|
||||
AC_MSG_RESULT([$]{ac_t:-
|
||||
@@ -486,8 +564,7 @@ AC_DEFINE_UNQUOTED(ICONV_CONST, $am_cv_proto_iconv_arg1,
|
||||
|
||||
dnl AC_MSG_NOTICE([Looking in libraries: $LIBS])
|
||||
|
||||
AC_CHECK_FUNCS(inet_ntop, , [AC_LIBOBJ(lib/inet_ntop)])
|
||||
AC_CHECK_FUNCS(inet_pton, , [AC_LIBOBJ(lib/inet_pton)])
|
||||
AC_REPLACE_FUNCS([inet_ntop inet_pton])
|
||||
|
||||
AC_HAVE_TYPE([struct addrinfo], [#include <netdb.h>])
|
||||
AC_HAVE_TYPE([struct sockaddr_storage], [#include <sys/types.h>
|
||||
@@ -506,23 +583,19 @@ AC_CACHE_CHECK([whether defines needed by getaddrinfo exist],
|
||||
#endif],
|
||||
rsync_cv_HAVE_GETADDR_DEFINES=yes,
|
||||
rsync_cv_HAVE_GETADDR_DEFINES=no)])
|
||||
if test x"$rsync_cv_HAVE_GETADDR_DEFINES" = x"yes" -a x"$ac_cv_type_struct_addrinfo" = x"yes"; then
|
||||
AS_IF([test x"$rsync_cv_HAVE_GETADDR_DEFINES" = x"yes" -a x"$ac_cv_type_struct_addrinfo" = x"yes"],[
|
||||
# Tru64 UNIX has getaddrinfo() but has it renamed in libc as
|
||||
# something else so we must include <netdb.h> to get the
|
||||
# redefinition.
|
||||
AC_CHECK_FUNCS(getaddrinfo, ,
|
||||
[AC_MSG_CHECKING([for getaddrinfo by including <netdb.h>])
|
||||
AC_TRY_LINK([#include <sys/types.h>
|
||||
AC_LINK_IFELSE([AC_LANG_PROGRAM([[#include <sys/types.h>
|
||||
#include <sys/socket.h>
|
||||
#include <netdb.h>],[getaddrinfo(NULL, NULL, NULL, NULL);],
|
||||
[AC_MSG_RESULT([yes])
|
||||
#include <netdb.h>]], [[getaddrinfo(NULL, NULL, NULL, NULL);]])],[AC_MSG_RESULT([yes])
|
||||
AC_DEFINE(HAVE_GETADDRINFO, 1,
|
||||
[Define to 1 if you have the "getaddrinfo" function and required types.])],
|
||||
[AC_MSG_RESULT([no])
|
||||
AC_LIBOBJ(lib/getaddrinfo)])])
|
||||
else
|
||||
AC_LIBOBJ(lib/getaddrinfo)
|
||||
fi
|
||||
[Define to 1 if you have the "getaddrinfo" function and required types.])],[AC_MSG_RESULT([no])
|
||||
AC_LIBOBJ([getaddrinfo])])])
|
||||
],[AC_LIBOBJ([getaddrinfo])])
|
||||
|
||||
AC_CHECK_MEMBER([struct sockaddr.sa_len],
|
||||
[ AC_DEFINE(HAVE_SOCKADDR_LEN, 1, [Do we have sockaddr.sa_len?]) ],
|
||||
@@ -597,12 +670,13 @@ AC_FUNC_UTIME_NULL
|
||||
AC_FUNC_ALLOCA
|
||||
AC_CHECK_FUNCS(waitpid wait4 getcwd strdup chown chmod lchmod mknod mkfifo \
|
||||
fchmod fstat ftruncate strchr readlink link utime utimes lutimes strftime \
|
||||
chflags getattrlist \
|
||||
memmove lchown vsnprintf snprintf vasprintf asprintf setsid strpbrk \
|
||||
strlcat strlcpy strtol mallinfo getgroups setgroups geteuid getegid \
|
||||
setlocale setmode open64 lseek64 mkstemp64 mtrace va_copy __va_copy \
|
||||
seteuid strerror putenv iconv_open locale_charset nl_langinfo getxattr \
|
||||
extattr_get_link sigaction sigprocmask setattrlist getgrouplist \
|
||||
initgroups utimensat posix_fallocate attropen setvbuf)
|
||||
initgroups utimensat posix_fallocate attropen setvbuf nanosleep usleep)
|
||||
|
||||
dnl cygwin iconv.h defines iconv_open as libiconv_open
|
||||
if test x"$ac_cv_func_iconv_open" != x"yes"; then
|
||||
@@ -612,19 +686,46 @@ fi
|
||||
dnl Preallocation stuff (also fallocate, posix_fallocate function tests above):
|
||||
|
||||
AC_CACHE_CHECK([for useable fallocate],rsync_cv_have_fallocate,[
|
||||
AC_TRY_LINK([#include <fcntl.h>
|
||||
#include <sys/types.h>],
|
||||
[fallocate(0, 0, 0, 0);],
|
||||
rsync_cv_have_fallocate=yes,rsync_cv_have_fallocate=no)])
|
||||
AC_LINK_IFELSE([AC_LANG_PROGRAM([[#include <fcntl.h>
|
||||
#include <sys/types.h>]], [[fallocate(0, 0, 0, 0);]])],[rsync_cv_have_fallocate=yes],[rsync_cv_have_fallocate=no])])
|
||||
if test x"$rsync_cv_have_fallocate" = x"yes"; then
|
||||
AC_DEFINE(HAVE_FALLOCATE, 1, [Define to 1 if you have the fallocate function and it compiles and links without error])
|
||||
fi
|
||||
|
||||
AC_MSG_CHECKING([for FALLOC_FL_PUNCH_HOLE])
|
||||
AC_PREPROC_IFELSE([AC_LANG_SOURCE([[
|
||||
#define _GNU_SOURCE 1
|
||||
#include <linux/falloc.h>
|
||||
#ifndef FALLOC_FL_PUNCH_HOLE
|
||||
#error FALLOC_FL_PUNCH_HOLE is missing
|
||||
#endif
|
||||
]])], [
|
||||
AC_MSG_RESULT([yes])
|
||||
AC_DEFINE([HAVE_FALLOC_FL_PUNCH_HOLE], [1], [Define if FALLOC_FL_PUNCH_HOLE is available.])
|
||||
], [
|
||||
AC_MSG_RESULT([no])
|
||||
]
|
||||
)
|
||||
|
||||
AC_MSG_CHECKING([for FALLOC_FL_ZERO_RANGE])
|
||||
AC_PREPROC_IFELSE([AC_LANG_SOURCE([[
|
||||
#define _GNU_SOURCE 1
|
||||
#include <linux/falloc.h>
|
||||
#ifndef FALLOC_FL_ZERO_RANGE
|
||||
#error FALLOC_FL_ZERO_RANGE is missing
|
||||
#endif
|
||||
]])], [
|
||||
AC_MSG_RESULT([yes])
|
||||
AC_DEFINE([HAVE_FALLOC_FL_ZERO_RANGE], [1], [Define if FALLOC_FL_ZERO_RANGE is available.])
|
||||
], [
|
||||
AC_MSG_RESULT([no])
|
||||
]
|
||||
)
|
||||
|
||||
AC_CACHE_CHECK([for SYS_fallocate],rsync_cv_have_sys_fallocate,[
|
||||
AC_TRY_COMPILE([#include <sys/syscall.h>
|
||||
#include <sys/types.h>],
|
||||
[syscall(SYS_fallocate, 0, 0, (loff_t)0, (loff_t)0);],
|
||||
rsync_cv_have_sys_fallocate=yes,rsync_cv_have_sys_fallocate=no)])
|
||||
AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[#include <sys/syscall.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/types.h>]], [[syscall(SYS_fallocate, 0, 0, (loff_t)0, (loff_t)0);]])],[rsync_cv_have_sys_fallocate=yes],[rsync_cv_have_sys_fallocate=no])])
|
||||
if test x"$rsync_cv_have_sys_fallocate" = x"yes"; then
|
||||
AC_DEFINE(HAVE_SYS_FALLOCATE, 1, [Define to 1 if you have the SYS_fallocate syscall number])
|
||||
fi
|
||||
@@ -651,8 +752,7 @@ if test $ac_cv_func_getpgrp = yes; then
|
||||
fi
|
||||
|
||||
AC_ARG_ENABLE(iconv-open,
|
||||
AC_HELP_STRING([--disable-iconv-open],
|
||||
[disable all use of iconv_open() function]),
|
||||
AS_HELP_STRING([--disable-iconv-open],[disable all use of iconv_open() function]),
|
||||
[], [enable_iconv_open=$ac_cv_func_iconv_open])
|
||||
|
||||
if test x"$enable_iconv_open" != x"no"; then
|
||||
@@ -660,8 +760,7 @@ if test x"$enable_iconv_open" != x"no"; then
|
||||
fi
|
||||
|
||||
AC_ARG_ENABLE(iconv,
|
||||
AC_HELP_STRING([--disable-iconv],
|
||||
[disable rsync's --iconv option]),
|
||||
AS_HELP_STRING([--disable-iconv],[disable rsync's --iconv option]),
|
||||
[], [enable_iconv=$enable_iconv_open])
|
||||
AH_TEMPLATE([ICONV_OPTION],
|
||||
[Define if you want the --iconv option. Specifing a value will set the
|
||||
@@ -676,77 +775,78 @@ if test x"$enable_iconv" != x"no"; then
|
||||
fi
|
||||
|
||||
AC_CACHE_CHECK([whether chown() modifies symlinks],rsync_cv_chown_modifies_symlink,[
|
||||
AC_TRY_RUN([
|
||||
AC_RUN_IFELSE([AC_LANG_SOURCE([[
|
||||
#if HAVE_UNISTD_H
|
||||
# include <unistd.h>
|
||||
#endif
|
||||
#include <stdlib.h>
|
||||
#include <errno.h>
|
||||
main() {
|
||||
int main(void) {
|
||||
char const *dangling_symlink = "conftest.dangle";
|
||||
unlink(dangling_symlink);
|
||||
if (symlink("conftest.no-such", dangling_symlink) < 0) abort();
|
||||
if (chown(dangling_symlink, getuid(), getgid()) < 0 && errno == ENOENT) exit(1);
|
||||
exit(0);
|
||||
}],
|
||||
rsync_cv_chown_modifies_symlink=yes,rsync_cv_chown_modifies_symlink=no,rsync_cv_chown_modifies_symlink=no)])
|
||||
if (chown(dangling_symlink, getuid(), getgid()) < 0 && errno == ENOENT) return 1;
|
||||
return 0;
|
||||
}]])],[rsync_cv_chown_modifies_symlink=yes],[rsync_cv_chown_modifies_symlink=no],[rsync_cv_chown_modifies_symlink=no])])
|
||||
if test $rsync_cv_chown_modifies_symlink = yes; then
|
||||
AC_DEFINE(CHOWN_MODIFIES_SYMLINK, 1, [Define to 1 if chown modifies symlinks.])
|
||||
fi
|
||||
|
||||
AC_CACHE_CHECK([whether link() can hard-link symlinks],rsync_cv_can_hardlink_symlink,[
|
||||
AC_TRY_RUN([
|
||||
AC_RUN_IFELSE([AC_LANG_SOURCE([[
|
||||
#if HAVE_UNISTD_H
|
||||
# include <unistd.h>
|
||||
#endif
|
||||
#include <stdlib.h>
|
||||
#include <errno.h>
|
||||
#define FILENAME "conftest.dangle"
|
||||
main() {
|
||||
int main(void) {
|
||||
unlink(FILENAME);
|
||||
if (symlink("conftest.no-such", FILENAME) < 0) abort();
|
||||
if (link(FILENAME, FILENAME "2") < 0) exit(1);
|
||||
exit(0);
|
||||
}],
|
||||
rsync_cv_can_hardlink_symlink=yes,rsync_cv_can_hardlink_symlink=no,rsync_cv_can_hardlink_symlink=no)])
|
||||
unlink(FILENAME "2");
|
||||
if (link(FILENAME, FILENAME "2") < 0) return 1;
|
||||
return 0;
|
||||
}]])],[rsync_cv_can_hardlink_symlink=yes],[rsync_cv_can_hardlink_symlink=no],[rsync_cv_can_hardlink_symlink=no])])
|
||||
if test $rsync_cv_can_hardlink_symlink = yes; then
|
||||
AC_DEFINE(CAN_HARDLINK_SYMLINK, 1, [Define to 1 if link() can hard-link symlinks.])
|
||||
fi
|
||||
|
||||
AC_CACHE_CHECK([whether link() can hard-link special files],rsync_cv_can_hardlink_special,[
|
||||
AC_TRY_RUN([
|
||||
AC_RUN_IFELSE([AC_LANG_SOURCE([[
|
||||
#if HAVE_UNISTD_H
|
||||
# include <unistd.h>
|
||||
#endif
|
||||
#ifdef HAVE_SYS_STAT_H
|
||||
#include <sys/stat.h>
|
||||
#endif
|
||||
#include <stdlib.h>
|
||||
#include <errno.h>
|
||||
#define FILENAME "conftest.fifi"
|
||||
main() {
|
||||
int main(void) {
|
||||
unlink(FILENAME);
|
||||
if (mkfifo(FILENAME, 0777) < 0) abort();
|
||||
if (link(FILENAME, FILENAME "2") < 0) exit(1);
|
||||
exit(0);
|
||||
}],
|
||||
rsync_cv_can_hardlink_special=yes,rsync_cv_can_hardlink_special=no,rsync_cv_can_hardlink_special=no)])
|
||||
unlink(FILENAME "2");
|
||||
if (link(FILENAME, FILENAME "2") < 0) return 1;
|
||||
return 0;
|
||||
}]])],[rsync_cv_can_hardlink_special=yes],[rsync_cv_can_hardlink_special=no],[rsync_cv_can_hardlink_special=no])])
|
||||
if test $rsync_cv_can_hardlink_special = yes; then
|
||||
AC_DEFINE(CAN_HARDLINK_SPECIAL, 1, [Define to 1 if link() can hard-link special files.])
|
||||
fi
|
||||
|
||||
AC_CACHE_CHECK([for working socketpair],rsync_cv_HAVE_SOCKETPAIR,[
|
||||
AC_TRY_RUN([
|
||||
AC_RUN_IFELSE([AC_LANG_SOURCE([[
|
||||
#include <sys/types.h>
|
||||
#include <sys/socket.h>
|
||||
|
||||
main() {
|
||||
int main(void) {
|
||||
int fd[2];
|
||||
exit((socketpair(AF_UNIX, SOCK_STREAM, 0, fd) != -1) ? 0 : 1);
|
||||
}],
|
||||
rsync_cv_HAVE_SOCKETPAIR=yes,rsync_cv_HAVE_SOCKETPAIR=no,rsync_cv_HAVE_SOCKETPAIR=cross)])
|
||||
return (socketpair(AF_UNIX, SOCK_STREAM, 0, fd) != -1) ? 0 : 1;
|
||||
}]])],[rsync_cv_HAVE_SOCKETPAIR=yes],[rsync_cv_HAVE_SOCKETPAIR=no],[rsync_cv_HAVE_SOCKETPAIR=cross])])
|
||||
if test x"$rsync_cv_HAVE_SOCKETPAIR" = x"yes"; then
|
||||
AC_DEFINE(HAVE_SOCKETPAIR, 1, [Define to 1 if you have the "socketpair" function])
|
||||
fi
|
||||
|
||||
AC_CHECK_FUNCS(getpass, , [AC_LIBOBJ(lib/getpass)])
|
||||
AC_REPLACE_FUNCS([getpass])
|
||||
|
||||
if test x"$with_included_popt" != x"yes"; then
|
||||
AC_CHECK_LIB(popt, poptGetContext, , [with_included_popt=yes])
|
||||
@@ -765,7 +865,7 @@ AC_MSG_CHECKING([whether to use included libpopt])
|
||||
if test x"$with_included_popt" = x"yes"; then
|
||||
AC_MSG_RESULT($srcdir/popt)
|
||||
BUILD_POPT='$(popt_OBJS)'
|
||||
CFLAGS="$CFLAGS -I$srcdir/popt"
|
||||
CFLAGS="-I$srcdir/popt $CFLAGS"
|
||||
if test x"$ALLOCA" != x
|
||||
then
|
||||
# this can be removed when/if we add an included alloca.c;
|
||||
@@ -790,56 +890,53 @@ AC_MSG_CHECKING([whether to use included zlib])
|
||||
if test x"$with_included_zlib" = x"yes"; then
|
||||
AC_MSG_RESULT($srcdir/zlib)
|
||||
BUILD_ZLIB='$(zlib_OBJS)'
|
||||
CFLAGS="$CFLAGS -I$srcdir/zlib"
|
||||
CFLAGS="-I$srcdir/zlib $CFLAGS"
|
||||
else
|
||||
AC_DEFINE(EXTERNAL_ZLIB, 1, [Define to 1 if using external zlib])
|
||||
AC_MSG_RESULT(no)
|
||||
fi
|
||||
|
||||
AC_CACHE_CHECK([for unsigned char],rsync_cv_SIGNED_CHAR_OK,[
|
||||
AC_TRY_COMPILE([],[signed char *s = ""],
|
||||
rsync_cv_SIGNED_CHAR_OK=yes,rsync_cv_SIGNED_CHAR_OK=no)])
|
||||
AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[]], [[signed char *s = ""]])],[rsync_cv_SIGNED_CHAR_OK=yes],[rsync_cv_SIGNED_CHAR_OK=no])])
|
||||
if test x"$rsync_cv_SIGNED_CHAR_OK" = x"yes"; then
|
||||
AC_DEFINE(SIGNED_CHAR_OK, 1, [Define to 1 if "signed char" is a valid type])
|
||||
fi
|
||||
|
||||
AC_CACHE_CHECK([for broken readdir],rsync_cv_HAVE_BROKEN_READDIR,[
|
||||
AC_TRY_RUN([#include <sys/types.h>
|
||||
AC_RUN_IFELSE([AC_LANG_SOURCE([[#include <sys/types.h>
|
||||
#include <dirent.h>
|
||||
main() { struct dirent *di; DIR *d = opendir("."); di = readdir(d);
|
||||
int main(void) { struct dirent *di; DIR *d = opendir("."); di = readdir(d);
|
||||
if (di && di->d_name[-2] == '.' && di->d_name[-1] == 0 &&
|
||||
di->d_name[0] == 0) exit(0); exit(1);} ],
|
||||
rsync_cv_HAVE_BROKEN_READDIR=yes,rsync_cv_HAVE_BROKEN_READDIR=no,rsync_cv_HAVE_BROKEN_READDIR=cross)])
|
||||
di->d_name[0] == 0) return 0; return 1;} ]])],[rsync_cv_HAVE_BROKEN_READDIR=yes],[rsync_cv_HAVE_BROKEN_READDIR=no],[rsync_cv_HAVE_BROKEN_READDIR=cross])])
|
||||
if test x"$rsync_cv_HAVE_BROKEN_READDIR" = x"yes"; then
|
||||
AC_DEFINE(HAVE_BROKEN_READDIR, 1, [Define to 1 if readdir() is broken])
|
||||
fi
|
||||
|
||||
AC_CACHE_CHECK([for utimbuf],rsync_cv_HAVE_STRUCT_UTIMBUF,[
|
||||
AC_TRY_COMPILE([#include <sys/types.h>
|
||||
#include <utime.h>],
|
||||
[struct utimbuf tbuf; tbuf.actime = 0; tbuf.modtime = 1; exit(utime("foo.c",&tbuf));],
|
||||
rsync_cv_HAVE_STRUCT_UTIMBUF=yes,rsync_cv_HAVE_STRUCT_UTIMBUF=no)])
|
||||
AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[#include <sys/types.h>
|
||||
#include <utime.h>]], [[struct utimbuf tbuf; tbuf.actime = 0; tbuf.modtime = 1; return utime("foo.c",&tbuf);]])],[rsync_cv_HAVE_STRUCT_UTIMBUF=yes],[rsync_cv_HAVE_STRUCT_UTIMBUF=no])])
|
||||
if test x"$rsync_cv_HAVE_STRUCT_UTIMBUF" = x"yes"; then
|
||||
AC_DEFINE(HAVE_STRUCT_UTIMBUF, 1, [Define to 1 if you have the "struct utimbuf" type])
|
||||
fi
|
||||
|
||||
AC_CACHE_CHECK([if gettimeofday takes tz argument],rsync_cv_HAVE_GETTIMEOFDAY_TZ,[
|
||||
AC_TRY_COMPILE([#include <sys/time.h>
|
||||
#include <unistd.h>],
|
||||
[struct timeval tv; exit(gettimeofday(&tv, NULL));],
|
||||
rsync_cv_HAVE_GETTIMEOFDAY_TZ=yes,rsync_cv_HAVE_GETTIMEOFDAY_TZ=no)])
|
||||
AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[#include <sys/time.h>
|
||||
#include <unistd.h>]], [[struct timeval tv; return gettimeofday(&tv, NULL);]])],[rsync_cv_HAVE_GETTIMEOFDAY_TZ=yes],[rsync_cv_HAVE_GETTIMEOFDAY_TZ=no])])
|
||||
if test x"$rsync_cv_HAVE_GETTIMEOFDAY_TZ" != x"no"; then
|
||||
AC_DEFINE(HAVE_GETTIMEOFDAY_TZ, 1, [Define to 1 if gettimeofday() takes a time-zone arg])
|
||||
fi
|
||||
|
||||
AC_CACHE_CHECK([for C99 vsnprintf],rsync_cv_HAVE_C99_VSNPRINTF,[
|
||||
AC_TRY_RUN([
|
||||
AC_RUN_IFELSE([AC_LANG_SOURCE([[
|
||||
#include <sys/types.h>
|
||||
#include <stdarg.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
void foo(const char *format, ...) {
|
||||
va_list ap;
|
||||
int len;
|
||||
char buf[5];
|
||||
static char buf[] = "12345678901234567890";
|
||||
|
||||
va_start(ap, format);
|
||||
len = vsnprintf(0, 0, format, ap);
|
||||
@@ -847,35 +944,29 @@ void foo(const char *format, ...) {
|
||||
if (len != 5) exit(1);
|
||||
|
||||
if (snprintf(buf, 3, "hello") != 5 || strcmp(buf, "he") != 0) exit(1);
|
||||
|
||||
exit(0);
|
||||
}
|
||||
main() { foo("hello"); }
|
||||
],
|
||||
rsync_cv_HAVE_C99_VSNPRINTF=yes,rsync_cv_HAVE_C99_VSNPRINTF=no,rsync_cv_HAVE_C99_VSNPRINTF=cross)])
|
||||
int main(void) { foo("hello"); return 0; }
|
||||
]])],[rsync_cv_HAVE_C99_VSNPRINTF=yes],[rsync_cv_HAVE_C99_VSNPRINTF=no],[rsync_cv_HAVE_C99_VSNPRINTF=cross])])
|
||||
if test x"$rsync_cv_HAVE_C99_VSNPRINTF" = x"yes"; then
|
||||
AC_DEFINE(HAVE_C99_VSNPRINTF, 1, [Define to 1 if vsprintf has a C99-compatible return value])
|
||||
fi
|
||||
|
||||
|
||||
AC_CACHE_CHECK([for secure mkstemp],rsync_cv_HAVE_SECURE_MKSTEMP,[
|
||||
AC_TRY_RUN([#include <stdlib.h>
|
||||
AC_RUN_IFELSE([AC_LANG_SOURCE([[#include <stdlib.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <unistd.h>
|
||||
main() {
|
||||
int main(void) {
|
||||
struct stat st;
|
||||
char tpl[20]="/tmp/test.XXXXXX";
|
||||
int fd = mkstemp(tpl);
|
||||
if (fd == -1) exit(1);
|
||||
if (fd == -1) return 1;
|
||||
unlink(tpl);
|
||||
if (fstat(fd, &st) != 0) exit(1);
|
||||
if ((st.st_mode & 0777) != 0600) exit(1);
|
||||
exit(0);
|
||||
}],
|
||||
rsync_cv_HAVE_SECURE_MKSTEMP=yes,
|
||||
rsync_cv_HAVE_SECURE_MKSTEMP=no,
|
||||
rsync_cv_HAVE_SECURE_MKSTEMP=cross)])
|
||||
if (fstat(fd, &st) != 0) return 1;
|
||||
if ((st.st_mode & 0777) != 0600) return 1;
|
||||
return 0;
|
||||
}]])],[rsync_cv_HAVE_SECURE_MKSTEMP=yes],[rsync_cv_HAVE_SECURE_MKSTEMP=no],[rsync_cv_HAVE_SECURE_MKSTEMP=cross])])
|
||||
if test x"$rsync_cv_HAVE_SECURE_MKSTEMP" = x"yes"; then
|
||||
case $host_os in
|
||||
hpux*)
|
||||
@@ -892,29 +983,33 @@ fi
|
||||
|
||||
|
||||
AC_CACHE_CHECK([if mknod creates FIFOs],rsync_cv_MKNOD_CREATES_FIFOS,[
|
||||
AC_TRY_RUN([
|
||||
AC_RUN_IFELSE([AC_LANG_SOURCE([[
|
||||
#include <stdio.h>
|
||||
#include <sys/stat.h>
|
||||
#include <errno.h>
|
||||
main() { int rc, ec; char *fn = "fifo-test";
|
||||
#if HAVE_UNISTD_H
|
||||
# include <unistd.h>
|
||||
#endif
|
||||
int main(void) { int rc, ec; char *fn = "fifo-test";
|
||||
unlink(fn); rc = mknod(fn,S_IFIFO,0600); ec = errno; unlink(fn);
|
||||
if (rc) {printf("(%d %d) ",rc,ec); return ec;}
|
||||
return 0;}],
|
||||
rsync_cv_MKNOD_CREATES_FIFOS=yes,rsync_cv_MKNOD_CREATES_FIFOS=no,rsync_cv_MKNOD_CREATES_FIFOS=cross)])
|
||||
return 0;}]])],[rsync_cv_MKNOD_CREATES_FIFOS=yes],[rsync_cv_MKNOD_CREATES_FIFOS=no],[rsync_cv_MKNOD_CREATES_FIFOS=cross])])
|
||||
if test x"$rsync_cv_MKNOD_CREATES_FIFOS" = x"yes"; then
|
||||
AC_DEFINE(MKNOD_CREATES_FIFOS, 1, [Define to 1 if mknod() can create FIFOs.])
|
||||
fi
|
||||
|
||||
AC_CACHE_CHECK([if mknod creates sockets],rsync_cv_MKNOD_CREATES_SOCKETS,[
|
||||
AC_TRY_RUN([
|
||||
AC_RUN_IFELSE([AC_LANG_SOURCE([[
|
||||
#include <stdio.h>
|
||||
#include <sys/stat.h>
|
||||
#include <errno.h>
|
||||
main() { int rc, ec; char *fn = "sock-test";
|
||||
#if HAVE_UNISTD_H
|
||||
# include <unistd.h>
|
||||
#endif
|
||||
int main(void) { int rc, ec; char *fn = "sock-test";
|
||||
unlink(fn); rc = mknod(fn,S_IFSOCK,0600); ec = errno; unlink(fn);
|
||||
if (rc) {printf("(%d %d) ",rc,ec); return ec;}
|
||||
return 0;}],
|
||||
rsync_cv_MKNOD_CREATES_SOCKETS=yes,rsync_cv_MKNOD_CREATES_SOCKETS=no,rsync_cv_MKNOD_CREATES_SOCKETS=cross)])
|
||||
return 0;}]])],[rsync_cv_MKNOD_CREATES_SOCKETS=yes],[rsync_cv_MKNOD_CREATES_SOCKETS=no],[rsync_cv_MKNOD_CREATES_SOCKETS=cross])])
|
||||
if test x"$rsync_cv_MKNOD_CREATES_SOCKETS" = x"yes"; then
|
||||
AC_DEFINE(MKNOD_CREATES_SOCKETS, 1, [Define to 1 if mknod() can create sockets.])
|
||||
fi
|
||||
@@ -925,7 +1020,7 @@ fi
|
||||
AC_CACHE_CHECK([whether -c -o works],rsync_cv_DASHC_WORKS_WITH_DASHO,[
|
||||
rm -rf conftest*
|
||||
cat > conftest.$ac_ext <<EOF
|
||||
int main() { return 0; }
|
||||
int main(void) { return 0; }
|
||||
EOF
|
||||
${CC-cc} -c -o conftest..o conftest.$ac_ext
|
||||
if test -f conftest..o; then
|
||||
@@ -952,17 +1047,13 @@ AC_SUBST(BUILD_POPT)
|
||||
AC_SUBST(BUILD_ZLIB)
|
||||
AC_SUBST(MAKE_MAN)
|
||||
|
||||
AC_PATH_PROG([STUNNEL], [stunnel], [stunnel], [$PATH$PATH_SEPARATOR/usr/sbin$PATH_SEPARATOR/sbin])
|
||||
AC_PATH_PROG([STUNNEL4], [stunnel4], [$STUNNEL], [$PATH$PATH_SEPARATOR/usr/sbin$PATH_SEPARATOR/sbin])
|
||||
|
||||
AC_CHECK_FUNCS(_acl __acl _facl __facl)
|
||||
#################################################
|
||||
# check for ACL support
|
||||
|
||||
AC_MSG_CHECKING([whether to support ACLs])
|
||||
AC_ARG_ENABLE(acl-support,
|
||||
AC_HELP_STRING([--disable-acl-support],
|
||||
[disable ACL support]))
|
||||
AS_HELP_STRING([--disable-acl-support],[disable ACL support]))
|
||||
|
||||
if test x"$enable_acl_support" = x"no"; then
|
||||
AC_MSG_RESULT(no)
|
||||
@@ -973,7 +1064,7 @@ else
|
||||
AC_DEFINE(HAVE_UNIXWARE_ACLS, 1, [true if you have UnixWare ACLs])
|
||||
AC_DEFINE(SUPPORT_ACLS, 1, [Define to 1 to add support for ACLs])
|
||||
;;
|
||||
solaris*|*cygwin*)
|
||||
solaris*)
|
||||
AC_MSG_RESULT(Using solaris ACLs)
|
||||
AC_DEFINE(HAVE_SOLARIS_ACLS, 1, [true if you have solaris ACLs])
|
||||
AC_DEFINE(SUPPORT_ACLS, 1)
|
||||
@@ -1008,20 +1099,16 @@ else
|
||||
AC_MSG_RESULT(running tests:)
|
||||
AC_CHECK_LIB(acl,acl_get_file)
|
||||
AC_CACHE_CHECK([for ACL support],samba_cv_HAVE_POSIX_ACLS,[
|
||||
AC_TRY_LINK([#include <sys/types.h>
|
||||
#include <sys/acl.h>],
|
||||
[ acl_t acl; int entry_id; acl_entry_t *entry_p; return acl_get_entry( acl, entry_id, entry_p);],
|
||||
samba_cv_HAVE_POSIX_ACLS=yes,samba_cv_HAVE_POSIX_ACLS=no)])
|
||||
AC_LINK_IFELSE([AC_LANG_PROGRAM([[#include <sys/types.h>
|
||||
#include <sys/acl.h>]], [[ acl_t acl; int entry_id; acl_entry_t *entry_p; return acl_get_entry( acl, entry_id, entry_p);]])],[samba_cv_HAVE_POSIX_ACLS=yes],[samba_cv_HAVE_POSIX_ACLS=no])])
|
||||
AC_MSG_CHECKING(ACL test results)
|
||||
if test x"$samba_cv_HAVE_POSIX_ACLS" = x"yes"; then
|
||||
AC_MSG_RESULT(Using posix ACLs)
|
||||
AC_DEFINE(HAVE_POSIX_ACLS, 1, [true if you have posix ACLs])
|
||||
AC_DEFINE(SUPPORT_ACLS, 1)
|
||||
AC_CACHE_CHECK([for acl_get_perm_np],samba_cv_HAVE_ACL_GET_PERM_NP,[
|
||||
AC_TRY_LINK([#include <sys/types.h>
|
||||
#include <sys/acl.h>],
|
||||
[ acl_permset_t permset_d; acl_perm_t perm; return acl_get_perm_np( permset_d, perm);],
|
||||
samba_cv_HAVE_ACL_GET_PERM_NP=yes,samba_cv_HAVE_ACL_GET_PERM_NP=no)])
|
||||
AC_LINK_IFELSE([AC_LANG_PROGRAM([[#include <sys/types.h>
|
||||
#include <sys/acl.h>]], [[ acl_permset_t permset_d; acl_perm_t perm; return acl_get_perm_np( permset_d, perm);]])],[samba_cv_HAVE_ACL_GET_PERM_NP=yes],[samba_cv_HAVE_ACL_GET_PERM_NP=no])])
|
||||
if test x"$samba_cv_HAVE_ACL_GET_PERM_NP" = x"yes"; then
|
||||
AC_DEFINE(HAVE_ACL_GET_PERM_NP, 1, [true if you have acl_get_perm_np])
|
||||
fi
|
||||
@@ -1040,8 +1127,7 @@ fi
|
||||
# check for extended attribute support
|
||||
AC_MSG_CHECKING(whether to support extended attributes)
|
||||
AC_ARG_ENABLE(xattr-support,
|
||||
AC_HELP_STRING([--disable-xattr-support],
|
||||
[disable extended attributes]),
|
||||
AS_HELP_STRING([--disable-xattr-support],[disable extended attributes]),
|
||||
[], [case "$ac_cv_func_getxattr$ac_cv_func_extattr_get_link$ac_cv_func_attropen" in
|
||||
*yes*) enable_xattr_support=maybe ;;
|
||||
*) enable_xattr_support=no ;;
|
||||
@@ -1052,9 +1138,9 @@ if test x"$enable_xattr_support" = x"no"; then
|
||||
AC_MSG_RESULT(no)
|
||||
else
|
||||
case "$host_os" in
|
||||
*linux*)
|
||||
*linux*|*netbsd*)
|
||||
AC_MSG_RESULT(Using Linux xattrs)
|
||||
AC_DEFINE(HAVE_LINUX_XATTRS, 1, [True if you have Linux xattrs])
|
||||
AC_DEFINE(HAVE_LINUX_XATTRS, 1, [True if you have Linux xattrs (or equivalent)])
|
||||
AC_DEFINE(SUPPORT_XATTRS, 1)
|
||||
AC_DEFINE(NO_SYMLINK_USER_XATTRS, 1, [True if symlinks do not support user xattrs])
|
||||
AC_CHECK_LIB(attr,getxattr)
|
||||
@@ -1091,7 +1177,7 @@ if test x"$enable_acl_support" = x"no" -o x"$enable_xattr_support" = x"no" -o x"
|
||||
AC_MSG_CHECKING([whether $CC supports -Wno-unused-parameter])
|
||||
OLD_CFLAGS="$CFLAGS"
|
||||
CFLAGS="$CFLAGS -Wno-unused-parameter"
|
||||
AC_TRY_LINK([#include <stdio.h>], [printf("hello\n");], [rsync_warn_flag=yes], [rsync_warn_flag=no])
|
||||
AC_LINK_IFELSE([AC_LANG_PROGRAM([[#include <stdio.h>]], [[printf("hello\n");]])],[rsync_warn_flag=yes],[rsync_warn_flag=no])
|
||||
AC_MSG_RESULT([$rsync_warn_flag])
|
||||
if test x"$rsync_warn_flag" = x"no"; then
|
||||
CFLAGS="$OLD_CFLAGS"
|
||||
@@ -1110,8 +1196,3 @@ AC_OUTPUT
|
||||
AC_MSG_RESULT()
|
||||
AC_MSG_RESULT([ rsync ${RSYNC_VERSION} configuration successful])
|
||||
AC_MSG_RESULT()
|
||||
if test x$HAVE_YODL2MAN != x1; then
|
||||
AC_MSG_RESULT([ Note that yodl2man was not found, so pre-existing manpage files will be])
|
||||
AC_MSG_RESULT([ used w/o change (if available) -- no .yo file changes will be used.])
|
||||
AC_MSG_RESULT()
|
||||
fi
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
* Support the max connections option.
|
||||
*
|
||||
* Copyright (C) 1998 Andrew Tridgell
|
||||
* Copyright (C) 2006-2020 Wayne Davison
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
|
||||
6
delete.c
6
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-2014 Wayne Davison
|
||||
* Copyright (C) 2003-2020 Wayne Davison
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
@@ -89,8 +89,8 @@ static enum delret delete_dir_contents(char *fname, uint16 flags)
|
||||
if (fp->flags & FLAG_MOUNT_DIR && S_ISDIR(fp->mode)) {
|
||||
if (DEBUG_GTE(DEL, 1)) {
|
||||
rprintf(FINFO,
|
||||
"mount point, %s, pins parent directory\n",
|
||||
f_name(fp, NULL));
|
||||
"mount point, %s, pins parent directory\n",
|
||||
f_name(fp, NULL));
|
||||
}
|
||||
ret = DR_NOT_EMPTY;
|
||||
continue;
|
||||
|
||||
@@ -126,7 +126,7 @@
|
||||
|
||||
<para><option>-P</option>
|
||||
Display a progress indicator while files are transferred. This should
|
||||
normally be ommitted if rsync is not run on a terminal.
|
||||
normally be omitted if rsync is not run on a terminal.
|
||||
</para>
|
||||
</section>
|
||||
|
||||
@@ -348,4 +348,4 @@ running rsync giving the network directory.
|
||||
|
||||
<para><ulink url="http://www.ccp14.ac.uk/ccp14admin/rsync/"></ulink></para>
|
||||
</appendix>
|
||||
</book>
|
||||
</book>
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
* Error codes returned by rsync.
|
||||
*
|
||||
* Copyright (C) 1998-2000 Andrew Tridgell
|
||||
* Copyright (C) 2003-2014 Wayne Davison
|
||||
* Copyright (C) 2003-2019 Wayne Davison
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
|
||||
201
exclude.c
201
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-2014 Wayne Davison
|
||||
* Copyright (C) 2003-2020 Wayne Davison
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
@@ -44,6 +44,8 @@ filter_rule_list filter_list = { .debug_type = "" };
|
||||
filter_rule_list cvs_filter_list = { .debug_type = " [global CVS]" };
|
||||
filter_rule_list daemon_filter_list = { .debug_type = " [daemon]" };
|
||||
|
||||
int saw_xattr_filter = 0;
|
||||
|
||||
/* Need room enough for ":MODS " prefix plus some room to grow. */
|
||||
#define MAX_RULE_PREFIX (16)
|
||||
|
||||
@@ -100,52 +102,44 @@ static int mergelist_size = 0;
|
||||
|
||||
static void teardown_mergelist(filter_rule *ex)
|
||||
{
|
||||
int j;
|
||||
|
||||
if (!ex->u.mergelist)
|
||||
return;
|
||||
|
||||
if (DEBUG_GTE(FILTER, 2)) {
|
||||
rprintf(FINFO, "[%s] deactivating mergelist #%d%s\n",
|
||||
who_am_i(), mergelist_cnt - 1,
|
||||
ex->u.mergelist->debug_type);
|
||||
}
|
||||
|
||||
/* We should deactivate mergelists in LIFO order. */
|
||||
assert(mergelist_cnt > 0);
|
||||
assert(ex == mergelist_parents[mergelist_cnt - 1]);
|
||||
|
||||
/* The parent_dirscan filters should have been freed. */
|
||||
assert(ex->u.mergelist->parent_dirscan_head == NULL);
|
||||
|
||||
free(ex->u.mergelist->debug_type);
|
||||
free(ex->u.mergelist);
|
||||
mergelist_cnt--;
|
||||
|
||||
for (j = 0; j < mergelist_cnt; j++) {
|
||||
if (mergelist_parents[j] == ex) {
|
||||
mergelist_parents[j] = NULL;
|
||||
break;
|
||||
}
|
||||
}
|
||||
while (mergelist_cnt && mergelist_parents[mergelist_cnt-1] == NULL)
|
||||
mergelist_cnt--;
|
||||
}
|
||||
|
||||
static void free_filter(filter_rule *ex)
|
||||
{
|
||||
if (ex->rflags & FILTRULE_PERDIR_MERGE)
|
||||
teardown_mergelist(ex);
|
||||
free(ex->pattern);
|
||||
free(ex);
|
||||
}
|
||||
|
||||
static void free_filters(filter_rule *head)
|
||||
static void free_filters(filter_rule *ent)
|
||||
{
|
||||
filter_rule *rev_head = NULL;
|
||||
|
||||
/* Reverse the list so we deactivate mergelists in the proper LIFO
|
||||
* order. */
|
||||
while (head) {
|
||||
filter_rule *next = head->next;
|
||||
head->next = rev_head;
|
||||
rev_head = head;
|
||||
head = next;
|
||||
}
|
||||
|
||||
while (rev_head) {
|
||||
filter_rule *prev = rev_head->next;
|
||||
/* Tear down mergelists here, not in free_filter, so that we
|
||||
* affect only real filter lists and not temporarily allocated
|
||||
* filters. */
|
||||
if (rev_head->rflags & FILTRULE_PERDIR_MERGE)
|
||||
teardown_mergelist(rev_head);
|
||||
free_filter(rev_head);
|
||||
rev_head = prev;
|
||||
while (ent) {
|
||||
filter_rule *next = ent->next;
|
||||
free_filter(ent);
|
||||
ent = next;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -252,7 +246,10 @@ static void add_rule(filter_rule_list *listp, const char *pat, unsigned int pat_
|
||||
* add it again. */
|
||||
for (i = 0; i < mergelist_cnt; i++) {
|
||||
filter_rule *ex = mergelist_parents[i];
|
||||
const char *s = strrchr(ex->pattern, '/');
|
||||
const char *s;
|
||||
if (!ex)
|
||||
continue;
|
||||
s = strrchr(ex->pattern, '/');
|
||||
if (s)
|
||||
s++;
|
||||
else
|
||||
@@ -264,9 +261,8 @@ static void add_rule(filter_rule_list *listp, const char *pat, unsigned int pat_
|
||||
}
|
||||
}
|
||||
|
||||
if (!(lp = new_array(filter_rule_list, 1)))
|
||||
if (!(lp = new_array0(filter_rule_list, 1)))
|
||||
out_of_memory("add_rule");
|
||||
lp->head = lp->tail = lp->parent_dirscan_head = NULL;
|
||||
if (asprintf(&lp->debug_type, " [per-dir %s]", cp) < 0)
|
||||
out_of_memory("add_rule");
|
||||
rule->u.mergelist = lp;
|
||||
@@ -297,16 +293,23 @@ static void add_rule(filter_rule_list *listp, const char *pat, unsigned int pat_
|
||||
}
|
||||
}
|
||||
|
||||
static void clear_filter_list(filter_rule_list *listp)
|
||||
/* This frees any non-inherited items, leaving just inherited items on the list. */
|
||||
static void pop_filter_list(filter_rule_list *listp)
|
||||
{
|
||||
if (listp->tail) {
|
||||
/* Truncate any inherited items from the local list. */
|
||||
listp->tail->next = NULL;
|
||||
/* Now free everything that is left. */
|
||||
free_filters(listp->head);
|
||||
}
|
||||
filter_rule *inherited;
|
||||
|
||||
listp->head = listp->tail = NULL;
|
||||
if (!listp->tail)
|
||||
return;
|
||||
|
||||
inherited = listp->tail->next;
|
||||
|
||||
/* Truncate any inherited items from the local list. */
|
||||
listp->tail->next = NULL;
|
||||
/* Now free everything that is left. */
|
||||
free_filters(listp->head);
|
||||
|
||||
listp->head = inherited;
|
||||
listp->tail = NULL;
|
||||
}
|
||||
|
||||
/* This returns an expanded (absolute) filename for the merge-file name if
|
||||
@@ -457,8 +460,6 @@ static BOOL setup_merge_file(int mergelist_num, filter_rule *ex,
|
||||
strlcpy(y, save, MAXPATHLEN);
|
||||
while ((*x++ = *y++) != '/') {}
|
||||
}
|
||||
/* Save current head for freeing when the mergelist becomes inactive. */
|
||||
lp->parent_dirscan_head = lp->head;
|
||||
parent_dirscan = False;
|
||||
if (DEBUG_GTE(FILTER, 2)) {
|
||||
rprintf(FINFO, "[%s] completed parent_dirscan for mergelist #%d%s\n",
|
||||
@@ -501,15 +502,20 @@ void *push_local_filters(const char *dir, unsigned int dirlen)
|
||||
|
||||
push->mergelist_cnt = mergelist_cnt;
|
||||
for (i = 0; i < mergelist_cnt; i++) {
|
||||
memcpy(&push->mergelists[i], mergelist_parents[i]->u.mergelist,
|
||||
sizeof (filter_rule_list));
|
||||
filter_rule *ex = mergelist_parents[i];
|
||||
if (!ex)
|
||||
continue;
|
||||
memcpy(&push->mergelists[i], ex->u.mergelist, sizeof (filter_rule_list));
|
||||
}
|
||||
|
||||
/* Note: parse_filter_file() might increase mergelist_cnt, so keep
|
||||
* this loop separate from the above loop. */
|
||||
for (i = 0; i < mergelist_cnt; i++) {
|
||||
filter_rule *ex = mergelist_parents[i];
|
||||
filter_rule_list *lp = ex->u.mergelist;
|
||||
filter_rule_list *lp;
|
||||
if (!ex)
|
||||
continue;
|
||||
lp = ex->u.mergelist;
|
||||
|
||||
if (DEBUG_GTE(FILTER, 2)) {
|
||||
rprintf(FINFO, "[%s] pushing mergelist #%d%s\n",
|
||||
@@ -553,44 +559,38 @@ void pop_local_filters(void *mem)
|
||||
|
||||
for (i = mergelist_cnt; i-- > 0; ) {
|
||||
filter_rule *ex = mergelist_parents[i];
|
||||
filter_rule_list *lp = ex->u.mergelist;
|
||||
filter_rule_list *lp;
|
||||
if (!ex)
|
||||
continue;
|
||||
lp = ex->u.mergelist;
|
||||
|
||||
if (DEBUG_GTE(FILTER, 2)) {
|
||||
rprintf(FINFO, "[%s] popping mergelist #%d%s\n",
|
||||
who_am_i(), i, lp->debug_type);
|
||||
}
|
||||
|
||||
clear_filter_list(lp);
|
||||
|
||||
if (i >= old_mergelist_cnt) {
|
||||
/* This mergelist does not exist in the state to be
|
||||
* restored. Free its parent_dirscan list to clean up
|
||||
* any per-dir mergelists defined there so we don't
|
||||
* crash trying to restore nonexistent state for them
|
||||
* below. (Counterpart to setup_merge_file call in
|
||||
* push_local_filters. Must be done here, not in
|
||||
* free_filter, for LIFO order.) */
|
||||
pop_filter_list(lp);
|
||||
if (i >= old_mergelist_cnt && lp->head) {
|
||||
/* This mergelist does not exist in the state to be restored, but it
|
||||
* still has inherited rules. This can sometimes happen if a per-dir
|
||||
* merge file calls setup_merge_file() in push_local_filters() and that
|
||||
* leaves some inherited rules that aren't in the pushed list state. */
|
||||
if (DEBUG_GTE(FILTER, 2)) {
|
||||
rprintf(FINFO, "[%s] freeing parent_dirscan filters of mergelist #%d%s\n",
|
||||
who_am_i(), i, ex->u.mergelist->debug_type);
|
||||
}
|
||||
free_filters(lp->parent_dirscan_head);
|
||||
lp->parent_dirscan_head = NULL;
|
||||
pop_filter_list(lp);
|
||||
}
|
||||
}
|
||||
|
||||
/* If we cleaned things up properly, the only still-active mergelists
|
||||
* should be those with a state to be restored. */
|
||||
assert(mergelist_cnt == old_mergelist_cnt);
|
||||
if (!pop)
|
||||
return; /* No state to restore. */
|
||||
|
||||
if (!pop) {
|
||||
/* No state to restore. */
|
||||
return;
|
||||
}
|
||||
|
||||
for (i = 0; i < mergelist_cnt; i++) {
|
||||
memcpy(mergelist_parents[i]->u.mergelist, &pop->mergelists[i],
|
||||
sizeof (filter_rule_list));
|
||||
for (i = 0; i < old_mergelist_cnt; i++) {
|
||||
filter_rule *ex = mergelist_parents[i];
|
||||
if (!ex)
|
||||
continue;
|
||||
memcpy(ex->u.mergelist, &pop->mergelists[i], sizeof (filter_rule_list));
|
||||
}
|
||||
|
||||
free(pop);
|
||||
@@ -624,7 +624,7 @@ void change_local_filter_dir(const char *dname, int dlen, int dir_depth)
|
||||
filt_array[cur_depth] = push_local_filters(dname, dlen);
|
||||
}
|
||||
|
||||
static int rule_matches(const char *fname, filter_rule *ex, int name_is_dir)
|
||||
static int rule_matches(const char *fname, filter_rule *ex, int name_flags)
|
||||
{
|
||||
int slash_handling, str_cnt = 0, anchored_match = 0;
|
||||
int ret_match = ex->rflags & FILTRULE_NEGATE ? 0 : 1;
|
||||
@@ -635,6 +635,9 @@ static int rule_matches(const char *fname, filter_rule *ex, int name_is_dir)
|
||||
if (!*name)
|
||||
return 0;
|
||||
|
||||
if (!(name_flags & NAME_IS_XATTR) ^ !(ex->rflags & FILTRULE_XATTR))
|
||||
return 0;
|
||||
|
||||
if (!ex->u.slash_cnt && !(ex->rflags & FILTRULE_WILD2)) {
|
||||
/* If the pattern does not have any slashes AND it does
|
||||
* not have a "**" (which could match a slash), then we
|
||||
@@ -652,7 +655,7 @@ static int rule_matches(const char *fname, filter_rule *ex, int name_is_dir)
|
||||
strings[str_cnt++] = "/";
|
||||
}
|
||||
strings[str_cnt++] = name;
|
||||
if (name_is_dir) {
|
||||
if (name_flags & NAME_IS_DIR) {
|
||||
/* Allow a trailing "/"+"***" to match the directory. */
|
||||
if (ex->rflags & FILTRULE_WILD3_SUFFIX)
|
||||
strings[str_cnt++] = "/";
|
||||
@@ -704,7 +707,7 @@ static int rule_matches(const char *fname, filter_rule *ex, int name_is_dir)
|
||||
|
||||
static void report_filter_result(enum logcode code, char const *name,
|
||||
filter_rule const *ent,
|
||||
int name_is_dir, const char *type)
|
||||
int name_flags, const char *type)
|
||||
{
|
||||
/* If a trailing slash is present to match only directories,
|
||||
* then it is stripped out by add_rule(). So as a special
|
||||
@@ -714,17 +717,40 @@ static void report_filter_result(enum logcode code, char const *name,
|
||||
static char *actions[2][2]
|
||||
= { {"show", "hid"}, {"risk", "protect"} };
|
||||
const char *w = who_am_i();
|
||||
const char *t = name_flags & NAME_IS_XATTR ? "xattr"
|
||||
: name_flags & NAME_IS_DIR ? "directory"
|
||||
: "file";
|
||||
rprintf(code, "[%s] %sing %s %s because of pattern %s%s%s\n",
|
||||
w, actions[*w!='s'][!(ent->rflags & FILTRULE_INCLUDE)],
|
||||
name_is_dir ? "directory" : "file", name, ent->pattern,
|
||||
t, name, ent->pattern,
|
||||
ent->rflags & FILTRULE_DIRECTORY ? "/" : "", type);
|
||||
}
|
||||
}
|
||||
|
||||
/* This function is used to check if a file should be included/excluded
|
||||
* from the list of files based on its name and type etc. The value of
|
||||
* filter_level is set to either SERVER_FILTERS or ALL_FILTERS. */
|
||||
int name_is_excluded(const char *fname, int name_flags, int filter_level)
|
||||
{
|
||||
if (daemon_filter_list.head && check_filter(&daemon_filter_list, FLOG, fname, name_flags) < 0) {
|
||||
if (!(name_flags & NAME_IS_XATTR))
|
||||
errno = ENOENT;
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (filter_level != ALL_FILTERS)
|
||||
return 0;
|
||||
|
||||
if (filter_list.head && check_filter(&filter_list, FINFO, fname, name_flags) < 0)
|
||||
return 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Return -1 if file "name" is defined to be excluded by the specified
|
||||
* exclude list, 1 if it is included, and 0 if it was not matched. */
|
||||
int check_filter(filter_rule_list *listp, enum logcode code,
|
||||
const char *name, int name_is_dir)
|
||||
const char *name, int name_flags)
|
||||
{
|
||||
filter_rule *ent;
|
||||
|
||||
@@ -732,22 +758,19 @@ int check_filter(filter_rule_list *listp, enum logcode code,
|
||||
if (ignore_perishable && ent->rflags & FILTRULE_PERISHABLE)
|
||||
continue;
|
||||
if (ent->rflags & FILTRULE_PERDIR_MERGE) {
|
||||
int rc = check_filter(ent->u.mergelist, code, name,
|
||||
name_is_dir);
|
||||
int rc = check_filter(ent->u.mergelist, code, name, name_flags);
|
||||
if (rc)
|
||||
return rc;
|
||||
continue;
|
||||
}
|
||||
if (ent->rflags & FILTRULE_CVS_IGNORE) {
|
||||
int rc = check_filter(&cvs_filter_list, code, name,
|
||||
name_is_dir);
|
||||
int rc = check_filter(&cvs_filter_list, code, name, name_flags);
|
||||
if (rc)
|
||||
return rc;
|
||||
continue;
|
||||
}
|
||||
if (rule_matches(name, ent, name_is_dir)) {
|
||||
report_filter_result(code, name, ent, name_is_dir,
|
||||
listp->debug_type);
|
||||
if (rule_matches(name, ent, name_flags)) {
|
||||
report_filter_result(code, name, ent, name_flags, listp->debug_type);
|
||||
return ent->rflags & FILTRULE_INCLUDE ? 1 : -1;
|
||||
}
|
||||
}
|
||||
@@ -872,7 +895,7 @@ static filter_rule *parse_rule_tok(const char **rulestr_ptr,
|
||||
switch (ch) {
|
||||
case ':':
|
||||
rule->rflags |= FILTRULE_PERDIR_MERGE
|
||||
| FILTRULE_FINISH_SETUP;
|
||||
| FILTRULE_FINISH_SETUP;
|
||||
/* FALL THROUGH */
|
||||
case '.':
|
||||
rule->rflags |= FILTRULE_MERGE_FILE;
|
||||
@@ -972,6 +995,10 @@ static filter_rule *parse_rule_tok(const char **rulestr_ptr,
|
||||
goto invalid;
|
||||
rule->rflags |= FILTRULE_WORD_SPLIT;
|
||||
break;
|
||||
case 'x':
|
||||
rule->rflags |= FILTRULE_XATTR;
|
||||
saw_xattr_filter = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (*s)
|
||||
@@ -1093,7 +1120,8 @@ void parse_filter_str(filter_rule_list *listp, const char *rulestr,
|
||||
"[%s] clearing filter list%s\n",
|
||||
who_am_i(), listp->debug_type);
|
||||
}
|
||||
clear_filter_list(listp);
|
||||
pop_filter_list(listp);
|
||||
listp->head = NULL;
|
||||
goto free_continue;
|
||||
}
|
||||
|
||||
@@ -1258,6 +1286,8 @@ char *get_rule_prefix(filter_rule *rule, const char *pat, int for_xfer,
|
||||
}
|
||||
if (rule->rflags & FILTRULE_EXCLUDE_SELF)
|
||||
*op++ = 'e';
|
||||
if (rule->rflags & FILTRULE_XATTR)
|
||||
*op++ = 'x';
|
||||
if (rule->rflags & FILTRULE_SENDER_SIDE
|
||||
&& (!for_xfer || protocol_version >= 29))
|
||||
*op++ = 's';
|
||||
@@ -1376,8 +1406,7 @@ void recv_filter_list(int f_in)
|
||||
char line[BIGPATHBUFLEN];
|
||||
int xflags = protocol_version >= 29 ? 0 : XFLG_OLD_PREFIXES;
|
||||
int receiver_wants_list = prune_empty_dirs
|
||||
|| (delete_mode
|
||||
&& (!delete_excluded || protocol_version >= 29));
|
||||
|| (delete_mode && (!delete_excluded || protocol_version >= 29));
|
||||
unsigned int len;
|
||||
|
||||
if (!local_server && (am_sender || receiver_wants_list)) {
|
||||
|
||||
83
fileio.c
83
fileio.c
@@ -3,7 +3,7 @@
|
||||
*
|
||||
* Copyright (C) 1998 Andrew Tridgell
|
||||
* Copyright (C) 2002 Martin Pool
|
||||
* Copyright (C) 2004-2014 Wayne Davison
|
||||
* Copyright (C) 2004-2020 Wayne Davison
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
@@ -26,21 +26,26 @@
|
||||
#define ENODATA EAGAIN
|
||||
#endif
|
||||
|
||||
/* We want all reads to be aligned on 1K boundries. */
|
||||
#define ALIGN_BOUNDRY 1024
|
||||
/* We want all reads to be aligned on 1K boundaries. */
|
||||
#define ALIGN_BOUNDARY 1024
|
||||
/* How far past the boundary is an offset? */
|
||||
#define ALIGNED_OVERSHOOT(oft) ((oft) & (ALIGN_BOUNDRY-1))
|
||||
#define ALIGNED_OVERSHOOT(oft) ((oft) & (ALIGN_BOUNDARY-1))
|
||||
/* Round up a length to the next boundary */
|
||||
#define ALIGNED_LENGTH(len) ((((len) - 1) | (ALIGN_BOUNDRY-1)) + 1)
|
||||
#define ALIGNED_LENGTH(len) ((((len) - 1) | (ALIGN_BOUNDARY-1)) + 1)
|
||||
|
||||
extern int sparse_files;
|
||||
|
||||
OFF_T preallocated_len = 0;
|
||||
|
||||
static OFF_T sparse_seek = 0;
|
||||
static OFF_T sparse_past_write = 0;
|
||||
|
||||
int sparse_end(int f, OFF_T size)
|
||||
{
|
||||
int ret;
|
||||
|
||||
sparse_past_write = 0;
|
||||
|
||||
if (!sparse_seek)
|
||||
return 0;
|
||||
|
||||
@@ -63,8 +68,10 @@ int sparse_end(int f, OFF_T size)
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
static int write_sparse(int f, char *buf, int len)
|
||||
/* Note that the offset is just the caller letting us know where
|
||||
* the current file position is in the file. The use_seek arg tells
|
||||
* us that we should seek over matching data instead of writing it. */
|
||||
static int write_sparse(int f, int use_seek, OFF_T offset, const char *buf, int len)
|
||||
{
|
||||
int l1 = 0, l2 = 0;
|
||||
int ret;
|
||||
@@ -77,9 +84,24 @@ static int write_sparse(int f, char *buf, int len)
|
||||
if (l1 == len)
|
||||
return len;
|
||||
|
||||
if (sparse_seek)
|
||||
do_lseek(f, sparse_seek, SEEK_CUR);
|
||||
if (sparse_seek) {
|
||||
if (sparse_past_write >= preallocated_len) {
|
||||
if (do_lseek(f, sparse_seek, SEEK_CUR) < 0)
|
||||
return -1;
|
||||
} else if (do_punch_hole(f, sparse_past_write, sparse_seek) < 0) {
|
||||
sparse_seek = 0;
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
sparse_seek = l2;
|
||||
sparse_past_write = offset + len - l2;
|
||||
|
||||
if (use_seek) {
|
||||
/* The in-place data already matches. */
|
||||
if (do_lseek(f, len - (l1+l2), SEEK_CUR) < 0)
|
||||
return -1;
|
||||
return len;
|
||||
}
|
||||
|
||||
while ((ret = write(f, buf + l1, len - (l1+l2))) <= 0) {
|
||||
if (ret < 0 && errno == EINTR)
|
||||
@@ -96,7 +118,6 @@ static int write_sparse(int f, char *buf, int len)
|
||||
return len;
|
||||
}
|
||||
|
||||
|
||||
static char *wf_writeBuf;
|
||||
static size_t wf_writeBufSize;
|
||||
static size_t wf_writeBufCnt;
|
||||
@@ -118,12 +139,10 @@ int flush_write_file(int f)
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* write_file does not allow incomplete writes. It loops internally
|
||||
* until len bytes are written or errno is set.
|
||||
*/
|
||||
int write_file(int f, char *buf, int len)
|
||||
/* write_file does not allow incomplete writes. It loops internally
|
||||
* until len bytes are written or errno is set. Note that use_seek and
|
||||
* offset are only used in sparse processing (see write_sparse()). */
|
||||
int write_file(int f, int use_seek, OFF_T offset, const char *buf, int len)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
@@ -131,7 +150,8 @@ int write_file(int f, char *buf, int len)
|
||||
int r1;
|
||||
if (sparse_files > 0) {
|
||||
int len1 = MIN(len, SPARSE_WRITE_SIZE);
|
||||
r1 = write_sparse(f, buf, len1);
|
||||
r1 = write_sparse(f, use_seek, offset, buf, len1);
|
||||
offset += r1;
|
||||
} else {
|
||||
if (!wf_writeBuf) {
|
||||
wf_writeBufSize = WRITE_SIZE * 8;
|
||||
@@ -164,6 +184,30 @@ int write_file(int f, char *buf, int len)
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* An in-place update found identical data at an identical location. We either
|
||||
* just seek past it, or (for an in-place sparse update), we give the data to
|
||||
* the sparse processor with the use_seek flag set. */
|
||||
int skip_matched(int fd, OFF_T offset, const char *buf, int len)
|
||||
{
|
||||
OFF_T pos;
|
||||
|
||||
if (sparse_files > 0) {
|
||||
if (write_file(fd, 1, offset, buf, len) != len)
|
||||
return -1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (flush_write_file(fd) < 0)
|
||||
return -1;
|
||||
|
||||
if ((pos = do_lseek(fd, len, SEEK_CUR)) != offset + len) {
|
||||
rsyserr(FERROR_XFER, errno, "lseek returned %s, not %s",
|
||||
big_num(pos), big_num(offset));
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* This provides functionality somewhat similar to mmap() but using read().
|
||||
* It gives sliding window access to a file. mmap() is not used because of
|
||||
@@ -271,7 +315,6 @@ char *map_ptr(struct map_struct *map, OFF_T offset, int32 len)
|
||||
return map->p + align_fudge;
|
||||
}
|
||||
|
||||
|
||||
int unmap_file(struct map_struct *map)
|
||||
{
|
||||
int ret;
|
||||
@@ -281,7 +324,9 @@ int unmap_file(struct map_struct *map)
|
||||
map->p = NULL;
|
||||
}
|
||||
ret = map->status;
|
||||
memset(map, 0, sizeof map[0]);
|
||||
#if 0 /* I don't think we really need this. */
|
||||
force_memzero(map, sizeof map[0]);
|
||||
#endif
|
||||
free(map);
|
||||
|
||||
return ret;
|
||||
|
||||
297
flist.c
297
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-2014 Wayne Davison
|
||||
* Copyright (C) 2002-2020 Wayne Davison
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
@@ -33,9 +33,11 @@ extern int am_sender;
|
||||
extern int am_generator;
|
||||
extern int inc_recurse;
|
||||
extern int always_checksum;
|
||||
extern int checksum_type;
|
||||
extern int module_id;
|
||||
extern int ignore_errors;
|
||||
extern int numeric_ids;
|
||||
extern int quiet;
|
||||
extern int recurse;
|
||||
extern int use_qsort;
|
||||
extern int xfer_dirs;
|
||||
@@ -53,6 +55,7 @@ extern int preserve_specials;
|
||||
extern int delete_during;
|
||||
extern int missing_args;
|
||||
extern int eol_nulls;
|
||||
extern int atimes_ndx;
|
||||
extern int relative_paths;
|
||||
extern int implied_dirs;
|
||||
extern int ignore_perishable;
|
||||
@@ -89,7 +92,7 @@ extern iconv_t ic_send, ic_recv;
|
||||
#define PTR_SIZE (sizeof (struct file_struct *))
|
||||
|
||||
int io_error;
|
||||
int checksum_len;
|
||||
int flist_csum_len;
|
||||
dev_t filesystem_dev; /* used to implement -x */
|
||||
|
||||
struct file_list *cur_flist, *first_flist, *dir_flist;
|
||||
@@ -98,6 +101,7 @@ int flist_cnt = 0; /* how many (non-tmp) file list objects exist */
|
||||
int file_total = 0; /* total of all active items over all file-lists */
|
||||
int file_old_total = 0; /* total of active items that will soon be gone */
|
||||
int flist_eof = 0; /* all the file-lists are now known */
|
||||
int xfer_flags_as_varint = 0;
|
||||
|
||||
#define NORMAL_NAME 0
|
||||
#define SLASH_ENDING_NAME 1
|
||||
@@ -127,6 +131,7 @@ static char tmp_sum[MAX_DIGEST_LEN];
|
||||
|
||||
static char empty_sum[MAX_DIGEST_LEN];
|
||||
static int flist_count_offset; /* for --delete --progress */
|
||||
static int show_filelist_progress;
|
||||
|
||||
static void flist_sort_and_clean(struct file_list *flist, int strip_root);
|
||||
static void output_flist(struct file_list *flist);
|
||||
@@ -137,18 +142,15 @@ void init_flist(void)
|
||||
rprintf(FINFO, "FILE_STRUCT_LEN=%d, EXTRA_LEN=%d\n",
|
||||
(int)FILE_STRUCT_LEN, (int)EXTRA_LEN);
|
||||
}
|
||||
checksum_len = protocol_version < 21 ? 2
|
||||
: protocol_version < 30 ? MD4_DIGEST_LEN
|
||||
: MD5_DIGEST_LEN;
|
||||
}
|
||||
flist_csum_len = csum_len_for_type(checksum_type, 1);
|
||||
|
||||
static int show_filelist_p(void)
|
||||
{
|
||||
return INFO_GTE(FLIST, 1) && xfer_dirs && !am_server && !inc_recurse;
|
||||
show_filelist_progress = INFO_GTE(FLIST, 1) && xfer_dirs && !am_server && !inc_recurse;
|
||||
}
|
||||
|
||||
static void start_filelist_progress(char *kind)
|
||||
{
|
||||
if (quiet)
|
||||
return;
|
||||
rprintf(FCLIENT, "%s ... ", kind);
|
||||
output_needs_newline = 1;
|
||||
rflush(FINFO);
|
||||
@@ -156,23 +158,28 @@ static void start_filelist_progress(char *kind)
|
||||
|
||||
static void emit_filelist_progress(int count)
|
||||
{
|
||||
if (quiet)
|
||||
return;
|
||||
if (output_needs_newline == 2) /* avoid a newline in the middle of this filelist-progress output */
|
||||
output_needs_newline = 0;
|
||||
rprintf(FCLIENT, " %d files...\r", count);
|
||||
output_needs_newline = 2;
|
||||
}
|
||||
|
||||
static void maybe_emit_filelist_progress(int count)
|
||||
{
|
||||
if (INFO_GTE(FLIST, 2) && show_filelist_p() && (count % 100) == 0)
|
||||
if (INFO_GTE(FLIST, 2) && show_filelist_progress && (count % 100) == 0)
|
||||
emit_filelist_progress(count);
|
||||
}
|
||||
|
||||
static void finish_filelist_progress(const struct file_list *flist)
|
||||
{
|
||||
output_needs_newline = 0;
|
||||
if (INFO_GTE(FLIST, 2)) {
|
||||
/* This overwrites the progress line */
|
||||
rprintf(FINFO, "%d file%sto consider\n",
|
||||
flist->used, flist->used == 1 ? " " : "s ");
|
||||
} else {
|
||||
output_needs_newline = 0;
|
||||
rprintf(FINFO, "done\n");
|
||||
}
|
||||
}
|
||||
@@ -237,16 +244,6 @@ int link_stat(const char *path, STRUCT_STAT *stp, int follow_dirlinks)
|
||||
#endif
|
||||
}
|
||||
|
||||
static inline int is_daemon_excluded(const char *fname, int is_dir)
|
||||
{
|
||||
if (daemon_filter_list.head
|
||||
&& check_filter(&daemon_filter_list, FLOG, fname, is_dir) < 0) {
|
||||
errno = ENOENT;
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline int path_is_daemon_excluded(char *path, int ignore_filename)
|
||||
{
|
||||
if (daemon_filter_list.head) {
|
||||
@@ -273,23 +270,9 @@ static inline int path_is_daemon_excluded(char *path, int ignore_filename)
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* This function is used to check if a file should be included/excluded
|
||||
* from the list of files based on its name and type etc. The value of
|
||||
* filter_level is set to either SERVER_FILTERS or ALL_FILTERS. */
|
||||
static int is_excluded(const char *fname, int is_dir, int filter_level)
|
||||
static inline int is_excluded(const char *fname, int is_dir, int filter_level)
|
||||
{
|
||||
#if 0 /* This currently never happens, so avoid a useless compare. */
|
||||
if (filter_level == NO_FILTERS)
|
||||
return 0;
|
||||
#endif
|
||||
if (is_daemon_excluded(fname, is_dir))
|
||||
return 1;
|
||||
if (filter_level != ALL_FILTERS)
|
||||
return 0;
|
||||
if (filter_list.head
|
||||
&& check_filter(&filter_list, FINFO, fname, is_dir) < 0)
|
||||
return 1;
|
||||
return 0;
|
||||
return name_is_excluded(fname, is_dir ? NAME_IS_DIR : NAME_IS_FILE, filter_level);
|
||||
}
|
||||
|
||||
static void send_directory(int f, struct file_list *flist,
|
||||
@@ -397,7 +380,7 @@ static void send_file_entry(int f, const char *fname, struct file_struct *file,
|
||||
#endif
|
||||
int ndx, int first_ndx)
|
||||
{
|
||||
static time_t modtime;
|
||||
static time_t modtime, atime;
|
||||
static mode_t mode;
|
||||
#ifdef SUPPORT_HARD_LINKS
|
||||
static int64 dev;
|
||||
@@ -497,14 +480,20 @@ static void send_file_entry(int f, const char *fname, struct file_struct *file,
|
||||
modtime = file->modtime;
|
||||
if (NSEC_BUMP(file) && protocol_version >= 31)
|
||||
xflags |= XMIT_MOD_NSEC;
|
||||
if (atimes_ndx && !S_ISDIR(mode)) {
|
||||
if (F_ATIME(file) == atime)
|
||||
xflags |= XMIT_SAME_ATIME;
|
||||
else
|
||||
atime = F_ATIME(file);
|
||||
}
|
||||
|
||||
#ifdef SUPPORT_HARD_LINKS
|
||||
if (tmp_dev != -1) {
|
||||
if (protocol_version >= 30) {
|
||||
struct ht_int64_node *np = idev_find(tmp_dev, tmp_ino);
|
||||
first_hlink_ndx = (int32)(long)np->data - 1;
|
||||
first_hlink_ndx = (int32)(long)np->data; /* is -1 when new */
|
||||
if (first_hlink_ndx < 0) {
|
||||
np->data = (void*)(long)(first_ndx + ndx + 1);
|
||||
np->data = (void*)(long)(first_ndx + ndx);
|
||||
xflags |= XMIT_HLINK_FIRST;
|
||||
}
|
||||
if (DEBUG_GTE(HLINK, 1)) {
|
||||
@@ -539,11 +528,14 @@ static void send_file_entry(int f, const char *fname, struct file_struct *file,
|
||||
if (l2 > 255)
|
||||
xflags |= XMIT_LONG_NAME;
|
||||
|
||||
/* We must make sure we don't send a zero flag byte or the
|
||||
* other end will terminate the flist transfer. Note that
|
||||
* the use of XMIT_TOP_DIR on a non-dir has no meaning, so
|
||||
* it's harmless way to add a bit to the first flag byte. */
|
||||
if (protocol_version >= 28) {
|
||||
/* We must avoid sending a flag value of 0 (or an initial byte of
|
||||
* 0 for the older xflags protocol) or it will signal the end of
|
||||
* the list. Note that the use of XMIT_TOP_DIR on a non-dir has
|
||||
* no meaning, so it's a harmless way to add a bit to the first
|
||||
* flag byte. */
|
||||
if (xfer_flags_as_varint)
|
||||
write_varint(f, xflags ? xflags : XMIT_EXTENDED_FLAGS);
|
||||
else if (protocol_version >= 28) {
|
||||
if (!xflags && !S_ISDIR(mode))
|
||||
xflags |= XMIT_TOP_DIR;
|
||||
if ((xflags & 0xFF00) || !xflags) {
|
||||
@@ -583,6 +575,8 @@ static void send_file_entry(int f, const char *fname, struct file_struct *file,
|
||||
write_varint(f, F_MOD_NSEC(file));
|
||||
if (!(xflags & XMIT_SAME_MODE))
|
||||
write_int(f, to_wire_mode(mode));
|
||||
if (atimes_ndx && !S_ISDIR(mode) && !(xflags & XMIT_SAME_ATIME))
|
||||
write_varlong(f, atime, 4);
|
||||
if (preserve_uid && !(xflags & XMIT_SAME_UID)) {
|
||||
if (protocol_version < 30)
|
||||
write_int(f, uid);
|
||||
@@ -656,7 +650,7 @@ static void send_file_entry(int f, const char *fname, struct file_struct *file,
|
||||
/* Prior to 28, we sent a useless set of nulls. */
|
||||
sum = empty_sum;
|
||||
}
|
||||
write_buf(f, sum, checksum_len);
|
||||
write_buf(f, sum, flist_csum_len);
|
||||
}
|
||||
|
||||
#ifdef SUPPORT_HARD_LINKS
|
||||
@@ -670,7 +664,7 @@ static void send_file_entry(int f, const char *fname, struct file_struct *file,
|
||||
|
||||
static struct file_struct *recv_file_entry(int f, struct file_list *flist, int xflags)
|
||||
{
|
||||
static int64 modtime;
|
||||
static int64 modtime, atime;
|
||||
static mode_t mode;
|
||||
#ifdef SUPPORT_HARD_LINKS
|
||||
static int64 dev;
|
||||
@@ -777,8 +771,10 @@ static struct file_struct *recv_file_entry(int f, struct file_list *flist, int x
|
||||
struct file_struct *first = flist->files[first_hlink_ndx - flist->ndx_start];
|
||||
file_length = F_LENGTH(first);
|
||||
modtime = first->modtime;
|
||||
modtime_nsec = F_MOD_NSEC(first);
|
||||
modtime_nsec = F_MOD_NSEC_or_0(first);
|
||||
mode = first->mode;
|
||||
if (atimes_ndx && !S_ISDIR(mode))
|
||||
atime = F_ATIME(first);
|
||||
if (preserve_uid)
|
||||
uid = F_OWNER(first);
|
||||
if (preserve_gid)
|
||||
@@ -817,6 +813,16 @@ static struct file_struct *recv_file_entry(int f, struct file_list *flist, int x
|
||||
modtime_nsec = 0;
|
||||
if (!(xflags & XMIT_SAME_MODE))
|
||||
mode = from_wire_mode(read_int(f));
|
||||
if (atimes_ndx && !S_ISDIR(mode) && !(xflags & XMIT_SAME_ATIME)) {
|
||||
atime = read_varlong(f, 4);
|
||||
#if SIZEOF_TIME_T < SIZEOF_INT64
|
||||
if (!am_generator && (int64)(time_t)atime != atime) {
|
||||
rprintf(FERROR_XFER,
|
||||
"Access time value of %s truncated on receiver.\n",
|
||||
lastname);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
if (chmod_modes && !S_ISLNK(mode) && mode)
|
||||
mode = tweak_mode(mode, chmod_modes);
|
||||
@@ -913,7 +919,7 @@ static struct file_struct *recv_file_entry(int f, struct file_list *flist, int x
|
||||
if (file_length > 0xFFFFFFFFu && S_ISREG(mode))
|
||||
extra_len += EXTRA_LEN;
|
||||
#endif
|
||||
#ifdef HAVE_UTIMENSAT
|
||||
#ifdef CAN_SET_NSEC
|
||||
if (modtime_nsec)
|
||||
extra_len += EXTRA_LEN;
|
||||
#endif
|
||||
@@ -948,14 +954,21 @@ static struct file_struct *recv_file_entry(int f, struct file_list *flist, int x
|
||||
memcpy(bp, basename, basename_len);
|
||||
|
||||
#ifdef SUPPORT_HARD_LINKS
|
||||
if (xflags & XMIT_HLINKED)
|
||||
if (xflags & XMIT_HLINKED
|
||||
#ifndef CAN_HARDLINK_SYMLINK
|
||||
&& !S_ISLNK(mode)
|
||||
#endif
|
||||
#ifndef CAN_HARDLINK_SPECIAL
|
||||
&& !IS_SPECIAL(mode) && !IS_DEVICE(mode)
|
||||
#endif
|
||||
)
|
||||
file->flags |= FLAG_HLINKED;
|
||||
#endif
|
||||
file->modtime = (time_t)modtime;
|
||||
#ifdef HAVE_UTIMENSAT
|
||||
#ifdef CAN_SET_NSEC
|
||||
if (modtime_nsec) {
|
||||
file->flags |= FLAG_MOD_NSEC;
|
||||
OPT_EXTRA(file, 0)->unum = modtime_nsec;
|
||||
F_MOD_NSEC(file) = modtime_nsec;
|
||||
}
|
||||
#endif
|
||||
file->len32 = (uint32)file_length;
|
||||
@@ -966,7 +979,7 @@ static struct file_struct *recv_file_entry(int f, struct file_list *flist, int x
|
||||
exit_cleanup(RERR_UNSUPPORTED);
|
||||
#else
|
||||
file->flags |= FLAG_LENGTH64;
|
||||
OPT_EXTRA(file, NSEC_BUMP(file))->unum = (uint32)(file_length >> 32);
|
||||
F_HIGH_LEN(file) = (uint32)(file_length >> 32);
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
@@ -977,6 +990,8 @@ static struct file_struct *recv_file_entry(int f, struct file_list *flist, int x
|
||||
F_GROUP(file) = gid;
|
||||
file->flags |= gid_flags;
|
||||
}
|
||||
if (atimes_ndx && !S_ISDIR(mode))
|
||||
F_ATIME(file) = atime;
|
||||
if (unsort_ndx)
|
||||
F_NDX(file) = flist->used + flist->ndx_start;
|
||||
|
||||
@@ -1086,10 +1101,10 @@ static struct file_struct *recv_file_entry(int f, struct file_list *flist, int x
|
||||
ino = read_longint(f);
|
||||
}
|
||||
np = idev_find(dev, ino);
|
||||
ndx = (int32)(long)np->data - 1;
|
||||
ndx = (int32)(long)np->data; /* is -1 when new */
|
||||
if (ndx < 0) {
|
||||
ndx = cnt++;
|
||||
np->data = (void*)(long)cnt;
|
||||
ndx = cnt++;
|
||||
}
|
||||
F_HL_GNUM(file) = ndx;
|
||||
}
|
||||
@@ -1105,9 +1120,9 @@ static struct file_struct *recv_file_entry(int f, struct file_list *flist, int x
|
||||
}
|
||||
if (first_hlink_ndx >= flist->ndx_start) {
|
||||
struct file_struct *first = flist->files[first_hlink_ndx - flist->ndx_start];
|
||||
memcpy(bp, F_SUM(first), checksum_len);
|
||||
memcpy(bp, F_SUM(first), flist_csum_len);
|
||||
} else
|
||||
read_buf(f, bp, checksum_len);
|
||||
read_buf(f, bp, flist_csum_len);
|
||||
}
|
||||
|
||||
#ifdef SUPPORT_ACLS
|
||||
@@ -1357,14 +1372,14 @@ struct file_struct *make_file(const char *fname, struct file_list *flist,
|
||||
#ifdef ST_MTIME_NSEC
|
||||
if (st.ST_MTIME_NSEC && protocol_version >= 31) {
|
||||
file->flags |= FLAG_MOD_NSEC;
|
||||
OPT_EXTRA(file, 0)->unum = st.ST_MTIME_NSEC;
|
||||
F_MOD_NSEC(file) = st.ST_MTIME_NSEC;
|
||||
}
|
||||
#endif
|
||||
file->len32 = (uint32)st.st_size;
|
||||
#if SIZEOF_CAPITAL_OFF_T >= 8
|
||||
if (st.st_size > 0xFFFFFFFFu && S_ISREG(st.st_mode)) {
|
||||
file->flags |= FLAG_LENGTH64;
|
||||
OPT_EXTRA(file, NSEC_BUMP(file))->unum = (uint32)(st.st_size >> 32);
|
||||
F_HIGH_LEN(file) = (uint32)(st.st_size >> 32);
|
||||
}
|
||||
#endif
|
||||
file->mode = st.st_mode;
|
||||
@@ -1374,6 +1389,8 @@ struct file_struct *make_file(const char *fname, struct file_list *flist,
|
||||
F_GROUP(file) = st.st_gid;
|
||||
if (am_generator && st.st_uid == our_uid)
|
||||
file->flags |= FLAG_OWNED_BY_US;
|
||||
if (atimes_ndx && !S_ISDIR(file->mode))
|
||||
F_ATIME(file) = st.st_atime;
|
||||
|
||||
if (basename != thisname)
|
||||
file->dirname = lastdir;
|
||||
@@ -1395,7 +1412,7 @@ struct file_struct *make_file(const char *fname, struct file_list *flist,
|
||||
}
|
||||
|
||||
if (sender_keeps_checksum && S_ISREG(st.st_mode))
|
||||
memcpy(F_SUM(file), tmp_sum, checksum_len);
|
||||
memcpy(F_SUM(file), tmp_sum, flist_csum_len);
|
||||
|
||||
if (unsort_ndx)
|
||||
F_NDX(file) = stats.num_dirs;
|
||||
@@ -1403,6 +1420,20 @@ struct file_struct *make_file(const char *fname, struct file_list *flist,
|
||||
return file;
|
||||
}
|
||||
|
||||
OFF_T get_device_size(int fd, const char *fname)
|
||||
{
|
||||
OFF_T off = lseek(fd, 0, SEEK_END);
|
||||
|
||||
if (off == (OFF_T) -1) {
|
||||
rsyserr(FERROR, errno, "failed to get device size via seek: %s", fname);
|
||||
return 0;
|
||||
}
|
||||
if (lseek(fd, 0, SEEK_SET) != 0)
|
||||
rsyserr(FERROR, errno, "failed to seek device back to start: %s", fname);
|
||||
|
||||
return off;
|
||||
}
|
||||
|
||||
/* Only called for temporary file_struct entries created by make_file(). */
|
||||
void unmake_file(struct file_struct *file)
|
||||
{
|
||||
@@ -1647,6 +1678,7 @@ static void add_dirs_to_tree(int parent_ndx, struct file_list *from_flist,
|
||||
int32 *parent_dp = parent_ndx < 0 ? NULL
|
||||
: F_DIR_NODE_P(dir_flist->sorted[parent_ndx]);
|
||||
|
||||
/* The sending side is adding entries to dir_flist in sorted order, so sorted & files are the same. */
|
||||
flist_expand(dir_flist, dir_cnt);
|
||||
dir_flist->sorted = dir_flist->files;
|
||||
|
||||
@@ -1714,6 +1746,8 @@ static void send_directory(int f, struct file_list *flist, char *fbuf, int len,
|
||||
interpret_stat_error(fbuf, True);
|
||||
return;
|
||||
}
|
||||
if (errno == ENOTDIR && (flags & FLAG_PERHAPS_DIR))
|
||||
return;
|
||||
io_error |= IOERR_GENERAL;
|
||||
rsyserr(FERROR_XFER, errno, "opendir %s failed", full_fname(fbuf));
|
||||
return;
|
||||
@@ -1952,6 +1986,18 @@ static void send1extra(int f, struct file_struct *file, struct file_list *flist)
|
||||
free(relname_list);
|
||||
}
|
||||
|
||||
static void write_end_of_flist(int f, int send_io_error)
|
||||
{
|
||||
if (xfer_flags_as_varint) {
|
||||
write_varint(f, 0);
|
||||
write_varint(f, send_io_error ? io_error : 0);
|
||||
} else if (send_io_error) {
|
||||
write_shortint(f, XMIT_EXTENDED_FLAGS|XMIT_IO_ERROR_ENDLIST);
|
||||
write_varint(f, io_error);
|
||||
} else
|
||||
write_byte(f, 0);
|
||||
}
|
||||
|
||||
void send_extra_file_list(int f, int at_least)
|
||||
{
|
||||
struct file_list *flist;
|
||||
@@ -1981,7 +2027,7 @@ void send_extra_file_list(int f, int at_least)
|
||||
else
|
||||
dir_ndx = send_dir_ndx;
|
||||
write_ndx(f, NDX_FLIST_OFFSET - dir_ndx);
|
||||
flist->parent_ndx = dir_ndx;
|
||||
flist->parent_ndx = send_dir_ndx; /* the sending side must remember the sorted ndx value */
|
||||
|
||||
send1extra(f, file, flist);
|
||||
prev_flags = file->flags;
|
||||
@@ -2003,14 +2049,13 @@ void send_extra_file_list(int f, int at_least)
|
||||
}
|
||||
|
||||
if (io_error == save_io_error || ignore_errors)
|
||||
write_byte(f, 0);
|
||||
else if (use_safe_inc_flist) {
|
||||
write_shortint(f, XMIT_EXTENDED_FLAGS|XMIT_IO_ERROR_ENDLIST);
|
||||
write_varint(f, io_error);
|
||||
} else {
|
||||
write_end_of_flist(f, 0);
|
||||
else if (use_safe_inc_flist)
|
||||
write_end_of_flist(f, 1);
|
||||
else {
|
||||
if (delete_during)
|
||||
fatal_unsafe_io_error();
|
||||
write_byte(f, 0);
|
||||
write_end_of_flist(f, 0);
|
||||
}
|
||||
|
||||
if (need_unsorted_flist) {
|
||||
@@ -2080,7 +2125,7 @@ struct file_list *send_file_list(int f, int argc, char *argv[])
|
||||
int implied_dot_dir = 0;
|
||||
|
||||
rprintf(FLOG, "building file list\n");
|
||||
if (show_filelist_p())
|
||||
if (show_filelist_progress)
|
||||
start_filelist_progress("building file list");
|
||||
else if (inc_recurse && INFO_GTE(FLIST, 1) && !am_server)
|
||||
rprintf(FCLIENT, "sending incremental file list\n");
|
||||
@@ -2255,7 +2300,7 @@ struct file_list *send_file_list(int f, int argc, char *argv[])
|
||||
memmove(fbuf, fn, len + 1);
|
||||
|
||||
if (link_stat(fbuf, &st, copy_dirlinks || name_type != NORMAL_NAME) != 0
|
||||
|| (name_type != DOTDIR_NAME && is_daemon_excluded(fbuf, S_ISDIR(st.st_mode)))
|
||||
|| (name_type != DOTDIR_NAME && is_excluded(fbuf, S_ISDIR(st.st_mode) != 0, SERVER_FILTERS))
|
||||
|| (relative_paths && path_is_daemon_excluded(fbuf, 1))) {
|
||||
if (errno != ENOENT || missing_args == 0) {
|
||||
/* This is a transfer error, but inhibit deletion
|
||||
@@ -2339,14 +2384,13 @@ struct file_list *send_file_list(int f, int argc, char *argv[])
|
||||
|
||||
/* Indicate end of file list */
|
||||
if (io_error == 0 || ignore_errors)
|
||||
write_byte(f, 0);
|
||||
else if (use_safe_inc_flist) {
|
||||
write_shortint(f, XMIT_EXTENDED_FLAGS|XMIT_IO_ERROR_ENDLIST);
|
||||
write_varint(f, io_error);
|
||||
} else {
|
||||
write_end_of_flist(f, 0);
|
||||
else if (use_safe_inc_flist)
|
||||
write_end_of_flist(f, 1);
|
||||
else {
|
||||
if (delete_during && inc_recurse)
|
||||
fatal_unsafe_io_error();
|
||||
write_byte(f, 0);
|
||||
write_end_of_flist(f, 0);
|
||||
}
|
||||
|
||||
#ifdef SUPPORT_HARD_LINKS
|
||||
@@ -2354,7 +2398,7 @@ struct file_list *send_file_list(int f, int argc, char *argv[])
|
||||
idev_destroy();
|
||||
#endif
|
||||
|
||||
if (show_filelist_p())
|
||||
if (show_filelist_progress)
|
||||
finish_filelist_progress(flist);
|
||||
|
||||
gettimeofday(&end_tv, NULL);
|
||||
@@ -2428,14 +2472,15 @@ struct file_list *send_file_list(int f, int argc, char *argv[])
|
||||
return flist;
|
||||
}
|
||||
|
||||
struct file_list *recv_file_list(int f)
|
||||
struct file_list *recv_file_list(int f, int dir_ndx)
|
||||
{
|
||||
const char *good_dirname = NULL;
|
||||
struct file_list *flist;
|
||||
int dstart, flags;
|
||||
int64 start_read;
|
||||
|
||||
if (!first_flist) {
|
||||
if (show_filelist_p())
|
||||
if (show_filelist_progress)
|
||||
start_filelist_progress("receiving file list");
|
||||
else if (inc_recurse && INFO_GTE(FLIST, 1) && !am_server)
|
||||
rprintf(FCLIENT, "receiving incremental file list\n");
|
||||
@@ -2464,27 +2509,56 @@ struct file_list *recv_file_list(int f)
|
||||
dstart = 0;
|
||||
}
|
||||
|
||||
while ((flags = read_byte(f)) != 0) {
|
||||
while (1) {
|
||||
struct file_struct *file;
|
||||
|
||||
if (protocol_version >= 28 && (flags & XMIT_EXTENDED_FLAGS))
|
||||
flags |= read_byte(f) << 8;
|
||||
|
||||
if (flags == (XMIT_EXTENDED_FLAGS|XMIT_IO_ERROR_ENDLIST)) {
|
||||
int err;
|
||||
if (!use_safe_inc_flist) {
|
||||
rprintf(FERROR, "Invalid flist flag: %x\n", flags);
|
||||
exit_cleanup(RERR_PROTOCOL);
|
||||
if (xfer_flags_as_varint) {
|
||||
if ((flags = read_varint(f)) == 0) {
|
||||
int err = read_varint(f);
|
||||
if (!ignore_errors)
|
||||
io_error |= err;
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
if ((flags = read_byte(f)) == 0)
|
||||
break;
|
||||
|
||||
if (protocol_version >= 28 && (flags & XMIT_EXTENDED_FLAGS))
|
||||
flags |= read_byte(f) << 8;
|
||||
|
||||
if (flags == (XMIT_EXTENDED_FLAGS|XMIT_IO_ERROR_ENDLIST)) {
|
||||
int err;
|
||||
if (!use_safe_inc_flist) {
|
||||
rprintf(FERROR, "Invalid flist flag: %x\n", flags);
|
||||
exit_cleanup(RERR_PROTOCOL);
|
||||
}
|
||||
err = read_varint(f);
|
||||
if (!ignore_errors)
|
||||
io_error |= err;
|
||||
break;
|
||||
}
|
||||
err = read_varint(f);
|
||||
if (!ignore_errors)
|
||||
io_error |= err;
|
||||
break;
|
||||
}
|
||||
|
||||
flist_expand(flist, 1);
|
||||
file = recv_file_entry(f, flist, flags);
|
||||
|
||||
if (inc_recurse) {
|
||||
static const char empty_dir[] = "\0";
|
||||
const char *cur_dir = file->dirname ? file->dirname : empty_dir;
|
||||
if (relative_paths && *cur_dir == '/')
|
||||
cur_dir++;
|
||||
if (cur_dir != good_dirname) {
|
||||
const char *d = dir_ndx >= 0 ? f_name(dir_flist->files[dir_ndx], NULL) : empty_dir;
|
||||
if (strcmp(cur_dir, d) != 0) {
|
||||
rprintf(FERROR,
|
||||
"ABORTING due to invalid path from sender: %s/%s\n",
|
||||
cur_dir, file->basename);
|
||||
exit_cleanup(RERR_PROTOCOL);
|
||||
}
|
||||
good_dirname = cur_dir;
|
||||
}
|
||||
}
|
||||
|
||||
if (S_ISREG(file->mode)) {
|
||||
/* Already counted */
|
||||
} else if (S_ISDIR(file->mode)) {
|
||||
@@ -2514,7 +2588,7 @@ struct file_list *recv_file_list(int f)
|
||||
if (DEBUG_GTE(FLIST, 2))
|
||||
rprintf(FINFO, "received %d names\n", flist->used);
|
||||
|
||||
if (show_filelist_p())
|
||||
if (show_filelist_progress)
|
||||
finish_filelist_progress(flist);
|
||||
|
||||
if (need_unsorted_flist) {
|
||||
@@ -2608,7 +2682,7 @@ void recv_additional_file_list(int f)
|
||||
rprintf(FINFO, "[%s] receiving flist for dir %d\n",
|
||||
who_am_i(), ndx);
|
||||
}
|
||||
flist = recv_file_list(f);
|
||||
flist = recv_file_list(f, ndx);
|
||||
flist->parent_ndx = ndx;
|
||||
}
|
||||
}
|
||||
@@ -2664,6 +2738,34 @@ int flist_find(struct file_list *flist, struct file_struct *f)
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Search for a name in the file list. You must specify want_dir_match as:
|
||||
* 1=match directories, 0=match non-directories, or -1=match either. */
|
||||
int flist_find_name(struct file_list *flist, const char *fname, int want_dir_match)
|
||||
{
|
||||
struct { /* We have to create a temporary file_struct for the search. */
|
||||
struct file_struct f;
|
||||
char name_space[MAXPATHLEN];
|
||||
} t;
|
||||
char fbuf[MAXPATHLEN];
|
||||
const char *slash = strrchr(fname, '/');
|
||||
const char *basename = slash ? slash+1 : fname;
|
||||
|
||||
memset(&t.f, 0, FILE_STRUCT_LEN);
|
||||
memcpy((void *)t.f.basename, basename, strlen(basename)+1);
|
||||
|
||||
if (slash) {
|
||||
strlcpy(fbuf, fname, slash - fname + 1);
|
||||
t.f.dirname = fbuf;
|
||||
} else
|
||||
t.f.dirname = NULL;
|
||||
|
||||
t.f.mode = want_dir_match > 0 ? S_IFDIR : S_IFREG;
|
||||
|
||||
if (want_dir_match < 0)
|
||||
return flist_find_ignore_dirness(flist, &t.f);
|
||||
return flist_find(flist, &t.f);
|
||||
}
|
||||
|
||||
/* Search for an identically-named item in the file list. Differs from
|
||||
* flist_find in that an item that agrees with "f" in directory-ness is
|
||||
* preferred but one that does not is still found. */
|
||||
@@ -2908,8 +3010,7 @@ static void flist_sort_and_clean(struct file_list *flist, int strip_root)
|
||||
clear_file(fp);
|
||||
}
|
||||
prev_depth = F_DEPTH(file);
|
||||
if (is_excluded(f_name(file, fbuf), 1,
|
||||
ALL_FILTERS)) {
|
||||
if (is_excluded(f_name(file, fbuf), 1, ALL_FILTERS)) {
|
||||
/* Keep dirs through this dir. */
|
||||
for (j = prev_depth-1; ; j--) {
|
||||
fp = flist->sorted[prev_i];
|
||||
@@ -3194,6 +3295,7 @@ struct file_list *get_dirlist(char *dirname, int dlen, int flags)
|
||||
int save_xfer_dirs = xfer_dirs;
|
||||
int save_prune_empty_dirs = prune_empty_dirs;
|
||||
int senddir_fd = flags & GDL_IGNORE_FILTER_RULES ? -2 : -1;
|
||||
int senddir_flags = FLAG_CONTENT_DIR;
|
||||
|
||||
if (dlen < 0) {
|
||||
dlen = strlcpy(dirbuf, dirname, MAXPATHLEN);
|
||||
@@ -3204,9 +3306,12 @@ struct file_list *get_dirlist(char *dirname, int dlen, int flags)
|
||||
|
||||
dirlist = flist_new(FLIST_TEMP, "get_dirlist");
|
||||
|
||||
if (flags & GDL_PERHAPS_DIR)
|
||||
senddir_flags |= FLAG_PERHAPS_DIR;
|
||||
|
||||
recurse = 0;
|
||||
xfer_dirs = 1;
|
||||
send_directory(senddir_fd, dirlist, dirname, dlen, FLAG_CONTENT_DIR);
|
||||
send_directory(senddir_fd, dirlist, dirname, dlen, senddir_flags);
|
||||
xfer_dirs = save_xfer_dirs;
|
||||
recurse = save_recurse;
|
||||
if (INFO_GTE(PROGRESS, 1))
|
||||
|
||||
338
generator.c
338
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-2014 Wayne Davison
|
||||
* Copyright (C) 2003-2020 Wayne Davison
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
@@ -39,6 +39,7 @@ extern int preserve_acls;
|
||||
extern int preserve_xattrs;
|
||||
extern int preserve_links;
|
||||
extern int preserve_devices;
|
||||
extern int write_devices;
|
||||
extern int preserve_specials;
|
||||
extern int preserve_hard_links;
|
||||
extern int preserve_executability;
|
||||
@@ -57,6 +58,8 @@ extern int update_only;
|
||||
extern int human_readable;
|
||||
extern int ignore_existing;
|
||||
extern int ignore_non_existing;
|
||||
extern int want_xattr_optim;
|
||||
extern int modify_window;
|
||||
extern int inplace;
|
||||
extern int append_mode;
|
||||
extern int make_backups;
|
||||
@@ -73,11 +76,9 @@ extern int protocol_version;
|
||||
extern int file_total;
|
||||
extern int fuzzy_basis;
|
||||
extern int always_checksum;
|
||||
extern int checksum_len;
|
||||
extern int flist_csum_len;
|
||||
extern char *partial_dir;
|
||||
extern int compare_dest;
|
||||
extern int copy_dest;
|
||||
extern int link_dest;
|
||||
extern int alt_dest_type;
|
||||
extern int whole_file;
|
||||
extern int list_only;
|
||||
extern int read_batch;
|
||||
@@ -98,6 +99,7 @@ extern struct file_list *cur_flist, *first_flist, *dir_flist;
|
||||
extern filter_rule_list filter_list, daemon_filter_list;
|
||||
|
||||
int maybe_ATTRS_REPORT = 0;
|
||||
int maybe_ATTRS_ACCURATE_TIME = 0;
|
||||
|
||||
static dev_t dev_zero;
|
||||
static int deldelay_size = 0, deldelay_cnt = 0;
|
||||
@@ -111,7 +113,7 @@ static int need_retouch_dir_perms;
|
||||
static const char *solo_file = NULL;
|
||||
|
||||
enum nonregtype {
|
||||
TYPE_DIR, TYPE_SPECIAL, TYPE_DEVICE, TYPE_SYMLINK
|
||||
TYPE_DIR, TYPE_SPECIAL, TYPE_DEVICE, TYPE_SYMLINK
|
||||
};
|
||||
|
||||
/* Forward declarations. */
|
||||
@@ -169,10 +171,8 @@ static int remember_delete(struct file_struct *file, const char *fname, int flag
|
||||
deldelay_buf[deldelay_cnt++] = '!';
|
||||
|
||||
while (1) {
|
||||
len = snprintf(deldelay_buf + deldelay_cnt,
|
||||
deldelay_size - deldelay_cnt,
|
||||
"%x %s%c",
|
||||
(int)file->mode, fname, '\0');
|
||||
len = snprintf(deldelay_buf + deldelay_cnt, deldelay_size - deldelay_cnt,
|
||||
"%x %s%c", (int)file->mode, fname, '\0');
|
||||
if ((deldelay_cnt += len) <= deldelay_size)
|
||||
break;
|
||||
deldelay_cnt -= len;
|
||||
@@ -209,8 +209,7 @@ static int read_delay_line(char *buf, int *flags_p)
|
||||
deldelay_size - deldelay_cnt);
|
||||
if (len == 0) {
|
||||
if (deldelay_cnt) {
|
||||
rprintf(FERROR,
|
||||
"ERROR: unexpected EOF in delete-delay file.\n");
|
||||
rprintf(FERROR, "ERROR: unexpected EOF in delete-delay file.\n");
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
@@ -274,6 +273,7 @@ static void do_delayed_deletions(char *delbuf)
|
||||
static void delete_in_dir(char *fbuf, struct file_struct *file, dev_t *fs_dev)
|
||||
{
|
||||
static int already_warned = 0;
|
||||
static struct hashtable *dev_tbl;
|
||||
struct file_list *dirlist;
|
||||
char delbuf[MAXPATHLEN];
|
||||
int dlen, i;
|
||||
@@ -302,10 +302,16 @@ static void delete_in_dir(char *fbuf, struct file_struct *file, dev_t *fs_dev)
|
||||
change_local_filter_dir(fbuf, dlen, F_DEPTH(file));
|
||||
|
||||
if (one_file_system) {
|
||||
if (file->flags & FLAG_TOP_DIR)
|
||||
if (!dev_tbl)
|
||||
dev_tbl = hashtable_create(16, HT_KEY64);
|
||||
if (file->flags & FLAG_TOP_DIR) {
|
||||
hashtable_find(dev_tbl, *fs_dev+1, "");
|
||||
filesystem_dev = *fs_dev;
|
||||
else if (filesystem_dev != *fs_dev)
|
||||
return;
|
||||
} else if (filesystem_dev != *fs_dev) {
|
||||
if (!hashtable_find(dev_tbl, *fs_dev+1, NULL))
|
||||
return;
|
||||
filesystem_dev = *fs_dev; /* it's a prior top-dir dev */
|
||||
}
|
||||
}
|
||||
|
||||
dirlist = get_dirlist(fbuf, dlen, 0);
|
||||
@@ -381,9 +387,13 @@ static void do_delete_pass(void)
|
||||
rprintf(FINFO, " \r");
|
||||
}
|
||||
|
||||
static inline int time_differs(struct file_struct *file, stat_x *sxp)
|
||||
static inline int mtime_differs(STRUCT_STAT *stp, struct file_struct *file)
|
||||
{
|
||||
return cmp_time(sxp->st.st_mtime, file->modtime);
|
||||
#ifdef ST_MTIME_NSEC
|
||||
return !same_time(stp->st_mtime, stp->ST_MTIME_NSEC, file->modtime, F_MOD_NSEC_or_0(file));
|
||||
#else
|
||||
return !same_time(stp->st_mtime, 0, file->modtime, 0);
|
||||
#endif
|
||||
}
|
||||
|
||||
static inline int perms_differ(struct file_struct *file, stat_x *sxp)
|
||||
@@ -440,7 +450,7 @@ int unchanged_attrs(const char *fname, struct file_struct *file, stat_x *sxp)
|
||||
{
|
||||
if (S_ISLNK(file->mode)) {
|
||||
#ifdef CAN_SET_SYMLINK_TIMES
|
||||
if (preserve_times & PRESERVE_LINK_TIMES && time_differs(file, sxp))
|
||||
if (preserve_times & PRESERVE_LINK_TIMES && mtime_differs(&sxp->st, file))
|
||||
return 0;
|
||||
#endif
|
||||
#ifdef CAN_CHMOD_SYMLINK
|
||||
@@ -460,7 +470,7 @@ int unchanged_attrs(const char *fname, struct file_struct *file, stat_x *sxp)
|
||||
return 0;
|
||||
#endif
|
||||
} else {
|
||||
if (preserve_times && time_differs(file, sxp))
|
||||
if (preserve_times && mtime_differs(&sxp->st, file))
|
||||
return 0;
|
||||
if (perms_differ(file, sxp))
|
||||
return 0;
|
||||
@@ -495,10 +505,13 @@ void itemize(const char *fnamecmp, struct file_struct *file, int ndx, int statre
|
||||
if (iflags & ITEM_LOCAL_CHANGE)
|
||||
iflags |= symlink_timeset_failed_flags;
|
||||
} else if (keep_time
|
||||
? cmp_time(file->modtime, sxp->st.st_mtime) != 0
|
||||
? mtime_differs(&sxp->st, file)
|
||||
: iflags & (ITEM_TRANSFER|ITEM_LOCAL_CHANGE) && !(iflags & ITEM_MATCHED)
|
||||
&& (!(iflags & ITEM_XNAME_FOLLOWS) || *xname))
|
||||
iflags |= ITEM_REPORT_TIME;
|
||||
if (atimes_ndx && !S_ISDIR(file->mode) && !S_ISLNK(file->mode)
|
||||
&& !same_time(F_ATIME(file), 0, sxp->st.st_atime, 0))
|
||||
iflags |= ITEM_REPORT_ATIME;
|
||||
#if !defined HAVE_LCHMOD && !defined HAVE_SETATTRLIST
|
||||
if (S_ISLNK(file->mode)) {
|
||||
;
|
||||
@@ -512,8 +525,7 @@ void itemize(const char *fnamecmp, struct file_struct *file, int ndx, int statre
|
||||
iflags |= ITEM_REPORT_PERMS;
|
||||
if (uid_ndx && am_root && (uid_t)F_OWNER(file) != sxp->st.st_uid)
|
||||
iflags |= ITEM_REPORT_OWNER;
|
||||
if (gid_ndx && !(file->flags & FLAG_SKIP_GROUP)
|
||||
&& sxp->st.st_gid != (gid_t)F_GROUP(file))
|
||||
if (gid_ndx && !(file->flags & FLAG_SKIP_GROUP) && sxp->st.st_gid != (gid_t)F_GROUP(file))
|
||||
iflags |= ITEM_REPORT_GROUP;
|
||||
#ifdef SUPPORT_ACLS
|
||||
if (preserve_acls && !S_ISLNK(file->mode)) {
|
||||
@@ -553,7 +565,9 @@ void itemize(const char *fnamecmp, struct file_struct *file, int ndx, int statre
|
||||
#ifdef SUPPORT_XATTRS
|
||||
if (preserve_xattrs && do_xfers
|
||||
&& iflags & (ITEM_REPORT_XATTR|ITEM_TRANSFER)) {
|
||||
int fd = iflags & ITEM_REPORT_XATTR ? sock_f_out : -1;
|
||||
int fd = iflags & ITEM_REPORT_XATTR
|
||||
&& !(want_xattr_optim && BITS_SET(iflags, ITEM_XNAME_FOLLOWS|ITEM_LOCAL_CHANGE))
|
||||
? sock_f_out : -1;
|
||||
send_xattr_request(NULL, file, fd);
|
||||
}
|
||||
#endif
|
||||
@@ -576,7 +590,7 @@ int unchanged_file(char *fn, struct file_struct *file, STRUCT_STAT *st)
|
||||
if (always_checksum > 0 && S_ISREG(st->st_mode)) {
|
||||
char sum[MAX_DIGEST_LEN];
|
||||
file_checksum(fn, st, sum);
|
||||
return memcmp(sum, F_SUM(file), checksum_len) == 0;
|
||||
return memcmp(sum, F_SUM(file), flist_csum_len) == 0;
|
||||
}
|
||||
|
||||
if (size_only > 0)
|
||||
@@ -585,7 +599,7 @@ int unchanged_file(char *fn, struct file_struct *file, STRUCT_STAT *st)
|
||||
if (ignore_times)
|
||||
return 0;
|
||||
|
||||
return cmp_time(st->st_mtime, file->modtime) == 0;
|
||||
return !mtime_differs(st, file);
|
||||
}
|
||||
|
||||
|
||||
@@ -630,14 +644,14 @@ static void sum_sizes_sqroot(struct sum_struct *sum, int64 len)
|
||||
if (c < 0 || c >= max_blength)
|
||||
blength = max_blength;
|
||||
else {
|
||||
blength = 0;
|
||||
do {
|
||||
blength |= c;
|
||||
if (len < (int64)blength * blength)
|
||||
blength &= ~c;
|
||||
c >>= 1;
|
||||
} while (c >= 8); /* round to multiple of 8 */
|
||||
blength = MAX(blength, BLOCK_SIZE);
|
||||
blength = 0;
|
||||
do {
|
||||
blength |= c;
|
||||
if (len < (int64)blength * blength)
|
||||
blength &= ~c;
|
||||
c >>= 1;
|
||||
} while (c >= 8); /* round to multiple of 8 */
|
||||
blength = MAX(blength, BLOCK_SIZE);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -762,7 +776,7 @@ static struct file_struct *find_fuzzy(struct file_struct *file, struct file_list
|
||||
if (!S_ISREG(fp->mode) || !F_LENGTH(fp) || fp->flags & FLAG_FILE_SENT)
|
||||
continue;
|
||||
|
||||
if (F_LENGTH(fp) == F_LENGTH(file) && cmp_time(fp->modtime, file->modtime) == 0) {
|
||||
if (F_LENGTH(fp) == F_LENGTH(file) && same_time(fp->modtime, 0, file->modtime, 0)) {
|
||||
if (DEBUG_GTE(FUZZY, 2))
|
||||
rprintf(FINFO, "fuzzy size/modtime match for %s\n", f_name(fp, NULL));
|
||||
*fnamecmp_type_ptr = FNAMECMP_FUZZY + i;
|
||||
@@ -868,52 +882,47 @@ static int try_dests_reg(struct file_struct *file, char *fname, int ndx,
|
||||
pathjoin(cmpbuf, MAXPATHLEN, basis_dir[j], fname);
|
||||
if (link_stat(cmpbuf, &sxp->st, 0) < 0 || !S_ISREG(sxp->st.st_mode))
|
||||
continue;
|
||||
switch (match_level) {
|
||||
case 0:
|
||||
if (match_level == 0) {
|
||||
best_match = j;
|
||||
match_level = 1;
|
||||
/* FALL THROUGH */
|
||||
case 1:
|
||||
if (!unchanged_file(cmpbuf, file, &sxp->st))
|
||||
continue;
|
||||
}
|
||||
if (!unchanged_file(cmpbuf, file, &sxp->st))
|
||||
continue;
|
||||
if (match_level == 1) {
|
||||
best_match = j;
|
||||
match_level = 2;
|
||||
/* FALL THROUGH */
|
||||
case 2:
|
||||
if (!unchanged_attrs(cmpbuf, file, sxp)) {
|
||||
free_stat_x(sxp);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
if (unchanged_attrs(cmpbuf, file, sxp)) {
|
||||
best_match = j;
|
||||
match_level = 3;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
free_stat_x(sxp);
|
||||
} while (basis_dir[++j] != NULL);
|
||||
|
||||
if (!match_level)
|
||||
return -1;
|
||||
goto got_nothing_for_ya;
|
||||
|
||||
if (j != best_match) {
|
||||
j = best_match;
|
||||
pathjoin(cmpbuf, MAXPATHLEN, basis_dir[j], fname);
|
||||
if (link_stat(cmpbuf, &sxp->st, 0) < 0)
|
||||
return -1;
|
||||
goto got_nothing_for_ya;
|
||||
}
|
||||
|
||||
if (match_level == 3 && !copy_dest) {
|
||||
if (match_level == 3 && alt_dest_type != COPY_DEST) {
|
||||
if (find_exact_for_existing) {
|
||||
if (link_dest && real_st.st_dev == sxp->st.st_dev && real_st.st_ino == sxp->st.st_ino)
|
||||
if (alt_dest_type == LINK_DEST && real_st.st_dev == sxp->st.st_dev && real_st.st_ino == sxp->st.st_ino)
|
||||
return -1;
|
||||
if (do_unlink(fname) < 0 && errno != ENOENT) {
|
||||
sxp->st = real_st;
|
||||
return -1;
|
||||
}
|
||||
if (do_unlink(fname) < 0 && errno != ENOENT)
|
||||
goto got_nothing_for_ya;
|
||||
}
|
||||
#ifdef SUPPORT_HARD_LINKS
|
||||
if (link_dest) {
|
||||
if (alt_dest_type == LINK_DEST) {
|
||||
if (!hard_link_one(file, fname, cmpbuf, 1))
|
||||
goto try_a_copy;
|
||||
if (atimes_ndx)
|
||||
set_file_attrs(fname, file, sxp, NULL, 0);
|
||||
if (preserve_hard_links && F_IS_HLINKED(file))
|
||||
finish_hard_link(file, fname, ndx, &sxp->st, itemizing, code, j);
|
||||
if (!maybe_ATTRS_REPORT && (INFO_GTE(NAME, 2) || stdout_format_has_i > 1)) {
|
||||
@@ -932,10 +941,8 @@ static int try_dests_reg(struct file_struct *file, char *fname, int ndx,
|
||||
return -2;
|
||||
}
|
||||
|
||||
if (find_exact_for_existing) {
|
||||
sxp->st = real_st;
|
||||
return -1;
|
||||
}
|
||||
if (find_exact_for_existing)
|
||||
goto got_nothing_for_ya;
|
||||
|
||||
if (match_level >= 2) {
|
||||
#ifdef SUPPORT_HARD_LINKS
|
||||
@@ -943,7 +950,7 @@ static int try_dests_reg(struct file_struct *file, char *fname, int ndx,
|
||||
#endif
|
||||
if (!dry_run && copy_altdest_file(cmpbuf, fname, file) < 0) {
|
||||
if (find_exact_for_existing) /* Can get here via hard-link failure */
|
||||
sxp->st = real_st;
|
||||
goto got_nothing_for_ya;
|
||||
return -1;
|
||||
}
|
||||
if (itemizing)
|
||||
@@ -963,6 +970,10 @@ static int try_dests_reg(struct file_struct *file, char *fname, int ndx,
|
||||
}
|
||||
|
||||
return FNAMECMP_BASIS_DIR_LOW + j;
|
||||
|
||||
got_nothing_for_ya:
|
||||
sxp->st = real_st;
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* This is only called for non-regular files. We return -2 if we've finished
|
||||
@@ -1077,7 +1088,7 @@ static int try_dests_non(struct file_struct *file, char *fname, int ndx,
|
||||
|
||||
if (match_level == 3) {
|
||||
#ifdef SUPPORT_HARD_LINKS
|
||||
if (link_dest
|
||||
if (alt_dest_type == LINK_DEST
|
||||
#ifndef CAN_HARDLINK_SYMLINK
|
||||
&& !S_ISLNK(file->mode)
|
||||
#endif
|
||||
@@ -1098,7 +1109,7 @@ static int try_dests_non(struct file_struct *file, char *fname, int ndx,
|
||||
match_level = 2;
|
||||
if (itemizing && stdout_format_has_i
|
||||
&& (INFO_GTE(NAME, 2) || stdout_format_has_i > 1)) {
|
||||
int chg = compare_dest && type != TYPE_DIR ? 0
|
||||
int chg = alt_dest_type == COMPARE_DEST && type != TYPE_DIR ? 0
|
||||
: ITEM_LOCAL_CHANGE + (match_level == 3 ? ITEM_XNAME_FOLLOWS : 0);
|
||||
char *lp = match_level == 3 ? "" : NULL;
|
||||
itemize(cmpbuf, file, ndx, 0, sxp, chg + ITEM_MATCHED, 0, lp);
|
||||
@@ -1116,35 +1127,40 @@ static int try_dests_non(struct file_struct *file, char *fname, int ndx,
|
||||
static void list_file_entry(struct file_struct *f)
|
||||
{
|
||||
char permbuf[PERMSTRING_SIZE];
|
||||
int64 len;
|
||||
int colwidth = human_readable ? 14 : 11;
|
||||
const char *mtime_str = timestring(f->modtime);
|
||||
int size_width = human_readable ? 14 : 11;
|
||||
int mtime_width = 1 + strlen(mtime_str);
|
||||
int atime_width = atimes_ndx ? mtime_width : 0;
|
||||
|
||||
if (!F_IS_ACTIVE(f)) {
|
||||
/* this can happen if duplicate names were removed */
|
||||
return;
|
||||
}
|
||||
|
||||
permstring(permbuf, f->mode);
|
||||
len = F_LENGTH(f);
|
||||
|
||||
/* TODO: indicate '+' if the entry has an ACL. */
|
||||
|
||||
#ifdef SUPPORT_LINKS
|
||||
if (preserve_links && S_ISLNK(f->mode)) {
|
||||
rprintf(FINFO, "%s %*s %s %s -> %s\n",
|
||||
permbuf, colwidth, human_num(len),
|
||||
timestring(f->modtime), f_name(f, NULL),
|
||||
F_SYMLINK(f));
|
||||
} else
|
||||
#endif
|
||||
if (missing_args == 2 && f->mode == 0) {
|
||||
rprintf(FINFO, "%-*s %s\n",
|
||||
colwidth + 31, "*missing",
|
||||
10 + 1 + size_width + mtime_width + atime_width, "*missing",
|
||||
f_name(f, NULL));
|
||||
} else {
|
||||
rprintf(FINFO, "%s %*s %s %s\n",
|
||||
permbuf, colwidth, human_num(len),
|
||||
timestring(f->modtime), f_name(f, NULL));
|
||||
const char *atime_str = atimes_ndx && !S_ISDIR(f->mode) ? timestring(F_ATIME(f)) : "";
|
||||
const char *arrow, *lnk;
|
||||
|
||||
permstring(permbuf, f->mode);
|
||||
|
||||
#ifdef SUPPORT_LINKS
|
||||
if (preserve_links && S_ISLNK(f->mode)) {
|
||||
arrow = " -> ";
|
||||
lnk = F_SYMLINK(f);
|
||||
} else
|
||||
#endif
|
||||
arrow = lnk = "";
|
||||
|
||||
rprintf(FINFO, "%s %*s %s%*s %s%s%s\n",
|
||||
permbuf, size_width, human_num(F_LENGTH(f)),
|
||||
timestring(f->modtime), atime_width, atime_str,
|
||||
f_name(f, NULL), arrow, lnk);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1174,6 +1190,7 @@ static void recv_generator(char *fname, struct file_struct *file, int ndx,
|
||||
int itemizing, enum logcode code, int f_out)
|
||||
{
|
||||
static const char *parent_dirname = "";
|
||||
static struct file_struct *prior_dir_file = NULL;
|
||||
/* Missing dir not created due to --dry-run; will still be scanned. */
|
||||
static struct file_struct *dry_missing_dir = NULL;
|
||||
/* Missing dir whose contents are skipped altogether due to
|
||||
@@ -1206,6 +1223,8 @@ static void recv_generator(char *fname, struct file_struct *file, int ndx,
|
||||
return;
|
||||
}
|
||||
|
||||
maybe_ATTRS_ACCURATE_TIME = always_checksum ? ATTRS_ACCURATE_TIME : 0;
|
||||
|
||||
if (skip_dir) {
|
||||
if (is_below(file, skip_dir)) {
|
||||
if (is_dir)
|
||||
@@ -1253,6 +1272,24 @@ static void recv_generator(char *fname, struct file_struct *file, int ndx,
|
||||
const char *dn = file->dirname ? file->dirname : ".";
|
||||
dry_missing_dir = NULL;
|
||||
if (parent_dirname != dn && strcmp(parent_dirname, dn) != 0) {
|
||||
/* Each parent dir must be in the file list or the flist data is bad.
|
||||
* Optimization: most of the time the parent dir will be the last dir
|
||||
* this function was asked to process in the file list. */
|
||||
if (!inc_recurse
|
||||
&& (*dn != '.' || dn[1]) /* Avoid an issue with --relative and the "." dir. */
|
||||
&& (!prior_dir_file || strcmp(dn, f_name(prior_dir_file, NULL)) != 0)
|
||||
&& flist_find_name(cur_flist, dn, 1) < 0) {
|
||||
/* The --delete-missing-args option can actually put invalid entries into
|
||||
* the file list, so if that option was specified, we'll just complain about
|
||||
* it and allow it. */
|
||||
if (missing_args == 2 && file->mode == 0)
|
||||
rprintf(FERROR, "WARNING: parent dir is absent in the file list: %s\n", dn);
|
||||
else {
|
||||
rprintf(FERROR, "ABORTING due to invalid path from sender: %s/%s\n",
|
||||
dn, file->basename);
|
||||
exit_cleanup(RERR_PROTOCOL);
|
||||
}
|
||||
}
|
||||
if (relative_paths && !implied_dirs
|
||||
&& do_stat(dn, &sx.st) < 0) {
|
||||
if (dry_run)
|
||||
@@ -1280,21 +1317,6 @@ static void recv_generator(char *fname, struct file_struct *file, int ndx,
|
||||
}
|
||||
parent_dirname = dn;
|
||||
|
||||
if (need_fuzzy_dirlist && S_ISREG(file->mode)) {
|
||||
int i;
|
||||
strlcpy(fnamecmpbuf, dn, sizeof fnamecmpbuf);
|
||||
for (i = 0; i < fuzzy_basis; i++) {
|
||||
if (i && pathjoin(fnamecmpbuf, MAXPATHLEN, basis_dir[i-1], dn) >= MAXPATHLEN)
|
||||
continue;
|
||||
fuzzy_dirlist[i] = get_dirlist(fnamecmpbuf, -1, GDL_IGNORE_FILTER_RULES);
|
||||
if (fuzzy_dirlist[i] && fuzzy_dirlist[i]->used == 0) {
|
||||
flist_free(fuzzy_dirlist[i]);
|
||||
fuzzy_dirlist[i] = NULL;
|
||||
}
|
||||
}
|
||||
need_fuzzy_dirlist = 0;
|
||||
}
|
||||
|
||||
statret = link_stat(fname, &sx.st, keep_dirlinks && is_dir);
|
||||
stat_errno = errno;
|
||||
}
|
||||
@@ -1354,7 +1376,7 @@ static void recv_generator(char *fname, struct file_struct *file, int ndx,
|
||||
added_perms = 0;
|
||||
if (is_dir < 0) {
|
||||
if (!(preserve_times & PRESERVE_DIR_TIMES))
|
||||
return;
|
||||
goto cleanup;
|
||||
/* In inc_recurse mode we want to make sure any missing
|
||||
* directories get created while we're still processing
|
||||
* the parent dir (which allows us to touch the parent
|
||||
@@ -1389,12 +1411,10 @@ static void recv_generator(char *fname, struct file_struct *file, int ndx,
|
||||
if (file->flags & FLAG_DIR_CREATED)
|
||||
statret = -1;
|
||||
if (!preserve_perms) { /* See comment in non-dir code below. */
|
||||
file->mode = dest_mode(file->mode, sx.st.st_mode,
|
||||
dflt_perms, statret == 0);
|
||||
file->mode = dest_mode(file->mode, sx.st.st_mode, dflt_perms, statret == 0);
|
||||
}
|
||||
if (statret != 0 && basis_dir[0] != NULL) {
|
||||
int j = try_dests_non(file, fname, ndx, fnamecmpbuf, &sx,
|
||||
itemizing, code);
|
||||
int j = try_dests_non(file, fname, ndx, fnamecmpbuf, &sx, itemizing, code);
|
||||
if (j == -2) {
|
||||
itemizing = 0;
|
||||
code = FNONE;
|
||||
@@ -1416,8 +1436,7 @@ static void recv_generator(char *fname, struct file_struct *file, int ndx,
|
||||
"recv_generator: mkdir %s failed",
|
||||
full_fname(fname));
|
||||
skipping_dir_contents:
|
||||
rprintf(FERROR,
|
||||
"*** Skipping any contents from this failed directory ***\n");
|
||||
rprintf(FERROR, "*** Skipping any contents from this failed directory ***\n");
|
||||
skip_dir = file;
|
||||
file->flags |= FLAG_MISSING_DIR;
|
||||
goto cleanup;
|
||||
@@ -1429,7 +1448,7 @@ static void recv_generator(char *fname, struct file_struct *file, int ndx,
|
||||
copy_xattrs(fnamecmpbuf, fname);
|
||||
#endif
|
||||
if (set_file_attrs(fname, file, real_ret ? NULL : &real_sx, NULL, 0)
|
||||
&& INFO_GTE(NAME, 1) && code != FNONE && f_out != -1)
|
||||
&& INFO_GTE(NAME, 1) && code != FNONE && f_out != -1)
|
||||
rprintf(code, "%s/\n", fname);
|
||||
|
||||
/* We need to ensure that the dirs in the transfer have both
|
||||
@@ -1464,6 +1483,7 @@ static void recv_generator(char *fname, struct file_struct *file, int ndx,
|
||||
else
|
||||
change_local_filter_dir(fname, strlen(fname), F_DEPTH(file));
|
||||
}
|
||||
prior_dir_file = file;
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
@@ -1471,8 +1491,7 @@ static void recv_generator(char *fname, struct file_struct *file, int ndx,
|
||||
* mode based on the local permissions and some heuristics. */
|
||||
if (!preserve_perms) {
|
||||
int exists = statret == 0 && !S_ISDIR(sx.st.st_mode);
|
||||
file->mode = dest_mode(file->mode, sx.st.st_mode, dflt_perms,
|
||||
exists);
|
||||
file->mode = dest_mode(file->mode, sx.st.st_mode, dflt_perms, exists);
|
||||
}
|
||||
|
||||
#ifdef SUPPORT_HARD_LINKS
|
||||
@@ -1495,7 +1514,7 @@ static void recv_generator(char *fname, struct file_struct *file, int ndx,
|
||||
"ignoring unsafe symlink \"%s\" -> \"%s\"\n",
|
||||
fname, sl);
|
||||
}
|
||||
return;
|
||||
goto cleanup;
|
||||
}
|
||||
if (statret == 0) {
|
||||
char lnk[MAXPATHLEN];
|
||||
@@ -1508,7 +1527,7 @@ static void recv_generator(char *fname, struct file_struct *file, int ndx,
|
||||
set_file_attrs(fname, file, &sx, NULL, maybe_ATTRS_REPORT);
|
||||
if (itemizing)
|
||||
itemize(fname, file, ndx, 0, &sx, 0, 0, NULL);
|
||||
#if defined SUPPORT_HARD_LINKS && defined CAN_HARDLINK_SYMLINK
|
||||
#ifdef SUPPORT_HARD_LINKS
|
||||
if (preserve_hard_links && F_IS_HLINKED(file))
|
||||
finish_hard_link(file, fname, ndx, &sx.st, itemizing, code, -1);
|
||||
#endif
|
||||
@@ -1517,15 +1536,14 @@ static void recv_generator(char *fname, struct file_struct *file, int ndx,
|
||||
goto cleanup;
|
||||
}
|
||||
} else if (basis_dir[0] != NULL) {
|
||||
int j = try_dests_non(file, fname, ndx, fnamecmpbuf, &sx,
|
||||
itemizing, code);
|
||||
int j = try_dests_non(file, fname, ndx, fnamecmpbuf, &sx, itemizing, code);
|
||||
if (j == -2) {
|
||||
#ifndef CAN_HARDLINK_SYMLINK
|
||||
if (link_dest) {
|
||||
if (alt_dest_type == LINK_DEST) {
|
||||
/* Resort to --copy-dest behavior. */
|
||||
} else
|
||||
#endif
|
||||
if (!copy_dest)
|
||||
if (alt_dest_type != COPY_DEST)
|
||||
goto cleanup;
|
||||
itemizing = 0;
|
||||
code = FNONE;
|
||||
@@ -1534,7 +1552,7 @@ static void recv_generator(char *fname, struct file_struct *file, int ndx,
|
||||
fnamecmp = fnamecmpbuf;
|
||||
}
|
||||
}
|
||||
if (atomic_create(file, fname, sl, MAKEDEV(0, 0), &sx, statret == 0 ? DEL_FOR_SYMLINK : 0)) {
|
||||
if (atomic_create(file, fname, sl, NULL, MAKEDEV(0, 0), &sx, statret == 0 ? DEL_FOR_SYMLINK : 0)) {
|
||||
set_file_attrs(fname, file, NULL, NULL, 0);
|
||||
if (itemizing) {
|
||||
if (statret == 0 && !S_ISLNK(sx.st.st_mode))
|
||||
@@ -1593,15 +1611,14 @@ static void recv_generator(char *fname, struct file_struct *file, int ndx,
|
||||
goto cleanup;
|
||||
}
|
||||
} else if (basis_dir[0] != NULL) {
|
||||
int j = try_dests_non(file, fname, ndx, fnamecmpbuf, &sx,
|
||||
itemizing, code);
|
||||
int j = try_dests_non(file, fname, ndx, fnamecmpbuf, &sx, itemizing, code);
|
||||
if (j == -2) {
|
||||
#ifndef CAN_HARDLINK_SPECIAL
|
||||
if (link_dest) {
|
||||
if (alt_dest_type == LINK_DEST) {
|
||||
/* Resort to --copy-dest behavior. */
|
||||
} else
|
||||
#endif
|
||||
if (!copy_dest)
|
||||
if (alt_dest_type != COPY_DEST)
|
||||
goto cleanup;
|
||||
itemizing = 0;
|
||||
code = FNONE;
|
||||
@@ -1615,7 +1632,7 @@ static void recv_generator(char *fname, struct file_struct *file, int ndx,
|
||||
fname, (int)file->mode,
|
||||
(long)major(rdev), (long)minor(rdev));
|
||||
}
|
||||
if (atomic_create(file, fname, NULL, rdev, &sx, del_for_flag)) {
|
||||
if (atomic_create(file, fname, NULL, NULL, rdev, &sx, del_for_flag)) {
|
||||
set_file_attrs(fname, file, NULL, NULL, 0);
|
||||
if (itemizing) {
|
||||
itemize(fnamecmp, file, ndx, statret, &sx,
|
||||
@@ -1657,8 +1674,7 @@ static void recv_generator(char *fname, struct file_struct *file, int ndx,
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
if (update_only > 0 && statret == 0
|
||||
&& cmp_time(sx.st.st_mtime, file->modtime) > 0) {
|
||||
if (update_only > 0 && statret == 0 && file->modtime - sx.st.st_mtime <= modify_window) {
|
||||
if (INFO_GTE(SKIP, 1))
|
||||
rprintf(FINFO, "%s is newer\n", fname);
|
||||
#ifdef SUPPORT_HARD_LINKS
|
||||
@@ -1670,16 +1686,15 @@ static void recv_generator(char *fname, struct file_struct *file, int ndx,
|
||||
|
||||
fnamecmp_type = FNAMECMP_FNAME;
|
||||
|
||||
if (statret == 0 && !S_ISREG(sx.st.st_mode)) {
|
||||
if (statret == 0 && !(S_ISREG(sx.st.st_mode) || (write_devices && IS_DEVICE(sx.st.st_mode)))) {
|
||||
if (delete_item(fname, sx.st.st_mode, del_opts | DEL_FOR_FILE) != 0)
|
||||
goto cleanup;
|
||||
statret = -1;
|
||||
stat_errno = ENOENT;
|
||||
}
|
||||
|
||||
if (basis_dir[0] != NULL && (statret != 0 || !copy_dest)) {
|
||||
int j = try_dests_reg(file, fname, ndx, fnamecmpbuf, &sx,
|
||||
statret == 0, itemizing, code);
|
||||
if (basis_dir[0] != NULL && (statret != 0 || alt_dest_type != COPY_DEST)) {
|
||||
int j = try_dests_reg(file, fname, ndx, fnamecmpbuf, &sx, statret == 0, itemizing, code);
|
||||
if (j == -2) {
|
||||
if (remove_source_files == 1)
|
||||
goto return_with_success;
|
||||
@@ -1697,14 +1712,30 @@ static void recv_generator(char *fname, struct file_struct *file, int ndx,
|
||||
real_ret = statret;
|
||||
|
||||
if (partial_dir && (partialptr = partial_dir_fname(fname)) != NULL
|
||||
&& link_stat(partialptr, &partial_st, 0) == 0
|
||||
&& S_ISREG(partial_st.st_mode)) {
|
||||
&& link_stat(partialptr, &partial_st, 0) == 0
|
||||
&& S_ISREG(partial_st.st_mode)) {
|
||||
if (statret != 0)
|
||||
goto prepare_to_open;
|
||||
} else
|
||||
partialptr = NULL;
|
||||
|
||||
if (statret != 0 && fuzzy_basis) {
|
||||
if (need_fuzzy_dirlist && S_ISREG(file->mode)) {
|
||||
const char *dn = file->dirname ? file->dirname : ".";
|
||||
int i;
|
||||
strlcpy(fnamecmpbuf, dn, sizeof fnamecmpbuf);
|
||||
for (i = 0; i < fuzzy_basis; i++) {
|
||||
if (i && pathjoin(fnamecmpbuf, MAXPATHLEN, basis_dir[i-1], dn) >= MAXPATHLEN)
|
||||
continue;
|
||||
fuzzy_dirlist[i] = get_dirlist(fnamecmpbuf, -1, GDL_IGNORE_FILTER_RULES | GDL_PERHAPS_DIR);
|
||||
if (fuzzy_dirlist[i] && fuzzy_dirlist[i]->used == 0) {
|
||||
flist_free(fuzzy_dirlist[i]);
|
||||
fuzzy_dirlist[i] = NULL;
|
||||
}
|
||||
}
|
||||
need_fuzzy_dirlist = 0;
|
||||
}
|
||||
|
||||
/* Sets fnamecmp_type to FNAMECMP_FUZZY or above. */
|
||||
fuzzy_file = find_fuzzy(file, fuzzy_dirlist, &fnamecmp_type);
|
||||
if (fuzzy_file) {
|
||||
@@ -1735,14 +1766,14 @@ static void recv_generator(char *fname, struct file_struct *file, int ndx,
|
||||
|
||||
if (fnamecmp_type <= FNAMECMP_BASIS_DIR_HIGH)
|
||||
;
|
||||
else if (fnamecmp_type == FNAMECMP_FUZZY)
|
||||
else if (fnamecmp_type >= FNAMECMP_FUZZY)
|
||||
;
|
||||
else if (unchanged_file(fnamecmp, file, &sx.st)) {
|
||||
if (partialptr) {
|
||||
do_unlink(partialptr);
|
||||
handle_partial_dir(partialptr, PDIR_DELETE);
|
||||
}
|
||||
set_file_attrs(fname, file, &sx, NULL, maybe_ATTRS_REPORT);
|
||||
set_file_attrs(fname, file, &sx, NULL, maybe_ATTRS_REPORT | maybe_ATTRS_ACCURATE_TIME);
|
||||
if (itemizing)
|
||||
itemize(fnamecmp, file, ndx, statret, &sx, 0, 0, NULL);
|
||||
#ifdef SUPPORT_HARD_LINKS
|
||||
@@ -1889,8 +1920,8 @@ static void recv_generator(char *fname, struct file_struct *file, int ndx,
|
||||
} else {
|
||||
if (generate_and_send_sums(fd, sx.st.st_size, f_out, f_copy) < 0) {
|
||||
rprintf(FWARNING,
|
||||
"WARNING: file is too large for checksum sending: %s\n",
|
||||
fnamecmp);
|
||||
"WARNING: file is too large for checksum sending: %s\n",
|
||||
fnamecmp);
|
||||
write_sum_head(f_out, NULL);
|
||||
}
|
||||
close(fd);
|
||||
@@ -1920,11 +1951,11 @@ static void recv_generator(char *fname, struct file_struct *file, int ndx,
|
||||
}
|
||||
|
||||
/* If we are replacing an existing hard link, symlink, device, or special file,
|
||||
* create a temp-name item and rename it into place. Only a symlink or hard
|
||||
* link puts a non-NULL value into the lnk arg. Only a device puts a non-0
|
||||
* value into the rdev arg. Specify 0 for the del_for_flag if there is not a
|
||||
* file to replace. This returns 1 on success and 0 on failure. */
|
||||
int atomic_create(struct file_struct *file, char *fname, const char *lnk,
|
||||
* create a temp-name item and rename it into place. A symlimk specifies slnk,
|
||||
* a hard link specifies hlnk, otherwise we create a device based on rdev.
|
||||
* Specify 0 for the del_for_flag if there is not a file to replace. This
|
||||
* returns 1 on success and 0 on failure. */
|
||||
int atomic_create(struct file_struct *file, char *fname, const char *slnk, const char *hlnk,
|
||||
dev_t rdev, stat_x *sxp, int del_for_flag)
|
||||
{
|
||||
char tmpname[MAXPATHLEN];
|
||||
@@ -1949,23 +1980,22 @@ int atomic_create(struct file_struct *file, char *fname, const char *lnk,
|
||||
|
||||
create_name = skip_atomic ? fname : tmpname;
|
||||
|
||||
if (lnk) {
|
||||
if (slnk) {
|
||||
#ifdef SUPPORT_LINKS
|
||||
if (S_ISLNK(file->mode)
|
||||
#ifdef SUPPORT_HARD_LINKS /* The first symlink in a hard-linked cluster is always created. */
|
||||
&& (!F_IS_HLINKED(file) || file->flags & FLAG_HLINK_FIRST)
|
||||
#endif
|
||||
) {
|
||||
if (do_symlink(lnk, create_name) < 0) {
|
||||
rsyserr(FERROR_XFER, errno, "symlink %s -> \"%s\" failed",
|
||||
full_fname(create_name), lnk);
|
||||
return 0;
|
||||
}
|
||||
} else
|
||||
#endif
|
||||
#ifdef SUPPORT_HARD_LINKS
|
||||
if (!hard_link_one(file, create_name, lnk, 0))
|
||||
if (do_symlink(slnk, create_name) < 0) {
|
||||
rsyserr(FERROR_XFER, errno, "symlink %s -> \"%s\" failed",
|
||||
full_fname(create_name), slnk);
|
||||
return 0;
|
||||
}
|
||||
#else
|
||||
return 0;
|
||||
#endif
|
||||
} else if (hlnk) {
|
||||
#ifdef SUPPORT_HARD_LINKS
|
||||
if (!hard_link_one(file, create_name, hlnk, 0))
|
||||
return 0;
|
||||
#else
|
||||
return 0;
|
||||
#endif
|
||||
} else {
|
||||
if (do_mknod(create_name, file->mode, rdev) < 0) {
|
||||
@@ -2046,9 +2076,13 @@ static void touch_up_dirs(struct file_list *flist, int ndx)
|
||||
do_chmod(fname, file->mode);
|
||||
if (need_retouch_dir_times) {
|
||||
STRUCT_STAT st;
|
||||
if (link_stat(fname, &st, 0) == 0
|
||||
&& cmp_time(st.st_mtime, file->modtime) != 0)
|
||||
set_modtime(fname, file->modtime, F_MOD_NSEC(file), file->mode);
|
||||
if (link_stat(fname, &st, 0) == 0 && mtime_differs(&st, file)) {
|
||||
st.st_mtime = file->modtime;
|
||||
#ifdef ST_MTIME_NSEC
|
||||
st.ST_MTIME_NSEC = F_MOD_NSEC_or_0(file);
|
||||
#endif
|
||||
set_times(fname, &st);
|
||||
}
|
||||
}
|
||||
if (counter >= loopchk_limit) {
|
||||
if (allowed_lull)
|
||||
|
||||
@@ -15,8 +15,7 @@
|
||||
fprintf(stderr, "Unable to stat `%s'\n", *argv);
|
||||
exit(1);
|
||||
}
|
||||
printf("%ld/%ld\n", (long)major(st.st_dev),
|
||||
(long)minor(st.st_dev));
|
||||
printf("%ld/%ld\n", (long)major(st.st_dev), (long)minor(st.st_dev));
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
* `id -G` on Linux, but it's too hard to find a portable equivalent.
|
||||
*
|
||||
* Copyright (C) 2002 Martin Pool
|
||||
* Copyright (C) 2003-2014 Wayne Davison
|
||||
* Copyright (C) 2003-2019 Wayne Davison
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 3 as
|
||||
|
||||
344
hashtable.c
344
hashtable.c
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* Routines to provide a memory-efficient hashtable.
|
||||
*
|
||||
* Copyright (C) 2007-2014 Wayne Davison
|
||||
* Copyright (C) 2007-2020 Wayne Davison
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
@@ -66,9 +66,19 @@ void hashtable_destroy(struct hashtable *tbl)
|
||||
free(tbl);
|
||||
}
|
||||
|
||||
/* This returns the node for the indicated key, either newly created or
|
||||
* already existing. Returns NULL if not allocating and not found. */
|
||||
void *hashtable_find(struct hashtable *tbl, int64 key, int allocate_if_missing)
|
||||
/* Returns the node that holds the indicated key if it exists. When it does not
|
||||
* exist, it returns either NULL (when data_when_new is NULL), or it returns a
|
||||
* new node with its node->data set to the indicated value.
|
||||
*
|
||||
* If your code doesn't know the data value for a new node in advance (usually
|
||||
* because it doesn't know if a node is new or not) you should pass in a unique
|
||||
* (non-0) value that you can use to check if the returned node is new. You can
|
||||
* then overwrite the data with any value you want (even 0) since it only needs
|
||||
* to be different than whatever data_when_new value you use later on.
|
||||
*
|
||||
* This return is a void* just because it might be pointing at a ht_int32_node
|
||||
* or a ht_int64_node, and that makes the caller's assignment a little easier. */
|
||||
void *hashtable_find(struct hashtable *tbl, int64 key, void *data_when_new)
|
||||
{
|
||||
int key64 = tbl->key64;
|
||||
struct ht_int32_node *node;
|
||||
@@ -79,7 +89,7 @@ void *hashtable_find(struct hashtable *tbl, int64 key, int allocate_if_missing)
|
||||
exit_cleanup(RERR_MESSAGEIO);
|
||||
}
|
||||
|
||||
if (allocate_if_missing && tbl->entries > HASH_LOAD_LIMIT(tbl->size)) {
|
||||
if (data_when_new && tbl->entries > HASH_LOAD_LIMIT(tbl->size)) {
|
||||
void *old_nodes = tbl->nodes;
|
||||
int size = tbl->size * 2;
|
||||
int i;
|
||||
@@ -99,8 +109,12 @@ void *hashtable_find(struct hashtable *tbl, int64 key, int allocate_if_missing)
|
||||
int64 move_key = HT_KEY(move_node, key64);
|
||||
if (move_key == 0)
|
||||
continue;
|
||||
node = hashtable_find(tbl, move_key, 1);
|
||||
node->data = move_node->data;
|
||||
if (move_node->data)
|
||||
hashtable_find(tbl, move_key, move_node->data);
|
||||
else {
|
||||
node = hashtable_find(tbl, move_key, "");
|
||||
node->data = 0;
|
||||
}
|
||||
}
|
||||
|
||||
free(old_nodes);
|
||||
@@ -155,7 +169,7 @@ void *hashtable_find(struct hashtable *tbl, int64 key, int allocate_if_missing)
|
||||
if (nkey == key)
|
||||
return node;
|
||||
if (nkey == 0) {
|
||||
if (!allocate_if_missing)
|
||||
if (!data_when_new)
|
||||
return NULL;
|
||||
break;
|
||||
}
|
||||
@@ -167,6 +181,320 @@ void *hashtable_find(struct hashtable *tbl, int64 key, int allocate_if_missing)
|
||||
((struct ht_int64_node*)node)->key = key;
|
||||
else
|
||||
node->key = (int32)key;
|
||||
node->data = data_when_new;
|
||||
tbl->entries++;
|
||||
return node;
|
||||
}
|
||||
|
||||
#ifndef WORDS_BIGENDIAN
|
||||
# define HASH_LITTLE_ENDIAN 1
|
||||
# define HASH_BIG_ENDIAN 0
|
||||
#else
|
||||
# define HASH_LITTLE_ENDIAN 0
|
||||
# define HASH_BIG_ENDIAN 1
|
||||
#endif
|
||||
|
||||
/*
|
||||
-------------------------------------------------------------------------------
|
||||
lookup3.c, by Bob Jenkins, May 2006, Public Domain.
|
||||
|
||||
These are functions for producing 32-bit hashes for hash table lookup.
|
||||
hash_word(), hashlittle(), hashlittle2(), hashbig(), mix(), and final()
|
||||
are externally useful functions. Routines to test the hash are included
|
||||
if SELF_TEST is defined. You can use this free for any purpose. It's in
|
||||
the public domain. It has no warranty.
|
||||
|
||||
You probably want to use hashlittle(). hashlittle() and hashbig()
|
||||
hash byte arrays. hashlittle() is is faster than hashbig() on
|
||||
little-endian machines. Intel and AMD are little-endian machines.
|
||||
On second thought, you probably want hashlittle2(), which is identical to
|
||||
hashlittle() except it returns two 32-bit hashes for the price of one.
|
||||
You could implement hashbig2() if you wanted but I haven't bothered here.
|
||||
|
||||
If you want to find a hash of, say, exactly 7 integers, do
|
||||
a = i1; b = i2; c = i3;
|
||||
mix(a,b,c);
|
||||
a += i4; b += i5; c += i6;
|
||||
mix(a,b,c);
|
||||
a += i7;
|
||||
final(a,b,c);
|
||||
then use c as the hash value. If you have a variable length array of
|
||||
4-byte integers to hash, use hash_word(). If you have a byte array (like
|
||||
a character string), use hashlittle(). If you have several byte arrays, or
|
||||
a mix of things, see the comments above hashlittle().
|
||||
|
||||
Why is this so big? I read 12 bytes at a time into 3 4-byte integers,
|
||||
then mix those integers. This is fast (you can do a lot more thorough
|
||||
mixing with 12*3 instructions on 3 integers than you can with 3 instructions
|
||||
on 1 byte), but shoehorning those bytes into integers efficiently is messy.
|
||||
*/
|
||||
|
||||
#define hashsize(n) ((uint32_t)1<<(n))
|
||||
#define hashmask(n) (hashsize(n)-1)
|
||||
#define rot(x,k) (((x)<<(k)) | ((x)>>(32-(k))))
|
||||
|
||||
/*
|
||||
-------------------------------------------------------------------------------
|
||||
mix -- mix 3 32-bit values reversibly.
|
||||
|
||||
This is reversible, so any information in (a,b,c) before mix() is
|
||||
still in (a,b,c) after mix().
|
||||
|
||||
If four pairs of (a,b,c) inputs are run through mix(), or through
|
||||
mix() in reverse, there are at least 32 bits of the output that
|
||||
are sometimes the same for one pair and different for another pair.
|
||||
This was tested for:
|
||||
* pairs that differed by one bit, by two bits, in any combination
|
||||
of top bits of (a,b,c), or in any combination of bottom bits of
|
||||
(a,b,c).
|
||||
* "differ" is defined as +, -, ^, or ~^. For + and -, I transformed
|
||||
the output delta to a Gray code (a^(a>>1)) so a string of 1's (as
|
||||
is commonly produced by subtraction) look like a single 1-bit
|
||||
difference.
|
||||
* the base values were pseudorandom, all zero but one bit set, or
|
||||
all zero plus a counter that starts at zero.
|
||||
|
||||
Some k values for my "a-=c; a^=rot(c,k); c+=b;" arrangement that
|
||||
satisfy this are
|
||||
4 6 8 16 19 4
|
||||
9 15 3 18 27 15
|
||||
14 9 3 7 17 3
|
||||
Well, "9 15 3 18 27 15" didn't quite get 32 bits diffing
|
||||
for "differ" defined as + with a one-bit base and a two-bit delta. I
|
||||
used http://burtleburtle.net/bob/hash/avalanche.html to choose
|
||||
the operations, constants, and arrangements of the variables.
|
||||
|
||||
This does not achieve avalanche. There are input bits of (a,b,c)
|
||||
that fail to affect some output bits of (a,b,c), especially of a. The
|
||||
most thoroughly mixed value is c, but it doesn't really even achieve
|
||||
avalanche in c.
|
||||
|
||||
This allows some parallelism. Read-after-writes are good at doubling
|
||||
the number of bits affected, so the goal of mixing pulls in the opposite
|
||||
direction as the goal of parallelism. I did what I could. Rotates
|
||||
seem to cost as much as shifts on every machine I could lay my hands
|
||||
on, and rotates are much kinder to the top and bottom bits, so I used
|
||||
rotates.
|
||||
-------------------------------------------------------------------------------
|
||||
*/
|
||||
#define mix(a,b,c) \
|
||||
{ \
|
||||
a -= c; a ^= rot(c, 4); c += b; \
|
||||
b -= a; b ^= rot(a, 6); a += c; \
|
||||
c -= b; c ^= rot(b, 8); b += a; \
|
||||
a -= c; a ^= rot(c,16); c += b; \
|
||||
b -= a; b ^= rot(a,19); a += c; \
|
||||
c -= b; c ^= rot(b, 4); b += a; \
|
||||
}
|
||||
|
||||
/*
|
||||
-------------------------------------------------------------------------------
|
||||
final -- final mixing of 3 32-bit values (a,b,c) into c
|
||||
|
||||
Pairs of (a,b,c) values differing in only a few bits will usually
|
||||
produce values of c that look totally different. This was tested for
|
||||
* pairs that differed by one bit, by two bits, in any combination
|
||||
of top bits of (a,b,c), or in any combination of bottom bits of
|
||||
(a,b,c).
|
||||
* "differ" is defined as +, -, ^, or ~^. For + and -, I transformed
|
||||
the output delta to a Gray code (a^(a>>1)) so a string of 1's (as
|
||||
is commonly produced by subtraction) look like a single 1-bit
|
||||
difference.
|
||||
* the base values were pseudorandom, all zero but one bit set, or
|
||||
all zero plus a counter that starts at zero.
|
||||
|
||||
These constants passed:
|
||||
14 11 25 16 4 14 24
|
||||
12 14 25 16 4 14 24
|
||||
and these came close:
|
||||
4 8 15 26 3 22 24
|
||||
10 8 15 26 3 22 24
|
||||
11 8 15 26 3 22 24
|
||||
-------------------------------------------------------------------------------
|
||||
*/
|
||||
#define final(a,b,c) \
|
||||
{ \
|
||||
c ^= b; c -= rot(b,14); \
|
||||
a ^= c; a -= rot(c,11); \
|
||||
b ^= a; b -= rot(a,25); \
|
||||
c ^= b; c -= rot(b,16); \
|
||||
a ^= c; a -= rot(c,4); \
|
||||
b ^= a; b -= rot(a,14); \
|
||||
c ^= b; c -= rot(b,24); \
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
-------------------------------------------------------------------------------
|
||||
hashlittle() -- hash a variable-length key into a 32-bit value
|
||||
k : the key (the unaligned variable-length array of bytes)
|
||||
length : the length of the key, counting by bytes
|
||||
val2 : IN: can be any 4-byte value OUT: second 32 bit hash.
|
||||
Returns a 32-bit value. Every bit of the key affects every bit of
|
||||
the return value. Two keys differing by one or two bits will have
|
||||
totally different hash values. Note that the return value is better
|
||||
mixed than val2, so use that first.
|
||||
|
||||
The best hash table sizes are powers of 2. There is no need to do
|
||||
mod a prime (mod is sooo slow!). If you need less than 32 bits,
|
||||
use a bitmask. For example, if you need only 10 bits, do
|
||||
h = (h & hashmask(10));
|
||||
In which case, the hash table should have hashsize(10) elements.
|
||||
|
||||
If you are hashing n strings (uint8_t **)k, do it like this:
|
||||
for (i=0, h=0; i<n; ++i) h = hashlittle( k[i], len[i], h);
|
||||
|
||||
By Bob Jenkins, 2006. bob_jenkins@burtleburtle.net. You may use this
|
||||
code any way you wish, private, educational, or commercial. It's free.
|
||||
|
||||
Use for hash table lookup, or anything where one collision in 2^^32 is
|
||||
acceptable. Do NOT use for cryptographic purposes.
|
||||
-------------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
uint32_t hashlittle(const void *key, size_t length)
|
||||
{
|
||||
uint32_t a,b,c; /* internal state */
|
||||
union { const void *ptr; size_t i; } u; /* needed for Mac Powerbook G4 */
|
||||
|
||||
/* Set up the internal state */
|
||||
a = b = c = 0xdeadbeef + ((uint32_t)length);
|
||||
|
||||
u.ptr = key;
|
||||
if (HASH_LITTLE_ENDIAN && ((u.i & 0x3) == 0)) {
|
||||
const uint32_t *k = (const uint32_t *)key; /* read 32-bit chunks */
|
||||
const uint8_t *k8;
|
||||
|
||||
/*------ all but last block: aligned reads and affect 32 bits of (a,b,c) */
|
||||
while (length > 12)
|
||||
{
|
||||
a += k[0];
|
||||
b += k[1];
|
||||
c += k[2];
|
||||
mix(a,b,c);
|
||||
length -= 12;
|
||||
k += 3;
|
||||
}
|
||||
|
||||
/*----------------------------- handle the last (probably partial) block */
|
||||
k8 = (const uint8_t *)k;
|
||||
switch(length)
|
||||
{
|
||||
case 12: c+=k[2]; b+=k[1]; a+=k[0]; break;
|
||||
case 11: c+=((uint32_t)k8[10])<<16; /* fall through */
|
||||
case 10: c+=((uint32_t)k8[9])<<8; /* fall through */
|
||||
case 9 : c+=k8[8]; /* fall through */
|
||||
case 8 : b+=k[1]; a+=k[0]; break;
|
||||
case 7 : b+=((uint32_t)k8[6])<<16; /* fall through */
|
||||
case 6 : b+=((uint32_t)k8[5])<<8; /* fall through */
|
||||
case 5 : b+=k8[4]; /* fall through */
|
||||
case 4 : a+=k[0]; break;
|
||||
case 3 : a+=((uint32_t)k8[2])<<16; /* fall through */
|
||||
case 2 : a+=((uint32_t)k8[1])<<8; /* fall through */
|
||||
case 1 : a+=k8[0]; break;
|
||||
case 0 : return c;
|
||||
}
|
||||
} else if (HASH_LITTLE_ENDIAN && ((u.i & 0x1) == 0)) {
|
||||
const uint16_t *k = (const uint16_t *)key; /* read 16-bit chunks */
|
||||
const uint8_t *k8;
|
||||
|
||||
/*--------------- all but last block: aligned reads and different mixing */
|
||||
while (length > 12)
|
||||
{
|
||||
a += k[0] + (((uint32_t)k[1])<<16);
|
||||
b += k[2] + (((uint32_t)k[3])<<16);
|
||||
c += k[4] + (((uint32_t)k[5])<<16);
|
||||
mix(a,b,c);
|
||||
length -= 12;
|
||||
k += 6;
|
||||
}
|
||||
|
||||
/*----------------------------- handle the last (probably partial) block */
|
||||
k8 = (const uint8_t *)k;
|
||||
switch(length)
|
||||
{
|
||||
case 12: c+=k[4]+(((uint32_t)k[5])<<16);
|
||||
b+=k[2]+(((uint32_t)k[3])<<16);
|
||||
a+=k[0]+(((uint32_t)k[1])<<16);
|
||||
break;
|
||||
case 11: c+=((uint32_t)k8[10])<<16; /* fall through */
|
||||
case 10: c+=k[4];
|
||||
b+=k[2]+(((uint32_t)k[3])<<16);
|
||||
a+=k[0]+(((uint32_t)k[1])<<16);
|
||||
break;
|
||||
case 9 : c+=k8[8]; /* fall through */
|
||||
case 8 : b+=k[2]+(((uint32_t)k[3])<<16);
|
||||
a+=k[0]+(((uint32_t)k[1])<<16);
|
||||
break;
|
||||
case 7 : b+=((uint32_t)k8[6])<<16; /* fall through */
|
||||
case 6 : b+=k[2];
|
||||
a+=k[0]+(((uint32_t)k[1])<<16);
|
||||
break;
|
||||
case 5 : b+=k8[4]; /* fall through */
|
||||
case 4 : a+=k[0]+(((uint32_t)k[1])<<16);
|
||||
break;
|
||||
case 3 : a+=((uint32_t)k8[2])<<16; /* fall through */
|
||||
case 2 : a+=k[0];
|
||||
break;
|
||||
case 1 : a+=k8[0];
|
||||
break;
|
||||
case 0 : return c; /* zero length requires no mixing */
|
||||
}
|
||||
|
||||
} else { /* need to read the key one byte at a time */
|
||||
const uint8_t *k = (const uint8_t *)key;
|
||||
|
||||
/*--------------- all but the last block: affect some 32 bits of (a,b,c) */
|
||||
while (length > 12)
|
||||
{
|
||||
a += k[0];
|
||||
a += ((uint32_t)k[1])<<8;
|
||||
a += ((uint32_t)k[2])<<16;
|
||||
a += ((uint32_t)k[3])<<24;
|
||||
b += k[4];
|
||||
b += ((uint32_t)k[5])<<8;
|
||||
b += ((uint32_t)k[6])<<16;
|
||||
b += ((uint32_t)k[7])<<24;
|
||||
c += k[8];
|
||||
c += ((uint32_t)k[9])<<8;
|
||||
c += ((uint32_t)k[10])<<16;
|
||||
c += ((uint32_t)k[11])<<24;
|
||||
mix(a,b,c);
|
||||
length -= 12;
|
||||
k += 12;
|
||||
}
|
||||
|
||||
/*-------------------------------- last block: affect all 32 bits of (c) */
|
||||
switch(length) /* all the case statements fall through */
|
||||
{
|
||||
case 12: c+=((uint32_t)k[11])<<24;
|
||||
/* FALLTHROUGH */
|
||||
case 11: c+=((uint32_t)k[10])<<16;
|
||||
/* FALLTHROUGH */
|
||||
case 10: c+=((uint32_t)k[9])<<8;
|
||||
/* FALLTHROUGH */
|
||||
case 9 : c+=k[8];
|
||||
/* FALLTHROUGH */
|
||||
case 8 : b+=((uint32_t)k[7])<<24;
|
||||
/* FALLTHROUGH */
|
||||
case 7 : b+=((uint32_t)k[6])<<16;
|
||||
/* FALLTHROUGH */
|
||||
case 6 : b+=((uint32_t)k[5])<<8;
|
||||
/* FALLTHROUGH */
|
||||
case 5 : b+=k[4];
|
||||
/* FALLTHROUGH */
|
||||
case 4 : a+=((uint32_t)k[3])<<24;
|
||||
/* FALLTHROUGH */
|
||||
case 3 : a+=((uint32_t)k[2])<<16;
|
||||
/* FALLTHROUGH */
|
||||
case 2 : a+=((uint32_t)k[1])<<8;
|
||||
/* FALLTHROUGH */
|
||||
case 1 : a+=k[0];
|
||||
break;
|
||||
case 0 : return c;
|
||||
}
|
||||
}
|
||||
|
||||
final(a,b,c);
|
||||
return c;
|
||||
}
|
||||
|
||||
33
help-from-md
Executable file
33
help-from-md
Executable file
@@ -0,0 +1,33 @@
|
||||
#!/bin/bash
|
||||
|
||||
if [[ "$#" != 2 ]]; then
|
||||
echo "Usage: $0 MD_FILE HELP_FILE.h"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
mdfile="$1"
|
||||
helpfile="$2"
|
||||
newfile="$helpfile.new"
|
||||
findfile="${helpfile/./\\.}"
|
||||
|
||||
sed -e '1,/^\[comment\].*'"$findfile"'/d' \
|
||||
-e '1,/^```/d' \
|
||||
-e '/^```/,$d' \
|
||||
-e 's/"/\\"/g' \
|
||||
-e 's/^/ rprintf(F,"/' \
|
||||
-e 's/$/\\n");/' \
|
||||
<"$mdfile" >"$newfile"
|
||||
|
||||
if [[ ! -s "$newfile" ]]; then
|
||||
rm "$newfile"
|
||||
echo "Discarding empty output for $helpfile file from $mdfile"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
(cat <<EOT
|
||||
/* DO NOT EDIT THIS FILE! It is auto-generated from the option list in $mdfile! */
|
||||
|
||||
EOT
|
||||
cat "$newfile"
|
||||
) >"$helpfile"
|
||||
rm "$newfile"
|
||||
42
hlink.c
42
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-2014 Wayne Davison
|
||||
* Copyright (C) 2004-2020 Wayne Davison
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
@@ -29,7 +29,7 @@ extern int list_only;
|
||||
extern int am_sender;
|
||||
extern int inc_recurse;
|
||||
extern int do_xfers;
|
||||
extern int link_dest;
|
||||
extern int alt_dest_type;
|
||||
extern int preserve_acls;
|
||||
extern int preserve_xattrs;
|
||||
extern int protocol_version;
|
||||
@@ -48,6 +48,8 @@ extern struct file_list *cur_flist;
|
||||
* we can avoid the pool of dev+inode data. For incremental recursion mode,
|
||||
* the receiver will use a ndx hash to remember old pathnames. */
|
||||
|
||||
static void *data_when_new = "";
|
||||
|
||||
static struct hashtable *dev_tbl;
|
||||
|
||||
static struct hashtable *prior_hlinks;
|
||||
@@ -57,32 +59,29 @@ static struct file_list *hlink_flist;
|
||||
void init_hard_links(void)
|
||||
{
|
||||
if (am_sender || protocol_version < 30)
|
||||
dev_tbl = hashtable_create(16, 1);
|
||||
dev_tbl = hashtable_create(16, HT_KEY64);
|
||||
else if (inc_recurse)
|
||||
prior_hlinks = hashtable_create(1024, 0);
|
||||
prior_hlinks = hashtable_create(1024, HT_KEY32);
|
||||
}
|
||||
|
||||
struct ht_int64_node *idev_find(int64 dev, int64 ino)
|
||||
{
|
||||
static struct ht_int64_node *dev_node = NULL;
|
||||
struct hashtable *tbl;
|
||||
|
||||
/* Note that some OSes have a dev == 0, so increment to avoid storing a 0. */
|
||||
if (!dev_node || dev_node->key != dev+1) {
|
||||
/* We keep a separate hash table of inodes for every device. */
|
||||
dev_node = hashtable_find(dev_tbl, dev+1, 1);
|
||||
if (!(tbl = dev_node->data)) {
|
||||
tbl = dev_node->data = hashtable_create(512, 1);
|
||||
dev_node = hashtable_find(dev_tbl, dev+1, data_when_new);
|
||||
if (dev_node->data == data_when_new) {
|
||||
dev_node->data = hashtable_create(512, HT_KEY64);
|
||||
if (DEBUG_GTE(HLINK, 3)) {
|
||||
rprintf(FINFO,
|
||||
"[%s] created hashtable for dev %s\n",
|
||||
who_am_i(), big_num(dev));
|
||||
rprintf(FINFO, "[%s] created hashtable for dev %s\n",
|
||||
who_am_i(), big_num(dev));
|
||||
}
|
||||
}
|
||||
} else
|
||||
tbl = dev_node->data;
|
||||
}
|
||||
|
||||
return hashtable_find(tbl, ino, 1);
|
||||
return hashtable_find(dev_node->data, ino, (void*)-1L);
|
||||
}
|
||||
|
||||
void idev_destroy(void)
|
||||
@@ -118,15 +117,14 @@ static void match_gnums(int32 *ndx_list, int ndx_count)
|
||||
struct ht_int32_node *node = NULL;
|
||||
int32 gnum, gnum_next;
|
||||
|
||||
qsort(ndx_list, ndx_count, sizeof ndx_list[0],
|
||||
(int (*)()) hlink_compare_gnum);
|
||||
qsort(ndx_list, ndx_count, sizeof ndx_list[0], (int (*)()) hlink_compare_gnum);
|
||||
|
||||
for (from = 0; from < ndx_count; from++) {
|
||||
file = hlink_flist->sorted[ndx_list[from]];
|
||||
gnum = F_HL_GNUM(file);
|
||||
if (inc_recurse) {
|
||||
node = hashtable_find(prior_hlinks, gnum, 1);
|
||||
if (!node->data) {
|
||||
node = hashtable_find(prior_hlinks, gnum, data_when_new);
|
||||
if (node->data == data_when_new) {
|
||||
if (!(node->data = new_array0(char, 5)))
|
||||
out_of_memory("match_gnums");
|
||||
assert(gnum >= hlink_flist->ndx_start);
|
||||
@@ -231,7 +229,7 @@ static int maybe_hard_link(struct file_struct *file, int ndx,
|
||||
}
|
||||
}
|
||||
|
||||
if (atomic_create(file, fname, oldname, MAKEDEV(0, 0), sxp, statret == 0 ? DEL_FOR_FILE : 0)) {
|
||||
if (atomic_create(file, fname, NULL, oldname, MAKEDEV(0, 0), sxp, statret == 0 ? DEL_FOR_FILE : 0)) {
|
||||
if (itemizing) {
|
||||
itemize(fname, file, ndx, statret, sxp,
|
||||
ITEM_LOCAL_CHANGE | ITEM_XNAME_FOLLOWS, 0,
|
||||
@@ -269,7 +267,7 @@ static char *check_prior(struct file_struct *file, int gnum,
|
||||
}
|
||||
|
||||
if (inc_recurse
|
||||
&& (node = hashtable_find(prior_hlinks, gnum, 0)) != NULL) {
|
||||
&& (node = hashtable_find(prior_hlinks, gnum, NULL)) != NULL) {
|
||||
assert(node->data != NULL);
|
||||
if (CVAL(node->data, 0) != 0) {
|
||||
*prev_ndx_p = -1;
|
||||
@@ -396,7 +394,7 @@ int hard_link_check(struct file_struct *file, int ndx, char *fname,
|
||||
pathjoin(cmpbuf, MAXPATHLEN, basis_dir[j], fname);
|
||||
if (link_stat(cmpbuf, &alt_sx.st, 0) < 0)
|
||||
continue;
|
||||
if (link_dest) {
|
||||
if (alt_dest_type == LINK_DEST) {
|
||||
if (prev_st.st_dev != alt_sx.st.st_dev
|
||||
|| prev_st.st_ino != alt_sx.st.st_ino)
|
||||
continue;
|
||||
@@ -528,7 +526,7 @@ void finish_hard_link(struct file_struct *file, const char *fname, int fin_ndx,
|
||||
|
||||
if (inc_recurse) {
|
||||
int gnum = F_HL_GNUM(file);
|
||||
struct ht_int32_node *node = hashtable_find(prior_hlinks, gnum, 0);
|
||||
struct ht_int32_node *node = hashtable_find(prior_hlinks, gnum, NULL);
|
||||
if (node == NULL) {
|
||||
rprintf(FERROR, "Unable to find a hlink node for %d (%s)\n", gnum, f_name(file, prev_name));
|
||||
exit_cleanup(RERR_MESSAGEIO);
|
||||
|
||||
2
ifuncs.h
2
ifuncs.h
@@ -1,6 +1,6 @@
|
||||
/* Inline functions for rsync.
|
||||
*
|
||||
* Copyright (C) 2007-2014 Wayne Davison
|
||||
* Copyright (C) 2007-2019 Wayne Davison
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
|
||||
2
inums.h
2
inums.h
@@ -1,6 +1,6 @@
|
||||
/* Inline functions for rsync.
|
||||
*
|
||||
* Copyright (C) 2008-2014 Wayne Davison
|
||||
* Copyright (C) 2008-2019 Wayne Davison
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
|
||||
60
io.c
60
io.c
@@ -4,7 +4,7 @@
|
||||
* Copyright (C) 1996-2001 Andrew Tridgell
|
||||
* Copyright (C) 1996 Paul Mackerras
|
||||
* Copyright (C) 2001, 2002 Martin Pool <mbp@samba.org>
|
||||
* Copyright (C) 2003-2014 Wayne Davison
|
||||
* Copyright (C) 2003-2020 Wayne Davison
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
@@ -44,6 +44,7 @@ extern int am_generator;
|
||||
extern int msgs2stderr;
|
||||
extern int inc_recurse;
|
||||
extern int io_error;
|
||||
extern int batch_fd;
|
||||
extern int eol_nulls;
|
||||
extern int flist_eof;
|
||||
extern int file_total;
|
||||
@@ -67,7 +68,6 @@ extern iconv_t ic_send, ic_recv;
|
||||
|
||||
int csum_length = SHORT_SUM_LENGTH; /* initial value */
|
||||
int allowed_lull = 0;
|
||||
int batch_fd = -1;
|
||||
int msgdone_cnt = 0;
|
||||
int forward_flist_data = 0;
|
||||
BOOL flist_receiving_enabled = False;
|
||||
@@ -251,8 +251,7 @@ static size_t safe_read(int fd, char *buf, size_t len)
|
||||
cnt = select(fd+1, &r_fds, NULL, &e_fds, &tv);
|
||||
if (cnt <= 0) {
|
||||
if (cnt < 0 && errno == EBADF) {
|
||||
rsyserr(FERROR, errno, "safe_read select failed [%s]",
|
||||
who_am_i());
|
||||
rsyserr(FERROR, errno, "safe_read select failed");
|
||||
exit_cleanup(RERR_FILEIO);
|
||||
}
|
||||
check_timeout(1, MSK_ALLOW_FLUSH);
|
||||
@@ -271,8 +270,7 @@ static size_t safe_read(int fd, char *buf, size_t len)
|
||||
if (n < 0) {
|
||||
if (errno == EINTR)
|
||||
continue;
|
||||
rsyserr(FERROR, errno, "safe_read failed to read %ld bytes [%s]",
|
||||
(long)len, who_am_i());
|
||||
rsyserr(FERROR, errno, "safe_read failed to read %ld bytes", (long)len);
|
||||
exit_cleanup(RERR_STREAMIO);
|
||||
}
|
||||
if ((got += (size_t)n) == len)
|
||||
@@ -315,8 +313,8 @@ static void safe_write(int fd, const char *buf, size_t len)
|
||||
if (errno != EINTR && errno != EWOULDBLOCK && errno != EAGAIN) {
|
||||
write_failed:
|
||||
rsyserr(FERROR, errno,
|
||||
"safe_write failed to write %ld bytes to %s [%s]",
|
||||
(long)len, what_fd_is(fd), who_am_i());
|
||||
"safe_write failed to write %ld bytes to %s",
|
||||
(long)len, what_fd_is(fd));
|
||||
exit_cleanup(RERR_STREAMIO);
|
||||
}
|
||||
} else {
|
||||
@@ -337,8 +335,7 @@ static void safe_write(int fd, const char *buf, size_t len)
|
||||
cnt = select(fd + 1, NULL, &w_fds, NULL, &tv);
|
||||
if (cnt <= 0) {
|
||||
if (cnt < 0 && errno == EBADF) {
|
||||
rsyserr(FERROR, errno, "safe_write select failed on %s [%s]",
|
||||
what_fd_is(fd), who_am_i());
|
||||
rsyserr(FERROR, errno, "safe_write select failed on %s", what_fd_is(fd));
|
||||
exit_cleanup(RERR_FILEIO);
|
||||
}
|
||||
if (io_timeout)
|
||||
@@ -815,7 +812,7 @@ static char *perform_io(size_t needed, int flags)
|
||||
msgs2stderr = 1;
|
||||
iobuf.out_fd = -2;
|
||||
iobuf.out.len = iobuf.msg.len = iobuf.raw_flushing_ends_before = 0;
|
||||
rsyserr(FERROR_SOCKET, errno, "[%s] write error", who_am_i());
|
||||
rsyserr(FERROR_SOCKET, errno, "write error");
|
||||
drain_multiplex_messages();
|
||||
exit_cleanup(RERR_SOCKETIO);
|
||||
}
|
||||
@@ -915,7 +912,7 @@ void noop_io_until_death(void)
|
||||
{
|
||||
char buf[1024];
|
||||
|
||||
if (!iobuf.in.buf || !iobuf.out.buf || iobuf.in_fd < 0 || iobuf.out_fd < 0 || kluge_around_eof)
|
||||
if (!iobuf.in.buf || !iobuf.out.buf || iobuf.in_fd < 0 || iobuf.out_fd < 0 || kluge_around_eof || msgs2stderr)
|
||||
return;
|
||||
|
||||
kluge_around_eof = 2;
|
||||
@@ -954,8 +951,17 @@ int send_msg(enum msgcode code, const char *buf, size_t len, int convert)
|
||||
} else
|
||||
#endif
|
||||
needed = len + 4 + 3;
|
||||
if (iobuf.msg.len + needed > iobuf.msg.size)
|
||||
perform_io(needed, PIO_NEED_MSGROOM);
|
||||
if (iobuf.msg.len + needed > iobuf.msg.size) {
|
||||
if (!am_receiver)
|
||||
perform_io(needed, PIO_NEED_MSGROOM);
|
||||
else { /* We allow the receiver to increase their iobuf.msg size to avoid a deadlock. */
|
||||
size_t old_size = iobuf.msg.size;
|
||||
restore_iobuf_size(&iobuf.msg);
|
||||
realloc_xbuf(&iobuf.msg, iobuf.msg.size * 2);
|
||||
if (iobuf.msg.pos + iobuf.msg.len > old_size)
|
||||
memcpy(iobuf.msg.buf + old_size, iobuf.msg.buf, iobuf.msg.pos + iobuf.msg.len - old_size);
|
||||
}
|
||||
}
|
||||
|
||||
pos = iobuf.msg.pos + iobuf.msg.len; /* Must be set after any flushing. */
|
||||
if (pos >= iobuf.msg.size)
|
||||
@@ -1113,8 +1119,7 @@ static void check_for_d_option_error(const char *msg)
|
||||
}
|
||||
|
||||
if (saw_d) {
|
||||
rprintf(FWARNING,
|
||||
"*** Try using \"--old-d\" if remote rsync is <= 2.6.3 ***\n");
|
||||
rprintf(FWARNING, "*** Try using \"--old-d\" if remote rsync is <= 2.6.3 ***\n");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1176,7 +1181,7 @@ int read_line(int fd, char *buf, size_t bufsiz, int flags)
|
||||
|
||||
#ifdef ICONV_OPTION
|
||||
if (flags & RL_CONVERT && iconv_buf.size < bufsiz)
|
||||
realloc_xbuf(&iconv_buf, bufsiz + 1024);
|
||||
realloc_xbuf(&iconv_buf, ROUND_UP_1024(bufsiz) + 1024);
|
||||
#endif
|
||||
|
||||
start:
|
||||
@@ -1685,7 +1690,7 @@ void wait_for_receiver(void)
|
||||
rprintf(FINFO, "[%s] receiving flist for dir %d\n",
|
||||
who_am_i(), ndx);
|
||||
}
|
||||
flist = recv_file_list(iobuf.in_fd);
|
||||
flist = recv_file_list(iobuf.in_fd, ndx);
|
||||
flist->parent_ndx = ndx;
|
||||
#ifdef SUPPORT_HARD_LINKS
|
||||
if (preserve_hard_links)
|
||||
@@ -1982,13 +1987,14 @@ static void sleep_for_bwlimit(int bytes_written)
|
||||
total_written = (sleep_usec - elapsed_usec) * bwlimit / (ONE_SEC/1024);
|
||||
}
|
||||
|
||||
void io_flush(int flush_it_all)
|
||||
void io_flush(int flush_type)
|
||||
{
|
||||
if (iobuf.out.len > iobuf.out_empty_len) {
|
||||
if (flush_it_all) /* FULL_FLUSH: flush everything in the output buffers */
|
||||
if (flush_type == FULL_FLUSH) /* flush everything in the output buffers */
|
||||
perform_io(iobuf.out.size - iobuf.out_empty_len, PIO_NEED_OUTROOM);
|
||||
else /* NORMAL_FLUSH: flush at least 1 byte */
|
||||
else if (flush_type == NORMAL_FLUSH) /* flush at least 1 byte */
|
||||
perform_io(iobuf.out.size - iobuf.out.len + 1, PIO_NEED_OUTROOM);
|
||||
/* MSG_FLUSH: flush iobuf.msg only */
|
||||
}
|
||||
if (iobuf.msg.len)
|
||||
perform_io(iobuf.msg.size, PIO_NEED_MSGROOM);
|
||||
@@ -2013,20 +2019,20 @@ void write_varint(int f, int32 x)
|
||||
{
|
||||
char b[5];
|
||||
uchar bit;
|
||||
int cnt = 4;
|
||||
int cnt;
|
||||
|
||||
SIVAL(b, 1, x);
|
||||
|
||||
while (cnt > 1 && b[cnt] == 0)
|
||||
cnt--;
|
||||
for (cnt = 4; cnt > 1 && b[cnt] == 0; cnt--) {}
|
||||
bit = ((uchar)1<<(7-cnt+1));
|
||||
|
||||
if (CVAL(b, cnt) >= bit) {
|
||||
cnt++;
|
||||
*b = ~(bit-1);
|
||||
} else if (cnt > 1)
|
||||
*b = b[cnt] | ~(bit*2-1);
|
||||
else
|
||||
*b = b[cnt];
|
||||
*b = b[1];
|
||||
|
||||
write_buf(f, b, cnt);
|
||||
}
|
||||
@@ -2283,7 +2289,7 @@ void io_printf(int fd, const char *format, ...)
|
||||
if (len < 0)
|
||||
exit_cleanup(RERR_PROTOCOL);
|
||||
|
||||
if (len > (int)sizeof buf) {
|
||||
if (len >= (int)sizeof buf) {
|
||||
rprintf(FERROR, "io_printf() was too long for the buffer.\n");
|
||||
exit_cleanup(RERR_PROTOCOL);
|
||||
}
|
||||
@@ -2368,7 +2374,7 @@ void start_write_batch(int fd)
|
||||
* is involved. */
|
||||
write_int(batch_fd, protocol_version);
|
||||
if (protocol_version >= 30)
|
||||
write_byte(batch_fd, compat_flags);
|
||||
write_varint(batch_fd, compat_flags);
|
||||
write_int(batch_fd, checksum_seed);
|
||||
|
||||
if (am_sender)
|
||||
|
||||
2
io.h
2
io.h
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2007-2014 Wayne Davison
|
||||
* Copyright (C) 2007-2019 Wayne Davison
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
|
||||
8
itypes.h
8
itypes.h
@@ -1,6 +1,6 @@
|
||||
/* Inline functions for rsync.
|
||||
*
|
||||
* Copyright (C) 2007-2014 Wayne Davison
|
||||
* Copyright (C) 2007-2020 Wayne Davison
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
@@ -22,6 +22,12 @@ isDigit(const char *ptr)
|
||||
return isdigit(*(unsigned char *)ptr);
|
||||
}
|
||||
|
||||
static inline int
|
||||
isHexDigit(const char *ptr)
|
||||
{
|
||||
return isxdigit(*(unsigned char *)ptr);
|
||||
}
|
||||
|
||||
static inline int
|
||||
isPrint(const char *ptr)
|
||||
{
|
||||
|
||||
1
latest-year.h
Normal file
1
latest-year.h
Normal file
@@ -0,0 +1 @@
|
||||
#define LATEST_YEAR "2020"
|
||||
@@ -3,7 +3,7 @@
|
||||
*
|
||||
* Copyright (C) 1998 Andrew Tridgell
|
||||
* Copyright (C) 2002 Martin Pool
|
||||
* Copyright (C) 2004-2014 Wayne Davison
|
||||
* Copyright (C) 2004-2020 Wayne Davison
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
@@ -79,7 +79,7 @@ static char number_separator;
|
||||
|
||||
#ifndef HAVE_STRPBRK
|
||||
/**
|
||||
* Find the first ocurrence in @p s of any character in @p accept.
|
||||
* Find the first occurrence in @p s of any character in @p accept.
|
||||
*
|
||||
* Derived from glibc
|
||||
**/
|
||||
|
||||
693
lib/md5-asm-x86_64.s
Normal file
693
lib/md5-asm-x86_64.s
Normal file
@@ -0,0 +1,693 @@
|
||||
/*
|
||||
* x86-64 optimized assembler MD5 implementation
|
||||
*
|
||||
* Author: Marc Bevand, 2004
|
||||
*
|
||||
* This code was placed in the public domain by the author. The original
|
||||
* publication can be found at:
|
||||
*
|
||||
* https://www.zorinaq.com/papers/md5-amd64.html
|
||||
*/
|
||||
/*
|
||||
* No modifications were made aside from changing the function and file names.
|
||||
* The MD5_CTX structure as expected here (from OpenSSL) is binary compatible
|
||||
* with the md_context used by rsync, for the fields accessed.
|
||||
*
|
||||
* Benchmarks (in MB/s) C ASM
|
||||
* - Intel Atom D2700 302 334
|
||||
* - Intel i7-7700hq 351 376
|
||||
* - AMD ThreadRipper 2950x 728 784
|
||||
*
|
||||
* The original code was also incorporated into OpenSSL. It has since been
|
||||
* modified there. Those changes have not been made here due to licensing
|
||||
* incompatibilities. Benchmarks of those changes on the above CPUs did not
|
||||
* show any significant difference in performance, though.
|
||||
*/
|
||||
|
||||
.text
|
||||
.align 16
|
||||
|
||||
.globl md5_process_asm
|
||||
.type md5_process_asm,@function
|
||||
md5_process_asm:
|
||||
push %rbp
|
||||
push %rbx
|
||||
push %r12
|
||||
push %r13 # not really useful (r13 is unused)
|
||||
push %r14
|
||||
push %r15
|
||||
|
||||
# rdi = arg #1 (ctx, MD5_CTX pointer)
|
||||
# rsi = arg #2 (ptr, data pointer)
|
||||
# rdx = arg #3 (nbr, number of 16-word blocks to process)
|
||||
mov %rdi, %rbp # rbp = ctx
|
||||
shl $6, %rdx # rdx = nbr in bytes
|
||||
lea (%rsi,%rdx), %rdi # rdi = end
|
||||
mov 0*4(%rbp), %eax # eax = ctx->A
|
||||
mov 1*4(%rbp), %ebx # ebx = ctx->B
|
||||
mov 2*4(%rbp), %ecx # ecx = ctx->C
|
||||
mov 3*4(%rbp), %edx # edx = ctx->D
|
||||
# end is 'rdi'
|
||||
# ptr is 'rsi'
|
||||
# A is 'eax'
|
||||
# B is 'ebx'
|
||||
# C is 'ecx'
|
||||
# D is 'edx'
|
||||
|
||||
cmp %rdi, %rsi # cmp end with ptr
|
||||
je 1f # jmp if ptr == end
|
||||
|
||||
# BEGIN of loop over 16-word blocks
|
||||
2: # save old values of A, B, C, D
|
||||
mov %eax, %r8d
|
||||
mov %ebx, %r9d
|
||||
mov %ecx, %r14d
|
||||
mov %edx, %r15d
|
||||
mov 0*4(%rsi), %r10d /* (NEXT STEP) X[0] */
|
||||
mov %edx, %r11d /* (NEXT STEP) z' = %edx */
|
||||
xor %ecx, %r11d /* y ^ ... */
|
||||
lea -680876936(%eax,%r10d),%eax /* Const + dst + ... */
|
||||
and %ebx, %r11d /* x & ... */
|
||||
xor %edx, %r11d /* z ^ ... */
|
||||
mov 1*4(%rsi),%r10d /* (NEXT STEP) X[1] */
|
||||
add %r11d, %eax /* dst += ... */
|
||||
rol $7, %eax /* dst <<< s */
|
||||
mov %ecx, %r11d /* (NEXT STEP) z' = %ecx */
|
||||
add %ebx, %eax /* dst += x */
|
||||
xor %ebx, %r11d /* y ^ ... */
|
||||
lea -389564586(%edx,%r10d),%edx /* Const + dst + ... */
|
||||
and %eax, %r11d /* x & ... */
|
||||
xor %ecx, %r11d /* z ^ ... */
|
||||
mov 2*4(%rsi),%r10d /* (NEXT STEP) X[2] */
|
||||
add %r11d, %edx /* dst += ... */
|
||||
rol $12, %edx /* dst <<< s */
|
||||
mov %ebx, %r11d /* (NEXT STEP) z' = %ebx */
|
||||
add %eax, %edx /* dst += x */
|
||||
xor %eax, %r11d /* y ^ ... */
|
||||
lea 606105819(%ecx,%r10d),%ecx /* Const + dst + ... */
|
||||
and %edx, %r11d /* x & ... */
|
||||
xor %ebx, %r11d /* z ^ ... */
|
||||
mov 3*4(%rsi),%r10d /* (NEXT STEP) X[3] */
|
||||
add %r11d, %ecx /* dst += ... */
|
||||
rol $17, %ecx /* dst <<< s */
|
||||
mov %eax, %r11d /* (NEXT STEP) z' = %eax */
|
||||
add %edx, %ecx /* dst += x */
|
||||
xor %edx, %r11d /* y ^ ... */
|
||||
lea -1044525330(%ebx,%r10d),%ebx /* Const + dst + ... */
|
||||
and %ecx, %r11d /* x & ... */
|
||||
xor %eax, %r11d /* z ^ ... */
|
||||
mov 4*4(%rsi),%r10d /* (NEXT STEP) X[4] */
|
||||
add %r11d, %ebx /* dst += ... */
|
||||
rol $22, %ebx /* dst <<< s */
|
||||
mov %edx, %r11d /* (NEXT STEP) z' = %edx */
|
||||
add %ecx, %ebx /* dst += x */
|
||||
xor %ecx, %r11d /* y ^ ... */
|
||||
lea -176418897(%eax,%r10d),%eax /* Const + dst + ... */
|
||||
and %ebx, %r11d /* x & ... */
|
||||
xor %edx, %r11d /* z ^ ... */
|
||||
mov 5*4(%rsi),%r10d /* (NEXT STEP) X[5] */
|
||||
add %r11d, %eax /* dst += ... */
|
||||
rol $7, %eax /* dst <<< s */
|
||||
mov %ecx, %r11d /* (NEXT STEP) z' = %ecx */
|
||||
add %ebx, %eax /* dst += x */
|
||||
xor %ebx, %r11d /* y ^ ... */
|
||||
lea 1200080426(%edx,%r10d),%edx /* Const + dst + ... */
|
||||
and %eax, %r11d /* x & ... */
|
||||
xor %ecx, %r11d /* z ^ ... */
|
||||
mov 6*4(%rsi),%r10d /* (NEXT STEP) X[6] */
|
||||
add %r11d, %edx /* dst += ... */
|
||||
rol $12, %edx /* dst <<< s */
|
||||
mov %ebx, %r11d /* (NEXT STEP) z' = %ebx */
|
||||
add %eax, %edx /* dst += x */
|
||||
xor %eax, %r11d /* y ^ ... */
|
||||
lea -1473231341(%ecx,%r10d),%ecx /* Const + dst + ... */
|
||||
and %edx, %r11d /* x & ... */
|
||||
xor %ebx, %r11d /* z ^ ... */
|
||||
mov 7*4(%rsi),%r10d /* (NEXT STEP) X[7] */
|
||||
add %r11d, %ecx /* dst += ... */
|
||||
rol $17, %ecx /* dst <<< s */
|
||||
mov %eax, %r11d /* (NEXT STEP) z' = %eax */
|
||||
add %edx, %ecx /* dst += x */
|
||||
xor %edx, %r11d /* y ^ ... */
|
||||
lea -45705983(%ebx,%r10d),%ebx /* Const + dst + ... */
|
||||
and %ecx, %r11d /* x & ... */
|
||||
xor %eax, %r11d /* z ^ ... */
|
||||
mov 8*4(%rsi),%r10d /* (NEXT STEP) X[8] */
|
||||
add %r11d, %ebx /* dst += ... */
|
||||
rol $22, %ebx /* dst <<< s */
|
||||
mov %edx, %r11d /* (NEXT STEP) z' = %edx */
|
||||
add %ecx, %ebx /* dst += x */
|
||||
xor %ecx, %r11d /* y ^ ... */
|
||||
lea 1770035416(%eax,%r10d),%eax /* Const + dst + ... */
|
||||
and %ebx, %r11d /* x & ... */
|
||||
xor %edx, %r11d /* z ^ ... */
|
||||
mov 9*4(%rsi),%r10d /* (NEXT STEP) X[9] */
|
||||
add %r11d, %eax /* dst += ... */
|
||||
rol $7, %eax /* dst <<< s */
|
||||
mov %ecx, %r11d /* (NEXT STEP) z' = %ecx */
|
||||
add %ebx, %eax /* dst += x */
|
||||
xor %ebx, %r11d /* y ^ ... */
|
||||
lea -1958414417(%edx,%r10d),%edx /* Const + dst + ... */
|
||||
and %eax, %r11d /* x & ... */
|
||||
xor %ecx, %r11d /* z ^ ... */
|
||||
mov 10*4(%rsi),%r10d /* (NEXT STEP) X[10] */
|
||||
add %r11d, %edx /* dst += ... */
|
||||
rol $12, %edx /* dst <<< s */
|
||||
mov %ebx, %r11d /* (NEXT STEP) z' = %ebx */
|
||||
add %eax, %edx /* dst += x */
|
||||
xor %eax, %r11d /* y ^ ... */
|
||||
lea -42063(%ecx,%r10d),%ecx /* Const + dst + ... */
|
||||
and %edx, %r11d /* x & ... */
|
||||
xor %ebx, %r11d /* z ^ ... */
|
||||
mov 11*4(%rsi),%r10d /* (NEXT STEP) X[11] */
|
||||
add %r11d, %ecx /* dst += ... */
|
||||
rol $17, %ecx /* dst <<< s */
|
||||
mov %eax, %r11d /* (NEXT STEP) z' = %eax */
|
||||
add %edx, %ecx /* dst += x */
|
||||
xor %edx, %r11d /* y ^ ... */
|
||||
lea -1990404162(%ebx,%r10d),%ebx /* Const + dst + ... */
|
||||
and %ecx, %r11d /* x & ... */
|
||||
xor %eax, %r11d /* z ^ ... */
|
||||
mov 12*4(%rsi),%r10d /* (NEXT STEP) X[12] */
|
||||
add %r11d, %ebx /* dst += ... */
|
||||
rol $22, %ebx /* dst <<< s */
|
||||
mov %edx, %r11d /* (NEXT STEP) z' = %edx */
|
||||
add %ecx, %ebx /* dst += x */
|
||||
xor %ecx, %r11d /* y ^ ... */
|
||||
lea 1804603682(%eax,%r10d),%eax /* Const + dst + ... */
|
||||
and %ebx, %r11d /* x & ... */
|
||||
xor %edx, %r11d /* z ^ ... */
|
||||
mov 13*4(%rsi),%r10d /* (NEXT STEP) X[13] */
|
||||
add %r11d, %eax /* dst += ... */
|
||||
rol $7, %eax /* dst <<< s */
|
||||
mov %ecx, %r11d /* (NEXT STEP) z' = %ecx */
|
||||
add %ebx, %eax /* dst += x */
|
||||
xor %ebx, %r11d /* y ^ ... */
|
||||
lea -40341101(%edx,%r10d),%edx /* Const + dst + ... */
|
||||
and %eax, %r11d /* x & ... */
|
||||
xor %ecx, %r11d /* z ^ ... */
|
||||
mov 14*4(%rsi),%r10d /* (NEXT STEP) X[14] */
|
||||
add %r11d, %edx /* dst += ... */
|
||||
rol $12, %edx /* dst <<< s */
|
||||
mov %ebx, %r11d /* (NEXT STEP) z' = %ebx */
|
||||
add %eax, %edx /* dst += x */
|
||||
xor %eax, %r11d /* y ^ ... */
|
||||
lea -1502002290(%ecx,%r10d),%ecx /* Const + dst + ... */
|
||||
and %edx, %r11d /* x & ... */
|
||||
xor %ebx, %r11d /* z ^ ... */
|
||||
mov 15*4(%rsi),%r10d /* (NEXT STEP) X[15] */
|
||||
add %r11d, %ecx /* dst += ... */
|
||||
rol $17, %ecx /* dst <<< s */
|
||||
mov %eax, %r11d /* (NEXT STEP) z' = %eax */
|
||||
add %edx, %ecx /* dst += x */
|
||||
xor %edx, %r11d /* y ^ ... */
|
||||
lea 1236535329(%ebx,%r10d),%ebx /* Const + dst + ... */
|
||||
and %ecx, %r11d /* x & ... */
|
||||
xor %eax, %r11d /* z ^ ... */
|
||||
mov 0*4(%rsi),%r10d /* (NEXT STEP) X[0] */
|
||||
add %r11d, %ebx /* dst += ... */
|
||||
rol $22, %ebx /* dst <<< s */
|
||||
mov %edx, %r11d /* (NEXT STEP) z' = %edx */
|
||||
add %ecx, %ebx /* dst += x */
|
||||
mov 1*4(%rsi), %r10d /* (NEXT STEP) X[1] */
|
||||
mov %edx, %r11d /* (NEXT STEP) z' = %edx */
|
||||
mov %edx, %r12d /* (NEXT STEP) z' = %edx */
|
||||
not %r11d /* not z */
|
||||
lea -165796510(%eax,%r10d),%eax /* Const + dst + ... */
|
||||
and %ebx, %r12d /* x & z */
|
||||
and %ecx, %r11d /* y & (not z) */
|
||||
mov 6*4(%rsi),%r10d /* (NEXT STEP) X[6] */
|
||||
or %r11d, %r12d /* (y & (not z)) | (x & z) */
|
||||
mov %ecx, %r11d /* (NEXT STEP) z' = %ecx */
|
||||
add %r12d, %eax /* dst += ... */
|
||||
mov %ecx, %r12d /* (NEXT STEP) z' = %ecx */
|
||||
rol $5, %eax /* dst <<< s */
|
||||
add %ebx, %eax /* dst += x */
|
||||
not %r11d /* not z */
|
||||
lea -1069501632(%edx,%r10d),%edx /* Const + dst + ... */
|
||||
and %eax, %r12d /* x & z */
|
||||
and %ebx, %r11d /* y & (not z) */
|
||||
mov 11*4(%rsi),%r10d /* (NEXT STEP) X[11] */
|
||||
or %r11d, %r12d /* (y & (not z)) | (x & z) */
|
||||
mov %ebx, %r11d /* (NEXT STEP) z' = %ebx */
|
||||
add %r12d, %edx /* dst += ... */
|
||||
mov %ebx, %r12d /* (NEXT STEP) z' = %ebx */
|
||||
rol $9, %edx /* dst <<< s */
|
||||
add %eax, %edx /* dst += x */
|
||||
not %r11d /* not z */
|
||||
lea 643717713(%ecx,%r10d),%ecx /* Const + dst + ... */
|
||||
and %edx, %r12d /* x & z */
|
||||
and %eax, %r11d /* y & (not z) */
|
||||
mov 0*4(%rsi),%r10d /* (NEXT STEP) X[0] */
|
||||
or %r11d, %r12d /* (y & (not z)) | (x & z) */
|
||||
mov %eax, %r11d /* (NEXT STEP) z' = %eax */
|
||||
add %r12d, %ecx /* dst += ... */
|
||||
mov %eax, %r12d /* (NEXT STEP) z' = %eax */
|
||||
rol $14, %ecx /* dst <<< s */
|
||||
add %edx, %ecx /* dst += x */
|
||||
not %r11d /* not z */
|
||||
lea -373897302(%ebx,%r10d),%ebx /* Const + dst + ... */
|
||||
and %ecx, %r12d /* x & z */
|
||||
and %edx, %r11d /* y & (not z) */
|
||||
mov 5*4(%rsi),%r10d /* (NEXT STEP) X[5] */
|
||||
or %r11d, %r12d /* (y & (not z)) | (x & z) */
|
||||
mov %edx, %r11d /* (NEXT STEP) z' = %edx */
|
||||
add %r12d, %ebx /* dst += ... */
|
||||
mov %edx, %r12d /* (NEXT STEP) z' = %edx */
|
||||
rol $20, %ebx /* dst <<< s */
|
||||
add %ecx, %ebx /* dst += x */
|
||||
not %r11d /* not z */
|
||||
lea -701558691(%eax,%r10d),%eax /* Const + dst + ... */
|
||||
and %ebx, %r12d /* x & z */
|
||||
and %ecx, %r11d /* y & (not z) */
|
||||
mov 10*4(%rsi),%r10d /* (NEXT STEP) X[10] */
|
||||
or %r11d, %r12d /* (y & (not z)) | (x & z) */
|
||||
mov %ecx, %r11d /* (NEXT STEP) z' = %ecx */
|
||||
add %r12d, %eax /* dst += ... */
|
||||
mov %ecx, %r12d /* (NEXT STEP) z' = %ecx */
|
||||
rol $5, %eax /* dst <<< s */
|
||||
add %ebx, %eax /* dst += x */
|
||||
not %r11d /* not z */
|
||||
lea 38016083(%edx,%r10d),%edx /* Const + dst + ... */
|
||||
and %eax, %r12d /* x & z */
|
||||
and %ebx, %r11d /* y & (not z) */
|
||||
mov 15*4(%rsi),%r10d /* (NEXT STEP) X[15] */
|
||||
or %r11d, %r12d /* (y & (not z)) | (x & z) */
|
||||
mov %ebx, %r11d /* (NEXT STEP) z' = %ebx */
|
||||
add %r12d, %edx /* dst += ... */
|
||||
mov %ebx, %r12d /* (NEXT STEP) z' = %ebx */
|
||||
rol $9, %edx /* dst <<< s */
|
||||
add %eax, %edx /* dst += x */
|
||||
not %r11d /* not z */
|
||||
lea -660478335(%ecx,%r10d),%ecx /* Const + dst + ... */
|
||||
and %edx, %r12d /* x & z */
|
||||
and %eax, %r11d /* y & (not z) */
|
||||
mov 4*4(%rsi),%r10d /* (NEXT STEP) X[4] */
|
||||
or %r11d, %r12d /* (y & (not z)) | (x & z) */
|
||||
mov %eax, %r11d /* (NEXT STEP) z' = %eax */
|
||||
add %r12d, %ecx /* dst += ... */
|
||||
mov %eax, %r12d /* (NEXT STEP) z' = %eax */
|
||||
rol $14, %ecx /* dst <<< s */
|
||||
add %edx, %ecx /* dst += x */
|
||||
not %r11d /* not z */
|
||||
lea -405537848(%ebx,%r10d),%ebx /* Const + dst + ... */
|
||||
and %ecx, %r12d /* x & z */
|
||||
and %edx, %r11d /* y & (not z) */
|
||||
mov 9*4(%rsi),%r10d /* (NEXT STEP) X[9] */
|
||||
or %r11d, %r12d /* (y & (not z)) | (x & z) */
|
||||
mov %edx, %r11d /* (NEXT STEP) z' = %edx */
|
||||
add %r12d, %ebx /* dst += ... */
|
||||
mov %edx, %r12d /* (NEXT STEP) z' = %edx */
|
||||
rol $20, %ebx /* dst <<< s */
|
||||
add %ecx, %ebx /* dst += x */
|
||||
not %r11d /* not z */
|
||||
lea 568446438(%eax,%r10d),%eax /* Const + dst + ... */
|
||||
and %ebx, %r12d /* x & z */
|
||||
and %ecx, %r11d /* y & (not z) */
|
||||
mov 14*4(%rsi),%r10d /* (NEXT STEP) X[14] */
|
||||
or %r11d, %r12d /* (y & (not z)) | (x & z) */
|
||||
mov %ecx, %r11d /* (NEXT STEP) z' = %ecx */
|
||||
add %r12d, %eax /* dst += ... */
|
||||
mov %ecx, %r12d /* (NEXT STEP) z' = %ecx */
|
||||
rol $5, %eax /* dst <<< s */
|
||||
add %ebx, %eax /* dst += x */
|
||||
not %r11d /* not z */
|
||||
lea -1019803690(%edx,%r10d),%edx /* Const + dst + ... */
|
||||
and %eax, %r12d /* x & z */
|
||||
and %ebx, %r11d /* y & (not z) */
|
||||
mov 3*4(%rsi),%r10d /* (NEXT STEP) X[3] */
|
||||
or %r11d, %r12d /* (y & (not z)) | (x & z) */
|
||||
mov %ebx, %r11d /* (NEXT STEP) z' = %ebx */
|
||||
add %r12d, %edx /* dst += ... */
|
||||
mov %ebx, %r12d /* (NEXT STEP) z' = %ebx */
|
||||
rol $9, %edx /* dst <<< s */
|
||||
add %eax, %edx /* dst += x */
|
||||
not %r11d /* not z */
|
||||
lea -187363961(%ecx,%r10d),%ecx /* Const + dst + ... */
|
||||
and %edx, %r12d /* x & z */
|
||||
and %eax, %r11d /* y & (not z) */
|
||||
mov 8*4(%rsi),%r10d /* (NEXT STEP) X[8] */
|
||||
or %r11d, %r12d /* (y & (not z)) | (x & z) */
|
||||
mov %eax, %r11d /* (NEXT STEP) z' = %eax */
|
||||
add %r12d, %ecx /* dst += ... */
|
||||
mov %eax, %r12d /* (NEXT STEP) z' = %eax */
|
||||
rol $14, %ecx /* dst <<< s */
|
||||
add %edx, %ecx /* dst += x */
|
||||
not %r11d /* not z */
|
||||
lea 1163531501(%ebx,%r10d),%ebx /* Const + dst + ... */
|
||||
and %ecx, %r12d /* x & z */
|
||||
and %edx, %r11d /* y & (not z) */
|
||||
mov 13*4(%rsi),%r10d /* (NEXT STEP) X[13] */
|
||||
or %r11d, %r12d /* (y & (not z)) | (x & z) */
|
||||
mov %edx, %r11d /* (NEXT STEP) z' = %edx */
|
||||
add %r12d, %ebx /* dst += ... */
|
||||
mov %edx, %r12d /* (NEXT STEP) z' = %edx */
|
||||
rol $20, %ebx /* dst <<< s */
|
||||
add %ecx, %ebx /* dst += x */
|
||||
not %r11d /* not z */
|
||||
lea -1444681467(%eax,%r10d),%eax /* Const + dst + ... */
|
||||
and %ebx, %r12d /* x & z */
|
||||
and %ecx, %r11d /* y & (not z) */
|
||||
mov 2*4(%rsi),%r10d /* (NEXT STEP) X[2] */
|
||||
or %r11d, %r12d /* (y & (not z)) | (x & z) */
|
||||
mov %ecx, %r11d /* (NEXT STEP) z' = %ecx */
|
||||
add %r12d, %eax /* dst += ... */
|
||||
mov %ecx, %r12d /* (NEXT STEP) z' = %ecx */
|
||||
rol $5, %eax /* dst <<< s */
|
||||
add %ebx, %eax /* dst += x */
|
||||
not %r11d /* not z */
|
||||
lea -51403784(%edx,%r10d),%edx /* Const + dst + ... */
|
||||
and %eax, %r12d /* x & z */
|
||||
and %ebx, %r11d /* y & (not z) */
|
||||
mov 7*4(%rsi),%r10d /* (NEXT STEP) X[7] */
|
||||
or %r11d, %r12d /* (y & (not z)) | (x & z) */
|
||||
mov %ebx, %r11d /* (NEXT STEP) z' = %ebx */
|
||||
add %r12d, %edx /* dst += ... */
|
||||
mov %ebx, %r12d /* (NEXT STEP) z' = %ebx */
|
||||
rol $9, %edx /* dst <<< s */
|
||||
add %eax, %edx /* dst += x */
|
||||
not %r11d /* not z */
|
||||
lea 1735328473(%ecx,%r10d),%ecx /* Const + dst + ... */
|
||||
and %edx, %r12d /* x & z */
|
||||
and %eax, %r11d /* y & (not z) */
|
||||
mov 12*4(%rsi),%r10d /* (NEXT STEP) X[12] */
|
||||
or %r11d, %r12d /* (y & (not z)) | (x & z) */
|
||||
mov %eax, %r11d /* (NEXT STEP) z' = %eax */
|
||||
add %r12d, %ecx /* dst += ... */
|
||||
mov %eax, %r12d /* (NEXT STEP) z' = %eax */
|
||||
rol $14, %ecx /* dst <<< s */
|
||||
add %edx, %ecx /* dst += x */
|
||||
not %r11d /* not z */
|
||||
lea -1926607734(%ebx,%r10d),%ebx /* Const + dst + ... */
|
||||
and %ecx, %r12d /* x & z */
|
||||
and %edx, %r11d /* y & (not z) */
|
||||
mov 0*4(%rsi),%r10d /* (NEXT STEP) X[0] */
|
||||
or %r11d, %r12d /* (y & (not z)) | (x & z) */
|
||||
mov %edx, %r11d /* (NEXT STEP) z' = %edx */
|
||||
add %r12d, %ebx /* dst += ... */
|
||||
mov %edx, %r12d /* (NEXT STEP) z' = %edx */
|
||||
rol $20, %ebx /* dst <<< s */
|
||||
add %ecx, %ebx /* dst += x */
|
||||
mov 5*4(%rsi), %r10d /* (NEXT STEP) X[5] */
|
||||
mov %ecx, %r11d /* (NEXT STEP) y' = %ecx */
|
||||
lea -378558(%eax,%r10d),%eax /* Const + dst + ... */
|
||||
mov 8*4(%rsi),%r10d /* (NEXT STEP) X[8] */
|
||||
xor %edx, %r11d /* z ^ ... */
|
||||
xor %ebx, %r11d /* x ^ ... */
|
||||
add %r11d, %eax /* dst += ... */
|
||||
rol $4, %eax /* dst <<< s */
|
||||
mov %ebx, %r11d /* (NEXT STEP) y' = %ebx */
|
||||
add %ebx, %eax /* dst += x */
|
||||
lea -2022574463(%edx,%r10d),%edx /* Const + dst + ... */
|
||||
mov 11*4(%rsi),%r10d /* (NEXT STEP) X[11] */
|
||||
xor %ecx, %r11d /* z ^ ... */
|
||||
xor %eax, %r11d /* x ^ ... */
|
||||
add %r11d, %edx /* dst += ... */
|
||||
rol $11, %edx /* dst <<< s */
|
||||
mov %eax, %r11d /* (NEXT STEP) y' = %eax */
|
||||
add %eax, %edx /* dst += x */
|
||||
lea 1839030562(%ecx,%r10d),%ecx /* Const + dst + ... */
|
||||
mov 14*4(%rsi),%r10d /* (NEXT STEP) X[14] */
|
||||
xor %ebx, %r11d /* z ^ ... */
|
||||
xor %edx, %r11d /* x ^ ... */
|
||||
add %r11d, %ecx /* dst += ... */
|
||||
rol $16, %ecx /* dst <<< s */
|
||||
mov %edx, %r11d /* (NEXT STEP) y' = %edx */
|
||||
add %edx, %ecx /* dst += x */
|
||||
lea -35309556(%ebx,%r10d),%ebx /* Const + dst + ... */
|
||||
mov 1*4(%rsi),%r10d /* (NEXT STEP) X[1] */
|
||||
xor %eax, %r11d /* z ^ ... */
|
||||
xor %ecx, %r11d /* x ^ ... */
|
||||
add %r11d, %ebx /* dst += ... */
|
||||
rol $23, %ebx /* dst <<< s */
|
||||
mov %ecx, %r11d /* (NEXT STEP) y' = %ecx */
|
||||
add %ecx, %ebx /* dst += x */
|
||||
lea -1530992060(%eax,%r10d),%eax /* Const + dst + ... */
|
||||
mov 4*4(%rsi),%r10d /* (NEXT STEP) X[4] */
|
||||
xor %edx, %r11d /* z ^ ... */
|
||||
xor %ebx, %r11d /* x ^ ... */
|
||||
add %r11d, %eax /* dst += ... */
|
||||
rol $4, %eax /* dst <<< s */
|
||||
mov %ebx, %r11d /* (NEXT STEP) y' = %ebx */
|
||||
add %ebx, %eax /* dst += x */
|
||||
lea 1272893353(%edx,%r10d),%edx /* Const + dst + ... */
|
||||
mov 7*4(%rsi),%r10d /* (NEXT STEP) X[7] */
|
||||
xor %ecx, %r11d /* z ^ ... */
|
||||
xor %eax, %r11d /* x ^ ... */
|
||||
add %r11d, %edx /* dst += ... */
|
||||
rol $11, %edx /* dst <<< s */
|
||||
mov %eax, %r11d /* (NEXT STEP) y' = %eax */
|
||||
add %eax, %edx /* dst += x */
|
||||
lea -155497632(%ecx,%r10d),%ecx /* Const + dst + ... */
|
||||
mov 10*4(%rsi),%r10d /* (NEXT STEP) X[10] */
|
||||
xor %ebx, %r11d /* z ^ ... */
|
||||
xor %edx, %r11d /* x ^ ... */
|
||||
add %r11d, %ecx /* dst += ... */
|
||||
rol $16, %ecx /* dst <<< s */
|
||||
mov %edx, %r11d /* (NEXT STEP) y' = %edx */
|
||||
add %edx, %ecx /* dst += x */
|
||||
lea -1094730640(%ebx,%r10d),%ebx /* Const + dst + ... */
|
||||
mov 13*4(%rsi),%r10d /* (NEXT STEP) X[13] */
|
||||
xor %eax, %r11d /* z ^ ... */
|
||||
xor %ecx, %r11d /* x ^ ... */
|
||||
add %r11d, %ebx /* dst += ... */
|
||||
rol $23, %ebx /* dst <<< s */
|
||||
mov %ecx, %r11d /* (NEXT STEP) y' = %ecx */
|
||||
add %ecx, %ebx /* dst += x */
|
||||
lea 681279174(%eax,%r10d),%eax /* Const + dst + ... */
|
||||
mov 0*4(%rsi),%r10d /* (NEXT STEP) X[0] */
|
||||
xor %edx, %r11d /* z ^ ... */
|
||||
xor %ebx, %r11d /* x ^ ... */
|
||||
add %r11d, %eax /* dst += ... */
|
||||
rol $4, %eax /* dst <<< s */
|
||||
mov %ebx, %r11d /* (NEXT STEP) y' = %ebx */
|
||||
add %ebx, %eax /* dst += x */
|
||||
lea -358537222(%edx,%r10d),%edx /* Const + dst + ... */
|
||||
mov 3*4(%rsi),%r10d /* (NEXT STEP) X[3] */
|
||||
xor %ecx, %r11d /* z ^ ... */
|
||||
xor %eax, %r11d /* x ^ ... */
|
||||
add %r11d, %edx /* dst += ... */
|
||||
rol $11, %edx /* dst <<< s */
|
||||
mov %eax, %r11d /* (NEXT STEP) y' = %eax */
|
||||
add %eax, %edx /* dst += x */
|
||||
lea -722521979(%ecx,%r10d),%ecx /* Const + dst + ... */
|
||||
mov 6*4(%rsi),%r10d /* (NEXT STEP) X[6] */
|
||||
xor %ebx, %r11d /* z ^ ... */
|
||||
xor %edx, %r11d /* x ^ ... */
|
||||
add %r11d, %ecx /* dst += ... */
|
||||
rol $16, %ecx /* dst <<< s */
|
||||
mov %edx, %r11d /* (NEXT STEP) y' = %edx */
|
||||
add %edx, %ecx /* dst += x */
|
||||
lea 76029189(%ebx,%r10d),%ebx /* Const + dst + ... */
|
||||
mov 9*4(%rsi),%r10d /* (NEXT STEP) X[9] */
|
||||
xor %eax, %r11d /* z ^ ... */
|
||||
xor %ecx, %r11d /* x ^ ... */
|
||||
add %r11d, %ebx /* dst += ... */
|
||||
rol $23, %ebx /* dst <<< s */
|
||||
mov %ecx, %r11d /* (NEXT STEP) y' = %ecx */
|
||||
add %ecx, %ebx /* dst += x */
|
||||
lea -640364487(%eax,%r10d),%eax /* Const + dst + ... */
|
||||
mov 12*4(%rsi),%r10d /* (NEXT STEP) X[12] */
|
||||
xor %edx, %r11d /* z ^ ... */
|
||||
xor %ebx, %r11d /* x ^ ... */
|
||||
add %r11d, %eax /* dst += ... */
|
||||
rol $4, %eax /* dst <<< s */
|
||||
mov %ebx, %r11d /* (NEXT STEP) y' = %ebx */
|
||||
add %ebx, %eax /* dst += x */
|
||||
lea -421815835(%edx,%r10d),%edx /* Const + dst + ... */
|
||||
mov 15*4(%rsi),%r10d /* (NEXT STEP) X[15] */
|
||||
xor %ecx, %r11d /* z ^ ... */
|
||||
xor %eax, %r11d /* x ^ ... */
|
||||
add %r11d, %edx /* dst += ... */
|
||||
rol $11, %edx /* dst <<< s */
|
||||
mov %eax, %r11d /* (NEXT STEP) y' = %eax */
|
||||
add %eax, %edx /* dst += x */
|
||||
lea 530742520(%ecx,%r10d),%ecx /* Const + dst + ... */
|
||||
mov 2*4(%rsi),%r10d /* (NEXT STEP) X[2] */
|
||||
xor %ebx, %r11d /* z ^ ... */
|
||||
xor %edx, %r11d /* x ^ ... */
|
||||
add %r11d, %ecx /* dst += ... */
|
||||
rol $16, %ecx /* dst <<< s */
|
||||
mov %edx, %r11d /* (NEXT STEP) y' = %edx */
|
||||
add %edx, %ecx /* dst += x */
|
||||
lea -995338651(%ebx,%r10d),%ebx /* Const + dst + ... */
|
||||
mov 0*4(%rsi),%r10d /* (NEXT STEP) X[0] */
|
||||
xor %eax, %r11d /* z ^ ... */
|
||||
xor %ecx, %r11d /* x ^ ... */
|
||||
add %r11d, %ebx /* dst += ... */
|
||||
rol $23, %ebx /* dst <<< s */
|
||||
mov %ecx, %r11d /* (NEXT STEP) y' = %ecx */
|
||||
add %ecx, %ebx /* dst += x */
|
||||
mov 0*4(%rsi), %r10d /* (NEXT STEP) X[0] */
|
||||
mov $0xffffffff, %r11d
|
||||
xor %edx, %r11d /* (NEXT STEP) not z' = not %edx*/
|
||||
lea -198630844(%eax,%r10d),%eax /* Const + dst + ... */
|
||||
or %ebx, %r11d /* x | ... */
|
||||
xor %ecx, %r11d /* y ^ ... */
|
||||
add %r11d, %eax /* dst += ... */
|
||||
mov 7*4(%rsi),%r10d /* (NEXT STEP) X[7] */
|
||||
mov $0xffffffff, %r11d
|
||||
rol $6, %eax /* dst <<< s */
|
||||
xor %ecx, %r11d /* (NEXT STEP) not z' = not %ecx */
|
||||
add %ebx, %eax /* dst += x */
|
||||
lea 1126891415(%edx,%r10d),%edx /* Const + dst + ... */
|
||||
or %eax, %r11d /* x | ... */
|
||||
xor %ebx, %r11d /* y ^ ... */
|
||||
add %r11d, %edx /* dst += ... */
|
||||
mov 14*4(%rsi),%r10d /* (NEXT STEP) X[14] */
|
||||
mov $0xffffffff, %r11d
|
||||
rol $10, %edx /* dst <<< s */
|
||||
xor %ebx, %r11d /* (NEXT STEP) not z' = not %ebx */
|
||||
add %eax, %edx /* dst += x */
|
||||
lea -1416354905(%ecx,%r10d),%ecx /* Const + dst + ... */
|
||||
or %edx, %r11d /* x | ... */
|
||||
xor %eax, %r11d /* y ^ ... */
|
||||
add %r11d, %ecx /* dst += ... */
|
||||
mov 5*4(%rsi),%r10d /* (NEXT STEP) X[5] */
|
||||
mov $0xffffffff, %r11d
|
||||
rol $15, %ecx /* dst <<< s */
|
||||
xor %eax, %r11d /* (NEXT STEP) not z' = not %eax */
|
||||
add %edx, %ecx /* dst += x */
|
||||
lea -57434055(%ebx,%r10d),%ebx /* Const + dst + ... */
|
||||
or %ecx, %r11d /* x | ... */
|
||||
xor %edx, %r11d /* y ^ ... */
|
||||
add %r11d, %ebx /* dst += ... */
|
||||
mov 12*4(%rsi),%r10d /* (NEXT STEP) X[12] */
|
||||
mov $0xffffffff, %r11d
|
||||
rol $21, %ebx /* dst <<< s */
|
||||
xor %edx, %r11d /* (NEXT STEP) not z' = not %edx */
|
||||
add %ecx, %ebx /* dst += x */
|
||||
lea 1700485571(%eax,%r10d),%eax /* Const + dst + ... */
|
||||
or %ebx, %r11d /* x | ... */
|
||||
xor %ecx, %r11d /* y ^ ... */
|
||||
add %r11d, %eax /* dst += ... */
|
||||
mov 3*4(%rsi),%r10d /* (NEXT STEP) X[3] */
|
||||
mov $0xffffffff, %r11d
|
||||
rol $6, %eax /* dst <<< s */
|
||||
xor %ecx, %r11d /* (NEXT STEP) not z' = not %ecx */
|
||||
add %ebx, %eax /* dst += x */
|
||||
lea -1894986606(%edx,%r10d),%edx /* Const + dst + ... */
|
||||
or %eax, %r11d /* x | ... */
|
||||
xor %ebx, %r11d /* y ^ ... */
|
||||
add %r11d, %edx /* dst += ... */
|
||||
mov 10*4(%rsi),%r10d /* (NEXT STEP) X[10] */
|
||||
mov $0xffffffff, %r11d
|
||||
rol $10, %edx /* dst <<< s */
|
||||
xor %ebx, %r11d /* (NEXT STEP) not z' = not %ebx */
|
||||
add %eax, %edx /* dst += x */
|
||||
lea -1051523(%ecx,%r10d),%ecx /* Const + dst + ... */
|
||||
or %edx, %r11d /* x | ... */
|
||||
xor %eax, %r11d /* y ^ ... */
|
||||
add %r11d, %ecx /* dst += ... */
|
||||
mov 1*4(%rsi),%r10d /* (NEXT STEP) X[1] */
|
||||
mov $0xffffffff, %r11d
|
||||
rol $15, %ecx /* dst <<< s */
|
||||
xor %eax, %r11d /* (NEXT STEP) not z' = not %eax */
|
||||
add %edx, %ecx /* dst += x */
|
||||
lea -2054922799(%ebx,%r10d),%ebx /* Const + dst + ... */
|
||||
or %ecx, %r11d /* x | ... */
|
||||
xor %edx, %r11d /* y ^ ... */
|
||||
add %r11d, %ebx /* dst += ... */
|
||||
mov 8*4(%rsi),%r10d /* (NEXT STEP) X[8] */
|
||||
mov $0xffffffff, %r11d
|
||||
rol $21, %ebx /* dst <<< s */
|
||||
xor %edx, %r11d /* (NEXT STEP) not z' = not %edx */
|
||||
add %ecx, %ebx /* dst += x */
|
||||
lea 1873313359(%eax,%r10d),%eax /* Const + dst + ... */
|
||||
or %ebx, %r11d /* x | ... */
|
||||
xor %ecx, %r11d /* y ^ ... */
|
||||
add %r11d, %eax /* dst += ... */
|
||||
mov 15*4(%rsi),%r10d /* (NEXT STEP) X[15] */
|
||||
mov $0xffffffff, %r11d
|
||||
rol $6, %eax /* dst <<< s */
|
||||
xor %ecx, %r11d /* (NEXT STEP) not z' = not %ecx */
|
||||
add %ebx, %eax /* dst += x */
|
||||
lea -30611744(%edx,%r10d),%edx /* Const + dst + ... */
|
||||
or %eax, %r11d /* x | ... */
|
||||
xor %ebx, %r11d /* y ^ ... */
|
||||
add %r11d, %edx /* dst += ... */
|
||||
mov 6*4(%rsi),%r10d /* (NEXT STEP) X[6] */
|
||||
mov $0xffffffff, %r11d
|
||||
rol $10, %edx /* dst <<< s */
|
||||
xor %ebx, %r11d /* (NEXT STEP) not z' = not %ebx */
|
||||
add %eax, %edx /* dst += x */
|
||||
lea -1560198380(%ecx,%r10d),%ecx /* Const + dst + ... */
|
||||
or %edx, %r11d /* x | ... */
|
||||
xor %eax, %r11d /* y ^ ... */
|
||||
add %r11d, %ecx /* dst += ... */
|
||||
mov 13*4(%rsi),%r10d /* (NEXT STEP) X[13] */
|
||||
mov $0xffffffff, %r11d
|
||||
rol $15, %ecx /* dst <<< s */
|
||||
xor %eax, %r11d /* (NEXT STEP) not z' = not %eax */
|
||||
add %edx, %ecx /* dst += x */
|
||||
lea 1309151649(%ebx,%r10d),%ebx /* Const + dst + ... */
|
||||
or %ecx, %r11d /* x | ... */
|
||||
xor %edx, %r11d /* y ^ ... */
|
||||
add %r11d, %ebx /* dst += ... */
|
||||
mov 4*4(%rsi),%r10d /* (NEXT STEP) X[4] */
|
||||
mov $0xffffffff, %r11d
|
||||
rol $21, %ebx /* dst <<< s */
|
||||
xor %edx, %r11d /* (NEXT STEP) not z' = not %edx */
|
||||
add %ecx, %ebx /* dst += x */
|
||||
lea -145523070(%eax,%r10d),%eax /* Const + dst + ... */
|
||||
or %ebx, %r11d /* x | ... */
|
||||
xor %ecx, %r11d /* y ^ ... */
|
||||
add %r11d, %eax /* dst += ... */
|
||||
mov 11*4(%rsi),%r10d /* (NEXT STEP) X[11] */
|
||||
mov $0xffffffff, %r11d
|
||||
rol $6, %eax /* dst <<< s */
|
||||
xor %ecx, %r11d /* (NEXT STEP) not z' = not %ecx */
|
||||
add %ebx, %eax /* dst += x */
|
||||
lea -1120210379(%edx,%r10d),%edx /* Const + dst + ... */
|
||||
or %eax, %r11d /* x | ... */
|
||||
xor %ebx, %r11d /* y ^ ... */
|
||||
add %r11d, %edx /* dst += ... */
|
||||
mov 2*4(%rsi),%r10d /* (NEXT STEP) X[2] */
|
||||
mov $0xffffffff, %r11d
|
||||
rol $10, %edx /* dst <<< s */
|
||||
xor %ebx, %r11d /* (NEXT STEP) not z' = not %ebx */
|
||||
add %eax, %edx /* dst += x */
|
||||
lea 718787259(%ecx,%r10d),%ecx /* Const + dst + ... */
|
||||
or %edx, %r11d /* x | ... */
|
||||
xor %eax, %r11d /* y ^ ... */
|
||||
add %r11d, %ecx /* dst += ... */
|
||||
mov 9*4(%rsi),%r10d /* (NEXT STEP) X[9] */
|
||||
mov $0xffffffff, %r11d
|
||||
rol $15, %ecx /* dst <<< s */
|
||||
xor %eax, %r11d /* (NEXT STEP) not z' = not %eax */
|
||||
add %edx, %ecx /* dst += x */
|
||||
lea -343485551(%ebx,%r10d),%ebx /* Const + dst + ... */
|
||||
or %ecx, %r11d /* x | ... */
|
||||
xor %edx, %r11d /* y ^ ... */
|
||||
add %r11d, %ebx /* dst += ... */
|
||||
mov 0*4(%rsi),%r10d /* (NEXT STEP) X[0] */
|
||||
mov $0xffffffff, %r11d
|
||||
rol $21, %ebx /* dst <<< s */
|
||||
xor %edx, %r11d /* (NEXT STEP) not z' = not %edx */
|
||||
add %ecx, %ebx /* dst += x */
|
||||
# add old values of A, B, C, D
|
||||
add %r8d, %eax
|
||||
add %r9d, %ebx
|
||||
add %r14d, %ecx
|
||||
add %r15d, %edx
|
||||
|
||||
# loop control
|
||||
add $64, %rsi # ptr += 64
|
||||
cmp %rdi, %rsi # cmp end with ptr
|
||||
jb 2b # jmp if ptr < end
|
||||
# END of loop over 16-word blocks
|
||||
1:
|
||||
mov %eax, 0*4(%rbp) # ctx->A = A
|
||||
mov %ebx, 1*4(%rbp) # ctx->B = B
|
||||
mov %ecx, 2*4(%rbp) # ctx->C = C
|
||||
mov %edx, 3*4(%rbp) # ctx->D = D
|
||||
|
||||
pop %r15
|
||||
pop %r14
|
||||
pop %r13 # not really useful (r13 is unused)
|
||||
pop %r12
|
||||
pop %rbx
|
||||
pop %rbp
|
||||
ret
|
||||
.L_md5_process_asm_end:
|
||||
.size md5_process_asm,.L_md5_process_asm_end-md5_process_asm
|
||||
20
lib/md5.c
20
lib/md5.c
@@ -2,6 +2,7 @@
|
||||
* RFC 1321 compliant MD5 implementation
|
||||
*
|
||||
* Copyright (C) 2001-2003 Christophe Devine
|
||||
* Copyright (C) 2007-2020 Wayne Davison
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
@@ -19,6 +20,7 @@
|
||||
|
||||
#include "rsync.h"
|
||||
|
||||
#ifndef USE_OPENSSL
|
||||
void md5_begin(md_context *ctx)
|
||||
{
|
||||
ctx->A = 0x67452301;
|
||||
@@ -146,6 +148,10 @@ static void md5_process(md_context *ctx, const uchar data[CSUM_CHUNK])
|
||||
ctx->D += D;
|
||||
}
|
||||
|
||||
#if defined(HAVE_SIMD) && (CSUM_CHUNK == 64)
|
||||
extern void md5_process_asm(md_context *ctx, const void *data, size_t num);
|
||||
#endif
|
||||
|
||||
void md5_update(md_context *ctx, const uchar *input, uint32 length)
|
||||
{
|
||||
uint32 left, fill;
|
||||
@@ -170,11 +176,20 @@ void md5_update(md_context *ctx, const uchar *input, uint32 length)
|
||||
left = 0;
|
||||
}
|
||||
|
||||
#if defined(HAVE_SIMD) && (CSUM_CHUNK == 64)
|
||||
if (length >= CSUM_CHUNK) {
|
||||
uint32 chunks = length / CSUM_CHUNK;
|
||||
md5_process_asm(ctx, input, chunks);
|
||||
length -= chunks * CSUM_CHUNK;
|
||||
input += chunks * CSUM_CHUNK;
|
||||
}
|
||||
#else
|
||||
while (length >= CSUM_CHUNK) {
|
||||
md5_process(ctx, input);
|
||||
length -= CSUM_CHUNK;
|
||||
input += CSUM_CHUNK;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (length)
|
||||
memcpy(ctx->buffer + left, input, length);
|
||||
@@ -206,6 +221,9 @@ void md5_result(md_context *ctx, uchar digest[MD5_DIGEST_LEN])
|
||||
SIVALu(digest, 8, ctx->C);
|
||||
SIVALu(digest, 12, ctx->D);
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef TEST_MD5
|
||||
|
||||
void get_md5(uchar *out, const uchar *input, int n)
|
||||
{
|
||||
@@ -215,8 +233,6 @@ void get_md5(uchar *out, const uchar *input, int n)
|
||||
md5_result(&ctx, out);
|
||||
}
|
||||
|
||||
#ifdef TEST_MD5
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
* An implementation of MD4 designed for use in the SMB authentication protocol.
|
||||
*
|
||||
* Copyright (C) 1997-1998 Andrew Tridgell
|
||||
* Copyright (C) 2005-2014 Wayne Davison
|
||||
* Copyright (C) 2005-2020 Wayne Davison
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
@@ -193,6 +193,8 @@ void mdfour_result(md_context *md, uchar digest[MD4_DIGEST_LEN])
|
||||
copy4(digest+12, m->D);
|
||||
}
|
||||
|
||||
#ifdef TEST_MDFOUR
|
||||
|
||||
void mdfour(uchar digest[MD4_DIGEST_LEN], uchar *in, int length)
|
||||
{
|
||||
md_context md;
|
||||
@@ -201,7 +203,6 @@ void mdfour(uchar digest[MD4_DIGEST_LEN], uchar *in, int length)
|
||||
mdfour_result(&md, digest);
|
||||
}
|
||||
|
||||
#ifdef TEST_MDFOUR
|
||||
int protocol_version = 28;
|
||||
|
||||
static void file_checksum1(char *fname)
|
||||
|
||||
@@ -1,11 +1,24 @@
|
||||
/* The include file for both the MD4 and MD5 routines. */
|
||||
|
||||
#ifdef USE_OPENSSL
|
||||
#include "openssl/md4.h"
|
||||
#include "openssl/md5.h"
|
||||
#endif
|
||||
|
||||
#define MD4_DIGEST_LEN 16
|
||||
#define MD5_DIGEST_LEN 16
|
||||
#define MAX_DIGEST_LEN MD5_DIGEST_LEN
|
||||
|
||||
#define CSUM_CHUNK 64
|
||||
|
||||
#define CSUM_NONE 0
|
||||
#define CSUM_MD4_ARCHAIC 1
|
||||
#define CSUM_MD4_BUSTED 2
|
||||
#define CSUM_MD4_OLD 3
|
||||
#define CSUM_MD4 4
|
||||
#define CSUM_MD5 5
|
||||
#define CSUM_XXH64 6
|
||||
|
||||
typedef struct {
|
||||
uint32 A, B, C, D;
|
||||
uint32 totalN; /* bit count, lower 32 bits */
|
||||
@@ -17,10 +30,13 @@ void mdfour_begin(md_context *md);
|
||||
void mdfour_update(md_context *md, const uchar *in, uint32 length);
|
||||
void mdfour_result(md_context *md, uchar digest[MD4_DIGEST_LEN]);
|
||||
|
||||
void get_mdfour(uchar digest[MD4_DIGEST_LEN], const uchar *in, int length);
|
||||
#ifndef USE_OPENSSL
|
||||
#define MD5_CTX md_context
|
||||
#define MD5_Init md5_begin
|
||||
#define MD5_Update md5_update
|
||||
#define MD5_Final(digest, cptr) md5_result(cptr, digest)
|
||||
|
||||
void md5_begin(md_context *ctx);
|
||||
void md5_update(md_context *ctx, const uchar *input, uint32 length);
|
||||
void md5_result(md_context *ctx, uchar digest[MD5_DIGEST_LEN]);
|
||||
|
||||
void get_md5(uchar digest[MD5_DIGEST_LEN], const uchar *input, int n);
|
||||
#endif
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
* Copyright (C) 1996 Andrew Tridgell
|
||||
* Copyright (C) 1996 Paul Mackerras
|
||||
* Copyright (C) 2001 Martin Pool <mbp@samba.org>
|
||||
* Copyright (C) 2003-2014 Wayne Davison
|
||||
* Copyright (C) 2003-2019 Wayne Davison
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
|
||||
@@ -49,15 +49,15 @@ pool_create(size_t size, size_t quantum, void (*bomb)(const char *), int flags)
|
||||
{
|
||||
struct alloc_pool *pool;
|
||||
|
||||
if (!(pool = new0(struct alloc_pool)))
|
||||
return NULL;
|
||||
|
||||
if ((MINALIGN & (MINALIGN - 1)) != 0) {
|
||||
if (bomb)
|
||||
(*bomb)("Compiler error: MINALIGN is not a power of 2\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (!(pool = new0(struct alloc_pool)))
|
||||
return NULL;
|
||||
|
||||
if (!size)
|
||||
size = POOL_DEF_EXTENT;
|
||||
if (!quantum)
|
||||
|
||||
@@ -34,7 +34,7 @@
|
||||
* probably requires libm on most operating systems. Don't yet
|
||||
* support the exponent (e,E) and sigfig (g,G). Also, fmtint()
|
||||
* was pretty badly broken, it just wasn't being exercised in ways
|
||||
* which showed it, so that's been fixed. Also, formated the code
|
||||
* which showed it, so that's been fixed. Also, formatted the code
|
||||
* to mutt conventions, and removed dead code left over from the
|
||||
* original. Also, there is now a builtin-test, just compile with:
|
||||
* gcc -I.. -DTEST_SNPRINTF -o snprintf snprintf.c -lm
|
||||
@@ -77,7 +77,7 @@
|
||||
* Fix incorrect zpadlen handling in fmtfp.
|
||||
* Thanks to Ollie Oldham <ollie.oldham@metro-optix.com> for spotting it.
|
||||
* few mods to make it easier to compile the tests.
|
||||
* addedd the "Ollie" test to the floating point ones.
|
||||
* added the "Ollie" test to the floating point ones.
|
||||
*
|
||||
* Martin Pool (mbp@samba.org) April 2003
|
||||
* Remove NO_CONFIG_H so that the test case can be built within a source
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
* Unix SMB/CIFS implementation.
|
||||
* Based on the Samba ACL support code.
|
||||
* Copyright (C) Jeremy Allison 2000.
|
||||
* Copyright (C) 2007-2014 Wayne Davison
|
||||
* Copyright (C) 2007-2020 Wayne Davison
|
||||
*
|
||||
* The permission functions have been changed to get/set all bits via
|
||||
* one call. Some functions that rsync doesn't need were also removed.
|
||||
@@ -450,7 +450,7 @@ SMB_ACL_T sys_acl_get_file(const char *path_p, SMB_ACL_TYPE_T type)
|
||||
*
|
||||
* Note: we assume that the acl() system call returned a
|
||||
* well formed ACL which is sorted so that all of the
|
||||
* access ACL entries preceed any default ACL entries
|
||||
* access ACL entries precede any default ACL entries
|
||||
*/
|
||||
for (naccess = 0; naccess < count; naccess++) {
|
||||
if (acl_d->acl[naccess].a_type & ACL_DEFAULT)
|
||||
@@ -932,7 +932,7 @@ SMB_ACL_T sys_acl_get_file(const char *path_p, SMB_ACL_TYPE_T type)
|
||||
*
|
||||
* Note: we assume that the acl() system call returned a
|
||||
* well formed ACL which is sorted so that all of the
|
||||
* access ACL entries preceed any default ACL entries
|
||||
* access ACL entries precede any default ACL entries
|
||||
*/
|
||||
for (naccess = 0; naccess < count; naccess++) {
|
||||
if (acl_d->acl[naccess].a_type & ACL_DEFAULT)
|
||||
@@ -1095,7 +1095,7 @@ struct hpux_acl_types {
|
||||
* structures.
|
||||
* Inputs:
|
||||
*
|
||||
* acl_count - Count of ACLs in the array of ACL strucutres.
|
||||
* acl_count - Count of ACLs in the array of ACL structures.
|
||||
* aclp - Array of ACL structures.
|
||||
* acl_type_count - Pointer to acl_types structure. Should already be
|
||||
* allocated.
|
||||
@@ -1256,7 +1256,7 @@ static int hpux_acl_sort(int acl_count, int calclass, struct acl *aclp)
|
||||
{
|
||||
#if !defined(HAVE_HPUX_ACLSORT)
|
||||
/*
|
||||
* The aclsort() system call is availabe on the latest HPUX General
|
||||
* The aclsort() system call is available on the latest HPUX General
|
||||
* Patch Bundles. So for HPUX, we developed our version of acl_sort
|
||||
* function. Because, we don't want to update to a new
|
||||
* HPUX GR bundle just for aclsort() call.
|
||||
@@ -1311,7 +1311,7 @@ or DEF_USER_OBJ or DEF_GROUP_OBJ or DEF_OTHER_OBJ\n"));
|
||||
* Sorting crieteria - First sort by ACL type. If there are multiple entries of
|
||||
* same ACL type, sort by ACL id.
|
||||
*
|
||||
* I am using the trival kind of sorting method here because, performance isn't
|
||||
* I am using the trivial kind of sorting method here because, performance isn't
|
||||
* really effected by the ACLs feature. More over there aren't going to be more
|
||||
* than 17 entries on HPUX.
|
||||
*/
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
* Version 2.2.x
|
||||
* Portable SMB ACL interface
|
||||
* Copyright (C) Jeremy Allison 2000
|
||||
* Copyright (C) 2007-2014 Wayne Davison
|
||||
* Copyright (C) 2007-2019 Wayne Davison
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
* Extended attribute support for rsync.
|
||||
*
|
||||
* Copyright (C) 2004 Red Hat, Inc.
|
||||
* Copyright (C) 2003-2014 Wayne Davison
|
||||
* Copyright (C) 2003-2019 Wayne Davison
|
||||
* Written by Jay Fenlason.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
|
||||
173
loadparm.c
173
loadparm.c
@@ -11,13 +11,12 @@
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, visit the http://fsf.org website.
|
||||
*/
|
||||
|
||||
/* This is based on loadparm.c from Samba, written by Andrew Tridgell
|
||||
*
|
||||
* This is based on loadparm.c from Samba, written by Andrew Tridgell
|
||||
* and Karl Auer. Some of the changes are:
|
||||
*
|
||||
* Copyright (C) 2001, 2002 Martin Pool <mbp@samba.org>
|
||||
* Copyright (C) 2003-2014 Wayne Davison <wayned@samba.org>
|
||||
* Copyright (C) 2003-2020 Wayne Davison
|
||||
*/
|
||||
|
||||
/* Load parameters.
|
||||
@@ -31,7 +30,7 @@
|
||||
* 1) add it to the global_vars or local_vars structure definition
|
||||
* 2) add it to the parm_table
|
||||
* 3) add it to the list of available functions (eg: using FN_GLOBAL_STRING())
|
||||
* 4) initialise it in the Defaults static stucture
|
||||
* 4) initialise it in the Defaults static structure
|
||||
*
|
||||
* Notes:
|
||||
* The configuration file is processed sequentially for speed. For this
|
||||
@@ -55,7 +54,8 @@ extern item_list dparam_list;
|
||||
|
||||
#define DEFAULT_DONT_COMPRESS "*.gz *.zip *.z *.rpm *.deb *.iso *.bz2" \
|
||||
" *.t[gb]z *.7z *.mp[34] *.mov *.avi *.ogg *.jpg *.jpeg *.png" \
|
||||
" *.lzo *.rzip *.lzma *.rar *.ace *.gpg *.xz *.txz *.lz *.tlz"
|
||||
" *.lzo *.rzip *.lzma *.rar *.ace *.gpg *.xz *.txz *.lz *.tlz" \
|
||||
" *.ogv *.web[mp] *.squashfs"
|
||||
|
||||
/* the following are used by loadparm for option lists */
|
||||
typedef enum {
|
||||
@@ -93,23 +93,38 @@ struct parm_struct {
|
||||
/* This structure describes global (ie., server-wide) parameters. */
|
||||
typedef struct {
|
||||
char *bind_address;
|
||||
char *daemon_chroot;
|
||||
char *daemon_gid;
|
||||
char *daemon_uid;
|
||||
char *motd_file;
|
||||
char *pid_file;
|
||||
char *socket_options;
|
||||
|
||||
/* Each _EXP var tracks if the associated char* var has been expanded yet or not. */
|
||||
BOOL bind_address_EXP;
|
||||
BOOL daemon_chroot_EXP;
|
||||
BOOL daemon_gid_EXP;
|
||||
BOOL daemon_uid_EXP;
|
||||
BOOL motd_file_EXP;
|
||||
BOOL pid_file_EXP;
|
||||
BOOL socket_options_EXP;
|
||||
|
||||
int listen_backlog;
|
||||
int rsync_port;
|
||||
|
||||
BOOL proxy_protocol;
|
||||
} global_vars;
|
||||
|
||||
/* This structure describes a single section. Their order must match the
|
||||
* initializers below, which you can accomplish by keeping each sub-section
|
||||
* sorted. (e.g. in vim, just visually select each subsection and use !sort.)
|
||||
* NOTE: the char* variables MUST all remain at the start of the stuct! */
|
||||
* NOTE: the char* variables MUST all remain at the start of the struct! */
|
||||
typedef struct {
|
||||
char *auth_users;
|
||||
char *charset;
|
||||
char *comment;
|
||||
char *dont_compress;
|
||||
char *early_exec;
|
||||
char *exclude;
|
||||
char *exclude_from;
|
||||
char *filter;
|
||||
@@ -129,10 +144,38 @@ typedef struct {
|
||||
char *prexfer_exec;
|
||||
char *refuse_options;
|
||||
char *secrets_file;
|
||||
char *syslog_tag;
|
||||
char *temp_dir;
|
||||
char *uid;
|
||||
/* NOTE: update this macro if the last char* variable changes! */
|
||||
#define LOCAL_STRING_COUNT() (offsetof(local_vars, uid) / sizeof (char*) + 1)
|
||||
|
||||
/* Each _EXP var tracks if the associated char* var has been expanded yet or not. */
|
||||
BOOL auth_users_EXP;
|
||||
BOOL charset_EXP;
|
||||
BOOL comment_EXP;
|
||||
BOOL dont_compress_EXP;
|
||||
BOOL early_exec_EXP;
|
||||
BOOL exclude_EXP;
|
||||
BOOL exclude_from_EXP;
|
||||
BOOL filter_EXP;
|
||||
BOOL gid_EXP;
|
||||
BOOL hosts_allow_EXP;
|
||||
BOOL hosts_deny_EXP;
|
||||
BOOL include_EXP;
|
||||
BOOL include_from_EXP;
|
||||
BOOL incoming_chmod_EXP;
|
||||
BOOL lock_file_EXP;
|
||||
BOOL log_file_EXP;
|
||||
BOOL log_format_EXP;
|
||||
BOOL name_EXP;
|
||||
BOOL outgoing_chmod_EXP;
|
||||
BOOL path_EXP;
|
||||
BOOL postxfer_exec_EXP;
|
||||
BOOL prexfer_exec_EXP;
|
||||
BOOL refuse_options_EXP;
|
||||
BOOL secrets_file_EXP;
|
||||
BOOL syslog_tag_EXP;
|
||||
BOOL temp_dir_EXP;
|
||||
BOOL uid_EXP;
|
||||
|
||||
int max_connections;
|
||||
int max_verbosity;
|
||||
@@ -172,12 +215,25 @@ static const all_vars Defaults = {
|
||||
/* ==== global_vars ==== */
|
||||
{
|
||||
/* bind_address; */ NULL,
|
||||
/* daemon_chroot; */ NULL,
|
||||
/* daemon_gid; */ NULL,
|
||||
/* daemon_uid; */ NULL,
|
||||
/* motd_file; */ NULL,
|
||||
/* pid_file; */ NULL,
|
||||
/* socket_options; */ NULL,
|
||||
|
||||
/* bind_address_EXP; */ False,
|
||||
/* daemon_chroot_EXP; */ False,
|
||||
/* daemon_gid_EXP; */ False,
|
||||
/* daemon_uid_EXP; */ False,
|
||||
/* motd_file_EXP; */ False,
|
||||
/* pid_file_EXP; */ False,
|
||||
/* socket_options_EXP; */ False,
|
||||
|
||||
/* listen_backlog; */ 5,
|
||||
/* rsync_port; */ 0,
|
||||
|
||||
/* proxy_protocol; */ False,
|
||||
},
|
||||
|
||||
/* ==== local_vars ==== */
|
||||
@@ -186,7 +242,8 @@ static const all_vars Defaults = {
|
||||
/* charset; */ NULL,
|
||||
/* comment; */ NULL,
|
||||
/* dont_compress; */ DEFAULT_DONT_COMPRESS,
|
||||
/* exclude; */ NULL,
|
||||
/* early_exec; */ NULL,
|
||||
/* exclude; */ NULL,
|
||||
/* exclude_from; */ NULL,
|
||||
/* filter; */ NULL,
|
||||
/* gid; */ NULL,
|
||||
@@ -205,9 +262,38 @@ static const all_vars Defaults = {
|
||||
/* prexfer_exec; */ NULL,
|
||||
/* refuse_options; */ NULL,
|
||||
/* secrets_file; */ NULL,
|
||||
/* syslog_tag; */ "rsyncd",
|
||||
/* temp_dir; */ NULL,
|
||||
/* uid; */ NULL,
|
||||
|
||||
/* auth_users_EXP; */ False,
|
||||
/* charset_EXP; */ False,
|
||||
/* comment_EXP; */ False,
|
||||
/* dont_compress_EXP; */ False,
|
||||
/* early_exec_EXP; */ False,
|
||||
/* exclude_EXP; */ False,
|
||||
/* exclude_from_EXP; */ False,
|
||||
/* filter_EXP; */ False,
|
||||
/* gid_EXP; */ False,
|
||||
/* hosts_allow_EXP; */ False,
|
||||
/* hosts_deny_EXP; */ False,
|
||||
/* include_EXP; */ False,
|
||||
/* include_from_EXP; */ False,
|
||||
/* incoming_chmod_EXP; */ False,
|
||||
/* lock_file_EXP; */ False,
|
||||
/* log_file_EXP; */ False,
|
||||
/* log_format_EXP; */ False,
|
||||
/* name_EXP; */ False,
|
||||
/* outgoing_chmod_EXP; */ False,
|
||||
/* path_EXP; */ False,
|
||||
/* postxfer_exec_EXP; */ False,
|
||||
/* prexfer_exec_EXP; */ False,
|
||||
/* refuse_options_EXP; */ False,
|
||||
/* secrets_file_EXP; */ False,
|
||||
/* syslog_tag_EXP; */ False,
|
||||
/* temp_dir_EXP; */ False,
|
||||
/* uid_EXP; */ False,
|
||||
|
||||
/* max_connections; */ 0,
|
||||
/* max_verbosity; */ 1,
|
||||
/* syslog_facility; */ LOG_DAEMON,
|
||||
@@ -313,16 +399,21 @@ static struct enum_list enum_facilities[] = {
|
||||
static struct parm_struct parm_table[] =
|
||||
{
|
||||
{"address", P_STRING, P_GLOBAL,&Vars.g.bind_address, NULL,0},
|
||||
{"daemon chroot", P_STRING, P_GLOBAL,&Vars.g.daemon_chroot, NULL,0},
|
||||
{"daemon gid", P_STRING, P_GLOBAL,&Vars.g.daemon_gid, NULL,0},
|
||||
{"daemon uid", P_STRING, P_GLOBAL,&Vars.g.daemon_uid, NULL,0},
|
||||
{"listen backlog", P_INTEGER,P_GLOBAL,&Vars.g.listen_backlog, NULL,0},
|
||||
{"motd file", P_STRING, P_GLOBAL,&Vars.g.motd_file, NULL,0},
|
||||
{"pid file", P_STRING, P_GLOBAL,&Vars.g.pid_file, NULL,0},
|
||||
{"port", P_INTEGER,P_GLOBAL,&Vars.g.rsync_port, NULL,0},
|
||||
{"proxy protocol", P_BOOL, P_LOCAL, &Vars.g.proxy_protocol, NULL,0},
|
||||
{"socket options", P_STRING, P_GLOBAL,&Vars.g.socket_options, NULL,0},
|
||||
|
||||
{"auth users", P_STRING, P_LOCAL, &Vars.l.auth_users, NULL,0},
|
||||
{"charset", P_STRING, P_LOCAL, &Vars.l.charset, NULL,0},
|
||||
{"comment", P_STRING, P_LOCAL, &Vars.l.comment, NULL,0},
|
||||
{"dont compress", P_STRING, P_LOCAL, &Vars.l.dont_compress, NULL,0},
|
||||
{"early exec", P_STRING, P_LOCAL, &Vars.l.early_exec, NULL,0},
|
||||
{"exclude from", P_STRING, P_LOCAL, &Vars.l.exclude_from, NULL,0},
|
||||
{"exclude", P_STRING, P_LOCAL, &Vars.l.exclude, NULL,0},
|
||||
{"fake super", P_BOOL, P_LOCAL, &Vars.l.fake_super, NULL,0},
|
||||
@@ -357,6 +448,7 @@ static struct parm_struct parm_table[] =
|
||||
{"secrets file", P_STRING, P_LOCAL, &Vars.l.secrets_file, NULL,0},
|
||||
{"strict modes", P_BOOL, P_LOCAL, &Vars.l.strict_modes, NULL,0},
|
||||
{"syslog facility", P_ENUM, P_LOCAL, &Vars.l.syslog_facility, enum_facilities,0},
|
||||
{"syslog tag", P_STRING, P_LOCAL, &Vars.l.syslog_tag, NULL,0},
|
||||
{"temp dir", P_PATH, P_LOCAL, &Vars.l.temp_dir, NULL,0},
|
||||
{"timeout", P_INTEGER,P_LOCAL, &Vars.l.timeout, NULL,0},
|
||||
{"transfer logging", P_BOOL, P_LOCAL, &Vars.l.transfer_logging, NULL,0},
|
||||
@@ -367,7 +459,7 @@ static struct parm_struct parm_table[] =
|
||||
};
|
||||
|
||||
/* Initialise the Default all_vars structure. */
|
||||
static void reset_all_vars(void)
|
||||
void reset_daemon_vars(void)
|
||||
{
|
||||
memcpy(&Vars, &Defaults, sizeof Vars);
|
||||
}
|
||||
@@ -379,7 +471,7 @@ static char *expand_vars(char *str)
|
||||
char *buf, *t, *f;
|
||||
int bufsize;
|
||||
|
||||
if (strchr(str, '%') == NULL)
|
||||
if (!str || !strchr(str, '%'))
|
||||
return str;
|
||||
|
||||
bufsize = strlen(str) + 2048;
|
||||
@@ -422,20 +514,23 @@ static char *expand_vars(char *str)
|
||||
return buf;
|
||||
}
|
||||
|
||||
/* NOTE: use this function and all the FN_{GLOBAL,LOCAL} ones WITHOUT a trailing semicolon! */
|
||||
#define RETURN_EXPANDED(val) {if (!val ## _EXP) {val = expand_vars(val); val ## _EXP = True;} return val ? val : "";}
|
||||
|
||||
/* In this section all the functions that are used to access the
|
||||
* parameters from the rest of the program are defined. */
|
||||
|
||||
#define FN_GLOBAL_STRING(fn_name, ptr) \
|
||||
char *fn_name(void) {return expand_vars(*(char **)(ptr) ? *(char **)(ptr) : "");}
|
||||
#define FN_GLOBAL_BOOL(fn_name, ptr) \
|
||||
BOOL fn_name(void) {return *(BOOL *)(ptr);}
|
||||
#define FN_GLOBAL_CHAR(fn_name, ptr) \
|
||||
char fn_name(void) {return *(char *)(ptr);}
|
||||
#define FN_GLOBAL_INTEGER(fn_name, ptr) \
|
||||
int fn_name(void) {return *(int *)(ptr);}
|
||||
#define FN_GLOBAL_STRING(fn_name, val) \
|
||||
char *fn_name(void) RETURN_EXPANDED(Vars.g.val)
|
||||
#define FN_GLOBAL_BOOL(fn_name, val) \
|
||||
BOOL fn_name(void) {return Vars.g.val;}
|
||||
#define FN_GLOBAL_CHAR(fn_name, val) \
|
||||
char fn_name(void) {return Vars.g.val;}
|
||||
#define FN_GLOBAL_INTEGER(fn_name, val) \
|
||||
int fn_name(void) {return Vars.g.val;}
|
||||
|
||||
#define FN_LOCAL_STRING(fn_name, val) \
|
||||
char *fn_name(int i) {return expand_vars(LP_SNUM_OK(i) && iSECTION(i).val ? iSECTION(i).val : Vars.l.val ? Vars.l.val : "");}
|
||||
char *fn_name(int i) {if (LP_SNUM_OK(i) && iSECTION(i).val) RETURN_EXPANDED(iSECTION(i).val) else RETURN_EXPANDED(Vars.l.val)}
|
||||
#define FN_LOCAL_BOOL(fn_name, val) \
|
||||
BOOL fn_name(int i) {return LP_SNUM_OK(i)? iSECTION(i).val : Vars.l.val;}
|
||||
#define FN_LOCAL_CHAR(fn_name, val) \
|
||||
@@ -443,18 +538,24 @@ static char *expand_vars(char *str)
|
||||
#define FN_LOCAL_INTEGER(fn_name, val) \
|
||||
int fn_name(int i) {return LP_SNUM_OK(i)? iSECTION(i).val : Vars.l.val;}
|
||||
|
||||
FN_GLOBAL_STRING(lp_bind_address, &Vars.g.bind_address)
|
||||
FN_GLOBAL_STRING(lp_motd_file, &Vars.g.motd_file)
|
||||
FN_GLOBAL_STRING(lp_pid_file, &Vars.g.pid_file)
|
||||
FN_GLOBAL_STRING(lp_socket_options, &Vars.g.socket_options)
|
||||
FN_GLOBAL_STRING(lp_bind_address, bind_address)
|
||||
FN_GLOBAL_STRING(lp_daemon_chroot, daemon_chroot)
|
||||
FN_GLOBAL_STRING(lp_daemon_gid, daemon_gid)
|
||||
FN_GLOBAL_STRING(lp_daemon_uid, daemon_uid)
|
||||
FN_GLOBAL_STRING(lp_motd_file, motd_file)
|
||||
FN_GLOBAL_STRING(lp_pid_file, pid_file)
|
||||
FN_GLOBAL_STRING(lp_socket_options, socket_options)
|
||||
|
||||
FN_GLOBAL_INTEGER(lp_listen_backlog, &Vars.g.listen_backlog)
|
||||
FN_GLOBAL_INTEGER(lp_rsync_port, &Vars.g.rsync_port)
|
||||
FN_GLOBAL_INTEGER(lp_listen_backlog, listen_backlog)
|
||||
FN_GLOBAL_INTEGER(lp_rsync_port, rsync_port)
|
||||
|
||||
FN_GLOBAL_BOOL(lp_proxy_protocol, proxy_protocol)
|
||||
|
||||
FN_LOCAL_STRING(lp_auth_users, auth_users)
|
||||
FN_LOCAL_STRING(lp_charset, charset)
|
||||
FN_LOCAL_STRING(lp_comment, comment)
|
||||
FN_LOCAL_STRING(lp_dont_compress, dont_compress)
|
||||
FN_LOCAL_STRING(lp_early_exec, early_exec)
|
||||
FN_LOCAL_STRING(lp_exclude, exclude)
|
||||
FN_LOCAL_STRING(lp_exclude_from, exclude_from)
|
||||
FN_LOCAL_STRING(lp_filter, filter)
|
||||
@@ -474,6 +575,7 @@ FN_LOCAL_STRING(lp_postxfer_exec, postxfer_exec)
|
||||
FN_LOCAL_STRING(lp_prexfer_exec, prexfer_exec)
|
||||
FN_LOCAL_STRING(lp_refuse_options, refuse_options)
|
||||
FN_LOCAL_STRING(lp_secrets_file, secrets_file)
|
||||
FN_LOCAL_STRING(lp_syslog_tag, syslog_tag)
|
||||
FN_LOCAL_STRING(lp_temp_dir, temp_dir)
|
||||
FN_LOCAL_STRING(lp_uid, uid)
|
||||
|
||||
@@ -509,19 +611,10 @@ static inline void string_set(char **s, const char *v)
|
||||
out_of_memory("string_set");
|
||||
}
|
||||
|
||||
/* Copy the local_vars, strdup'ing any strings. NOTE: this depends on
|
||||
* the structure starting with a contiguous list of the char* variables,
|
||||
* and having an accurate count in the LOCAL_STRING_COUNT() macro. */
|
||||
/* Copy local_vars into a new section. No need to strdup since we don't free. */
|
||||
static void copy_section(local_vars *psectionDest, local_vars *psectionSource)
|
||||
{
|
||||
int count = LOCAL_STRING_COUNT();
|
||||
char **strings = (char**)psectionDest;
|
||||
|
||||
memcpy(psectionDest, psectionSource, sizeof psectionDest[0]);
|
||||
while (count--) {
|
||||
if (strings[count] && !(strings[count] = strdup(strings[count])))
|
||||
out_of_memory("copy_section");
|
||||
}
|
||||
}
|
||||
|
||||
/* Initialise a section to the defaults. */
|
||||
@@ -664,10 +757,10 @@ static BOOL do_parameter(char *parmname, char *parmvalue)
|
||||
switch (parm_table[parmnum].type) {
|
||||
case P_PATH:
|
||||
case P_STRING:
|
||||
/* delay expansion of vars */
|
||||
/* delay expansion of %VAR% strings */
|
||||
break;
|
||||
default:
|
||||
/* expand any %VARS% now */
|
||||
/* expand any %VAR% strings now */
|
||||
parmvalue = expand_vars(parmvalue);
|
||||
break;
|
||||
}
|
||||
@@ -792,7 +885,7 @@ int lp_load(char *pszFname, int globals_only)
|
||||
{
|
||||
bInGlobalSection = True;
|
||||
|
||||
reset_all_vars();
|
||||
reset_daemon_vars();
|
||||
|
||||
/* We get sections first, so have to start 'behind' to make up. */
|
||||
iSectionIndex = -1;
|
||||
|
||||
199
log.c
199
log.c
@@ -3,7 +3,7 @@
|
||||
*
|
||||
* Copyright (C) 1998-2001 Andrew Tridgell <tridge@samba.org>
|
||||
* Copyright (C) 2000-2001 Martin Pool <mbp@samba.org>
|
||||
* Copyright (C) 2003-2014 Wayne Davison
|
||||
* Copyright (C) 2003-2020 Wayne Davison
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
@@ -31,12 +31,13 @@ extern int am_generator;
|
||||
extern int local_server;
|
||||
extern int quiet;
|
||||
extern int module_id;
|
||||
extern int checksum_len;
|
||||
extern int allow_8bit_chars;
|
||||
extern int protocol_version;
|
||||
extern int always_checksum;
|
||||
extern int preserve_times;
|
||||
extern int msgs2stderr;
|
||||
extern int xfersum_type;
|
||||
extern int checksum_type;
|
||||
extern int stdout_format_has_i;
|
||||
extern int stdout_format_has_o_or_i;
|
||||
extern int logfile_format_has_i;
|
||||
@@ -74,8 +75,8 @@ static int64 initial_data_written;
|
||||
static int64 initial_data_read;
|
||||
|
||||
struct {
|
||||
int code;
|
||||
char const *name;
|
||||
int code;
|
||||
char const *name;
|
||||
} const rerr_names[] = {
|
||||
{ RERR_SYNTAX , "syntax or usage error" },
|
||||
{ RERR_PROTOCOL , "protocol incompatibility" },
|
||||
@@ -132,21 +133,16 @@ static void logit(int priority, const char *buf)
|
||||
|
||||
static void syslog_init()
|
||||
{
|
||||
static int been_here = 0;
|
||||
int options = LOG_PID;
|
||||
|
||||
if (been_here)
|
||||
return;
|
||||
been_here = 1;
|
||||
|
||||
#ifdef LOG_NDELAY
|
||||
options |= LOG_NDELAY;
|
||||
#endif
|
||||
|
||||
#ifdef LOG_DAEMON
|
||||
openlog("rsyncd", options, lp_syslog_facility(module_id));
|
||||
openlog(lp_syslog_tag(module_id), options, lp_syslog_facility(module_id));
|
||||
#else
|
||||
openlog("rsyncd", options);
|
||||
openlog(lp_syslog_tag(module_id), options);
|
||||
#endif
|
||||
|
||||
#ifndef LOG_NDELAY
|
||||
@@ -166,14 +162,16 @@ static void logfile_open(void)
|
||||
rsyserr(FERROR, fopen_errno,
|
||||
"failed to open log-file %s", logfile_name);
|
||||
rprintf(FINFO, "Ignoring \"log file\" setting.\n");
|
||||
logfile_name = "";
|
||||
}
|
||||
}
|
||||
|
||||
void log_init(int restart)
|
||||
{
|
||||
if (log_initialised) {
|
||||
if (!restart)
|
||||
if (!restart) /* Note: a restart only happens with am_daemon */
|
||||
return;
|
||||
assert(logfile_name); /* all am_daemon procs got at least an empty string */
|
||||
if (strcmp(logfile_name, lp_log_file(module_id)) != 0) {
|
||||
if (logfile_fp) {
|
||||
fclose(logfile_fp);
|
||||
@@ -183,7 +181,8 @@ void log_init(int restart)
|
||||
logfile_name = NULL;
|
||||
} else if (*logfile_name)
|
||||
return; /* unchanged, non-empty "log file" names */
|
||||
else if (lp_syslog_facility(-1) != lp_syslog_facility(module_id))
|
||||
else if (lp_syslog_facility(-1) != lp_syslog_facility(module_id)
|
||||
|| strcmp(lp_syslog_tag(-1), lp_syslog_tag(module_id)) != 0)
|
||||
closelog();
|
||||
else
|
||||
return; /* unchanged syslog settings */
|
||||
@@ -205,6 +204,7 @@ void log_init(int restart)
|
||||
syslog_init();
|
||||
}
|
||||
|
||||
/* Note that this close & reopen idiom intentionally ignores syslog logging. */
|
||||
void logfile_close(void)
|
||||
{
|
||||
if (logfile_fp) {
|
||||
@@ -222,25 +222,26 @@ void logfile_reopen(void)
|
||||
}
|
||||
}
|
||||
|
||||
static void filtered_fwrite(FILE *f, const char *buf, int len, int use_isprint)
|
||||
static void filtered_fwrite(FILE *f, const char *in_buf, int in_len, int use_isprint, char end_char)
|
||||
{
|
||||
const char *s, *end = buf + len;
|
||||
for (s = buf; s < end; s++) {
|
||||
if ((s < end - 4
|
||||
&& *s == '\\' && s[1] == '#'
|
||||
&& isDigit(s + 2)
|
||||
&& isDigit(s + 3)
|
||||
&& isDigit(s + 4))
|
||||
|| (*s != '\t'
|
||||
&& ((use_isprint && !isPrint(s))
|
||||
|| *(uchar*)s < ' '))) {
|
||||
if (s != buf && fwrite(buf, s - buf, 1, f) != 1)
|
||||
char outbuf[1024], *ob = outbuf;
|
||||
const char *end = in_buf + in_len;
|
||||
while (in_buf < end) {
|
||||
if (ob - outbuf >= (int)sizeof outbuf - 10) {
|
||||
if (fwrite(outbuf, ob - outbuf, 1, f) != 1)
|
||||
exit_cleanup(RERR_MESSAGEIO);
|
||||
fprintf(f, "\\#%03o", *(uchar*)s);
|
||||
buf = s + 1;
|
||||
ob = outbuf;
|
||||
}
|
||||
if ((in_buf < end - 4 && *in_buf == '\\' && in_buf[1] == '#'
|
||||
&& isDigit(in_buf + 2) && isDigit(in_buf + 3) && isDigit(in_buf + 4))
|
||||
|| (*in_buf != '\t' && ((use_isprint && !isPrint(in_buf)) || *(uchar*)in_buf < ' ')))
|
||||
ob += snprintf(ob, 6, "\\#%03o", *(uchar*)in_buf++);
|
||||
else
|
||||
*ob++ = *in_buf++;
|
||||
}
|
||||
if (buf != end && fwrite(buf, end - buf, 1, f) != 1)
|
||||
if (end_char) /* The "- 10" above means that there is always room for one more char here. */
|
||||
*ob++ = end_char;
|
||||
if (ob != outbuf && fwrite(outbuf, ob - outbuf, 1, f) != 1)
|
||||
exit_cleanup(RERR_MESSAGEIO);
|
||||
}
|
||||
|
||||
@@ -249,7 +250,7 @@ static void filtered_fwrite(FILE *f, const char *buf, int len, int use_isprint)
|
||||
* can happen with certain fatal conditions. */
|
||||
void rwrite(enum logcode code, const char *buf, int len, int is_utf8)
|
||||
{
|
||||
int trailing_CR_or_NL;
|
||||
char trailing_CR_or_NL;
|
||||
FILE *f = msgs2stderr ? stderr : stdout;
|
||||
#ifdef ICONV_OPTION
|
||||
iconv_t ic = is_utf8 && ic_recv != (iconv_t)-1 ? ic_recv : ic_chck;
|
||||
@@ -263,14 +264,13 @@ void rwrite(enum logcode code, const char *buf, int len, int is_utf8)
|
||||
exit_cleanup(RERR_MESSAGEIO);
|
||||
|
||||
if (msgs2stderr) {
|
||||
if (!am_daemon) {
|
||||
if (code == FLOG)
|
||||
return;
|
||||
goto output_msg;
|
||||
}
|
||||
if (code == FCLIENT)
|
||||
return;
|
||||
code = FLOG;
|
||||
/* A normal daemon can get msgs2stderr set if the socket is busted, so we
|
||||
* change the message destination into an FLOG message in order to try to
|
||||
* get some info about an abnormal-exit into the log file. An rsh daemon
|
||||
* can have this set via user request, so we'll leave the code alone so
|
||||
* that the msg gets logged and then sent to stderr after that. */
|
||||
if (am_daemon > 0 && code != FCLIENT)
|
||||
code = FLOG;
|
||||
} else if (send_msgs_to_gen) {
|
||||
assert(!is_utf8);
|
||||
/* Pass the message to our sibling in native charset. */
|
||||
@@ -306,10 +306,28 @@ void rwrite(enum logcode code, const char *buf, int len, int is_utf8)
|
||||
} else if (code == FLOG)
|
||||
return;
|
||||
|
||||
if (quiet && code == FINFO)
|
||||
return;
|
||||
switch (code) {
|
||||
case FERROR_XFER:
|
||||
got_xfer_error = 1;
|
||||
/* FALL THROUGH */
|
||||
case FERROR:
|
||||
case FWARNING:
|
||||
f = stderr;
|
||||
break;
|
||||
case FINFO:
|
||||
if (quiet)
|
||||
return;
|
||||
break;
|
||||
/*case FLOG:*/
|
||||
/*case FCLIENT:*/
|
||||
/*case FERROR_UTF8:*/
|
||||
/*case FERROR_SOCKET:*/
|
||||
default:
|
||||
fprintf(stderr, "Bad logcode in rwrite(): %d [%s]\n", (int)code, who_am_i());
|
||||
exit_cleanup(RERR_MESSAGEIO);
|
||||
}
|
||||
|
||||
if (am_server) {
|
||||
if (am_server && !msgs2stderr) {
|
||||
enum msgcode msg = (enum msgcode)code;
|
||||
if (protocol_version < 30) {
|
||||
if (msg == MSG_ERROR)
|
||||
@@ -320,33 +338,13 @@ void rwrite(enum logcode code, const char *buf, int len, int is_utf8)
|
||||
/* Pass the message to the non-server side. */
|
||||
if (send_msg(msg, buf, len, !is_utf8))
|
||||
return;
|
||||
if (am_daemon) {
|
||||
if (am_daemon > 0) {
|
||||
/* TODO: can we send the error to the user somehow? */
|
||||
return;
|
||||
}
|
||||
f = stderr;
|
||||
}
|
||||
|
||||
output_msg:
|
||||
switch (code) {
|
||||
case FERROR_XFER:
|
||||
got_xfer_error = 1;
|
||||
/* FALL THROUGH */
|
||||
case FERROR:
|
||||
case FERROR_UTF8:
|
||||
case FERROR_SOCKET:
|
||||
case FWARNING:
|
||||
f = stderr;
|
||||
break;
|
||||
case FLOG:
|
||||
case FINFO:
|
||||
case FCLIENT:
|
||||
break;
|
||||
default:
|
||||
fprintf(stderr, "Unknown logcode in rwrite(): %d [%s]\n", (int)code, who_am_i());
|
||||
exit_cleanup(RERR_MESSAGEIO);
|
||||
}
|
||||
|
||||
if (output_needs_newline) {
|
||||
fputc('\n', f);
|
||||
output_needs_newline = 0;
|
||||
@@ -374,21 +372,28 @@ output_msg:
|
||||
iconvbufs(ic, &inbuf, &outbuf, inbuf.pos ? 0 : ICB_INIT);
|
||||
ierrno = errno;
|
||||
if (outbuf.len) {
|
||||
filtered_fwrite(f, convbuf, outbuf.len, 0);
|
||||
filtered_fwrite(f, convbuf, outbuf.len, 0, 0);
|
||||
outbuf.len = 0;
|
||||
}
|
||||
if (!ierrno || ierrno == E2BIG)
|
||||
continue;
|
||||
fprintf(f, "\\#%03o", CVAL(inbuf.buf, inbuf.pos++));
|
||||
inbuf.len--;
|
||||
/* Log one byte of illegal/incomplete sequence and continue with
|
||||
* the next character. Check that the buffer is non-empty for the
|
||||
* sake of robustness. */
|
||||
if ((ierrno == EILSEQ || ierrno == EINVAL) && inbuf.len) {
|
||||
fprintf(f, "\\#%03o", CVAL(inbuf.buf, inbuf.pos++));
|
||||
inbuf.len--;
|
||||
}
|
||||
}
|
||||
|
||||
if (trailing_CR_or_NL) {
|
||||
fputc(trailing_CR_or_NL, f);
|
||||
fflush(f);
|
||||
}
|
||||
} else
|
||||
#endif
|
||||
filtered_fwrite(f, buf, len, !allow_8bit_chars);
|
||||
|
||||
if (trailing_CR_or_NL) {
|
||||
fputc(trailing_CR_or_NL, f);
|
||||
fflush(f);
|
||||
{
|
||||
filtered_fwrite(f, buf, len, !allow_8bit_chars, trailing_CR_or_NL);
|
||||
if (trailing_CR_or_NL)
|
||||
fflush(f);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -447,8 +452,7 @@ void rsyserr(enum logcode code, int errcode, const char *format, ...)
|
||||
char buf[BIGPATHBUFLEN];
|
||||
size_t len;
|
||||
|
||||
strlcpy(buf, RSYNC_NAME ": ", sizeof buf);
|
||||
len = (sizeof RSYNC_NAME ": ") - 1;
|
||||
len = snprintf(buf, sizeof buf, RSYNC_NAME ": [%s] ", who_am_i());
|
||||
|
||||
va_start(ap, format);
|
||||
len += vsnprintf(buf + len, sizeof buf - len, format, ap);
|
||||
@@ -656,21 +660,10 @@ static void log_formatted(enum logcode code, const char *format, const char *op,
|
||||
n = auth_user;
|
||||
break;
|
||||
case 'b':
|
||||
if (!(iflags & ITEM_TRANSFER))
|
||||
b = 0;
|
||||
else if (am_sender)
|
||||
b = total_data_written - initial_data_written;
|
||||
else
|
||||
b = total_data_read - initial_data_read;
|
||||
strlcat(fmt, "s", sizeof fmt);
|
||||
snprintf(buf2, sizeof buf2, fmt,
|
||||
do_big_num(b, humanize, NULL));
|
||||
n = buf2;
|
||||
break;
|
||||
case 'c':
|
||||
if (!(iflags & ITEM_TRANSFER))
|
||||
b = 0;
|
||||
else if (!am_sender)
|
||||
else if ((!!am_sender) ^ (*p == 'c'))
|
||||
b = total_data_written - initial_data_written;
|
||||
else
|
||||
b = total_data_read - initial_data_read;
|
||||
@@ -680,15 +673,18 @@ static void log_formatted(enum logcode code, const char *format, const char *op,
|
||||
n = buf2;
|
||||
break;
|
||||
case 'C':
|
||||
if (protocol_version >= 30
|
||||
&& (iflags & ITEM_TRANSFER
|
||||
|| (always_checksum && S_ISREG(file->mode)))) {
|
||||
const char *sum = iflags & ITEM_TRANSFER
|
||||
? sender_file_sum : F_SUM(file);
|
||||
n = sum_as_hex(sum);
|
||||
} else {
|
||||
memset(buf2, ' ', checksum_len*2);
|
||||
buf2[checksum_len*2] = '\0';
|
||||
n = NULL;
|
||||
if (S_ISREG(file->mode)) {
|
||||
if (always_checksum)
|
||||
n = sum_as_hex(checksum_type, F_SUM(file), 1);
|
||||
else if (iflags & ITEM_TRANSFER)
|
||||
n = sum_as_hex(xfersum_type, sender_file_sum, 0);
|
||||
}
|
||||
if (!n) {
|
||||
int sum_len = csum_len_for_type(always_checksum ? checksum_type : xfersum_type,
|
||||
always_checksum);
|
||||
memset(buf2, ' ', sum_len*2);
|
||||
buf2[sum_len*2] = '\0';
|
||||
n = buf2;
|
||||
}
|
||||
break;
|
||||
@@ -699,7 +695,7 @@ static void log_formatted(enum logcode code, const char *format, const char *op,
|
||||
}
|
||||
n = c = buf2 + MAXPATHLEN - 32;
|
||||
c[0] = iflags & ITEM_LOCAL_CHANGE
|
||||
? iflags & ITEM_XNAME_FOLLOWS ? 'h' : 'c'
|
||||
? iflags & ITEM_XNAME_FOLLOWS ? 'h' : 'c'
|
||||
: !(iflags & ITEM_TRANSFER) ? '.'
|
||||
: !local_server && *op == 's' ? '<' : '>';
|
||||
if (S_ISLNK(file->mode)) {
|
||||
@@ -720,7 +716,8 @@ static void log_formatted(enum logcode code, const char *format, const char *op,
|
||||
c[5] = !(iflags & ITEM_REPORT_PERMS) ? '.' : 'p';
|
||||
c[6] = !(iflags & ITEM_REPORT_OWNER) ? '.' : 'o';
|
||||
c[7] = !(iflags & ITEM_REPORT_GROUP) ? '.' : 'g';
|
||||
c[8] = !(iflags & ITEM_REPORT_ATIME) ? '.' : 'u';
|
||||
c[8] = !(iflags & ITEM_REPORT_ATIME) ? '.'
|
||||
: S_ISLNK(file->mode) ? 'U' : 'u';
|
||||
c[9] = !(iflags & ITEM_REPORT_ACL) ? '.' : 'a';
|
||||
c[10] = !(iflags & ITEM_REPORT_XATTR) ? '.' : 'x';
|
||||
c[11] = '\0';
|
||||
@@ -817,8 +814,7 @@ void log_item(enum logcode code, struct file_struct *file, int iflags, const cha
|
||||
log_formatted(FLOG, logfile_format, s_or_r, file, NULL, iflags, hlink);
|
||||
}
|
||||
|
||||
void maybe_log_item(struct file_struct *file, int iflags, int itemizing,
|
||||
const char *buf)
|
||||
void maybe_log_item(struct file_struct *file, int iflags, int itemizing, const char *buf)
|
||||
{
|
||||
int significant_flags = iflags & SIGNIFICANT_ITEM_FLAGS;
|
||||
int see_item = itemizing && (significant_flags || *buf
|
||||
@@ -872,12 +868,15 @@ void log_delete(const char *fname, int mode)
|
||||
*/
|
||||
void log_exit(int code, const char *file, int line)
|
||||
{
|
||||
if (code == 0) {
|
||||
/* The receiving side's stats are split between 2 procs until the
|
||||
* end of the run, so only the sender can output non-final info. */
|
||||
if (code == 0 || am_sender) {
|
||||
rprintf(FLOG,"sent %s bytes received %s bytes total size %s\n",
|
||||
big_num(stats.total_written),
|
||||
big_num(stats.total_read),
|
||||
big_num(stats.total_size));
|
||||
} else if (am_server != 2) {
|
||||
}
|
||||
if (code != 0 && am_server != 2) {
|
||||
const char *name;
|
||||
|
||||
name = rerr_name(code);
|
||||
|
||||
22
m4/have_type.m4
Normal file
22
m4/have_type.m4
Normal file
@@ -0,0 +1,22 @@
|
||||
dnl AC_HAVE_TYPE(TYPE,INCLUDES)
|
||||
AC_DEFUN([AC_HAVE_TYPE], [
|
||||
AC_REQUIRE([AC_HEADER_STDC])
|
||||
cv=`echo "$1" | sed 'y%./+- %__p__%'`
|
||||
AC_MSG_CHECKING(for $1)
|
||||
AC_CACHE_VAL([ac_cv_type_$cv],
|
||||
AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[
|
||||
AC_INCLUDES_DEFAULT
|
||||
$2]],
|
||||
[[$1 foo;]])],
|
||||
[eval "ac_cv_type_$cv=yes"],
|
||||
[eval "ac_cv_type_$cv=no"]))dnl
|
||||
ac_foo=`eval echo \\$ac_cv_type_$cv`
|
||||
AC_MSG_RESULT($ac_foo)
|
||||
if test "$ac_foo" = yes; then
|
||||
ac_tr_hdr=HAVE_`echo $1 | sed 'y%abcdefghijklmnopqrstuvwxyz./- %ABCDEFGHIJKLMNOPQRSTUVWXYZ____%'`
|
||||
if false; then
|
||||
AC_CHECK_TYPES($1)
|
||||
fi
|
||||
AC_DEFINE_UNQUOTED($ac_tr_hdr, 1, [Define if you have type `$1'])
|
||||
fi
|
||||
])
|
||||
27
m4/header_major_fixed.m4
Normal file
27
m4/header_major_fixed.m4
Normal file
@@ -0,0 +1,27 @@
|
||||
AC_DEFUN([AC_HEADER_MAJOR_FIXED],
|
||||
[AC_CACHE_CHECK(whether sys/types.h defines makedev,
|
||||
ac_cv_header_sys_types_h_makedev,
|
||||
[AC_LINK_IFELSE([AC_LANG_PROGRAM([[@%:@include <sys/types.h>]],
|
||||
[[return makedev(0, 0);]])],
|
||||
[if grep sys/sysmacros.h conftest.err >/dev/null; then
|
||||
ac_cv_header_sys_types_h_makedev=no
|
||||
else
|
||||
ac_cv_header_sys_types_h_makedev=yes
|
||||
fi],
|
||||
[ac_cv_header_sys_types_h_makedev=no])
|
||||
])
|
||||
|
||||
if test $ac_cv_header_sys_types_h_makedev = no; then
|
||||
AC_CHECK_HEADER(sys/mkdev.h,
|
||||
[AC_DEFINE(MAJOR_IN_MKDEV, 1,
|
||||
[Define to 1 if `major', `minor', and `makedev' are
|
||||
declared in <mkdev.h>.])])
|
||||
|
||||
if test $ac_cv_header_sys_mkdev_h = no; then
|
||||
AC_CHECK_HEADER(sys/sysmacros.h,
|
||||
[AC_DEFINE(MAJOR_IN_SYSMACROS, 1,
|
||||
[Define to 1 if `major', `minor', and `makedev'
|
||||
are declared in <sysmacros.h>.])])
|
||||
fi
|
||||
fi
|
||||
])
|
||||
45
m4/socklen_t.m4
Normal file
45
m4/socklen_t.m4
Normal file
@@ -0,0 +1,45 @@
|
||||
dnl Check for socklen_t: historically on BSD it is an int, and in
|
||||
dnl POSIX 1g it is a type of its own, but some platforms use different
|
||||
dnl types for the argument to getsockopt, getpeername, etc. So we
|
||||
dnl have to test to find something that will work.
|
||||
|
||||
dnl This is no good, because passing the wrong pointer on C compilers is
|
||||
dnl likely to only generate a warning, not an error. We don't call this at
|
||||
dnl the moment.
|
||||
|
||||
AC_DEFUN([TYPE_SOCKLEN_T],
|
||||
[
|
||||
AC_CHECK_TYPE([socklen_t], ,[
|
||||
AC_MSG_CHECKING([for socklen_t equivalent])
|
||||
AC_CACHE_VAL([rsync_cv_socklen_t_equiv],
|
||||
[
|
||||
# Systems have either "struct sockaddr *" or
|
||||
# "void *" as the second argument to getpeername
|
||||
rsync_cv_socklen_t_equiv=
|
||||
for arg2 in "struct sockaddr" void; do
|
||||
for t in int size_t unsigned long "unsigned long"; do
|
||||
AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[
|
||||
#include <sys/types.h>
|
||||
#include <sys/socket.h>
|
||||
|
||||
int getpeername (int, $arg2 *, $t *);
|
||||
]],[[
|
||||
$t len;
|
||||
getpeername(0,0,&len);
|
||||
]])],[
|
||||
rsync_cv_socklen_t_equiv="$t"
|
||||
break
|
||||
])
|
||||
done
|
||||
done
|
||||
|
||||
if test "x$rsync_cv_socklen_t_equiv" = x; then
|
||||
AC_MSG_ERROR([Cannot find a type to use in place of socklen_t])
|
||||
fi
|
||||
])
|
||||
AC_MSG_RESULT($rsync_cv_socklen_t_equiv)
|
||||
AC_DEFINE_UNQUOTED(socklen_t, $rsync_cv_socklen_t_equiv,
|
||||
[type to use in place of socklen_t if not defined])],
|
||||
[#include <sys/types.h>
|
||||
#include <sys/socket.h>])
|
||||
])
|
||||
23
m4/validate_cache_system_type.m4
Normal file
23
m4/validate_cache_system_type.m4
Normal file
@@ -0,0 +1,23 @@
|
||||
dnl AC_VALIDATE_CACHE_SYSTEM_TYPE[(cmd)]
|
||||
dnl if the cache file is inconsistent with the current host,
|
||||
dnl target and build system types, execute CMD or print a default
|
||||
dnl error message.
|
||||
AC_DEFUN([AC_VALIDATE_CACHE_SYSTEM_TYPE], [
|
||||
AC_REQUIRE([AC_CANONICAL_SYSTEM])
|
||||
AC_MSG_CHECKING([config.cache system type])
|
||||
if { test x"${ac_cv_host_system_type+set}" = x"set" &&
|
||||
test x"$ac_cv_host_system_type" != x"$host"; } ||
|
||||
{ test x"${ac_cv_build_system_type+set}" = x"set" &&
|
||||
test x"$ac_cv_build_system_type" != x"$build"; } ||
|
||||
{ test x"${ac_cv_target_system_type+set}" = x"set" &&
|
||||
test x"$ac_cv_target_system_type" != x"$target"; }; then
|
||||
AC_MSG_RESULT([different])
|
||||
ifelse($#, 1, [$1],
|
||||
[AC_MSG_ERROR(["you must remove config.cache and restart configure"])])
|
||||
else
|
||||
AC_MSG_RESULT([same])
|
||||
fi
|
||||
ac_cv_host_system_type="$host"
|
||||
ac_cv_build_system_type="$build"
|
||||
ac_cv_target_system_type="$target"
|
||||
])
|
||||
306
main.c
306
main.c
@@ -4,7 +4,7 @@
|
||||
* Copyright (C) 1996-2001 Andrew Tridgell <tridge@samba.org>
|
||||
* Copyright (C) 1996 Paul Mackerras
|
||||
* Copyright (C) 2001, 2002 Martin Pool <mbp@samba.org>
|
||||
* Copyright (C) 2003-2014 Wayne Davison
|
||||
* Copyright (C) 2003-2020 Wayne Davison
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
@@ -26,6 +26,7 @@
|
||||
#if defined CONFIG_LOCALE && defined HAVE_LOCALE_H
|
||||
#include <locale.h>
|
||||
#endif
|
||||
#include <popt.h>
|
||||
|
||||
extern int dry_run;
|
||||
extern int list_only;
|
||||
@@ -39,6 +40,7 @@ extern int blocking_io;
|
||||
extern int always_checksum;
|
||||
extern int remove_source_files;
|
||||
extern int output_needs_newline;
|
||||
extern int called_from_signal_handler;
|
||||
extern int need_messages_from_generator;
|
||||
extern int kluge_around_eof;
|
||||
extern int got_xfer_error;
|
||||
@@ -75,19 +77,21 @@ extern pid_t cleanup_child_pid;
|
||||
extern size_t bwlimit_writemax;
|
||||
extern unsigned int module_dirlen;
|
||||
extern BOOL flist_receiving_enabled;
|
||||
extern BOOL want_progress_now;
|
||||
extern BOOL shutting_down;
|
||||
extern int backup_dir_len;
|
||||
extern int basis_dir_cnt;
|
||||
extern int default_af_hint;
|
||||
extern struct stats stats;
|
||||
extern char *stdout_format;
|
||||
extern char *logfile_format;
|
||||
extern char *filesfrom_host;
|
||||
extern char *partial_dir;
|
||||
extern char *dest_option;
|
||||
extern char *rsync_path;
|
||||
extern char *shell_cmd;
|
||||
extern char *batch_name;
|
||||
extern char *password_file;
|
||||
extern char *backup_dir;
|
||||
extern char *copy_as;
|
||||
extern char curr_dir[MAXPATHLEN];
|
||||
extern char backup_dir_buf[MAXPATHLEN];
|
||||
extern char *basis_dir[MAX_BASIS_DIRS+1];
|
||||
@@ -103,6 +107,8 @@ int daemon_over_rsh = 0;
|
||||
mode_t orig_umask = 0;
|
||||
int batch_gen_fd = -1;
|
||||
int sender_keeps_checksum = 0;
|
||||
int raw_argc, cooked_argc;
|
||||
char **raw_argv, **cooked_argv;
|
||||
|
||||
/* There's probably never more than at most 2 outstanding child processes,
|
||||
* but set it higher, just in case. */
|
||||
@@ -153,6 +159,27 @@ pid_t wait_process(pid_t pid, int *status_ptr, int flags)
|
||||
return waited_pid;
|
||||
}
|
||||
|
||||
int shell_exec(const char *cmd)
|
||||
{
|
||||
char *shell = getenv("RSYNC_SHELL");
|
||||
int status;
|
||||
pid_t pid;
|
||||
|
||||
if (!shell)
|
||||
return system(cmd);
|
||||
|
||||
if ((pid = fork()) < 0)
|
||||
return -1;
|
||||
|
||||
if (pid == 0) {
|
||||
execlp(shell, shell, "-c", cmd, NULL);
|
||||
_exit(1);
|
||||
}
|
||||
|
||||
int ret = wait_process(pid, &status, 0);
|
||||
return ret < 0 ? -1 : status;
|
||||
}
|
||||
|
||||
/* Wait for a process to exit, calling io_flush while waiting. */
|
||||
static void wait_process_with_flush(pid_t pid, int *exit_code_ptr)
|
||||
{
|
||||
@@ -209,6 +236,74 @@ void read_del_stats(int f)
|
||||
stats.deleted_files += stats.deleted_specials = read_varint(f);
|
||||
}
|
||||
|
||||
static void become_copy_as_user()
|
||||
{
|
||||
char *gname;
|
||||
uid_t uid;
|
||||
gid_t gid;
|
||||
|
||||
if (!copy_as)
|
||||
return;
|
||||
|
||||
if (DEBUG_GTE(CMD, 2))
|
||||
rprintf(FINFO, "[%s] copy_as=%s\n", who_am_i(), copy_as);
|
||||
|
||||
if ((gname = strchr(copy_as, ':')) != NULL)
|
||||
*gname++ = '\0';
|
||||
|
||||
if (!user_to_uid(copy_as, &uid, True)) {
|
||||
rprintf(FERROR, "Invalid copy-as user: %s\n", copy_as);
|
||||
exit_cleanup(RERR_SYNTAX);
|
||||
}
|
||||
|
||||
if (gname) {
|
||||
if (!group_to_gid(gname, &gid, True)) {
|
||||
rprintf(FERROR, "Invalid copy-as group: %s\n", gname);
|
||||
exit_cleanup(RERR_SYNTAX);
|
||||
}
|
||||
} else {
|
||||
struct passwd *pw;
|
||||
if ((pw = getpwuid(uid)) == NULL) {
|
||||
rsyserr(FERROR, errno, "getpwuid failed");
|
||||
exit_cleanup(RERR_SYNTAX);
|
||||
}
|
||||
gid = pw->pw_gid;
|
||||
}
|
||||
|
||||
if (setgid(gid) < 0) {
|
||||
rsyserr(FERROR, errno, "setgid failed");
|
||||
exit_cleanup(RERR_SYNTAX);
|
||||
}
|
||||
#ifdef HAVE_SETGROUPS
|
||||
if (setgroups(1, &gid)) {
|
||||
rsyserr(FERROR, errno, "setgroups failed");
|
||||
exit_cleanup(RERR_SYNTAX);
|
||||
}
|
||||
#endif
|
||||
#ifdef HAVE_INITGROUPS
|
||||
if (!gname && initgroups(copy_as, gid) < 0) {
|
||||
rsyserr(FERROR, errno, "initgroups failed");
|
||||
exit_cleanup(RERR_SYNTAX);
|
||||
}
|
||||
#endif
|
||||
|
||||
if (setuid(uid) < 0
|
||||
#ifdef HAVE_SETEUID
|
||||
|| seteuid(uid) < 0
|
||||
#endif
|
||||
) {
|
||||
rsyserr(FERROR, errno, "setuid failed");
|
||||
exit_cleanup(RERR_SYNTAX);
|
||||
}
|
||||
|
||||
our_uid = MY_UID();
|
||||
our_gid = MY_GID();
|
||||
am_root = (our_uid == 0);
|
||||
|
||||
if (gname)
|
||||
gname[-1] = ':';
|
||||
}
|
||||
|
||||
/* This function gets called from all 3 processes. We want the client side
|
||||
* to actually output the text, but the sender is the only process that has
|
||||
* all the stats we need. So, if we're a client sender, we do the report.
|
||||
@@ -301,6 +396,13 @@ static void output_itemized_counts(const char *prefix, int *counts)
|
||||
rprintf(FINFO, "%s: %s%s\n", prefix, comma_num(total), buf);
|
||||
}
|
||||
|
||||
static const char *bytes_per_sec_human_dnum(void)
|
||||
{
|
||||
if (starttime == (time_t)-1 || endtime == (time_t)-1)
|
||||
return "UNKNOWN";
|
||||
return human_dnum((total_written + total_read) / (0.5 + (endtime - starttime)), 2);
|
||||
}
|
||||
|
||||
static void output_summary(void)
|
||||
{
|
||||
if (INFO_GTE(STATS, 2)) {
|
||||
@@ -341,7 +443,7 @@ static void output_summary(void)
|
||||
rprintf(FINFO,
|
||||
"sent %s bytes received %s bytes %s bytes/sec\n",
|
||||
human_num(total_written), human_num(total_read),
|
||||
human_dnum((total_written + total_read)/(0.5 + (endtime - starttime)), 2));
|
||||
bytes_per_sec_human_dnum());
|
||||
rprintf(FINFO, "total size is %s speedup is %s%s\n",
|
||||
human_num(stats.total_size),
|
||||
comma_dnum((double)stats.total_size / (total_written+total_read), 2),
|
||||
@@ -424,8 +526,8 @@ static pid_t do_cmd(char *cmd, char *machine, char *user, char **remote_argv, in
|
||||
if (!*f) {
|
||||
if (in_quote) {
|
||||
rprintf(FERROR,
|
||||
"Missing trailing-%c in remote-shell command.\n",
|
||||
in_quote);
|
||||
"Missing trailing-%c in remote-shell command.\n",
|
||||
in_quote);
|
||||
exit_cleanup(RERR_SYNTAX);
|
||||
}
|
||||
f--;
|
||||
@@ -446,8 +548,13 @@ static pid_t do_cmd(char *cmd, char *machine, char *user, char **remote_argv, in
|
||||
*t++ = '\0';
|
||||
}
|
||||
|
||||
/* check to see if we've already been given '-l user' in
|
||||
* the remote-shell command */
|
||||
/* NOTE: must preserve t == start of command name until the end of the args handling! */
|
||||
if ((t = strrchr(cmd, '/')) != NULL)
|
||||
t++;
|
||||
else
|
||||
t = cmd;
|
||||
|
||||
/* Check to see if we've already been given '-l user' in the remote-shell command. */
|
||||
for (i = 0; i < argc-1; i++) {
|
||||
if (!strcmp(args[i], "-l") && args[i+1][0] != '-')
|
||||
dash_l_set = 1;
|
||||
@@ -465,22 +572,23 @@ static pid_t do_cmd(char *cmd, char *machine, char *user, char **remote_argv, in
|
||||
args[argc++] = "-l";
|
||||
args[argc++] = user;
|
||||
}
|
||||
#ifdef AF_INET
|
||||
if (default_af_hint == AF_INET && strcmp(t, "ssh") == 0)
|
||||
args[argc++] = "-4"; /* we're using ssh so we can add a -4 option */
|
||||
#endif
|
||||
#ifdef AF_INET6
|
||||
if (default_af_hint == AF_INET6 && strcmp(t, "ssh") == 0)
|
||||
args[argc++] = "-6"; /* we're using ssh so we can add a -6 option */
|
||||
#endif
|
||||
args[argc++] = machine;
|
||||
#endif
|
||||
|
||||
args[argc++] = rsync_path;
|
||||
|
||||
if (blocking_io < 0) {
|
||||
char *cp;
|
||||
if ((cp = strrchr(cmd, '/')) != NULL)
|
||||
cp++;
|
||||
else
|
||||
cp = cmd;
|
||||
if (strcmp(cp, "rsh") == 0 || strcmp(cp, "remsh") == 0)
|
||||
blocking_io = 1;
|
||||
}
|
||||
if (blocking_io < 0 && (strcmp(t, "rsh") == 0 || strcmp(t, "remsh") == 0))
|
||||
blocking_io = 1;
|
||||
|
||||
server_options(args,&argc);
|
||||
server_options(args, &argc);
|
||||
|
||||
if (argc >= MAX_ARGS - 2)
|
||||
goto arg_overflow;
|
||||
@@ -584,7 +692,7 @@ static char *get_local_name(struct file_list *flist, char *dest_path)
|
||||
|
||||
/* Treat an empty string as a copy into the current directory. */
|
||||
if (!*dest_path)
|
||||
dest_path = ".";
|
||||
dest_path = ".";
|
||||
|
||||
if (daemon_filter_list.head) {
|
||||
char *slash = strrchr(dest_path, '/');
|
||||
@@ -645,8 +753,7 @@ static char *get_local_name(struct file_list *flist, char *dest_path)
|
||||
*cp = '\0';
|
||||
|
||||
if (statret == 0) {
|
||||
rprintf(FERROR,
|
||||
"ERROR: destination path is not a directory\n");
|
||||
rprintf(FERROR, "ERROR: destination path is not a directory\n");
|
||||
exit_cleanup(RERR_SYNTAX);
|
||||
}
|
||||
|
||||
@@ -720,21 +827,21 @@ static void check_alt_basis_dirs(void)
|
||||
if (!new)
|
||||
out_of_memory("check_alt_basis_dirs");
|
||||
if (slash && strncmp(bdir, "../", 3) == 0) {
|
||||
/* We want to remove only one leading "../" prefix for
|
||||
* the directory we couldn't create in dry-run mode:
|
||||
* this ensures that any other ".." references get
|
||||
* evaluated the same as they would for a live copy. */
|
||||
*slash = '\0';
|
||||
pathjoin(new, len, curr_dir, bdir + 3);
|
||||
*slash = '/';
|
||||
/* We want to remove only one leading "../" prefix for
|
||||
* the directory we couldn't create in dry-run mode:
|
||||
* this ensures that any other ".." references get
|
||||
* evaluated the same as they would for a live copy. */
|
||||
*slash = '\0';
|
||||
pathjoin(new, len, curr_dir, bdir + 3);
|
||||
*slash = '/';
|
||||
} else
|
||||
pathjoin(new, len, curr_dir, bdir);
|
||||
pathjoin(new, len, curr_dir, bdir);
|
||||
basis_dir[j] = bdir = new;
|
||||
}
|
||||
if (do_stat(bdir, &st) < 0)
|
||||
rprintf(FWARNING, "%s arg does not exist: %s\n", dest_option, bdir);
|
||||
rprintf(FWARNING, "%s arg does not exist: %s\n", alt_dest_opt(0), bdir);
|
||||
else if (!S_ISDIR(st.st_mode))
|
||||
rprintf(FWARNING, "%s arg is not a dir: %s\n", dest_option, bdir);
|
||||
rprintf(FWARNING, "%s arg is not a dir: %s\n", alt_dest_opt(0), bdir);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -775,7 +882,7 @@ static void read_final_goodbye(int f_in, int f_out)
|
||||
static void do_server_sender(int f_in, int f_out, int argc, char *argv[])
|
||||
{
|
||||
struct file_list *flist;
|
||||
char *dir = argv[0];
|
||||
char *dir;
|
||||
|
||||
if (DEBUG_GTE(SEND, 1))
|
||||
rprintf(FINFO, "server_sender starting pid=%d\n", (int)getpid());
|
||||
@@ -783,16 +890,21 @@ static void do_server_sender(int f_in, int f_out, int argc, char *argv[])
|
||||
if (am_daemon && lp_write_only(module_id)) {
|
||||
rprintf(FERROR, "ERROR: module is write only\n");
|
||||
exit_cleanup(RERR_SYNTAX);
|
||||
return;
|
||||
}
|
||||
if (am_daemon && read_only && remove_source_files) {
|
||||
rprintf(FERROR,
|
||||
"ERROR: --remove-%s-files cannot be used with a read-only module\n",
|
||||
remove_source_files == 1 ? "source" : "sent");
|
||||
"ERROR: --remove-%s-files cannot be used with a read-only module\n",
|
||||
remove_source_files == 1 ? "source" : "sent");
|
||||
exit_cleanup(RERR_SYNTAX);
|
||||
}
|
||||
if (argc < 1) {
|
||||
rprintf(FERROR, "ERROR: do_server_sender called without args\n");
|
||||
exit_cleanup(RERR_SYNTAX);
|
||||
return;
|
||||
}
|
||||
|
||||
become_copy_as_user();
|
||||
|
||||
dir = argv[0];
|
||||
if (!relative_paths) {
|
||||
if (!change_dir(dir, CD_NORMAL)) {
|
||||
rsyserr(FERROR, errno, "change_dir#3 %s failed",
|
||||
@@ -850,13 +962,26 @@ static int do_recv(int f_in, int f_out, char *local_name)
|
||||
}
|
||||
|
||||
if (backup_dir) {
|
||||
int ret = make_path(backup_dir_buf, MKP_DROP_NAME); /* drops trailing slash */
|
||||
if (ret < 0)
|
||||
exit_cleanup(RERR_SYNTAX);
|
||||
if (ret)
|
||||
rprintf(FINFO, "Created backup_dir %s\n", backup_dir_buf);
|
||||
else if (INFO_GTE(BACKUP, 1))
|
||||
STRUCT_STAT st;
|
||||
int ret;
|
||||
if (backup_dir_len > 1)
|
||||
backup_dir_buf[backup_dir_len-1] = '\0';
|
||||
ret = do_stat(backup_dir_buf, &st);
|
||||
if (ret != 0 || !S_ISDIR(st.st_mode)) {
|
||||
if (ret == 0) {
|
||||
rprintf(FERROR, "The backup-dir is not a directory: %s\n", backup_dir_buf);
|
||||
exit_cleanup(RERR_SYNTAX);
|
||||
}
|
||||
if (errno != ENOENT) {
|
||||
rprintf(FERROR, "Failed to stat %s: %s\n", backup_dir_buf, strerror(errno));
|
||||
exit_cleanup(RERR_FILEIO);
|
||||
}
|
||||
if (INFO_GTE(BACKUP, 1))
|
||||
rprintf(FINFO, "(new) backup_dir is %s\n", backup_dir_buf);
|
||||
} else if (INFO_GTE(BACKUP, 1))
|
||||
rprintf(FINFO, "backup_dir is %s\n", backup_dir_buf);
|
||||
if (backup_dir_len > 1)
|
||||
backup_dir_buf[backup_dir_len-1] = '/';
|
||||
}
|
||||
|
||||
io_flush(FULL_FLUSH);
|
||||
@@ -982,6 +1107,8 @@ static void do_server_recv(int f_in, int f_out, int argc, char *argv[])
|
||||
return;
|
||||
}
|
||||
|
||||
become_copy_as_user();
|
||||
|
||||
if (argc > 0) {
|
||||
char *dir = argv[0];
|
||||
argc--;
|
||||
@@ -1009,7 +1136,7 @@ static void do_server_recv(int f_in, int f_out, int argc, char *argv[])
|
||||
filesfrom_fd = -1;
|
||||
}
|
||||
|
||||
flist = recv_file_list(f_in);
|
||||
flist = recv_file_list(f_in, -1);
|
||||
if (!flist) {
|
||||
rprintf(FERROR,"server_recv: recv_file_list error\n");
|
||||
exit_cleanup(RERR_FILESELECT);
|
||||
@@ -1048,8 +1175,7 @@ static void do_server_recv(int f_in, int f_out, int argc, char *argv[])
|
||||
if (partial_dir && *partial_dir == '/'
|
||||
&& check_filter(elp, FLOG, partial_dir + module_dirlen, 1) < 0) {
|
||||
options_rejected:
|
||||
rprintf(FERROR,
|
||||
"Your options have been rejected by the server.\n");
|
||||
rprintf(FERROR, "Your options have been rejected by the server.\n");
|
||||
exit_cleanup(RERR_SYNTAX);
|
||||
}
|
||||
}
|
||||
@@ -1141,6 +1267,9 @@ int client_run(int f_in, int f_out, pid_t pid, int argc, char *argv[])
|
||||
|
||||
if (write_batch && !am_server)
|
||||
start_write_batch(f_out);
|
||||
|
||||
become_copy_as_user();
|
||||
|
||||
flist = send_file_list(f_out, argc, argv);
|
||||
if (DEBUG_GTE(FLIST, 3))
|
||||
rprintf(FINFO,"file list sent\n");
|
||||
@@ -1174,6 +1303,8 @@ int client_run(int f_in, int f_out, pid_t pid, int argc, char *argv[])
|
||||
io_start_buffering_out(f_out);
|
||||
}
|
||||
|
||||
become_copy_as_user();
|
||||
|
||||
send_filter_list(read_batch ? -1 : f_out);
|
||||
|
||||
if (filesfrom_fd >= 0) {
|
||||
@@ -1183,7 +1314,7 @@ int client_run(int f_in, int f_out, pid_t pid, int argc, char *argv[])
|
||||
|
||||
if (write_batch && !am_server)
|
||||
start_write_batch(f_in);
|
||||
flist = recv_file_list(f_in);
|
||||
flist = recv_file_list(f_in, -1);
|
||||
if (inc_recurse && file_total == 1)
|
||||
recv_additional_file_list(f_in);
|
||||
|
||||
@@ -1234,7 +1365,7 @@ static int start_client(int argc, char *argv[])
|
||||
{
|
||||
char *p, *shell_machine = NULL, *shell_user = NULL;
|
||||
char **remote_argv;
|
||||
int remote_argc;
|
||||
int remote_argc, env_port = rsync_port;
|
||||
int f_in, f_out;
|
||||
int ret;
|
||||
pid_t pid;
|
||||
@@ -1263,8 +1394,7 @@ static int start_client(int argc, char *argv[])
|
||||
remote_argc--; /* don't count dest */
|
||||
argc = 1;
|
||||
}
|
||||
if (filesfrom_host && *filesfrom_host
|
||||
&& strcmp(filesfrom_host, shell_machine) != 0) {
|
||||
if (filesfrom_host && *filesfrom_host && strcmp(filesfrom_host, shell_machine) != 0) {
|
||||
rprintf(FERROR,
|
||||
"--files-from hostname is not the same as the transfer hostname\n");
|
||||
exit_cleanup(RERR_SYNTAX);
|
||||
@@ -1286,8 +1416,7 @@ static int start_client(int argc, char *argv[])
|
||||
remote_argc = 1;
|
||||
|
||||
path = check_for_hostspec(p, &shell_machine, &rsync_port);
|
||||
if (path && filesfrom_host && *filesfrom_host
|
||||
&& strcmp(filesfrom_host, shell_machine) != 0) {
|
||||
if (path && filesfrom_host && *filesfrom_host && strcmp(filesfrom_host, shell_machine) != 0) {
|
||||
rprintf(FERROR,
|
||||
"--files-from hostname is not the same as the transfer hostname\n");
|
||||
exit_cleanup(RERR_SYNTAX);
|
||||
@@ -1300,6 +1429,7 @@ static int start_client(int argc, char *argv[])
|
||||
exit_cleanup(RERR_SYNTAX);
|
||||
}
|
||||
shell_machine = NULL;
|
||||
rsync_port = 0;
|
||||
} else { /* hostspec was found, so dest is remote */
|
||||
argv[argc] = path;
|
||||
if (rsync_port)
|
||||
@@ -1314,6 +1444,7 @@ static int start_client(int argc, char *argv[])
|
||||
}
|
||||
remote_argv = argv += argc - 1;
|
||||
remote_argc = argc = 1;
|
||||
rsync_port = 0;
|
||||
}
|
||||
|
||||
if (!rsync_port && remote_argc && !**remote_argv) /* Turn an empty arg into a dot dir. */
|
||||
@@ -1360,6 +1491,11 @@ static int start_client(int argc, char *argv[])
|
||||
}
|
||||
}
|
||||
|
||||
if (rsync_port < 0)
|
||||
rsync_port = RSYNC_PORT;
|
||||
else
|
||||
env_port = rsync_port;
|
||||
|
||||
if (daemon_over_rsh < 0)
|
||||
return start_socket_client(shell_machine, remote_argc, remote_argv, argc, argv);
|
||||
|
||||
@@ -1390,8 +1526,12 @@ static int start_client(int argc, char *argv[])
|
||||
NS(remote_argv[0]));
|
||||
}
|
||||
|
||||
pid = do_cmd(shell_cmd, shell_machine, shell_user, remote_argv, remote_argc,
|
||||
&f_in, &f_out);
|
||||
#ifdef HAVE_PUTENV
|
||||
if (daemon_over_rsh)
|
||||
set_env_num("RSYNC_PORT", env_port);
|
||||
#endif
|
||||
|
||||
pid = do_cmd(shell_cmd, shell_machine, shell_user, remote_argv, remote_argc, &f_in, &f_out);
|
||||
|
||||
/* if we're running an rsync server on the remote host over a
|
||||
* remote shell command, we need to do the RSYNCD protocol first */
|
||||
@@ -1411,12 +1551,13 @@ static int start_client(int argc, char *argv[])
|
||||
}
|
||||
|
||||
|
||||
static RETSIGTYPE sigusr1_handler(UNUSED(int val))
|
||||
static void sigusr1_handler(UNUSED(int val))
|
||||
{
|
||||
called_from_signal_handler = 1;
|
||||
exit_cleanup(RERR_SIGNAL1);
|
||||
}
|
||||
|
||||
static RETSIGTYPE sigusr2_handler(UNUSED(int val))
|
||||
static void sigusr2_handler(UNUSED(int val))
|
||||
{
|
||||
if (!am_server)
|
||||
output_summary();
|
||||
@@ -1426,7 +1567,13 @@ static RETSIGTYPE sigusr2_handler(UNUSED(int val))
|
||||
_exit(0);
|
||||
}
|
||||
|
||||
RETSIGTYPE remember_children(UNUSED(int val))
|
||||
static void siginfo_handler(UNUSED(int val))
|
||||
{
|
||||
if (!am_server && !INFO_GTE(PROGRESS, 1))
|
||||
want_progress_now = True;
|
||||
}
|
||||
|
||||
void remember_children(UNUSED(int val))
|
||||
{
|
||||
#ifdef WNOHANG
|
||||
int cnt, status;
|
||||
@@ -1473,9 +1620,7 @@ const char *get_panic_action(void)
|
||||
|
||||
if (cmd_fmt)
|
||||
return cmd_fmt;
|
||||
else
|
||||
return "xterm -display :0 -T Panic -n Panic "
|
||||
"-e gdb /proc/%d/exe %d";
|
||||
return "xterm -display :0 -T Panic -n Panic -e gdb /proc/%d/exe %d";
|
||||
}
|
||||
|
||||
|
||||
@@ -1487,7 +1632,7 @@ const char *get_panic_action(void)
|
||||
* should just look at the environment variable, but I'm a bit leery
|
||||
* of a signal sending us into a busy loop.
|
||||
**/
|
||||
static RETSIGTYPE rsync_panic_handler(UNUSED(int whatsig))
|
||||
static void rsync_panic_handler(UNUSED(int whatsig))
|
||||
{
|
||||
char cmd_buf[300];
|
||||
int ret, pid_int = getpid();
|
||||
@@ -1496,7 +1641,7 @@ static RETSIGTYPE rsync_panic_handler(UNUSED(int whatsig))
|
||||
|
||||
/* Unless we failed to execute gdb, we allow the process to
|
||||
* continue. I'm not sure if that's right. */
|
||||
ret = system(cmd_buf);
|
||||
ret = shell_exec(cmd_buf);
|
||||
if (ret)
|
||||
_exit(ret);
|
||||
}
|
||||
@@ -1506,8 +1651,10 @@ static RETSIGTYPE rsync_panic_handler(UNUSED(int whatsig))
|
||||
int main(int argc,char *argv[])
|
||||
{
|
||||
int ret;
|
||||
int orig_argc = argc;
|
||||
char **orig_argv = argv;
|
||||
|
||||
raw_argc = argc;
|
||||
raw_argv = argv;
|
||||
|
||||
#ifdef HAVE_SIGACTION
|
||||
# ifdef HAVE_SIGPROCMASK
|
||||
sigset_t sigmask;
|
||||
@@ -1525,6 +1672,12 @@ int main(int argc,char *argv[])
|
||||
SIGACTMASK(SIGABRT, rsync_panic_handler);
|
||||
SIGACTMASK(SIGBUS, rsync_panic_handler);
|
||||
#endif
|
||||
#ifdef SIGINFO
|
||||
SIGACTMASK(SIGINFO, siginfo_handler);
|
||||
#endif
|
||||
#ifdef SIGVTALRM
|
||||
SIGACTMASK(SIGVTALRM, siginfo_handler);
|
||||
#endif
|
||||
|
||||
starttime = time(NULL);
|
||||
our_uid = MY_UID();
|
||||
@@ -1533,6 +1686,10 @@ int main(int argc,char *argv[])
|
||||
|
||||
memset(&stats, 0, sizeof(stats));
|
||||
|
||||
/* Even a non-daemon runs needs the default config values to be set, e.g.
|
||||
* lp_dont_compress() is queried when no --skip-compress option is set. */
|
||||
reset_daemon_vars();
|
||||
|
||||
if (argc < 2) {
|
||||
usage(FERROR);
|
||||
exit_cleanup(RERR_SYNTAX);
|
||||
@@ -1548,11 +1705,12 @@ int main(int argc,char *argv[])
|
||||
#endif
|
||||
|
||||
if (!parse_arguments(&argc, (const char ***) &argv)) {
|
||||
/* FIXME: We ought to call the same error-handling
|
||||
* code here, rather than relying on getopt. */
|
||||
option_error();
|
||||
exit_cleanup(RERR_SYNTAX);
|
||||
}
|
||||
if (write_batch
|
||||
&& poptDupArgv(argc, (const char **)argv, &cooked_argc, (const char ***)&cooked_argv) != 0)
|
||||
out_of_memory("main");
|
||||
|
||||
SIGACTMASK(SIGINT, sig_int);
|
||||
SIGACTMASK(SIGHUP, sig_int);
|
||||
@@ -1574,24 +1732,8 @@ int main(int argc,char *argv[])
|
||||
* that implement getcwd that way "pwd" can't be found after chroot. */
|
||||
change_dir(NULL, CD_NORMAL);
|
||||
|
||||
init_flist();
|
||||
|
||||
if ((write_batch || read_batch) && !am_server) {
|
||||
if (write_batch)
|
||||
write_batch_shell_file(orig_argc, orig_argv, argc);
|
||||
|
||||
if (read_batch && strcmp(batch_name, "-") == 0)
|
||||
batch_fd = STDIN_FILENO;
|
||||
else {
|
||||
batch_fd = do_open(batch_name,
|
||||
write_batch ? O_WRONLY | O_CREAT | O_TRUNC
|
||||
: O_RDONLY, S_IRUSR | S_IWUSR);
|
||||
}
|
||||
if (batch_fd < 0) {
|
||||
rsyserr(FERROR, errno, "Batch file %s open error",
|
||||
full_fname(batch_name));
|
||||
exit_cleanup(RERR_FILEIO);
|
||||
}
|
||||
open_batch_files(); /* sets batch_fd */
|
||||
if (read_batch)
|
||||
read_stream_flags(batch_fd);
|
||||
else
|
||||
|
||||
35
match.c
35
match.c
@@ -3,7 +3,7 @@
|
||||
*
|
||||
* Copyright (C) 1996 Andrew Tridgell
|
||||
* Copyright (C) 1996 Paul Mackerras
|
||||
* Copyright (C) 2003-2014 Wayne Davison
|
||||
* Copyright (C) 2003-2020 Wayne Davison
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
@@ -24,7 +24,7 @@
|
||||
|
||||
extern int checksum_seed;
|
||||
extern int append_mode;
|
||||
extern int checksum_len;
|
||||
extern int xfersum_type;
|
||||
|
||||
int updating_basis_file;
|
||||
char sender_file_sum[MAX_DIGEST_LEN];
|
||||
@@ -102,8 +102,7 @@ static OFF_T last_match;
|
||||
* If i >= 0, the number of a matched token. If < 0, indicates we have
|
||||
* only literal data. A -1 will send a 0-token-int too, and a -2 sends
|
||||
* only literal data, w/o any token-int. */
|
||||
static void matched(int f, struct sum_struct *s, struct map_struct *buf,
|
||||
OFF_T offset, int32 i)
|
||||
static void matched(int f, struct sum_struct *s, struct map_struct *buf, OFF_T offset, int32 i)
|
||||
{
|
||||
int32 n = (int32)(offset - last_match); /* max value: block_size (int32) */
|
||||
int32 j;
|
||||
@@ -207,7 +206,7 @@ static void hash_search(int f,struct sum_struct *s,
|
||||
* either >= our offset or identical data at that offset.
|
||||
* Remove any bypassed entries that we can never use. */
|
||||
if (updating_basis_file && s->sums[i].offset < offset
|
||||
&& !(s->sums[i].flags & SUMFLG_SAME_OFFSET)) {
|
||||
&& !(s->sums[i].flags & SUMFLG_SAME_OFFSET)) {
|
||||
*prev = s->sums[i].chain;
|
||||
continue;
|
||||
}
|
||||
@@ -288,10 +287,10 @@ static void hash_search(int f,struct sum_struct *s,
|
||||
/* we've found a match, but now check to see
|
||||
* if want_i can hint at a better match. */
|
||||
if (i != want_i && want_i < s->count
|
||||
&& (!updating_basis_file || s->sums[want_i].offset >= offset
|
||||
|| s->sums[want_i].flags & SUMFLG_SAME_OFFSET)
|
||||
&& sum == s->sums[want_i].sum1
|
||||
&& memcmp(sum2, s->sums[want_i].sum2, s->s2length) == 0) {
|
||||
&& (!updating_basis_file || s->sums[want_i].offset >= offset
|
||||
|| s->sums[want_i].flags & SUMFLG_SAME_OFFSET)
|
||||
&& sum == s->sums[want_i].sum1
|
||||
&& memcmp(sum2, s->sums[want_i].sum2, s->s2length) == 0) {
|
||||
/* we've found an adjacent match - the RLL coder
|
||||
* will be happy */
|
||||
i = want_i;
|
||||
@@ -317,8 +316,7 @@ static void hash_search(int f,struct sum_struct *s,
|
||||
|
||||
/* Trim off the first byte from the checksum */
|
||||
more = offset + k < len;
|
||||
map = (schar *)map_ptr(buf, offset - backup, k + more + backup)
|
||||
+ backup;
|
||||
map = (schar *)map_ptr(buf, offset - backup, k + more + backup) + backup;
|
||||
s1 -= map[0] + CHAR_OFFSET;
|
||||
s2 -= k * (map[0]+CHAR_OFFSET);
|
||||
|
||||
@@ -360,13 +358,15 @@ static void hash_search(int f,struct sum_struct *s,
|
||||
**/
|
||||
void match_sums(int f, struct sum_struct *s, struct map_struct *buf, OFF_T len)
|
||||
{
|
||||
int sum_len;
|
||||
|
||||
last_match = 0;
|
||||
false_alarms = 0;
|
||||
hash_hits = 0;
|
||||
matches = 0;
|
||||
data_transfer = 0;
|
||||
|
||||
sum_init(checksum_seed);
|
||||
sum_init(xfersum_type, checksum_seed);
|
||||
|
||||
if (append_mode > 0) {
|
||||
if (append_mode == 2) {
|
||||
@@ -407,23 +407,22 @@ void match_sums(int f, struct sum_struct *s, struct map_struct *buf, OFF_T len)
|
||||
matched(f, s, buf, len, -1);
|
||||
}
|
||||
|
||||
if (sum_end(sender_file_sum) != checksum_len)
|
||||
overflow_exit("checksum_len"); /* Impossible... */
|
||||
sum_len = sum_end(sender_file_sum);
|
||||
|
||||
/* If we had a read error, send a bad checksum. We use all bits
|
||||
* off as long as the checksum doesn't happen to be that, in
|
||||
* which case we turn the last 0 bit into a 1. */
|
||||
if (buf && buf->status != 0) {
|
||||
int i;
|
||||
for (i = 0; i < checksum_len && sender_file_sum[i] == 0; i++) {}
|
||||
memset(sender_file_sum, 0, checksum_len);
|
||||
if (i == checksum_len)
|
||||
for (i = 0; i < sum_len && sender_file_sum[i] == 0; i++) {}
|
||||
memset(sender_file_sum, 0, sum_len);
|
||||
if (i == sum_len)
|
||||
sender_file_sum[i-1]++;
|
||||
}
|
||||
|
||||
if (DEBUG_GTE(DELTASUM, 2))
|
||||
rprintf(FINFO,"sending file_sum\n");
|
||||
write_buf(f, sender_file_sum, checksum_len);
|
||||
write_buf(f, sender_file_sum, sum_len);
|
||||
|
||||
if (DEBUG_GTE(DELTASUM, 2)) {
|
||||
rprintf(FINFO, "false_alarms=%d hash_hits=%d matches=%d\n",
|
||||
|
||||
40
maybe-make-man
Executable file
40
maybe-make-man
Executable file
@@ -0,0 +1,40 @@
|
||||
#!/bin/sh
|
||||
|
||||
if [ x"$2" = x ]; then
|
||||
echo "Usage: $0 SRC_DIR NAME.NUM.md" 1>&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
srcdir="$1"
|
||||
inname="$2"
|
||||
flagfile="$srcdir/.md2man-works"
|
||||
|
||||
if [ ! -d "$srcdir" ]; then
|
||||
echo "The specified SRC_DIR is not a directory: $srcdir" 1>&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [ ! -f "$flagfile" ]; then
|
||||
# We test our smallest manpage just to see if the python setup works.
|
||||
if "$srcdir/md2man" --test "$srcdir/rsync-ssl.1.md" >/dev/null 2>&1; then
|
||||
touch $flagfile
|
||||
else
|
||||
outname=`echo "$inname" | sed 's/\.md$//'`
|
||||
if [ -f "$outname" ]; then
|
||||
exit 0
|
||||
elif [ -f "$srcdir/$outname" ]; then
|
||||
echo "Copying $srcdir/$outname"
|
||||
cp -p "$srcdir/$outname" .
|
||||
exit 0
|
||||
else
|
||||
echo "ERROR: $outname cannot be created."
|
||||
if [ -f "$HOME/build_farm/build_test.fns" ]; then
|
||||
exit 0 # No exit errorno to avoid a build failure in the samba build farm
|
||||
else
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
|
||||
"$srcdir/md2man" "$srcdir/$inname"
|
||||
369
md2man
Executable file
369
md2man
Executable file
@@ -0,0 +1,369 @@
|
||||
#!/usr/bin/python3
|
||||
|
||||
# This script takes a manpage written in markdown and turns it into an html web
|
||||
# page and a nroff man page. The input file must have the name of the program
|
||||
# and the section in this format: NAME.NUM.md. The output files are written
|
||||
# into the current directory named NAME.NUM.html and NAME.NUM. The input
|
||||
# format has one extra extension: if a numbered list starts at 0, it is turned
|
||||
# into a description list. The dl's dt tag is taken from the contents of the
|
||||
# first tag inside the li, which is usually a p, code, or strong tag. The
|
||||
# cmarkgfm or commonmark lib is used to transforms the input file into html.
|
||||
# The html.parser is used as a state machine that both tweaks the html and
|
||||
# outputs the nroff data based on the html tags.
|
||||
#
|
||||
# Copyright (C) 2020 Wayne Davison
|
||||
#
|
||||
# This program is freely redistributable.
|
||||
|
||||
import sys, os, re, argparse, subprocess, time
|
||||
from html.parser import HTMLParser
|
||||
|
||||
CONSUMES_TXT = set('h1 h2 p li pre'.split())
|
||||
|
||||
HTML_START = """\
|
||||
<html><head>
|
||||
<title>%s</title>
|
||||
<link href="https://fonts.googleapis.com/css2?family=Roboto&family=Roboto+Mono&display=swap" rel="stylesheet">
|
||||
<style>
|
||||
body {
|
||||
max-width: 50em;
|
||||
margin: auto;
|
||||
}
|
||||
body, b, strong, u {
|
||||
font-family: 'Roboto', sans-serif;
|
||||
}
|
||||
code {
|
||||
font-family: 'Roboto Mono', monospace;
|
||||
font-weight: bold;
|
||||
}
|
||||
pre code {
|
||||
display: block;
|
||||
font-weight: normal;
|
||||
}
|
||||
blockquote pre code {
|
||||
background: #f1f1f1;
|
||||
}
|
||||
dd p:first-of-type {
|
||||
margin-block-start: 0em;
|
||||
}
|
||||
</style>
|
||||
</head><body>
|
||||
"""
|
||||
|
||||
HTML_END = """\
|
||||
<div style="float: right"><p><i>%s</i></p></div>
|
||||
</body></html>
|
||||
"""
|
||||
|
||||
MAN_START = r"""
|
||||
.TH "%s" "%s" "%s" "%s" "User Commands"
|
||||
""".lstrip()
|
||||
|
||||
MAN_END = """\
|
||||
"""
|
||||
|
||||
NORM_FONT = ('\1', r"\fP")
|
||||
BOLD_FONT = ('\2', r"\fB")
|
||||
ULIN_FONT = ('\3', r"\fI")
|
||||
|
||||
md_parser = None
|
||||
|
||||
def main():
|
||||
fi = re.match(r'^(?P<fn>(?P<srcdir>.+/)?(?P<name>(?P<prog>[^/]+)\.(?P<sect>\d+))\.md)$', args.mdfile)
|
||||
if not fi:
|
||||
die('Failed to parse NAME.NUM.md out of input file:', args.mdfile)
|
||||
fi = argparse.Namespace(**fi.groupdict())
|
||||
|
||||
if not fi.srcdir:
|
||||
fi.srcdir = './'
|
||||
|
||||
fi.title = fi.prog + '(' + fi.sect + ') man page'
|
||||
fi.mtime = None
|
||||
|
||||
if os.path.lexists(fi.srcdir + '.git'):
|
||||
fi.mtime = int(subprocess.check_output('git log -1 --format=%at'.split()))
|
||||
|
||||
chk_files = 'NEWS.md Makefile'.split()
|
||||
for fn in chk_files:
|
||||
try:
|
||||
st = os.lstat(fi.srcdir + fn)
|
||||
except:
|
||||
die('Failed to find', fi.srcdir + fn)
|
||||
if not fi.mtime:
|
||||
fi.mtime = st.st_mtime
|
||||
|
||||
fi.date = time.strftime('%d %b %Y', time.localtime(fi.mtime))
|
||||
|
||||
env_subs = { 'prefix': os.environ.get('RSYNC_OVERRIDE_PREFIX', None) }
|
||||
|
||||
with open(fi.srcdir + 'Makefile', 'r', encoding='utf-8') as fh:
|
||||
for line in fh:
|
||||
m = re.match(r'^(\w+)=(.+)', line)
|
||||
if not m:
|
||||
continue
|
||||
var, val = (m[1], m[2])
|
||||
if var == 'prefix' and env_subs[var] is not None:
|
||||
continue
|
||||
while re.search(r'\$\{', val):
|
||||
val = re.sub(r'\$\{(\w+)\}', lambda m: env_subs[m[1]], val)
|
||||
env_subs[var] = val
|
||||
if var == 'VERSION':
|
||||
break
|
||||
|
||||
with open(fi.fn, 'r', encoding='utf-8') as fh:
|
||||
txt = fh.read()
|
||||
|
||||
txt = re.sub(r'@VERSION@', env_subs['VERSION'], txt)
|
||||
txt = re.sub(r'@LIBDIR@', env_subs['libdir'], txt)
|
||||
fi.html_in = md_parser(txt)
|
||||
txt = None
|
||||
|
||||
fi.man_headings = (fi.prog, fi.sect, fi.date, fi.prog + ' ' + env_subs['VERSION'])
|
||||
|
||||
HtmlToManPage(fi)
|
||||
|
||||
if args.test:
|
||||
print("The test was successful.")
|
||||
return
|
||||
|
||||
for fn, txt in ((fi.name + '.html', fi.html_out), (fi.name, fi.man_out)):
|
||||
print("Wrote:", fn)
|
||||
with open(fn, 'w', encoding='utf-8') as fh:
|
||||
fh.write(txt)
|
||||
|
||||
|
||||
def html_via_cmarkgfm(txt):
|
||||
return cmarkgfm.markdown_to_html(txt)
|
||||
|
||||
|
||||
def html_via_commonmark(txt):
|
||||
return commonmark.HtmlRenderer().render(commonmark.Parser().parse(txt))
|
||||
|
||||
|
||||
class HtmlToManPage(HTMLParser):
|
||||
def __init__(self, fi):
|
||||
HTMLParser.__init__(self, convert_charrefs=True)
|
||||
|
||||
st = self.state = argparse.Namespace(
|
||||
list_state = [ ],
|
||||
p_macro = ".P\n",
|
||||
at_first_tag_in_li = False,
|
||||
at_first_tag_in_dd = False,
|
||||
dt_from = None,
|
||||
in_pre = False,
|
||||
in_code = False,
|
||||
html_out = [ HTML_START % fi.title ],
|
||||
man_out = [ MAN_START % fi.man_headings ],
|
||||
txt = '',
|
||||
)
|
||||
|
||||
self.feed(fi.html_in)
|
||||
fi.html_in = None
|
||||
|
||||
st.html_out.append(HTML_END % fi.date)
|
||||
st.man_out.append(MAN_END)
|
||||
|
||||
fi.html_out = ''.join(st.html_out)
|
||||
st.html_out = None
|
||||
|
||||
fi.man_out = ''.join(st.man_out)
|
||||
st.man_out = None
|
||||
|
||||
|
||||
def handle_starttag(self, tag, attrs_list):
|
||||
st = self.state
|
||||
if args.debug:
|
||||
self.output_debug('START', (tag, attrs_list))
|
||||
if st.at_first_tag_in_li:
|
||||
if st.list_state[-1] == 'dl':
|
||||
st.dt_from = tag
|
||||
if tag == 'p':
|
||||
tag = 'dt'
|
||||
else:
|
||||
st.html_out.append('<dt>')
|
||||
st.at_first_tag_in_li = False
|
||||
if tag == 'p':
|
||||
if not st.at_first_tag_in_dd:
|
||||
st.man_out.append(st.p_macro)
|
||||
elif tag == 'li':
|
||||
st.at_first_tag_in_li = True
|
||||
lstate = st.list_state[-1]
|
||||
if lstate == 'dl':
|
||||
return
|
||||
if lstate == 'o':
|
||||
st.man_out.append(".IP o\n")
|
||||
else:
|
||||
st.man_out.append(".IP " + str(lstate) + ".\n")
|
||||
st.list_state[-1] += 1
|
||||
elif tag == 'blockquote':
|
||||
st.man_out.append(".RS 4\n")
|
||||
elif tag == 'pre':
|
||||
st.in_pre = True
|
||||
st.man_out.append(st.p_macro + ".nf\n")
|
||||
elif tag == 'code' and not st.in_pre:
|
||||
st.in_code = True
|
||||
st.txt += BOLD_FONT[0]
|
||||
elif tag == 'strong' or tag == 'b':
|
||||
st.txt += BOLD_FONT[0]
|
||||
elif tag == 'em' or tag == 'i':
|
||||
tag = 'u' # Change it into underline to be more like the man page
|
||||
st.txt += ULIN_FONT[0]
|
||||
elif tag == 'ol':
|
||||
start = 1
|
||||
for var, val in attrs_list:
|
||||
if var == 'start':
|
||||
start = int(val) # We only support integers.
|
||||
break
|
||||
if st.list_state:
|
||||
st.man_out.append(".RS\n")
|
||||
if start == 0:
|
||||
tag = 'dl'
|
||||
attrs_list = [ ]
|
||||
st.list_state.append('dl')
|
||||
else:
|
||||
st.list_state.append(start)
|
||||
st.man_out.append(st.p_macro)
|
||||
st.p_macro = ".IP\n"
|
||||
elif tag == 'ul':
|
||||
st.man_out.append(st.p_macro)
|
||||
if st.list_state:
|
||||
st.man_out.append(".RS\n")
|
||||
st.p_macro = ".IP\n"
|
||||
st.list_state.append('o')
|
||||
st.html_out.append('<' + tag + ''.join(' ' + var + '="' + htmlify(val) + '"' for var, val in attrs_list) + '>')
|
||||
st.at_first_tag_in_dd = False
|
||||
|
||||
|
||||
def handle_endtag(self, tag):
|
||||
st = self.state
|
||||
if args.debug:
|
||||
self.output_debug('END', (tag,))
|
||||
if tag in CONSUMES_TXT or st.dt_from == tag:
|
||||
txt = st.txt.strip()
|
||||
st.txt = ''
|
||||
else:
|
||||
txt = None
|
||||
add_to_txt = None
|
||||
if tag == 'h1':
|
||||
st.man_out.append(st.p_macro + '.SH "' + manify(txt) + '"\n')
|
||||
elif tag == 'h2':
|
||||
st.man_out.append(st.p_macro + '.SS "' + manify(txt) + '"\n')
|
||||
elif tag == 'p':
|
||||
if st.dt_from == 'p':
|
||||
tag = 'dt'
|
||||
st.man_out.append('.IP "' + manify(txt) + '"\n')
|
||||
st.dt_from = None
|
||||
elif txt != '':
|
||||
st.man_out.append(manify(txt) + "\n")
|
||||
elif tag == 'li':
|
||||
if st.list_state[-1] == 'dl':
|
||||
if st.at_first_tag_in_li:
|
||||
die("Invalid 0. -> td translation")
|
||||
tag = 'dd'
|
||||
if txt != '':
|
||||
st.man_out.append(manify(txt) + "\n")
|
||||
st.at_first_tag_in_li = False
|
||||
elif tag == 'blockquote':
|
||||
st.man_out.append(".RE\n")
|
||||
elif tag == 'pre':
|
||||
st.in_pre = False
|
||||
st.man_out.append(manify(txt) + "\n.fi\n")
|
||||
elif (tag == 'code' and not st.in_pre):
|
||||
st.in_code = False
|
||||
add_to_txt = NORM_FONT[0]
|
||||
elif tag == 'strong' or tag == 'b':
|
||||
add_to_txt = NORM_FONT[0]
|
||||
elif tag == 'em' or tag == 'i':
|
||||
tag = 'u' # Change it into underline to be more like the man page
|
||||
add_to_txt = NORM_FONT[0]
|
||||
elif tag == 'ol' or tag == 'ul':
|
||||
if st.list_state.pop() == 'dl':
|
||||
tag = 'dl'
|
||||
if st.list_state:
|
||||
st.man_out.append(".RE\n")
|
||||
else:
|
||||
st.p_macro = ".P\n"
|
||||
st.at_first_tag_in_dd = False
|
||||
st.html_out.append('</' + tag + '>')
|
||||
if add_to_txt:
|
||||
if txt is None:
|
||||
st.txt += add_to_txt
|
||||
else:
|
||||
txt += add_to_txt
|
||||
if st.dt_from == tag:
|
||||
st.man_out.append('.IP "' + manify(txt) + '"\n')
|
||||
st.html_out.append('</dt><dd>')
|
||||
st.at_first_tag_in_dd = True
|
||||
st.dt_from = None
|
||||
elif tag == 'dt':
|
||||
st.html_out.append('<dd>')
|
||||
st.at_first_tag_in_dd = True
|
||||
|
||||
|
||||
def handle_data(self, data):
|
||||
st = self.state
|
||||
if args.debug:
|
||||
self.output_debug('DATA', (data,))
|
||||
if st.in_code:
|
||||
data = re.sub(r'\s', '\xa0', data) # nbsp in non-pre code
|
||||
data = re.sub(r'\s--\s', '\xa0-- ', data)
|
||||
st.html_out.append(htmlify(data))
|
||||
st.txt += data
|
||||
|
||||
|
||||
def output_debug(self, event, extra):
|
||||
import pprint
|
||||
st = self.state
|
||||
if args.debug < 2:
|
||||
st = argparse.Namespace(**vars(st))
|
||||
if len(st.html_out) > 2:
|
||||
st.html_out = ['...'] + st.html_out[-2:]
|
||||
if len(st.man_out) > 2:
|
||||
st.man_out = ['...'] + st.man_out[-2:]
|
||||
print(event, extra)
|
||||
pprint.PrettyPrinter(indent=2).pprint(vars(st))
|
||||
|
||||
|
||||
def manify(txt):
|
||||
return re.sub(r"^(['.])", r'\&\1', txt.replace('\\', '\\\\')
|
||||
.replace("\xa0", r'\ ') # non-breaking space
|
||||
.replace('--', r'\-\-') # non-breaking double dash
|
||||
.replace(NORM_FONT[0], NORM_FONT[1])
|
||||
.replace(BOLD_FONT[0], BOLD_FONT[1])
|
||||
.replace(ULIN_FONT[0], ULIN_FONT[1]), flags=re.M)
|
||||
|
||||
|
||||
def htmlify(txt):
|
||||
return re.sub(r'(\W)-', r'\1‑',
|
||||
txt.replace('&', '&').replace('<', '<').replace('>', '>').replace('"', '"')
|
||||
.replace('--', '‑‑').replace("\xa0-", ' ‑').replace("\xa0", ' '))
|
||||
|
||||
|
||||
def warn(*msg):
|
||||
print(*msg, file=sys.stderr)
|
||||
|
||||
|
||||
def die(*msg):
|
||||
warn(*msg)
|
||||
sys.exit(1)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
parser = argparse.ArgumentParser(description='Transform a NAME.NUM.md markdown file into a NAME.NUM.html web page & a NAME.NUM man page.', add_help=False)
|
||||
parser.add_argument('--test', action='store_true', help='Test if we can parse the input w/o updating any files.')
|
||||
parser.add_argument('--debug', '-D', action='count', default=0, help='Output copious info on the html parsing. Repeat for even more.')
|
||||
parser.add_argument("--help", "-h", action="help", help="Output this help message and exit.")
|
||||
parser.add_argument('mdfile', help="The NAME.NUM.md file to parse.")
|
||||
args = parser.parse_args()
|
||||
|
||||
try:
|
||||
import cmarkgfm
|
||||
md_parser = html_via_cmarkgfm
|
||||
except:
|
||||
try:
|
||||
import commonmark
|
||||
md_parser = html_via_commonmark
|
||||
except:
|
||||
die("Failed to find cmarkgfm or commonmark for python3.")
|
||||
|
||||
main()
|
||||
39
mkproto.awk
Normal file
39
mkproto.awk
Normal file
@@ -0,0 +1,39 @@
|
||||
#!/usr/bin/awk -f
|
||||
|
||||
BEGIN {
|
||||
while ((getline i < "proto.h") > 0) old_protos = old_protos ? old_protos "\n" i : i
|
||||
protos = "/* This file is automatically generated with \"make proto\". DO NOT EDIT */\n"
|
||||
}
|
||||
|
||||
inheader {
|
||||
protos = protos "\n" ((inheader = /\)[ \t]*$/ ? 0 : 1) ? $0 : $0 ";")
|
||||
next
|
||||
}
|
||||
|
||||
/^FN_(LOCAL|GLOBAL)_[^(]+\([^,()]+/ {
|
||||
local = /^FN_LOCAL/
|
||||
gsub(/^FN_(LOC|GLOB)AL_|,.*$/, "")
|
||||
sub(/^BOOL\(/, "BOOL ")
|
||||
sub(/^CHAR\(/, "char ")
|
||||
sub(/^INTEGER\(/, "int ")
|
||||
sub(/^STRING\(/, "char *")
|
||||
protos = protos "\n" $0 (local ? "(int module_id);" : "(void);")
|
||||
next
|
||||
}
|
||||
|
||||
/^static|^extern|;/||!/^[A-Za-z][A-Za-z0-9_]* / { next }
|
||||
|
||||
/\(.*\)[ \t]*$/ {
|
||||
protos = protos "\n" $0 ";"
|
||||
next
|
||||
}
|
||||
|
||||
/\(/ {
|
||||
inheader = 1
|
||||
protos = protos "\n" $0
|
||||
}
|
||||
|
||||
END {
|
||||
if (old_protos != protos) print protos > "proto.h"
|
||||
printf "" > "proto.h-tstamp"
|
||||
}
|
||||
48
mkproto.pl
48
mkproto.pl
@@ -1,48 +0,0 @@
|
||||
# generate prototypes for rsync
|
||||
|
||||
$old_protos = '';
|
||||
if (open(IN, 'proto.h')) {
|
||||
$old_protos = join('', <IN>);
|
||||
close IN;
|
||||
}
|
||||
|
||||
%FN_MAP = (
|
||||
BOOL => 'BOOL ',
|
||||
CHAR => 'char ',
|
||||
INTEGER => 'int ',
|
||||
STRING => 'char *',
|
||||
);
|
||||
|
||||
$inheader = 0;
|
||||
$protos = qq|/* This file is automatically generated with "make proto". DO NOT EDIT */\n\n|;
|
||||
|
||||
while (<>) {
|
||||
if ($inheader) {
|
||||
if (/[)][ \t]*$/) {
|
||||
$inheader = 0;
|
||||
s/$/;/;
|
||||
}
|
||||
$protos .= $_;
|
||||
} elsif (/^FN_(LOCAL|GLOBAL)_([^(]+)\(([^,()]+)/) {
|
||||
$ret = $FN_MAP{$2};
|
||||
$func = $3;
|
||||
$arg = $1 eq 'LOCAL' ? 'int module_id' : 'void';
|
||||
$protos .= "$ret$func($arg);\n";
|
||||
} elsif (/^static|^extern/ || /[;]/ || !/^[A-Za-z][A-Za-z0-9_]* /) {
|
||||
;
|
||||
} elsif (/[(].*[)][ \t]*$/) {
|
||||
s/$/;/;
|
||||
$protos .= $_;
|
||||
} elsif (/[(]/) {
|
||||
$inheader = 1;
|
||||
$protos .= $_;
|
||||
}
|
||||
}
|
||||
|
||||
if ($old_protos ne $protos) {
|
||||
open(OUT, '>proto.h') or die $!;
|
||||
print OUT $protos;
|
||||
close OUT;
|
||||
}
|
||||
|
||||
open(OUT, '>proto.h-tstamp') and close OUT;
|
||||
@@ -1,6 +0,0 @@
|
||||
#!/bin/sh -e
|
||||
# This script gets git to run gpg with a --passphrase-file option.
|
||||
|
||||
PATH=`echo $PATH | sed 's/^[^:]*://'`
|
||||
|
||||
gpg --batch --passphrase-file=$GPG_PASSFILE "${@}"
|
||||
@@ -1,180 +1,174 @@
|
||||
#!/usr/bin/perl
|
||||
#!/usr/bin/python3 -B
|
||||
|
||||
use strict;
|
||||
use warnings;
|
||||
use Getopt::Long;
|
||||
# This script turns one or more diff files in the patches dir (which is
|
||||
# expected to be a checkout of the rsync-patches git repo) into a branch
|
||||
# in the main rsync git checkout. This allows the applied patch to be
|
||||
# merged with the latest rsync changes and tested. To update the diff
|
||||
# with the resulting changes, see the patch-update script.
|
||||
|
||||
&Getopt::Long::Configure('bundling');
|
||||
&usage if !&GetOptions(
|
||||
'branch|b=s' => \( my $master_branch = 'master' ),
|
||||
'skip-check' => \( my $skip_branch_check ),
|
||||
'delete' => \( my $delete_local_branches ),
|
||||
'help|h' => \( my $help_opt ),
|
||||
);
|
||||
&usage if $help_opt;
|
||||
import os, sys, re, argparse, glob
|
||||
|
||||
require 'packaging/git-status.pl';
|
||||
check_git_state($master_branch, !$skip_branch_check, 1);
|
||||
sys.path = ['packaging'] + sys.path
|
||||
|
||||
my %local_branch;
|
||||
open PIPE, '-|', 'git branch -l' or die "Unable to fork: $!\n";
|
||||
while (<PIPE>) {
|
||||
if (m# patch/\Q$master_branch\E/(.*)#o) {
|
||||
$local_branch{$1} = 1;
|
||||
}
|
||||
}
|
||||
close PIPE;
|
||||
from pkglib import *
|
||||
|
||||
if ($delete_local_branches) {
|
||||
foreach my $name (sort keys %local_branch) {
|
||||
my $branch = "patch/$master_branch/$name";
|
||||
system 'git', 'branch', '-D', $branch and exit 1;
|
||||
}
|
||||
%local_branch = ( );
|
||||
}
|
||||
def main():
|
||||
global created, info, local_branch
|
||||
|
||||
my @patch_list;
|
||||
foreach (@ARGV) {
|
||||
if (!-f $_) {
|
||||
die "File not found: $_\n";
|
||||
}
|
||||
die "Filename is not a .diff file: $_\n" unless /\.diff$/;
|
||||
push @patch_list, $_;
|
||||
}
|
||||
cur_branch, args.base_branch = check_git_state(args.base_branch, not args.skip_check, args.patches_dir)
|
||||
|
||||
exit unless @patch_list;
|
||||
local_branch = get_patch_branches(args.base_branch)
|
||||
|
||||
my(%scanned, %created, %info);
|
||||
if args.delete_local_branches:
|
||||
for name in sorted(local_branch):
|
||||
branch = f"patch/{args.base_branch}/{name}"
|
||||
cmd_chk(['git', 'branch', '-D', branch])
|
||||
local_branch = set()
|
||||
|
||||
foreach my $patch (@patch_list) {
|
||||
my($where, $name) = $patch =~ m{^(.*?)([^/]+)\.diff$};
|
||||
next if $scanned{$name}++;
|
||||
if args.add_missing:
|
||||
for fn in sorted(glob.glob(f"{args.patches_dir}/*.diff")):
|
||||
name = re.sub(r'\.diff$', '', re.sub(r'.+/', '', fn))
|
||||
if name not in local_branch and fn not in args.patch_files:
|
||||
args.patch_files.append(fn)
|
||||
|
||||
open IN, '<', $patch or die "Unable to open $patch: $!\n";
|
||||
if not args.patch_files:
|
||||
return
|
||||
|
||||
my $info = '';
|
||||
my $commit;
|
||||
while (<IN>) {
|
||||
if (m#^based-on: (\S+)#) {
|
||||
$commit = $1;
|
||||
last;
|
||||
}
|
||||
last if m#^index .*\.\..* \d#;
|
||||
last if m#^diff --git #;
|
||||
last if m#^--- (old|a)/#;
|
||||
$info .= $_;
|
||||
}
|
||||
close IN;
|
||||
for fn in args.patch_files:
|
||||
if not fn.endswith('.diff'):
|
||||
die(f"Filename is not a .diff file: {fn}")
|
||||
if not os.path.isfile(fn):
|
||||
die(f"File not found: {fn}")
|
||||
|
||||
$info =~ s/\s+\Z/\n/;
|
||||
scanned = set()
|
||||
info = { }
|
||||
|
||||
my $parent = $master_branch;
|
||||
my @patches = $info =~ m#patch -p1 <patches/(\S+)\.diff#g;
|
||||
if (@patches) {
|
||||
if ($patches[-1] eq $name) {
|
||||
pop @patches;
|
||||
} else {
|
||||
warn "No identity patch line in $patch\n";
|
||||
}
|
||||
if (@patches) {
|
||||
$parent = pop @patches;
|
||||
if (!$scanned{$parent}) {
|
||||
unless (-f "$where$parent.diff") {
|
||||
die "Unknown parent of $patch: $parent\n";
|
||||
}
|
||||
# Add parent to @patch_list so that we will look for the
|
||||
# parent's parent. Any duplicates will just be ignored.
|
||||
push @patch_list, "$where$parent.diff";
|
||||
}
|
||||
}
|
||||
} else {
|
||||
warn "No patch lines found in $patch\n";
|
||||
}
|
||||
patch_list = [ ]
|
||||
for fn in args.patch_files:
|
||||
m = re.match(r'^(?P<dir>.*?)(?P<name>[^/]+)\.diff$', fn)
|
||||
patch = argparse.Namespace(**m.groupdict())
|
||||
if patch.name in scanned:
|
||||
continue
|
||||
patch.fn = fn
|
||||
|
||||
$info{$name} = [ $parent, $info, $commit ];
|
||||
}
|
||||
lines = [ ]
|
||||
commit_hash = None
|
||||
with open(patch.fn, 'r', encoding='utf-8') as fh:
|
||||
for line in fh:
|
||||
m = re.match(r'^based-on: (\S+)', line)
|
||||
if m:
|
||||
commit_hash = m[1]
|
||||
break
|
||||
if (re.match(r'^index .*\.\..* \d', line)
|
||||
or re.match(r'^diff --git ', line)
|
||||
or re.match(r'^--- (old|a)/', line)):
|
||||
break
|
||||
lines.append(re.sub(r'\s*\Z', "\n", line, 1))
|
||||
info_txt = ''.join(lines).strip() + "\n"
|
||||
lines = None
|
||||
|
||||
foreach my $patch (@patch_list) {
|
||||
create_branch($patch);
|
||||
}
|
||||
parent = args.base_branch
|
||||
patches = re.findall(r'patch -p1 <%s/(\S+)\.diff' % args.patches_dir, info_txt)
|
||||
if patches:
|
||||
last = patches.pop()
|
||||
if last != patch.name:
|
||||
warn(f"No identity patch line in {patch.fn}")
|
||||
patches.append(last)
|
||||
if patches:
|
||||
parent = patches.pop()
|
||||
if parent not in scanned:
|
||||
diff_fn = patch.dir + parent + '.diff'
|
||||
if not os.path.isfile(diff_fn):
|
||||
die(f"Failed to find parent of {patch.fn}: {parent}")
|
||||
# Add parent to args.patch_files so that we will look for the
|
||||
# parent's parent. Any duplicates will be ignored.
|
||||
args.patch_files.append(diff_fn)
|
||||
else:
|
||||
warn(f"No patch lines found in {patch.fn}")
|
||||
|
||||
system 'git', 'checkout', $master_branch and exit 1;
|
||||
info[patch.name] = [ parent, info_txt, commit_hash ]
|
||||
|
||||
exit;
|
||||
patch_list.append(patch)
|
||||
|
||||
sub create_branch
|
||||
{
|
||||
my($patch) = @_;
|
||||
my($where, $name) = $patch =~ m{^(.*?)([^/]+)\.diff$};
|
||||
created = set()
|
||||
for patch in patch_list:
|
||||
create_branch(patch)
|
||||
|
||||
return if $created{$name}++;
|
||||
cmd_chk(['git', 'checkout', args.base_branch])
|
||||
|
||||
my $ref = $info{$name};
|
||||
my($parent, $info, $commit) = @$ref;
|
||||
|
||||
my $parent_branch;
|
||||
if ($parent eq $master_branch) {
|
||||
$parent_branch = $master_branch;
|
||||
$parent_branch = $commit if defined $commit;
|
||||
} else {
|
||||
create_branch("$where/$parent.diff");
|
||||
$parent_branch = "patch/$master_branch/$parent";
|
||||
}
|
||||
def create_branch(patch):
|
||||
if patch.name in created:
|
||||
return
|
||||
created.add(patch.name)
|
||||
|
||||
my $branch = "patch/$master_branch/$name";
|
||||
print "\n", '=' x 64, "\nProcessing $branch ($parent_branch)\n";
|
||||
parent, info_txt, commit_hash = info[patch.name]
|
||||
parent = argparse.Namespace(dir=patch.dir, name=parent, fn=patch.dir + parent + '.diff')
|
||||
|
||||
if ($local_branch{$name}) {
|
||||
system 'git', 'branch', '-D', $branch and exit 1;
|
||||
}
|
||||
if parent.name == args.base_branch:
|
||||
parent_branch = commit_hash if commit_hash else args.base_branch
|
||||
else:
|
||||
create_branch(parent)
|
||||
parent_branch = '/'.join(['patch', args.base_branch, parent.name])
|
||||
|
||||
system 'git', 'checkout', '-b', $branch, $parent_branch and exit 1;
|
||||
branch = '/'.join(['patch', args.base_branch, patch.name])
|
||||
print("\n" + '=' * 64)
|
||||
print(f"Processing {branch} ({parent_branch})")
|
||||
|
||||
open OUT, '>', "PATCH.$name" or die $!;
|
||||
print OUT $info;
|
||||
close OUT;
|
||||
system 'git', 'add', "PATCH.$name" and exit 1;
|
||||
if patch.name in local_branch:
|
||||
cmd_chk(['git', 'branch', '-D', branch])
|
||||
|
||||
open IN, '<', $patch or die "Unable to open $patch: $!\n";
|
||||
$_ = join('', <IN>);
|
||||
close IN;
|
||||
cmd_chk(['git', 'checkout', '-b', branch, parent_branch])
|
||||
|
||||
open PIPE, '|-', 'patch -p1' or die $!;
|
||||
print PIPE $_;
|
||||
close PIPE;
|
||||
info_fn = 'PATCH.' + patch.name
|
||||
with open(info_fn, 'w', encoding='utf-8') as fh:
|
||||
fh.write(info_txt)
|
||||
cmd_chk(['git', 'add', info_fn])
|
||||
|
||||
system 'rm -f *.orig */*.orig';
|
||||
with open(patch.fn, 'r', encoding='utf-8') as fh:
|
||||
patch_txt = fh.read()
|
||||
|
||||
while (m#\nnew file mode (\d+)\s+--- /dev/null\s+\Q+++\E b/(.*)#g) {
|
||||
chmod oct($1), $2;
|
||||
system 'git', 'add', $2;
|
||||
}
|
||||
cmd_run('patch -p1'.split(), input=patch_txt)
|
||||
|
||||
while (1) {
|
||||
system 'git status';
|
||||
print 'Press Enter to commit, Ctrl-C to abort, or type a wild-name to add a new file: ';
|
||||
$_ = <STDIN>;
|
||||
last if /^$/;
|
||||
chomp;
|
||||
system "git add $_";
|
||||
}
|
||||
for fn in glob.glob('*.orig') + glob.glob('*/*.orig'):
|
||||
os.unlink(fn)
|
||||
|
||||
while (system 'git', 'commit', '-a', '-m', "Creating branch from $name.diff.") {
|
||||
exit 1 if system '/bin/zsh';
|
||||
}
|
||||
}
|
||||
pos = 0
|
||||
new_file_re = re.compile(r'\nnew file mode (?P<mode>\d+)\s+--- /dev/null\s+\+\+\+ b/(?P<fn>.+)')
|
||||
while True:
|
||||
m = new_file_re.search(patch_txt, pos)
|
||||
if not m:
|
||||
break
|
||||
os.chmod(m['fn'], int(m['mode'], 8))
|
||||
cmd_chk(['git', 'add', m['fn']])
|
||||
pos = m.end()
|
||||
|
||||
sub usage
|
||||
{
|
||||
die <<EOT;
|
||||
Usage branch-from-patch [OPTIONS] patches/DIFF...
|
||||
while True:
|
||||
cmd_chk('git status'.split())
|
||||
ans = input('Press Enter to commit, Ctrl-C to abort, or type a wild-name to add a new file: ')
|
||||
if ans == '':
|
||||
break
|
||||
cmd_chk("git add " + ans, shell=True)
|
||||
|
||||
Options:
|
||||
-b, --branch=BRANCH Create branches relative to BRANCH if no "based-on"
|
||||
header was found in the patch file.
|
||||
--skip-check Skip the check that ensures starting with a clean branch.
|
||||
--delete Delete all the local patch/BASE/* branches, not just the ones
|
||||
that are being recreated.
|
||||
-h, --help Output this help message.
|
||||
EOT
|
||||
}
|
||||
while True:
|
||||
s = cmd_run(['git', 'commit', '-a', '-m', f"Creating branch from {patch.name}.diff."])
|
||||
if not s.returncode:
|
||||
break
|
||||
s = cmd_run(['/bin/zsh'])
|
||||
if s.returncode:
|
||||
die('Aborting due to shell error code')
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
parser = argparse.ArgumentParser(description="Create a git patch branch from an rsync patch file.", add_help=False)
|
||||
parser.add_argument('--branch', '-b', dest='base_branch', metavar='BASE_BRANCH', default='master', help="The branch the patch is based on. Default: master.")
|
||||
parser.add_argument('--add-missing', '-a', action='store_true', help="Add a branch for every patches/*.diff that doesn't have a branch.")
|
||||
parser.add_argument('--skip-check', action='store_true', help="Skip the check that ensures starting with a clean branch.")
|
||||
parser.add_argument('--delete', dest='delete_local_branches', action='store_true', help="Delete all the local patch/BASE/* branches, not just the ones that are being recreated.")
|
||||
parser.add_argument('--patches-dir', '-p', metavar='DIR', default='patches', help="Override the location of the rsync-patches dir. Default: patches.")
|
||||
parser.add_argument('patch_files', metavar='patches/DIFF_FILE', nargs='*', help="Specify what patch diff files to process. Default: all of them.")
|
||||
parser.add_argument("--help", "-h", action="help", help="Output this help message and exit.")
|
||||
args = parser.parse_args()
|
||||
main()
|
||||
|
||||
# vim: sw=4 et
|
||||
|
||||
@@ -5,13 +5,25 @@
|
||||
use strict;
|
||||
|
||||
our %short_no_arg;
|
||||
our %short_with_num;
|
||||
our %long_opt = (
|
||||
our %short_with_num = ( '@' => 1 );
|
||||
our %long_opt = ( # These include some extra long-args that BackupPC uses:
|
||||
'block-size' => 1,
|
||||
'daemon' => -1,
|
||||
'debug' => 1,
|
||||
'fake-super' => 0,
|
||||
'fuzzy' => 0,
|
||||
'group' => 0,
|
||||
'hard-links' => 0,
|
||||
'ignore-times' => 0,
|
||||
'info' => 1,
|
||||
'links' => 0,
|
||||
'log-file' => 3,
|
||||
'one-file-system' => 0,
|
||||
'owner' => 0,
|
||||
'perms' => 0,
|
||||
'recursive' => 0,
|
||||
'times' => 0,
|
||||
'write-devices' => -1,
|
||||
);
|
||||
our $last_long_opt;
|
||||
|
||||
@@ -28,13 +40,13 @@ while (<IN>) {
|
||||
$last_long_opt = $1;
|
||||
$long_opt{$1} = 0 unless exists $long_opt{$1};
|
||||
} elsif (defined($last_long_opt)
|
||||
&& /\Qargs[ac++]\E = ([^["\s]+);/ && $1 ne 'dest_option') {
|
||||
&& /\Qargs[ac++]\E = ([^["\s]+);/) {
|
||||
$long_opt{$last_long_opt} = 2;
|
||||
undef $last_long_opt;
|
||||
} elsif (/dest_option = "--([^"]+)"/) {
|
||||
} elsif (/return "--([^"]+-dest)";/) {
|
||||
$long_opt{$1} = 2;
|
||||
undef $last_long_opt;
|
||||
} elsif (/\Qasprintf(\E[^,]+, "--([^"=]+)=/ || /\Qargs[ac++]\E = "--([^"=]+)=/) {
|
||||
} elsif (/\Qasprintf(\E[^,]+, "--([^"=]+)=/ || /\Qargs[ac++]\E = "--([^"=]+)=/ || /fmt = .*: "--([^"=]+)=/) {
|
||||
$long_opt{$1} = 1;
|
||||
undef $last_long_opt;
|
||||
}
|
||||
@@ -65,7 +77,8 @@ foreach my $opt (sort keys %long_opt) {
|
||||
my $val = $long_opt{$opt};
|
||||
$val = 1 if $opt =~ /^(max-|min-)/;
|
||||
$val = 3 if $opt eq 'files-from';
|
||||
$val = '$ro ? -1 : ' . $val if $opt =~ /^remove-/;
|
||||
$val = q"$only eq 'r' ? -1 : " . $val if $opt =~ /^(remove-|log-file)/;
|
||||
$val = q"$only eq 'w' ? -1 : " . $val if $opt eq 'sender';
|
||||
print " '$opt' => $val,\n";
|
||||
}
|
||||
|
||||
|
||||
@@ -1,51 +0,0 @@
|
||||
# Do some git-status checking for the current dir and (optionally)
|
||||
# the patches dir.
|
||||
|
||||
sub check_git_state
|
||||
{
|
||||
my($master_branch, $fatal_unless_clean, $check_patches_dir) = @_;
|
||||
|
||||
my($cur_branch) = check_git_status($fatal_unless_clean);
|
||||
(my $branch = $cur_branch) =~ s{^patch/([^/]+)/[^/]+$}{$1}; # change patch/BRANCH/PATCH_NAME into BRANCH
|
||||
if ($branch ne $master_branch) {
|
||||
print "The checkout is not on the $master_branch branch.\n";
|
||||
exit 1 if $master_branch ne 'master';
|
||||
print "Do you want me to continue with --branch=$branch? [n] ";
|
||||
$_ = <STDIN>;
|
||||
exit 1 unless /^y/i;
|
||||
$_[0] = $master_branch = $branch; # Updates caller's $master_branch too.
|
||||
}
|
||||
|
||||
if ($check_patches_dir && -d 'patches/.git') {
|
||||
($branch) = check_git_status($fatal_unless_clean, 'patches');
|
||||
if ($branch ne $master_branch) {
|
||||
print "The *patches* checkout is on branch $branch, not branch $master_branch.\n";
|
||||
print "Do you want to change it to branch $master_branch? [n] ";
|
||||
$_ = <STDIN>;
|
||||
exit 1 unless /^y/i;
|
||||
system "cd patches && git checkout '$master_branch'";
|
||||
}
|
||||
}
|
||||
|
||||
return $cur_branch;
|
||||
}
|
||||
|
||||
sub check_git_status
|
||||
{
|
||||
my($fatal_unless_clean, $subdir) = @_;
|
||||
$subdir = '.' unless defined $subdir;
|
||||
my $status = `cd '$subdir' && git status`;
|
||||
my $is_clean = $status =~ /\nnothing to commit \(working directory clean\)/;
|
||||
my($cur_branch) = $status =~ /^# On branch (.+)\n/;
|
||||
if ($fatal_unless_clean && !$is_clean) {
|
||||
if ($subdir eq '.') {
|
||||
$subdir = '';
|
||||
} else {
|
||||
$subdir = " *$subdir*";
|
||||
}
|
||||
die "The$subdir checkout is not clean:\n", $status;
|
||||
}
|
||||
($cur_branch, $is_clean, $status);
|
||||
}
|
||||
|
||||
1;
|
||||
@@ -1,6 +1,6 @@
|
||||
Summary: A fast, versatile, remote (and local) file-copying tool
|
||||
Name: rsync
|
||||
Version: 3.1.1
|
||||
Version: 3.2.0
|
||||
%define fullversion %{version}pre2
|
||||
Release: 0.1.pre2
|
||||
%define srcdir src-previews
|
||||
@@ -13,11 +13,6 @@ URL: http://rsync.samba.org/
|
||||
Prefix: %{_prefix}
|
||||
BuildRoot: /var/tmp/%{name}-root
|
||||
|
||||
%package ssl-client
|
||||
Summary: Provides rsync-ssl
|
||||
Group: Applications/Internet
|
||||
Requires: rsync, stunnel >= 4
|
||||
|
||||
%package ssl-daemon
|
||||
Summary: An stunnel config file to support ssl rsync daemon connections.
|
||||
Group: Applications/Internet
|
||||
@@ -34,11 +29,6 @@ differences between the source files and the existing files in the
|
||||
destination. Rsync is widely used for backups and mirroring and as an
|
||||
improved copy command for everyday use.
|
||||
|
||||
%description ssl-client
|
||||
Provides the rsync-ssl script that makes use of stunnel 4 to open an ssl
|
||||
connection to an rsync daemon (on port 874). This setup does NOT require
|
||||
any local stunnel daemon to be running to connect to the remote ssl rsyncd.
|
||||
|
||||
%description ssl-daemon
|
||||
Provides a config file for stunnel that will (if you start your stunnel
|
||||
service) cause stunnel to listen for ssl rsync-daemon connections and run
|
||||
@@ -66,7 +56,7 @@ make
|
||||
|
||||
%install
|
||||
rm -rf $RPM_BUILD_ROOT
|
||||
make install install-ssl-client install-ssl-daemon DESTDIR=$RPM_BUILD_ROOT
|
||||
make install install-ssl-daemon DESTDIR=$RPM_BUILD_ROOT
|
||||
|
||||
mkdir -p $RPM_BUILD_ROOT/etc/xinetd.d $RPM_BUILD_ROOT/etc/rsync-ssl/certs
|
||||
install -m 644 packaging/lsb/rsync.xinetd $RPM_BUILD_ROOT/etc/xinetd.d/rsync
|
||||
@@ -76,23 +66,21 @@ rm -rf $RPM_BUILD_ROOT
|
||||
|
||||
%files
|
||||
%defattr(-,root,root)
|
||||
%doc COPYING NEWS OLDNEWS README support/ tech_report.tex
|
||||
%doc COPYING NEWS.md OLDNEWS.md README.md support/ tech_report.tex
|
||||
%config(noreplace) /etc/xinetd.d/rsync
|
||||
%{_prefix}/bin/rsync
|
||||
%{_mandir}/man1/rsync.1*
|
||||
%{_mandir}/man5/rsyncd.conf.5*
|
||||
|
||||
%files ssl-client
|
||||
%{_prefix}/bin/rsync-ssl
|
||||
%{_prefix}/bin/stunnel-rsync
|
||||
%{_mandir}/man1/rsync.1*
|
||||
%{_mandir}/man1/rsync-ssl.1*
|
||||
%{_mandir}/man5/rsyncd.conf.5*
|
||||
|
||||
%files ssl-daemon
|
||||
%config(noreplace) /etc/stunnel/rsyncd.conf
|
||||
%dir /etc/rsync-ssl/certs
|
||||
|
||||
%changelog
|
||||
* Mon May 26 2014 Wayne Davison <wayned@samba.org>
|
||||
Released 3.1.1pre2.
|
||||
* Mon Jun 15 2020 Wayne Davison <wayned@samba.org>
|
||||
Released 3.2.0pre2.
|
||||
|
||||
* Fri Mar 21 2008 Wayne Davison <wayned@samba.org>
|
||||
Added installation of /etc/xinetd.d/rsync file and some commented-out
|
||||
|
||||
96
packaging/md2html
Executable file
96
packaging/md2html
Executable file
@@ -0,0 +1,96 @@
|
||||
#!/usr/bin/python3
|
||||
|
||||
# Copyright (C) 2020 Wayne Davison
|
||||
#
|
||||
# This program is freely redistributable.
|
||||
|
||||
import re, argparse
|
||||
|
||||
HTML_START = """\
|
||||
<html><head>
|
||||
<title>%s</title>
|
||||
<link href="https://fonts.googleapis.com/css2?family=Roboto&family=Roboto+Mono&display=swap" rel="stylesheet">
|
||||
<style>
|
||||
body {
|
||||
max-width: 50em;
|
||||
margin: auto;
|
||||
}
|
||||
body, b, strong, u {
|
||||
font-family: 'Roboto', sans-serif;
|
||||
}
|
||||
code {
|
||||
font-family: 'Roboto Mono', monospace;
|
||||
font-weight: bold;
|
||||
}
|
||||
pre code {
|
||||
display: block;
|
||||
font-weight: normal;
|
||||
}
|
||||
blockquote pre code {
|
||||
background: #f1f1f1;
|
||||
}
|
||||
dd p:first-of-type {
|
||||
margin-block-start: 0em;
|
||||
}
|
||||
</style>
|
||||
</head><body>
|
||||
"""
|
||||
|
||||
HTML_END = """\
|
||||
</body></html>
|
||||
"""
|
||||
|
||||
md_parser = None
|
||||
|
||||
def main():
|
||||
for mdfn in args.mdfiles:
|
||||
if not mdfn.endswith('.md'):
|
||||
print('Ignoring non-md input file:', mdfn)
|
||||
continue
|
||||
title = re.sub(r'.*/', '', mdfn).replace('.md', '')
|
||||
htfn = mdfn.replace('.md', '.html')
|
||||
|
||||
print("Parsing", mdfn, '->', htfn)
|
||||
|
||||
with open(mdfn, 'r', encoding='utf-8') as fh:
|
||||
txt = fh.read()
|
||||
|
||||
txt = re.sub(r'\s--\s', '\xa0-- ', txt)
|
||||
|
||||
html = md_parser(txt)
|
||||
|
||||
html = re.sub(r'(<code>)([\s\S]*?)(</code>)', lambda m: m[1] + re.sub(r'\s', '\xa0', m[2]) + m[3], html)
|
||||
html = html.replace('--', '‑‑').replace("\xa0-", ' ‑').replace("\xa0", ' ')
|
||||
html = re.sub(r'(\W)-', r'\1‑', html)
|
||||
|
||||
with open(htfn, 'w', encoding='utf-8') as fh:
|
||||
fh.write(HTML_START % title)
|
||||
fh.write(html)
|
||||
fh.write(HTML_END)
|
||||
|
||||
|
||||
def html_via_cmarkgfm(txt):
|
||||
return cmarkgfm.markdown_to_html(txt)
|
||||
|
||||
|
||||
def html_via_commonmark(txt):
|
||||
return commonmark.HtmlRenderer().render(commonmark.Parser().parse(txt))
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
parser = argparse.ArgumentParser(description='Output html for md pages.', add_help=False)
|
||||
parser.add_argument("--help", "-h", action="help", help="Output this help message and exit.")
|
||||
parser.add_argument("mdfiles", nargs='+', help="The .md files to turn into .html files.")
|
||||
args = parser.parse_args()
|
||||
|
||||
try:
|
||||
import cmarkgfm
|
||||
md_parser = html_via_cmarkgfm
|
||||
except:
|
||||
try:
|
||||
import commonmark
|
||||
md_parser = html_via_commonmark
|
||||
except:
|
||||
die("Failed to find cmarkgfm or commonmark for python3.")
|
||||
|
||||
main()
|
||||
@@ -1,173 +1,106 @@
|
||||
#!/usr/bin/perl
|
||||
use strict;
|
||||
#!/usr/bin/python3 -B
|
||||
|
||||
# This script expects the directory ~/samba-rsync-ftp to exist and to be a
|
||||
# copy of the /home/ftp/pub/rsync dir on samba.org. It also requires a
|
||||
# git checkout of rsync (feel free to use your normal rsync build dir as
|
||||
# long as it doesn't have any uncommitted changes).
|
||||
#
|
||||
# If this is run with -ctu, it will make an updated "nightly" tar file in
|
||||
# If this is run with -tu, it will make an updated "nightly" tar file in
|
||||
# the nightly dir. It will also remove any old tar files, regenerate the
|
||||
# HTML man pages in the nightly dir, and then rsync the changes to the
|
||||
# samba.org server.
|
||||
|
||||
use Getopt::Long;
|
||||
use Date::Format;
|
||||
import os, sys, re, argparse, glob
|
||||
from datetime import datetime, timezone
|
||||
from getpass import getpass
|
||||
|
||||
sys.path = ['packaging'] + sys.path
|
||||
|
||||
from pkglib import *
|
||||
|
||||
# Where the local copy of /home/ftp/pub/rsync/dev/nightly should be updated.
|
||||
our $dest = $ENV{HOME} . '/samba-rsync-ftp/dev/nightly';
|
||||
our $nightly_symlink = "$dest/rsync-HEAD.tar.gz";
|
||||
dest = os.environ['HOME'] + '/samba-rsync-ftp/dev/nightly'
|
||||
samba_host = os.environ['SAMBA_HOST']
|
||||
nightly_symlink = f"{dest}/rsync-HEAD.tar.gz"
|
||||
|
||||
our($make_tar, $upload, $help_opt);
|
||||
&Getopt::Long::Configure('bundling');
|
||||
&usage if !&GetOptions(
|
||||
'make-tar|t' => \$make_tar,
|
||||
'upload|u' => \$upload,
|
||||
'help|h' => \$help_opt,
|
||||
) || $help_opt;
|
||||
def main():
|
||||
now = datetime.now(timezone.utc)
|
||||
name = now.strftime('rsync-HEAD-%Y%m%d-%H%MGMT')
|
||||
ztoday = now.strftime('%d %b %Y')
|
||||
today = ztoday.lstrip('0')
|
||||
gen_target = 'gensend' if args.upload else 'gen'
|
||||
|
||||
our $name = time2str('rsync-HEAD-%Y%m%d-%H%M%Z', time, 'GMT');
|
||||
our $ztoday = time2str('%d %b %Y', time);
|
||||
our $today = $ztoday;
|
||||
our $gen_target = $upload ? 'gensend' : 'gen';
|
||||
if not os.path.isdir(dest):
|
||||
die("$dest does not exist")
|
||||
if not os.path.isdir('.git'):
|
||||
die("There is no .git dir in the current directory.")
|
||||
if not os.path.exists('rsyncd.conf.5.md'):
|
||||
die("There is no rsync checkout in the current directory.")
|
||||
|
||||
die "$dest does not exist\n" unless -d $dest;
|
||||
die "There is no .git dir in the current directory.\n" unless -d '.git';
|
||||
die "There is no rsync checkout in the current directory.\n" unless -f 'rsyncd.conf.yo';
|
||||
mandate_gensend_hook()
|
||||
|
||||
if ($make_tar) {
|
||||
open(IN, '-|', 'git status') or die $!;
|
||||
my $status = join('', <IN>);
|
||||
close IN;
|
||||
die "The checkout is not clean:\n", $status unless $status =~ /\nnothing to commit \(working directory clean\)/;
|
||||
die "The checkout is not on the master branch.\n" unless $status =~ /^# On branch master\n/;
|
||||
system "make $gen_target" and die "make $gen_target failed!\n";
|
||||
if args.make_tar:
|
||||
check_git_state('master')
|
||||
cmd_chk(['touch', 'NEWS.md'])
|
||||
cmd_chk(['make', gen_target])
|
||||
cmd_chk(['rsync', '-a', *glob.glob('*.[1-9].html'), dest])
|
||||
|
||||
my @extra_files;
|
||||
open(IN, '<', 'Makefile.in') or die "Couldn't open Makefile.in: $!\n";
|
||||
while (<IN>) {
|
||||
if (s/^GENFILES=//) {
|
||||
while (s/\\$//) {
|
||||
$_ .= <IN>;
|
||||
}
|
||||
@extra_files = split(' ', $_);
|
||||
last;
|
||||
}
|
||||
}
|
||||
close IN;
|
||||
gen_files = get_gen_files()
|
||||
|
||||
my $confversion;
|
||||
open(IN, '<', 'configure.ac') or die "Unable to open configure.ac: $!\n";
|
||||
while (<IN>) {
|
||||
if (/^RSYNC_VERSION=(.*)/) {
|
||||
$confversion = $1;
|
||||
last;
|
||||
}
|
||||
}
|
||||
close IN;
|
||||
die "Unable to find RSYNC_VERSION in configure.ac\n" unless defined $confversion;
|
||||
confversion = get_configure_version()
|
||||
|
||||
open(IN, '<', 'OLDNEWS') or die "Unable to open OLDNEWS: $!\n";
|
||||
$_ = <IN>;
|
||||
my($lastversion) = /(\d+\.\d+\.\d+)/;
|
||||
my $last_protocol_version;
|
||||
while (<IN>) {
|
||||
if (my($ver,$pdate,$pver) = /^\s+\S\S\s\S\S\S\s\d\d\d\d\s+(\d+\.\d+\.\d+)\s+(\d\d \w\w\w \d\d\d\d\s+)?(\d+)$/) {
|
||||
$last_protocol_version = $pver if $ver eq $lastversion;
|
||||
}
|
||||
}
|
||||
close IN;
|
||||
die "Unable to determine protocol_version for $lastversion.\n" unless defined $last_protocol_version;
|
||||
# All version values are strings!
|
||||
last_version, last_protocol_version = get_OLDNEWS_version_info()
|
||||
protocol_version, subprotocol_version = get_protocol_versions()
|
||||
|
||||
my($protocol_version,$subprotocol_version);
|
||||
open(IN, '<', 'rsync.h') or die "Unable to open rsync.h: $!\n";
|
||||
while (<IN>) {
|
||||
if (/^#define\s+PROTOCOL_VERSION\s+(\d+)/) {
|
||||
$protocol_version = $1;
|
||||
} elsif (/^#define\s+SUBPROTOCOL_VERSION\s+(\d+)/) {
|
||||
$subprotocol_version = $1;
|
||||
}
|
||||
}
|
||||
close IN;
|
||||
die "Unable to determine the current PROTOCOL_VERSION.\n" unless defined $protocol_version;
|
||||
die "Unable to determine the current SUBPROTOCOL_VERSION.\n" unless defined $subprotocol_version;
|
||||
if 'dev' in confversion or 'pre' in confversion:
|
||||
if last_protocol_version != protocol_version:
|
||||
if subprotocol_version == '0':
|
||||
die("SUBPROTOCOL_VERSION must not be 0 for a non-final release with a changed PROTOCOL_VERSION.")
|
||||
elif subprotocol_version != '0':
|
||||
die("SUBPROTOCOL_VERSION must be 0 when the PROTOCOL_VERSION hasn't changed from the last release.")
|
||||
elif subprotocol_version != '0':
|
||||
die("SUBPROTOCOL_VERSION must be 0 for a final release.")
|
||||
|
||||
if ($confversion =~ /dev|pre/) {
|
||||
if ($last_protocol_version ne $protocol_version) {
|
||||
if ($subprotocol_version == 0) {
|
||||
die "SUBPROTOCOL_VERSION must not be 0 for a non-final release with a changed PROTOCOL_VERSION.\n";
|
||||
}
|
||||
} else {
|
||||
if ($subprotocol_version != 0) {
|
||||
die "SUBPROTOCOL_VERSION must be 0 when the PROTOCOL_VERSION hasn't changed from the last release.\n";
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if ($subprotocol_version != 0) {
|
||||
die "SUBPROTOCOL_VERSION must be 0 for a final release.\n";
|
||||
}
|
||||
}
|
||||
name_slash = name + '/'
|
||||
tar_name = f"{name}.tar.gz"
|
||||
|
||||
print "Creating $name.tar.gz\n";
|
||||
system "rsync -a @extra_files $name/";
|
||||
system "git archive --format=tar --prefix=$name/ HEAD | tar xf -";
|
||||
system "support/git-set-file-times --prefix=$name/";
|
||||
system "fakeroot tar czf $dest/$name.tar.gz $name; rm -rf $name";
|
||||
print('Creating', tar_name)
|
||||
|
||||
unlink($nightly_symlink);
|
||||
symlink("$name.tar.gz", $nightly_symlink);
|
||||
}
|
||||
cmd_chk(['rsync', '-a', *gen_files, name_slash])
|
||||
cmd_chk(f"git archive --format=tar --prefix={name}/ HEAD | tar xf -")
|
||||
cmd_chk(['support/git-set-file-times', '--quiet', '--prefix', name_slash])
|
||||
cmd_chk(['fakeroot', 'tar', 'czf', os.path.join(dest, tar_name), name])
|
||||
cmd_chk(['rm', '-rf', name])
|
||||
|
||||
foreach my $fn (qw( rsync.yo rsyncd.conf.yo )) {
|
||||
my $yo_tmp = "$dest/$fn";
|
||||
(my $html_fn = "$dest/$fn") =~ s/\.yo/.html/;
|
||||
if os.path.lexists(nightly_symlink):
|
||||
os.unlink(nightly_symlink)
|
||||
os.symlink(tar_name, nightly_symlink)
|
||||
|
||||
open(IN, '<', $fn) or die $!;
|
||||
undef $/; $_ = <IN>; $/ = "\n";
|
||||
close IN;
|
||||
os.chdir(dest)
|
||||
|
||||
s/^(manpage\([^)]+\)\(\d+\)\()[^)]+(\).*)/$1$today$2/m;
|
||||
#s/^(This man ?page is current for version) \S+ (of rsync)/$1 $version $2/m;
|
||||
tar_files = list(reversed(sorted(glob.glob('rsync-HEAD-*'))))
|
||||
if len(tar_files) > 10:
|
||||
for fn in tar_files[10:]:
|
||||
print('Removing', fn)
|
||||
os.unlink(fn)
|
||||
|
||||
open(OUT, '>', $yo_tmp) or die $!;
|
||||
print OUT $_;
|
||||
close OUT;
|
||||
cmd_run('ls -ltr'.split())
|
||||
|
||||
system 'yodl2html', '-o', $html_fn, $yo_tmp;
|
||||
if args.upload:
|
||||
cmd = 'rsync -aivHP --delete-after'.split()
|
||||
partial_dir = os.environ.get('RSYNC_PARTIAL_DIR', None)
|
||||
if partial_dir:
|
||||
cmd.append('-fR ' + partial_dir)
|
||||
cmd_chk([*cmd, '.', f"{samba_host}:/home/ftp/pub/rsync/dev/nightly"])
|
||||
|
||||
unlink($yo_tmp);
|
||||
}
|
||||
|
||||
chdir($dest) or die $!;
|
||||
if __name__ == '__main__':
|
||||
parser = argparse.ArgumentParser(description='A helper script for "nightly" tar files.', add_help=False)
|
||||
parser.add_argument('--make-tar', '-t', action='store_true', help=f"Create a new tar file in {dest}.")
|
||||
parser.add_argument('--upload', '-u', action='store_true', help="Upload the revised nightly dir to {samba_host}.")
|
||||
parser.add_argument("--help", "-h", action="help", help="Output this help message and exit.")
|
||||
args = parser.parse_args()
|
||||
main()
|
||||
|
||||
my $cnt = 0;
|
||||
open(PIPE, '-|', 'ls -1t rsync-HEAD-*') or die $!;
|
||||
while (<PIPE>) {
|
||||
chomp;
|
||||
next if $cnt++ < 10;
|
||||
unlink($_);
|
||||
}
|
||||
close PIPE;
|
||||
|
||||
system 'ls -ltr';
|
||||
|
||||
if ($upload) {
|
||||
my $opt = '';
|
||||
if (defined $ENV{RSYNC_PARTIAL_DIR}) {
|
||||
$opt = " -f 'R $ENV{RSYNC_PARTIAL_DIR}'";
|
||||
}
|
||||
system "rsync$opt -aviHP --delete-after . samba.org:/home/ftp/pub/rsync/dev/nightly";
|
||||
}
|
||||
|
||||
exit;
|
||||
|
||||
sub usage
|
||||
{
|
||||
die <<EOT;
|
||||
Usage: nightly-rsync [OPTIONS]
|
||||
|
||||
-t, --make-tar create a new tar file in $dest
|
||||
-u, --upload upload the revised nightly dir to samba.org
|
||||
-h, --help display this help
|
||||
EOT
|
||||
}
|
||||
# vim: sw=4 et
|
||||
|
||||
@@ -1,240 +1,210 @@
|
||||
#!/usr/bin/perl
|
||||
#!/usr/bin/python3 -B
|
||||
|
||||
# This script is used to turn one or more of the "patch/BASE/*" branches
|
||||
# into one or more diffs in the "patches" directory. Pass the option
|
||||
# --gen if you want generated files in the diffs. Pass the name of
|
||||
# one or more diffs if you want to just update a subset of all the
|
||||
# diffs.
|
||||
|
||||
use strict;
|
||||
use warnings;
|
||||
use Getopt::Long;
|
||||
import os, sys, re, argparse, time, shutil
|
||||
|
||||
my $patches_dir = 'patches';
|
||||
my $tmp_dir = "patches.$$";
|
||||
my $make_gen_cmd = 'make -f prepare-source.mak conf && ./config.status && make gen';
|
||||
sys.path = ['packaging'] + sys.path
|
||||
|
||||
&Getopt::Long::Configure('bundling');
|
||||
&usage if !&GetOptions(
|
||||
'branch|b=s' => \( my $master_branch = 'master' ),
|
||||
'skip-check' => \( my $skip_branch_check ),
|
||||
'shell|s' => \( my $launch_shell ),
|
||||
'gen:s' => \( my $incl_generated_files ),
|
||||
'help|h' => \( my $help_opt ),
|
||||
);
|
||||
&usage if $help_opt;
|
||||
from pkglib import *
|
||||
|
||||
if (defined $incl_generated_files) {
|
||||
$patches_dir = $incl_generated_files if $incl_generated_files ne '';
|
||||
$incl_generated_files = 1;
|
||||
}
|
||||
MAKE_GEN_CMDS = [
|
||||
'make -f prepare-source.mak conf'.split(),
|
||||
'./config.status'.split(),
|
||||
'make gen'.split(),
|
||||
]
|
||||
TMP_DIR = "patches.gen"
|
||||
|
||||
die "No '$patches_dir' directory was found.\n" unless -d $patches_dir;
|
||||
die "No '.git' directory present in the current dir.\n" unless -d '.git';
|
||||
os.environ['GIT_MERGE_AUTOEDIT'] = 'no'
|
||||
|
||||
require 'packaging/git-status.pl';
|
||||
my $starting_branch = check_git_state($master_branch, !$skip_branch_check, 1);
|
||||
def main():
|
||||
global master_commit, parent_patch, description, completed, last_touch
|
||||
|
||||
my $master_commit;
|
||||
open PIPE, '-|', "git log -1 --no-color $master_branch" or die $!;
|
||||
while (<PIPE>) {
|
||||
if (/^commit (\S+)/) {
|
||||
$master_commit = $1;
|
||||
last;
|
||||
}
|
||||
}
|
||||
close PIPE;
|
||||
die "Unable to determine commit hash for master branch: $master_branch\n" unless defined $master_commit;
|
||||
if not os.path.isdir(args.patches_dir):
|
||||
die(f'No "{args.patches_dir}" directory was found.')
|
||||
if not os.path.isdir('.git'):
|
||||
die('No ".git" directory present in the current dir.')
|
||||
|
||||
if ($incl_generated_files) {
|
||||
my @extra_files = get_extra_files();
|
||||
die "'$tmp_dir' must not exist in the current directory.\n" if -e $tmp_dir;
|
||||
mkdir($tmp_dir, 0700) or die "Unable to mkdir($tmp_dir): $!\n";
|
||||
system "$make_gen_cmd && rsync -a @extra_files $tmp_dir/master/" and exit 1;
|
||||
}
|
||||
our $last_touch = time;
|
||||
starting_branch, args.base_branch = check_git_state(args.base_branch, not args.skip_check, args.patches_dir)
|
||||
|
||||
my %patches;
|
||||
master_commit = latest_git_hash(args.base_branch)
|
||||
|
||||
# Start by finding all patches so that we can load all possible parents.
|
||||
open(PIPE, '-|', 'git', 'branch', '-l') or die $!;
|
||||
while (<PIPE>) {
|
||||
if (m# patch/\Q$master_branch\E/(.*)#o) {
|
||||
$patches{$1} = 1;
|
||||
}
|
||||
}
|
||||
close PIPE;
|
||||
if args.gen:
|
||||
if os.path.lexists(TMP_DIR):
|
||||
die(f'"{TMP_DIR}" must not exist in the current directory.')
|
||||
gen_files = get_gen_files()
|
||||
os.mkdir(TMP_DIR, 0o700)
|
||||
for cmd in MAKE_GEN_CMDS:
|
||||
cmd_chk(cmd)
|
||||
cmd_chk(['rsync', '-a', *gen_files, f'{TMP_DIR}/master/'])
|
||||
|
||||
my @patches = sort keys %patches;
|
||||
last_touch = time.time()
|
||||
|
||||
my(%parent, %description);
|
||||
foreach my $patch (@patches) {
|
||||
my $branch = "patch/$master_branch/$patch";
|
||||
my $desc = '';
|
||||
open(PIPE, '-|', 'git', 'diff', '-U1000', "$master_branch...$branch", '--', "PATCH.$patch") or die $!;
|
||||
while (<PIPE>) {
|
||||
last if /^@@ /;
|
||||
}
|
||||
while (<PIPE>) {
|
||||
next unless s/^[ +]//;
|
||||
if (m#patch -p1 <patches/(\S+)\.diff# && $1 ne $patch) {
|
||||
my $parent = $parent{$patch} = $1;
|
||||
if (!$patches{$parent}) {
|
||||
die "Parent of $patch is not a local branch: $parent\n";
|
||||
}
|
||||
}
|
||||
$desc .= $_;
|
||||
}
|
||||
close PIPE;
|
||||
$description{$patch} = $desc;
|
||||
}
|
||||
# Start by finding all patches so that we can load all possible parents.
|
||||
patches = sorted(list(get_patch_branches(args.base_branch)))
|
||||
|
||||
if (@ARGV) {
|
||||
# Limit the list of patches to actually process based on @ARGV.
|
||||
@patches = ( );
|
||||
foreach (@ARGV) {
|
||||
s{^patch(es)?/} {};
|
||||
s{\.diff$} {};
|
||||
if (!$patches{$_}) {
|
||||
die "Local branch not available for patch: $_\n";
|
||||
}
|
||||
push(@patches, $_);
|
||||
}
|
||||
}
|
||||
parent_patch = { }
|
||||
description = { }
|
||||
|
||||
my %completed;
|
||||
foreach my $patch (@patches) {
|
||||
next if $completed{$patch}++;
|
||||
last unless update_patch($patch);
|
||||
}
|
||||
for patch in patches:
|
||||
branch = f"patch/{args.base_branch}/{patch}"
|
||||
desc = ''
|
||||
proc = cmd_pipe(['git', 'diff', '-U1000', f"{args.base_branch}...{branch}", '--', f"PATCH.{patch}"])
|
||||
in_diff = False
|
||||
for line in proc.stdout:
|
||||
if in_diff:
|
||||
if not re.match(r'^[ +]', line):
|
||||
continue
|
||||
line = line[1:]
|
||||
m = re.search(r'patch -p1 <patches/(\S+)\.diff', line)
|
||||
if m and m[1] != patch:
|
||||
parpat = parent_patch[patch] = m[1]
|
||||
if not parpat in patches:
|
||||
die(f"Parent of {patch} is not a local branch: {parpat}")
|
||||
desc += line
|
||||
elif re.match(r'^@@ ', line):
|
||||
in_diff = True
|
||||
description[patch] = desc
|
||||
proc.communicate()
|
||||
|
||||
if ($incl_generated_files) {
|
||||
system "rm -rf $tmp_dir";
|
||||
}
|
||||
if args.patch_files: # Limit the list of patches to actually process
|
||||
valid_patches = patches
|
||||
patches = [ ]
|
||||
for fn in args.patch_files:
|
||||
name = re.sub(r'\.diff$', '', re.sub(r'.+/', '', fn))
|
||||
if name not in valid_patches:
|
||||
die(f"Local branch not available for patch: {name}")
|
||||
patches.append(name)
|
||||
|
||||
sleep 1 while $last_touch >= time;
|
||||
system "git checkout $starting_branch" and exit 1;
|
||||
completed = set()
|
||||
|
||||
exit;
|
||||
for patch in patches:
|
||||
if patch in completed:
|
||||
continue
|
||||
if not update_patch(patch):
|
||||
break
|
||||
|
||||
if args.gen:
|
||||
shutil.rmtree(TMP_DIR)
|
||||
|
||||
while last_touch >= time.time():
|
||||
time.sleep(1)
|
||||
cmd_chk(['git', 'checkout', starting_branch])
|
||||
|
||||
|
||||
sub update_patch
|
||||
{
|
||||
my($patch) = @_;
|
||||
def update_patch(patch):
|
||||
global last_touch
|
||||
|
||||
my $parent = $parent{$patch};
|
||||
my $based_on;
|
||||
if (defined $parent) {
|
||||
unless ($completed{$parent}++) {
|
||||
update_patch($parent);
|
||||
}
|
||||
$based_on = $parent = "patch/$master_branch/$parent";
|
||||
} else {
|
||||
$parent = $master_branch;
|
||||
$based_on = $master_commit;
|
||||
}
|
||||
completed.add(patch) # Mark it as completed early to short-circuit any (bogus) dependency loops.
|
||||
|
||||
print "======== $patch ========\n";
|
||||
parent = parent_patch.get(patch, None)
|
||||
if parent:
|
||||
if parent not in completed:
|
||||
if not update_patch(parent):
|
||||
return 0
|
||||
based_on = parent = f"patch/{args.base_branch}/{parent}"
|
||||
else:
|
||||
parent = args.base_branch
|
||||
based_on = master_commit
|
||||
|
||||
sleep 1 while $incl_generated_files && $last_touch >= time;
|
||||
system "git checkout patch/$master_branch/$patch" and return 0;
|
||||
print(f"======== {patch} ========")
|
||||
|
||||
my $ok = system("git merge $based_on") == 0;
|
||||
if (!$ok || $launch_shell) {
|
||||
my($parent_dir) = $parent =~ m{([^/]+)$};
|
||||
print qq|"git merge $based_on" incomplete -- please fix.\n| if !$ok;
|
||||
$ENV{PS1} = "[$parent_dir] $patch: ";
|
||||
while (1) {
|
||||
if (system($ENV{SHELL}) != 0) {
|
||||
print "Abort? [n/y] ";
|
||||
$_ = <STDIN>;
|
||||
next unless /^y/i;
|
||||
return 0;
|
||||
}
|
||||
my($cur_branch, $is_clean, $status) = check_git_status(0);
|
||||
last if $is_clean;
|
||||
print $status;
|
||||
}
|
||||
}
|
||||
while args.gen and last_touch >= time.time():
|
||||
time.sleep(1)
|
||||
s = cmd_run(f"git checkout patch/{args.base_branch}/{patch}".split())
|
||||
if s.returncode != 0:
|
||||
return 0
|
||||
|
||||
open(OUT, '>', "$patches_dir/$patch.diff") or die $!;
|
||||
print OUT $description{$patch}, "\nbased-on: $based_on\n";
|
||||
s = cmd_run(['git', 'merge', based_on])
|
||||
ok = s.returncode == 0
|
||||
if not ok or args.shell:
|
||||
m = re.search(r'([^/]+)$', parent)
|
||||
parent_dir = m[1]
|
||||
if not ok:
|
||||
print(f'"git merge {based_on}" incomplete -- please fix.')
|
||||
os.environ['PS1'] = f"[{parent_dir}] {patch}: "
|
||||
while True:
|
||||
s = cmd_run([os.environ.get('SHELL', '/bin/sh')])
|
||||
if s.returncode != 0:
|
||||
ans = input("Abort? [n/y] ")
|
||||
if re.match(r'^y', ans, flags=re.I):
|
||||
return 0
|
||||
continue
|
||||
cur_branch, is_clean, status_txt = check_git_status(0)
|
||||
if is_clean:
|
||||
break
|
||||
print(status_txt, end='')
|
||||
|
||||
my @extra_files;
|
||||
if ($incl_generated_files) {
|
||||
@extra_files = get_extra_files();
|
||||
system "$make_gen_cmd && rsync -a @extra_files $tmp_dir/$patch/" and exit 1;
|
||||
}
|
||||
$last_touch = time;
|
||||
with open(f"{args.patches_dir}/{patch}.diff", 'w', encoding='utf-8') as fh:
|
||||
fh.write(description[patch])
|
||||
fh.write(f"\nbased-on: {based_on}\n")
|
||||
|
||||
open(PIPE, '-|', 'git', 'diff', $based_on) or die $!;
|
||||
DIFF: while (<PIPE>) {
|
||||
while (m{^diff --git a/PATCH}) {
|
||||
while (<PIPE>) {
|
||||
last if m{^diff --git a/};
|
||||
}
|
||||
last DIFF if !defined $_;
|
||||
}
|
||||
next if /^index /;
|
||||
print OUT $_;
|
||||
}
|
||||
close PIPE;
|
||||
if args.gen:
|
||||
gen_files = get_gen_files()
|
||||
for cmd in MAKE_GEN_CMDS:
|
||||
cmd_chk(cmd)
|
||||
cmd_chk(['rsync', '-a', *gen_files, f"{TMP_DIR}/{patch}/"])
|
||||
else:
|
||||
gen_files = [ ]
|
||||
last_touch = time.time()
|
||||
|
||||
if ($incl_generated_files) {
|
||||
my $parent_dir;
|
||||
if ($parent eq $master_branch) {
|
||||
$parent_dir = 'master';
|
||||
} else {
|
||||
($parent_dir) = $parent =~ m{([^/]+)$};
|
||||
}
|
||||
open(PIPE, '-|', 'diff', '-Nurp', "$tmp_dir/$parent_dir", "$tmp_dir/$patch") or die $!;
|
||||
while (<PIPE>) {
|
||||
s#^(diff -Nurp) $tmp_dir/[^/]+/(.*?) $tmp_dir/[^/]+/(.*)#$1 a/$2 b/$3#o;
|
||||
s#^\Q---\E $tmp_dir/[^/]+/([^\t]+)\t.*#--- a/$1#o;
|
||||
s#^\Q+++\E $tmp_dir/[^/]+/([^\t]+)\t.*#+++ b/$1#o;
|
||||
print OUT $_;
|
||||
}
|
||||
close PIPE;
|
||||
unlink @extra_files;
|
||||
}
|
||||
proc = cmd_pipe(['git', 'diff', based_on])
|
||||
skipping = False
|
||||
for line in proc.stdout:
|
||||
if skipping:
|
||||
if not re.match(r'^diff --git a/', line):
|
||||
continue
|
||||
skipping = False
|
||||
elif re.match(r'^diff --git a/PATCH', line):
|
||||
skipping = True
|
||||
continue
|
||||
if not re.match(r'^index ', line):
|
||||
fh.write(line)
|
||||
proc.communicate()
|
||||
|
||||
close OUT;
|
||||
if args.gen:
|
||||
e_tmp_dir = re.escape(TMP_DIR)
|
||||
diff_re = re.compile(r'^(diff -Nurp) %s/[^/]+/(.*?) %s/[^/]+/(.*)' % (e_tmp_dir, e_tmp_dir))
|
||||
minus_re = re.compile(r'^\-\-\- %s/[^/]+/([^\t]+)\t.*' % e_tmp_dir)
|
||||
plus_re = re.compile(r'^\+\+\+ %s/[^/]+/([^\t]+)\t.*' % e_tmp_dir)
|
||||
|
||||
1;
|
||||
}
|
||||
if parent == args.base_branch:
|
||||
parent_dir = 'master'
|
||||
else:
|
||||
m = re.search(r'([^/]+)$', parent)
|
||||
parent_dir = m[1]
|
||||
|
||||
exit;
|
||||
proc = cmd_pipe(['diff', '-Nurp', f"{TMP_DIR}/{parent_dir}", f"{TMP_DIR}/{patch}"])
|
||||
for line in proc.stdout:
|
||||
line = diff_re.sub(r'\1 a/\2 b/\3', line)
|
||||
line = minus_re.sub(r'--- a/\1', line)
|
||||
line = plus_re.sub(r'+++ b/\1', line)
|
||||
fh.write(line)
|
||||
proc.communicate()
|
||||
for fn in gen_files:
|
||||
os.unlink(fn)
|
||||
|
||||
sub get_extra_files
|
||||
{
|
||||
my @extras;
|
||||
return 1
|
||||
|
||||
open(IN, '<', 'Makefile.in') or die "Couldn't open Makefile.in: $!\n";
|
||||
while (<IN>) {
|
||||
if (s/^GENFILES=//) {
|
||||
while (s/\\$//) {
|
||||
$_ .= <IN>;
|
||||
}
|
||||
@extras = split(' ', $_);
|
||||
last;
|
||||
}
|
||||
}
|
||||
close IN;
|
||||
|
||||
return @extras;
|
||||
}
|
||||
if __name__ == '__main__':
|
||||
parser = argparse.ArgumentParser(description="Turn a git branch back into a diff files in the patches dir.", add_help=False)
|
||||
parser.add_argument('--branch', '-b', dest='base_branch', metavar='BASE_BRANCH', default='master', help="The branch the patch is based on. Default: master.")
|
||||
parser.add_argument('--skip-check', action='store_true', help="Skip the check that ensures starting with a clean branch.")
|
||||
parser.add_argument('--shell', '-s', action='store_true', help="Launch a shell for every patch/BASE/* branch updated, not just when a conflict occurs.")
|
||||
parser.add_argument('--gen', metavar='DIR', nargs='?', const='', help='Include generated files. Optional DIR value overrides the default of using the "patches" dir.')
|
||||
parser.add_argument('--patches-dir', '-p', metavar='DIR', default='patches', help="Override the location of the rsync-patches dir. Default: patches.")
|
||||
parser.add_argument('patch_files', metavar='patches/DIFF_FILE', nargs='*', help="Specify what patch diff files to process. Default: all of them.")
|
||||
parser.add_argument("--help", "-h", action="help", help="Output this help message and exit.")
|
||||
args = parser.parse_args()
|
||||
if args.gen == '':
|
||||
args.gen = args.patches_dir
|
||||
elif args.gen is not None:
|
||||
args.patches_dir = args.gen
|
||||
main()
|
||||
|
||||
sub usage
|
||||
{
|
||||
die <<EOT;
|
||||
Usage: patch-update [OPTIONS] [patches/DIFF...]
|
||||
|
||||
Options:
|
||||
-b, --branch=BRANCH The master branch to merge into the patch/BASE/* branches.
|
||||
--gen[=DIR] Include generated files. Optional destination DIR
|
||||
arg overrides the default of using the "patches" dir.
|
||||
--skip-check Skip the check that ensures starting with a clean branch.
|
||||
-s, --shell Launch a shell for every patch/BASE/* branch updated, not
|
||||
just when a conflict occurs.
|
||||
-h, --help Output this help message.
|
||||
EOT
|
||||
}
|
||||
# vim: sw=4 et
|
||||
|
||||
261
packaging/pkglib.py
Normal file
261
packaging/pkglib.py
Normal file
@@ -0,0 +1,261 @@
|
||||
import os, sys, re, subprocess
|
||||
|
||||
# This python3 library provides a few helpful routines that are
|
||||
# used by the latest packaging scripts.
|
||||
|
||||
default_encoding = 'utf-8'
|
||||
|
||||
# Output the msg args to stderr. Accepts all the args that print() accepts.
|
||||
def warn(*msg):
|
||||
print(*msg, file=sys.stderr)
|
||||
|
||||
|
||||
# Output the msg args to stderr and die with a non-zero return-code.
|
||||
# Accepts all the args that print() accepts.
|
||||
def die(*msg):
|
||||
warn(*msg)
|
||||
sys.exit(1)
|
||||
|
||||
|
||||
# Set this to an encoding name or set it to None to avoid the default encoding idiom.
|
||||
def set_default_encoding(enc):
|
||||
default_encoding = enc
|
||||
|
||||
|
||||
# Set shell=True if the cmd is a string; sets a default encoding unless raw=True was specified.
|
||||
def _tweak_opts(cmd, opts, **maybe_set):
|
||||
# This sets any maybe_set value that isn't already set AND creates a copy of opts for us.
|
||||
opts = {**maybe_set, **opts}
|
||||
|
||||
if type(cmd) == str:
|
||||
opts = {'shell': True, **opts}
|
||||
|
||||
want_raw = opts.pop('raw', False)
|
||||
if default_encoding and not want_raw:
|
||||
opts = {'encoding': default_encoding, **opts}
|
||||
|
||||
capture = opts.pop('capture', None)
|
||||
if capture:
|
||||
if capture == 'stdout':
|
||||
opts = {'stdout': subprocess.PIPE, **opts}
|
||||
elif capture == 'stderr':
|
||||
opts = {'stderr': subprocess.PIPE, **opts}
|
||||
elif capture == 'output':
|
||||
opts = {'stdout': subprocess.PIPE, 'stderr': subprocess.PIPE, **opts}
|
||||
elif capture == 'combined':
|
||||
opts = {'stdout': subprocess.PIPE, 'stderr': subprocess.STDOUT, **opts}
|
||||
|
||||
discard = opts.pop('discard', None)
|
||||
if discard:
|
||||
# We DO want to override any already set stdout|stderr values (unlike above).
|
||||
if discard == 'stdout' or discard == 'output':
|
||||
opts['stdout'] = subprocess.DEVNULL
|
||||
if discard == 'stderr' or discard == 'output':
|
||||
opts['stderr'] = subprocess.DEVNULL
|
||||
|
||||
return opts
|
||||
|
||||
|
||||
# This does a normal subprocess.run() with some auto-args added to make life easier.
|
||||
def cmd_run(cmd, **opts):
|
||||
return subprocess.run(cmd, **_tweak_opts(cmd, opts))
|
||||
|
||||
|
||||
# Like cmd_run() with a default check=True specified.
|
||||
def cmd_chk(cmd, **opts):
|
||||
return subprocess.run(cmd, **_tweak_opts(cmd, opts, check=True))
|
||||
|
||||
|
||||
# Capture stdout in a string and return the (output, return_code) tuple.
|
||||
# Use capture='combined' opt to get both stdout and stderr together.
|
||||
def cmd_txt_status(cmd, **opts):
|
||||
input = opts.pop('input', None)
|
||||
if input is not None:
|
||||
opts['stdin'] = subprocess.PIPE
|
||||
proc = subprocess.Popen(cmd, **_tweak_opts(cmd, opts, capture='stdout'))
|
||||
out = proc.communicate(input=input)[0]
|
||||
return (out, proc.returncode)
|
||||
|
||||
|
||||
# Like cmd_txt_status() but just return the output.
|
||||
def cmd_txt(cmd, **opts):
|
||||
return cmd_txt_status(cmd, **opts)[0]
|
||||
|
||||
|
||||
# Capture stdout in a string and return the output if the command has a 0 return code.
|
||||
# Otherwise it throws an exception that indicates the return code and the output.
|
||||
def cmd_txt_chk(cmd, **opts):
|
||||
out, rc = cmd_txt_status(cmd, **opts)
|
||||
if rc != 0:
|
||||
cmd_err = f'Command "{cmd}" returned non-zero exit status "{rc}" and output:\n{out}'
|
||||
raise Exception(cmd_err)
|
||||
return out
|
||||
|
||||
|
||||
# Starts a piped-output command of stdout (by default) and leaves it up to you to read
|
||||
# the output and call communicate() on the returned object.
|
||||
def cmd_pipe(cmd, **opts):
|
||||
return subprocess.Popen(cmd, **_tweak_opts(cmd, opts, capture='stdout'))
|
||||
|
||||
|
||||
# Runs a "git status" command and dies if the checkout is not clean (the
|
||||
# arg fatal_unless_clean can be used to make that non-fatal. Returns a
|
||||
# tuple of the current branch, the is_clean flag, and the status text.
|
||||
def check_git_status(fatal_unless_clean=True, subdir='.'):
|
||||
status_txt = cmd_txt_chk(f"cd '{subdir}' && git status")
|
||||
is_clean = re.search(r'\nnothing to commit.+working (directory|tree) clean', status_txt) != None
|
||||
|
||||
if not is_clean and fatal_unless_clean:
|
||||
if subdir == '.':
|
||||
subdir = ''
|
||||
else:
|
||||
subdir = f" *{subdir}*"
|
||||
die(f"The{subdir} checkout is not clean:\n" + status_txt)
|
||||
|
||||
m = re.match(r'^(?:# )?On branch (.+)\n', status_txt)
|
||||
cur_branch = m[1] if m else None
|
||||
|
||||
return (cur_branch, is_clean, status_txt)
|
||||
|
||||
|
||||
# Calls check_git_status() on the current git checkout and (optionally) a subdir path's
|
||||
# checkout. Use fatal_unless_clean to indicate if an unclean checkout is fatal or not.
|
||||
# The master_branch arg indicates what branch we want both checkouts to be using, and
|
||||
# if the branch is wrong the user is given the option of either switching to the right
|
||||
# branch or aborting.
|
||||
def check_git_state(master_branch, fatal_unless_clean=True, check_extra_dir=None):
|
||||
cur_branch = check_git_status(fatal_unless_clean)[0]
|
||||
branch = re.sub(r'^patch/([^/]+)/[^/]+$', r'\1', cur_branch) # change patch/BRANCH/PATCH_NAME into BRANCH
|
||||
if branch != master_branch:
|
||||
print(f"The checkout is not on the {master_branch} branch.")
|
||||
if master_branch != 'master':
|
||||
sys.exit(1)
|
||||
ans = input(f"Do you want me to continue with --branch={branch}? [n] ")
|
||||
if not ans or not re.match(r'^y', ans, flags=re.I):
|
||||
sys.exit(1)
|
||||
master_branch = branch
|
||||
|
||||
if check_extra_dir and os.path.isdir(os.path.join(check_extra_dir, '.git')):
|
||||
branch = check_git_status(fatal_unless_clean, check_extra_dir)[0]
|
||||
if branch != master_branch:
|
||||
print(f"The *{check_extra_dir}* checkout is on branch {branch}, not branch {master_branch}.")
|
||||
ans = input(f"Do you want to change it to branch {master_branch}? [n] ")
|
||||
if not ans or not re.match(r'^y', ans, flags=re.I):
|
||||
sys.exit(1)
|
||||
subdir.check_call(f"cd {check_extra_dir} && git checkout '{master_branch}'", shell=True)
|
||||
|
||||
return (cur_branch, master_branch)
|
||||
|
||||
|
||||
# Return the git hash of the most recent commit.
|
||||
def latest_git_hash(branch):
|
||||
out = cmd_txt_chk(['git', 'log', '-1', '--no-color', branch])
|
||||
m = re.search(r'^commit (\S+)', out, flags=re.M)
|
||||
if not m:
|
||||
die(f"Unable to determine commit hash for master branch: {branch}")
|
||||
return m[1]
|
||||
|
||||
|
||||
# Return a set of all branch names that have the format "patch/BASE_BRANCH/NAME"
|
||||
# for the given base_branch string. Just the NAME portion is put into the set.
|
||||
def get_patch_branches(base_branch):
|
||||
branches = set()
|
||||
proc = cmd_pipe('git branch -l'.split())
|
||||
for line in proc.stdout:
|
||||
m = re.search(r' patch/([^/]+)/(.+)', line)
|
||||
if m and m[1] == base_branch:
|
||||
branches.add(m[2])
|
||||
proc.communicate()
|
||||
return branches
|
||||
|
||||
|
||||
def mandate_gensend_hook():
|
||||
hook = '.git/hooks/pre-push'
|
||||
if not os.path.exists(hook):
|
||||
print('Creating hook file:', hook)
|
||||
cmd_chk(['./rsync', '-a', 'packaging/pre-push', hook])
|
||||
else:
|
||||
out, rc = cmd_txt_status(['fgrep', 'make gensend', hook], discard='output')
|
||||
if rc:
|
||||
die('Please add a "make gensend" into your', hook, 'script.')
|
||||
|
||||
|
||||
# Snag the GENFILES values out of the Makefile.in file and return them as a list.
|
||||
def get_gen_files():
|
||||
cont_re = re.compile(r'\\\n')
|
||||
|
||||
extras = [ ]
|
||||
|
||||
with open('Makefile.in', 'r', encoding='utf-8') as fh:
|
||||
for line in fh:
|
||||
if not extras:
|
||||
chk = re.sub(r'^GENFILES=', '', line)
|
||||
if line == chk:
|
||||
continue
|
||||
line = chk
|
||||
m = re.search(r'\\$', line)
|
||||
line = re.sub(r'^\s+|\s*\\\n?$|\s+$', '', line)
|
||||
extras += line.split()
|
||||
if not m:
|
||||
break
|
||||
|
||||
return extras
|
||||
|
||||
|
||||
def get_configure_version():
|
||||
with open('configure.ac', 'r', encoding='utf-8') as fh:
|
||||
for line in fh:
|
||||
m = re.match(r'^AC_INIT\(\[rsync\],\s*\[(\d.+?)\]', line)
|
||||
if m:
|
||||
return m[1]
|
||||
die("Unable to find AC_INIT with version in configure.ac")
|
||||
|
||||
|
||||
def get_OLDNEWS_version_info():
|
||||
rel_re = re.compile(r'^\| \d{2} \w{3} \d{4}\s+\|\s+(?P<ver>\d+\.\d+\.\d+)\s+\|\s+(?P<pdate>\d{2} \w{3} \d{4}\s+)?\|\s+(?P<pver>\d+)\s+\|')
|
||||
last_version = last_protocol_version = None
|
||||
pdate = { }
|
||||
|
||||
with open('OLDNEWS.md', 'r', encoding='utf-8') as fh:
|
||||
for line in fh:
|
||||
if not last_version:
|
||||
m = re.search(r'(\d+\.\d+\.\d+)', line)
|
||||
if m:
|
||||
last_version = m[1]
|
||||
m = rel_re.match(line)
|
||||
if m:
|
||||
if m['pdate']:
|
||||
pdate[m['ver']] = m['pdate']
|
||||
if m['ver'] == last_version:
|
||||
last_protocol_version = m['pver']
|
||||
break
|
||||
|
||||
if not last_protocol_version:
|
||||
die(f"Unable to determine protocol_version for {last_version}.")
|
||||
|
||||
return last_version, last_protocol_version
|
||||
|
||||
|
||||
def get_protocol_versions():
|
||||
protocol_version = subprotocol_version = None
|
||||
|
||||
with open('rsync.h', 'r', encoding='utf-8') as fh:
|
||||
for line in fh:
|
||||
m = re.match(r'^#define\s+PROTOCOL_VERSION\s+(\d+)', line)
|
||||
if m:
|
||||
protocol_version = m[1]
|
||||
continue
|
||||
m = re.match(r'^#define\s+SUBPROTOCOL_VERSION\s+(\d+)', line)
|
||||
if m:
|
||||
subprotocol_version = m[1]
|
||||
break
|
||||
|
||||
if not protocol_version:
|
||||
die("Unable to determine the current PROTOCOL_VERSION.")
|
||||
|
||||
if not subprotocol_version:
|
||||
die("Unable to determine the current SUBPROTOCOL_VERSION.")
|
||||
|
||||
return protocol_version, subprotocol_version
|
||||
|
||||
# vim: sw=4 et
|
||||
3
packaging/pre-push
Executable file
3
packaging/pre-push
Executable file
@@ -0,0 +1,3 @@
|
||||
#!/bin/sh
|
||||
cat >/dev/null # Just discard stdin data
|
||||
make gensend
|
||||
@@ -1,421 +1,394 @@
|
||||
#!/usr/bin/perl
|
||||
#!/usr/bin/python3 -B
|
||||
|
||||
# This script expects the directory ~/samba-rsync-ftp to exist and to be a
|
||||
# copy of the /home/ftp/pub/rsync dir on samba.org. When the script is done,
|
||||
# the git repository in the current directory will be updated, and the local
|
||||
# ~/samba-rsync-ftp dir will be ready to be rsynced to samba.org.
|
||||
|
||||
use strict;
|
||||
use warnings;
|
||||
use Cwd;
|
||||
use Getopt::Long;
|
||||
use Term::ReadKey;
|
||||
use Date::Format;
|
||||
import os, sys, re, argparse, glob, shutil, signal
|
||||
from datetime import datetime
|
||||
from getpass import getpass
|
||||
|
||||
my $dest = $ENV{HOME} . '/samba-rsync-ftp';
|
||||
my $passfile = $ENV{HOME} . '/.rsyncpass';
|
||||
my $path = $ENV{PATH};
|
||||
my $make_gen_cmd = 'make -f prepare-source.mak conf && ./config.status && make gen';
|
||||
sys.path = ['packaging'] + sys.path
|
||||
|
||||
&Getopt::Long::Configure('bundling');
|
||||
&usage if !&GetOptions(
|
||||
'branch|b=s' => \( my $master_branch = 'master' ),
|
||||
'help|h' => \( my $help_opt ),
|
||||
);
|
||||
&usage if $help_opt;
|
||||
from pkglib import *
|
||||
|
||||
my $now = time;
|
||||
my $cl_today = time2str('* %a %b %d %Y', $now);
|
||||
my $year = time2str('%Y', $now);
|
||||
my $ztoday = time2str('%d %b %Y', $now);
|
||||
(my $today = $ztoday) =~ s/^0//;
|
||||
dest = os.environ['HOME'] + '/samba-rsync-ftp'
|
||||
ORIGINAL_PATH = os.environ['PATH']
|
||||
|
||||
my $curdir = Cwd::cwd;
|
||||
def main():
|
||||
now = datetime.now()
|
||||
cl_today = now.strftime('* %a %b %d %Y')
|
||||
year = now.strftime('%Y')
|
||||
ztoday = now.strftime('%d %b %Y')
|
||||
today = ztoday.lstrip('0')
|
||||
|
||||
END {
|
||||
unlink($passfile);
|
||||
}
|
||||
mandate_gensend_hook()
|
||||
|
||||
my @extra_files;
|
||||
open(IN, '<', 'Makefile.in') or die "Couldn't open Makefile.in: $!\n";
|
||||
while (<IN>) {
|
||||
if (s/^GENFILES=//) {
|
||||
while (s/\\$//) {
|
||||
$_ .= <IN>;
|
||||
}
|
||||
@extra_files = split(' ', $_);
|
||||
last;
|
||||
}
|
||||
}
|
||||
close IN;
|
||||
curdir = os.getcwd()
|
||||
|
||||
my $break = <<EOT;
|
||||
==========================================================================
|
||||
EOT
|
||||
signal.signal(signal.SIGINT, signal_handler)
|
||||
|
||||
print $break, <<EOT, $break, "\n";
|
||||
gen_files = get_gen_files()
|
||||
|
||||
dash_line = '=' * 74
|
||||
|
||||
print(f"""\
|
||||
{dash_line}
|
||||
== This will release a new version of rsync onto an unsuspecting world. ==
|
||||
EOT
|
||||
{dash_line}
|
||||
""")
|
||||
|
||||
die "$dest does not exist\n" unless -d $dest;
|
||||
die "There is no .git dir in the current directory.\n" unless -d '.git';
|
||||
die "'a' must not exist in the current directory.\n" if -e 'a';
|
||||
die "'b' must not exist in the current directory.\n" if -e 'b';
|
||||
if not os.path.isdir(dest):
|
||||
die(dest, "dest does not exist")
|
||||
if not os.path.isdir('.git'):
|
||||
die("There is no .git dir in the current directory.")
|
||||
if os.path.lexists('a'):
|
||||
die('"a" must not exist in the current directory.')
|
||||
if os.path.lexists('b'):
|
||||
die('"b" must not exist in the current directory.')
|
||||
if os.path.lexists('patches.gen'):
|
||||
die('"patches.gen" must not exist in the current directory.')
|
||||
|
||||
require 'packaging/git-status.pl';
|
||||
check_git_state($master_branch, 1, 1);
|
||||
check_git_state(args.master_branch, True, 'patches')
|
||||
|
||||
my $confversion;
|
||||
open(IN, '<', 'configure.ac') or die $!;
|
||||
while (<IN>) {
|
||||
if (/^RSYNC_VERSION=(.*)/) {
|
||||
$confversion = $1;
|
||||
last;
|
||||
}
|
||||
}
|
||||
close IN;
|
||||
die "Unable to find RSYNC_VERSION in configure.ac\n" unless defined $confversion;
|
||||
confversion = get_configure_version()
|
||||
|
||||
open(IN, '<', 'OLDNEWS') or die $!;
|
||||
$_ = <IN>;
|
||||
my($lastversion) = /(\d+\.\d+\.\d+)/;
|
||||
my($last_protocol_version, %pdate);
|
||||
while (<IN>) {
|
||||
if (my($ver,$pdate,$pver) = /^\s+\S\S\s\S\S\S\s\d\d\d\d\s+(\d+\.\d+\.\d+)\s+(\d\d \w\w\w \d\d\d\d\s+)?(\d+)$/) {
|
||||
$pdate{$ver} = $pdate if defined $pdate;
|
||||
$last_protocol_version = $pver if $ver eq $lastversion;
|
||||
}
|
||||
}
|
||||
close IN;
|
||||
die "Unable to determine protocol_version for $lastversion.\n" unless defined $last_protocol_version;
|
||||
# All version values are strings!
|
||||
lastversion, last_protocol_version = get_OLDNEWS_version_info()
|
||||
protocol_version, subprotocol_version = get_protocol_versions()
|
||||
|
||||
my $protocol_version;
|
||||
open(IN, '<', 'rsync.h') or die $!;
|
||||
while (<IN>) {
|
||||
if (/^#define\s+PROTOCOL_VERSION\s+(\d+)/) {
|
||||
$protocol_version = $1;
|
||||
last;
|
||||
}
|
||||
}
|
||||
close IN;
|
||||
die "Unable to determine the current PROTOCOL_VERSION.\n" unless defined $protocol_version;
|
||||
version = confversion
|
||||
m = re.search(r'pre(\d+)', version)
|
||||
if m:
|
||||
version = re.sub(r'pre\d+', 'pre' + str(int(m[1]) + 1), version)
|
||||
else:
|
||||
version = version.replace('dev', 'pre1')
|
||||
|
||||
my $version = $confversion;
|
||||
$version =~ s/dev/pre1/ || $version =~ s/pre(\d+)/ 'pre' . ($1 + 1) /e;
|
||||
ans = input(f"Please enter the version number of this release: [{version}] ")
|
||||
if ans == '.':
|
||||
version = re.sub(r'pre\d+', '', version)
|
||||
elif ans != '':
|
||||
version = ans
|
||||
if not re.match(r'^[\d.]+(pre\d+)?$', version):
|
||||
die(f'Invalid version: "{version}"')
|
||||
|
||||
print "Please enter the version number of this release: [$version] ";
|
||||
chomp($_ = <STDIN>);
|
||||
if ($_ eq '.') {
|
||||
$version =~ s/pre\d+//;
|
||||
} elsif ($_ ne '') {
|
||||
$version = $_;
|
||||
}
|
||||
die "Invalid version: `$version'\n" unless $version =~ /^[\d.]+(pre\d+)?$/;
|
||||
v_ver = 'v' + version
|
||||
rsync_ver = 'rsync-' + version
|
||||
|
||||
if (`git tag -l v$version` ne '') {
|
||||
print "Tag v$version already exists.\n\nDelete tag or quit? [q/del] ";
|
||||
$_ = <STDIN>;
|
||||
exit 1 unless /^del/i;
|
||||
system "git tag -d v$version";
|
||||
}
|
||||
if os.path.lexists(rsync_ver):
|
||||
die(f'"{rsync_ver}" must not exist in the current directory.')
|
||||
|
||||
if ($version =~ s/[-.]*pre[-.]*/pre/ && $confversion !~ /dev$/) {
|
||||
$lastversion = $confversion;
|
||||
}
|
||||
out = cmd_txt_chk(['git', 'tag', '-l', v_ver])
|
||||
if out != '':
|
||||
print(f"Tag {v_ver} already exists.")
|
||||
ans = input("\nDelete tag or quit? [Q/del] ")
|
||||
if not re.match(r'^del', ans, flags=re.I):
|
||||
die("Aborted")
|
||||
cmd_chk(['git', 'tag', '-d', v_ver])
|
||||
|
||||
print "Enter the previous version to produce a patch against: [$lastversion] ";
|
||||
chomp($_ = <STDIN>);
|
||||
$lastversion = $_ if $_ ne '';
|
||||
$lastversion =~ s/[-.]*pre[-.]*/pre/;
|
||||
version = re.sub(r'[-.]*pre[-.]*', 'pre', version)
|
||||
if 'pre' in version and not confversion.endswith('dev'):
|
||||
lastversion = confversion
|
||||
|
||||
my $pre = $version =~ /(pre\d+)/ ? $1 : '';
|
||||
ans = input(f"Enter the previous version to produce a patch against: [{lastversion}] ")
|
||||
if ans != '':
|
||||
lastversion = ans
|
||||
lastversion = re.sub(r'[-.]*pre[-.]*', 'pre', lastversion)
|
||||
|
||||
my $release = $pre ? '0.1' : '1';
|
||||
print "Please enter the RPM release number of this release: [$release] ";
|
||||
chomp($_ = <STDIN>);
|
||||
$release = $_ if $_ ne '';
|
||||
$release .= ".$pre" if $pre;
|
||||
rsync_lastver = 'rsync-' + lastversion
|
||||
if os.path.lexists(rsync_lastver):
|
||||
die(f'"{rsync_lastver}" must not exist in the current directory.')
|
||||
|
||||
(my $finalversion = $version) =~ s/pre\d+//;
|
||||
my($proto_changed,$proto_change_date);
|
||||
if ($protocol_version eq $last_protocol_version) {
|
||||
$proto_changed = 'unchanged';
|
||||
$proto_change_date = "\t\t";
|
||||
} else {
|
||||
$proto_changed = 'changed';
|
||||
if (!defined($proto_change_date = $pdate{$finalversion})) {
|
||||
while (1) {
|
||||
print "On what date did the protocol change to $protocol_version get checked in? (dd Mmm yyyy) ";
|
||||
chomp($_ = <STDIN>);
|
||||
last if /^\d\d \w\w\w \d\d\d\d$/;
|
||||
}
|
||||
$proto_change_date = "$_\t";
|
||||
}
|
||||
}
|
||||
m = re.search(r'(pre\d+)', version)
|
||||
pre = m[1] if m else ''
|
||||
|
||||
my($srcdir,$srcdiffdir,$lastsrcdir,$skipping);
|
||||
if ($lastversion =~ /pre/) {
|
||||
if (!$pre) {
|
||||
die "You should not diff a release version against a pre-release version.\n";
|
||||
}
|
||||
$srcdir = $srcdiffdir = $lastsrcdir = 'src-previews';
|
||||
$skipping = ' ** SKIPPING **';
|
||||
} elsif ($pre) {
|
||||
$srcdir = $srcdiffdir = 'src-previews';
|
||||
$lastsrcdir = 'src';
|
||||
$skipping = ' ** SKIPPING **';
|
||||
} else {
|
||||
$srcdir = $lastsrcdir = 'src';
|
||||
$srcdiffdir = 'src-diffs';
|
||||
$skipping = '';
|
||||
}
|
||||
release = '0.1' if pre else '1'
|
||||
ans = input(f"Please enter the RPM release number of this release: [{release}] ")
|
||||
if ans != '':
|
||||
release = ans
|
||||
if pre:
|
||||
release += '.' + pre
|
||||
|
||||
print "\n", $break, <<EOT;
|
||||
\$version is "$version"
|
||||
\$lastversion is "$lastversion"
|
||||
\$dest is "$dest"
|
||||
\$curdir is "$curdir"
|
||||
\$srcdir is "$srcdir"
|
||||
\$srcdiffdir is "$srcdiffdir"
|
||||
\$lastsrcdir is "$lastsrcdir"
|
||||
\$release is "$release"
|
||||
finalversion = re.sub(r'pre\d+', '', version)
|
||||
if protocol_version == last_protocol_version:
|
||||
proto_changed = 'unchanged'
|
||||
proto_change_date = ' ' * 11
|
||||
else:
|
||||
proto_changed = 'changed'
|
||||
if finalversion in pdate:
|
||||
proto_change_date = pdate[finalversion]
|
||||
else:
|
||||
while True:
|
||||
ans = input("On what date did the protocol change to {protocol_version} get checked in? (dd Mmm yyyy) ")
|
||||
if re.match(r'^\d\d \w\w\w \d\d\d\d$', ans):
|
||||
break
|
||||
proto_change_date = ans
|
||||
|
||||
if 'pre' in lastversion:
|
||||
if not pre:
|
||||
die("You should not diff a release version against a pre-release version.")
|
||||
srcdir = srcdiffdir = lastsrcdir = 'src-previews'
|
||||
skipping = ' ** SKIPPING **'
|
||||
elif pre:
|
||||
srcdir = srcdiffdir = 'src-previews'
|
||||
lastsrcdir = 'src'
|
||||
skipping = ' ** SKIPPING **'
|
||||
else:
|
||||
srcdir = lastsrcdir = 'src'
|
||||
srcdiffdir = 'src-diffs'
|
||||
skipping = ''
|
||||
|
||||
print(f"""
|
||||
{dash_line}
|
||||
version is "{version}"
|
||||
lastversion is "{lastversion}"
|
||||
dest is "{dest}"
|
||||
curdir is "{curdir}"
|
||||
srcdir is "{srcdir}"
|
||||
srcdiffdir is "{srcdiffdir}"
|
||||
lastsrcdir is "{lastsrcdir}"
|
||||
release is "{release}"
|
||||
|
||||
About to:
|
||||
- tweak SUBPROTOCOL_VERSION in rsync.h, if needed
|
||||
- tweak the version in configure.ac and the spec files
|
||||
- tweak NEWS and OLDNEWS to ensure header values are correct
|
||||
- tweak the date in the *.yo files and generate the manpages
|
||||
- tweak NEWS.md and OLDNEWS.md to ensure header values are correct
|
||||
- generate configure.sh, config.h.in, and proto.h
|
||||
- page through the differences
|
||||
""")
|
||||
ans = input("<Press Enter to continue> ")
|
||||
|
||||
EOT
|
||||
print "<Press Enter to continue> ";
|
||||
$_ = <STDIN>;
|
||||
specvars = {
|
||||
'Version:': finalversion,
|
||||
'Release:': release,
|
||||
'%define fullversion': f'%{{version}}{pre}',
|
||||
'Released': version + '.',
|
||||
'%define srcdir': srcdir,
|
||||
}
|
||||
|
||||
my %specvars = ( 'Version:' => $finalversion, 'Release:' => $release,
|
||||
'%define fullversion' => "\%{version}$pre", 'Released' => "$version.",
|
||||
'%define srcdir' => $srcdir );
|
||||
my @tweak_files = ( glob('packaging/*.spec'), glob('packaging/*/*.spec'), glob('*.yo'),
|
||||
qw( configure.ac rsync.h NEWS OLDNEWS options.c ) );
|
||||
tweak_files = 'configure.ac rsync.h NEWS.md OLDNEWS.md'.split()
|
||||
tweak_files += glob.glob('packaging/*.spec')
|
||||
tweak_files += glob.glob('packaging/*/*.spec')
|
||||
|
||||
foreach my $fn (@tweak_files) {
|
||||
open(IN, '<', $fn) or die $!;
|
||||
undef $/; $_ = <IN>; $/ = "\n";
|
||||
close IN;
|
||||
if ($fn =~ /configure/) {
|
||||
s/^RSYNC_VERSION=.*/RSYNC_VERSION=$version/m
|
||||
or die "Unable to update RSYNC_VERSION in $fn\n";
|
||||
} elsif ($fn =~ /\.spec/) {
|
||||
while (my($str, $val) = each %specvars) {
|
||||
s/^\Q$str\E .*/$str $val/m
|
||||
or die "Unable to update $str in $fn\n";
|
||||
}
|
||||
s/^\* \w\w\w \w\w\w \d\d \d\d\d\d (.*)/$cl_today $1/m
|
||||
or die "Unable to update ChangeLog header in $fn\n";
|
||||
} elsif ($fn =~ /\.yo/) {
|
||||
s/^(manpage\([^)]+\)\(\d+\)\()[^)]+(\).*)/$1$today$2/m
|
||||
or die "Unable to update date in manpage() header in $fn\n";
|
||||
s/^(This man ?page is current for version) \S+ (of rsync)/$1 $version $2/m
|
||||
or die "Unable to update current version info in $fn\n";
|
||||
} elsif ($fn eq 'rsync.h') {
|
||||
s{(#define\s+SUBPROTOCOL_VERSION)\s+(\d+)}
|
||||
{ $1 . ' ' . get_subprotocol_version($2) }e
|
||||
or die "Unable to find SUBPROTOCOL_VERSION define in $fn\n";
|
||||
} elsif ($fn eq 'NEWS') {
|
||||
s{^(NEWS for rsync \Q$finalversion\E )(\(UNRELEASED\))\s*(\nProtocol: )(\d+) (\([^)]+\))\n}
|
||||
{ $1 . ($pre ? $2 : "($today)") . "$3$protocol_version ($proto_changed)\n" }ei
|
||||
or die "The first 2 lines of $fn are not in the right format. They must be:\n"
|
||||
. "NEWS for rsync $finalversion (UNRELEASED)\n"
|
||||
. "Protocol: $protocol_version ($proto_changed)\n";
|
||||
} elsif ($fn eq 'OLDNEWS') {
|
||||
s{^(\t\S\S\s\S\S\S\s\d\d\d\d)(\t\Q$finalversion\E\t).*}
|
||||
{ ($pre ? $1 : "\t$ztoday") . $2 . $proto_change_date . $protocol_version }em
|
||||
or die "Unable to find \"?? ??? $year\t$finalversion\" line in $fn\n";
|
||||
} elsif ($fn eq 'options.c') {
|
||||
if (s/(Copyright \(C\) 2002-)(\d+)( Wayne Davison)/$1$year$3/
|
||||
&& $2 ne $year) {
|
||||
die "Copyright comments need to be updated to $year in all files!\n";
|
||||
}
|
||||
# Adjust the year in the --version output.
|
||||
s/(rprintf\(f, "Copyright \(C\) 1996-)(\d+)/$1$year/
|
||||
or die "Unable to find Copyright string in --version output of $fn\n";
|
||||
next if $2 eq $year;
|
||||
} else {
|
||||
die "Unrecognized file in \@tweak_files: $fn\n";
|
||||
}
|
||||
open(OUT, '>', $fn) or die $!;
|
||||
print OUT $_;
|
||||
close OUT;
|
||||
}
|
||||
for fn in tweak_files:
|
||||
with open(fn, 'r', encoding='utf-8') as fh:
|
||||
old_txt = txt = fh.read()
|
||||
if 'configure' in fn:
|
||||
x_re = re.compile(r'^(AC_INIT\(\[rsync\],\s*\[)\d.+?(\])', re.M)
|
||||
txt = replace_or_die(x_re, r'\g<1>%s\2' % version, txt, f"Unable to update AC_INIT with version in {fn}")
|
||||
elif '.spec' in fn:
|
||||
for var, val in specvars.items():
|
||||
x_re = re.compile(r'^%s .*' % re.escape(var), re.M)
|
||||
txt = replace_or_die(x_re, var + ' ' + val, txt, f"Unable to update {var} in {fn}")
|
||||
x_re = re.compile(r'^\* \w\w\w \w\w\w \d\d \d\d\d\d (.*)', re.M)
|
||||
txt = replace_or_die(x_re, r'%s \1' % cl_today, txt, f"Unable to update ChangeLog header in {fn}")
|
||||
elif fn == 'rsync.h':
|
||||
x_re = re.compile('(#define\s+SUBPROTOCOL_VERSION)\s+(\d+)')
|
||||
repl = lambda m: m[1] + ' ' + '0' if not pre or proto_changed != 'changed' else 1 if m[2] == '0' else m[2]
|
||||
txt = replace_or_die(x_re, repl, txt, f"Unable to find SUBPROTOCOL_VERSION define in {fn}")
|
||||
elif fn == 'NEWS.md':
|
||||
x_re = re.compile(
|
||||
r'^(# NEWS for rsync %s )(\(UNRELEASED\))\s*(\n\nProtocol: )(\d+) (\([^)]+\))\n' % re.escape(finalversion),
|
||||
re.I)
|
||||
repl = lambda m: m[1] + (m[2] if pre else f"({today})") + m[3] + f"{protocol_version} ({proto_changed})\n"
|
||||
msg = (f"The first 3 lines of {fn} are not in the right format. They must be:\n"
|
||||
+ f"# NEWS for rsync {finalversion} (UNRELEASED)\n\n"
|
||||
+ f"Protocol: {protocol_version} ({proto_changed})")
|
||||
txt = replace_or_die(x_re, repl, txt, msg)
|
||||
elif fn == 'OLDNEWS.md':
|
||||
efv = re.escape(finalversion)
|
||||
x_re = re.compile(r'^(\| )(\S{2} \S{3} \d{4})(\s+\|\s+%s\s+\| ).{11}(\s+\| )\S{2}(\s+\|+)$' % efv, re.M)
|
||||
repl = lambda m: m[1] + (m[2] if pre else ztoday) + m[3] + proto_change_date + m[4] + protocol_version + m[5]
|
||||
txt = replace_or_die(x_re, repl, txt, f'Unable to find "| ?? ??? {year} | {finalversion} | ... |" line in {fn}')
|
||||
else:
|
||||
die(f"Unrecognized file in tweak_files: {fn}")
|
||||
|
||||
print $break;
|
||||
system "git diff --color | less -p '^diff .*'";
|
||||
if txt != old_txt:
|
||||
print(f"Updating {fn}")
|
||||
with open(fn, 'w', encoding='utf-8') as fh:
|
||||
fh.write(txt)
|
||||
|
||||
my $srctar_name = "rsync-$version.tar.gz";
|
||||
my $pattar_name = "rsync-patches-$version.tar.gz";
|
||||
my $diff_name = "rsync-$lastversion-$version.diffs.gz";
|
||||
my $srctar_file = "$dest/$srcdir/$srctar_name";
|
||||
my $pattar_file = "$dest/$srcdir/$pattar_name";
|
||||
my $diff_file = "$dest/$srcdiffdir/$diff_name";
|
||||
my $news_file = "$dest/$srcdir/rsync-$version-NEWS";
|
||||
my $lasttar_file = "$dest/$lastsrcdir/rsync-$lastversion.tar.gz";
|
||||
cmd_chk(['packaging/year-tweak'])
|
||||
|
||||
print $break, <<EOT;
|
||||
print(dash_line)
|
||||
cmd_run("git diff --color | less -p '^diff .*'")
|
||||
|
||||
srctar_name = f"{rsync_ver}.tar.gz"
|
||||
pattar_name = f"rsync-patches-{version}.tar.gz"
|
||||
diff_name = f"{rsync_lastver}-{version}.diffs.gz"
|
||||
srctar_file = f"{dest}/{srcdir}/{srctar_name}"
|
||||
pattar_file = f"{dest}/{srcdir}/{pattar_name}"
|
||||
diff_file = f"{dest}/{srcdiffdir}/{diff_name}"
|
||||
news_file = f"{dest}/{srcdir}/{rsync_ver}-NEWS.md"
|
||||
lasttar_file = f"{dest}/{lastsrcdir}/{rsync_lastver}.tar.gz"
|
||||
|
||||
print(f"""\
|
||||
{dash_line}
|
||||
|
||||
About to:
|
||||
- commit all version changes
|
||||
- merge the $master_branch branch into the patch/$master_branch/* branches
|
||||
- git commit all changes
|
||||
- generate the manpages
|
||||
- merge the {args.master_branch} branch into the patch/{args.master_branch}/* branches
|
||||
- update the files in the "patches" dir and OPTIONALLY
|
||||
(if you type 'y') to launch a shell for each patch
|
||||
""")
|
||||
ans = input("<Press Enter OR 'y' to continue> ")
|
||||
|
||||
EOT
|
||||
print "<Press Enter OR 'y' to continue> ";
|
||||
my $ans = <STDIN>;
|
||||
s = cmd_run(['git', 'commit', '-a', '-m', f'Preparing for release of {version}'])
|
||||
if s.returncode:
|
||||
die('Aborting')
|
||||
|
||||
system "git commit -a -m 'Preparing for release of $version'" and exit 1;
|
||||
cmd_chk('make reconfigure ; make gen')
|
||||
cmd_chk(['rsync', '-a', *gen_files, 'SaVeDiR/'])
|
||||
|
||||
print "Updating files in \"patches\" dir ...\n";
|
||||
system "packaging/patch-update --branch=$master_branch";
|
||||
print(f'Creating any missing patch branches.')
|
||||
s = cmd_run(f'packaging/branch-from-patch --branch={args.master_branch} --add-missing')
|
||||
if s.returncode:
|
||||
die('Aborting')
|
||||
|
||||
if ($ans =~ /^y/i) {
|
||||
print "\nVisiting all \"patch/$master_branch/*\" branches ...\n";
|
||||
system "packaging/patch-update --branch=$master_branch --skip-check --shell";
|
||||
}
|
||||
print('Updating files in "patches" dir ...')
|
||||
s = cmd_run(f'packaging/patch-update --branch={args.master_branch}')
|
||||
if s.returncode:
|
||||
die('Aborting')
|
||||
|
||||
if (-d 'patches/.git') {
|
||||
system "cd patches && git commit -a -m 'The patches for $version.'" and exit 1;
|
||||
}
|
||||
if re.match(r'^y', ans, re.I):
|
||||
print(f'\nVisiting all "patch/{args.master_branch}/*" branches ...')
|
||||
cmd_run(f"packaging/patch-update --branch={args.master_branch} --skip-check --shell")
|
||||
|
||||
print $break, <<EOT;
|
||||
cmd_run("rm -f *.[o15] *.html")
|
||||
cmd_chk('rsync -a SaVeDiR/ .'.split())
|
||||
|
||||
if os.path.isdir('patches/.git'):
|
||||
s = cmd_run(f"cd patches && git commit -a -m 'The patches for {version}.'")
|
||||
if s.returncode:
|
||||
die('Aborting')
|
||||
|
||||
print(f"""\
|
||||
{dash_line}
|
||||
|
||||
About to:
|
||||
- create signed tag for this release: v$version
|
||||
- create release diffs, "$diff_name"
|
||||
- create release tar, "$srctar_name"
|
||||
- generate rsync-$version/patches/* files
|
||||
- create patches tar, "$pattar_name"
|
||||
- update top-level README, *NEWS, TODO, and ChangeLog
|
||||
- create signed tag for this release: {v_ver}
|
||||
- create release diffs, "{diff_name}"
|
||||
- create release tar, "{srctar_name}"
|
||||
- generate {rsync_ver}/patches/* files
|
||||
- create patches tar, "{pattar_name}"
|
||||
- update top-level README.md, *NEWS.md, TODO, and ChangeLog
|
||||
- update top-level rsync*.html manpages
|
||||
- gpg-sign the release files
|
||||
- update hard-linked top-level release files$skipping
|
||||
- update hard-linked top-level release files{skipping}
|
||||
""")
|
||||
ans = input("<Press Enter to continue> ")
|
||||
|
||||
EOT
|
||||
print "<Press Enter to continue> ";
|
||||
$_ = <STDIN>;
|
||||
# TODO: is there a better way to ensure that our passphrase is in the agent?
|
||||
cmd_run("touch TeMp; gpg --sign TeMp; rm TeMp*")
|
||||
|
||||
# We want to use our passphrase-providing "gpg" script, so modify the PATH.
|
||||
$ENV{PATH} = "$curdir/packaging/bin:$path";
|
||||
out = cmd_txt(f"git tag -s -m 'Version {version}.' {v_ver}", capture='combined')
|
||||
print(out, end='')
|
||||
if 'bad passphrase' in out or 'failed' in out:
|
||||
die('Aborting')
|
||||
|
||||
my $passphrase;
|
||||
while (1) {
|
||||
ReadMode('noecho');
|
||||
print "\nEnter your GPG pass-phrase: ";
|
||||
chomp($passphrase = <STDIN>);
|
||||
ReadMode(0);
|
||||
print "\n";
|
||||
if os.path.isdir('patches/.git'):
|
||||
out = cmd_txt(f"cd patches && git tag -s -m 'Version {version}.' {v_ver}", capture='combined')
|
||||
print(out, end='')
|
||||
if 'bad passphrase' in out or 'failed' in out:
|
||||
die('Aborting')
|
||||
|
||||
# Briefly create a temp file with the passphrase for git's tagging use.
|
||||
my $oldmask = umask 077;
|
||||
unlink($passfile);
|
||||
open(OUT, '>', $passfile) or die $!;
|
||||
print OUT $passphrase, "\n";
|
||||
close OUT;
|
||||
umask $oldmask;
|
||||
$ENV{'GPG_PASSFILE'} = $passfile;
|
||||
os.environ['PATH'] = ORIGINAL_PATH
|
||||
|
||||
$_ = `git tag -s -m 'Version $version.' v$version 2>&1`;
|
||||
print $_;
|
||||
next if /bad passphrase/;
|
||||
exit 1 if /failed/;
|
||||
# Extract the generated files from the old tar.
|
||||
tweaked_gen_files = [ f"{rsync_lastver}/{x}" for x in gen_files ]
|
||||
cmd_run(['tar', 'xzf', lasttar_file, *tweaked_gen_files])
|
||||
os.rename(rsync_lastver, 'a')
|
||||
|
||||
if (-d 'patches/.git') {
|
||||
$_ = `cd patches && git tag -s -m 'Version $version.' v$version 2>&1`;
|
||||
print $_;
|
||||
exit 1 if /bad passphrase|failed/;
|
||||
}
|
||||
print(f"Creating {diff_file} ...")
|
||||
cmd_chk(['rsync', '-a', *gen_files, 'b/'])
|
||||
|
||||
unlink($passfile);
|
||||
last;
|
||||
}
|
||||
sed_script = r's:^((---|\+\+\+) [ab]/[^\t]+)\t.*:\1:' # CAUTION: must not contain any single quotes!
|
||||
cmd_chk(f"(git diff v{lastversion} {v_ver} -- ':!.github'; diff -upN a b | sed -r '{sed_script}') | gzip -9 >{diff_file}")
|
||||
shutil.rmtree('a')
|
||||
os.rename('b', rsync_ver)
|
||||
|
||||
$ENV{PATH} = $path;
|
||||
print(f"Creating {srctar_file} ...")
|
||||
cmd_chk(f"git archive --format=tar --prefix={rsync_ver}/ {v_ver} | tar xf -")
|
||||
cmd_chk(f"support/git-set-file-times --quiet --prefix={rsync_ver}/")
|
||||
cmd_chk(['fakeroot', 'tar', 'czf', srctar_file, '--exclude=.github', rsync_ver])
|
||||
shutil.rmtree(rsync_ver)
|
||||
|
||||
# Extract the generated files from the old tar.
|
||||
@_ = @extra_files;
|
||||
map { s#^#rsync-$lastversion/# } @_;
|
||||
system "tar xzf $lasttar_file @_";
|
||||
rename("rsync-$lastversion", 'a');
|
||||
print(f'Updating files in "{rsync_ver}/patches" dir ...')
|
||||
os.mkdir(rsync_ver, 0o755)
|
||||
os.mkdir(f"{rsync_ver}/patches", 0o755)
|
||||
cmd_chk(f"packaging/patch-update --skip-check --branch={args.master_branch} --gen={rsync_ver}/patches".split())
|
||||
|
||||
print "Creating $diff_file ...\n";
|
||||
system "$make_gen_cmd && rsync -a @extra_files b/" and exit 1;
|
||||
my $sed_script = 's:^((---|\+\+\+) [ab]/[^\t]+)\t.*:\1:';
|
||||
system "(git diff v$lastversion v$version; diff -upN a b | sed -r '$sed_script') | gzip -9 >$diff_file";
|
||||
system "rm -rf a";
|
||||
rename('b', "rsync-$version");
|
||||
cmd_run("rm -f *.[o15] *.html")
|
||||
cmd_chk('rsync -a SaVeDiR/ .'.split())
|
||||
shutil.rmtree('SaVeDiR')
|
||||
cmd_chk('make gen'.split())
|
||||
|
||||
print "Creating $srctar_file ...\n";
|
||||
system "git archive --format=tar --prefix=rsync-$version/ v$version | tar xf -";
|
||||
system "support/git-set-file-times --prefix=rsync-$version/";
|
||||
system "fakeroot tar czf $srctar_file rsync-$version; rm -rf rsync-$version";
|
||||
print(f"Creating {pattar_file} ...")
|
||||
cmd_chk(['fakeroot', 'tar', 'chzf', pattar_file, rsync_ver + '/patches'])
|
||||
shutil.rmtree(rsync_ver)
|
||||
|
||||
print "Updating files in \"rsync-$version/patches\" dir ...\n";
|
||||
mkdir("rsync-$version", 0755);
|
||||
mkdir("rsync-$version/patches", 0755);
|
||||
system "packaging/patch-update --skip-check --branch=$master_branch --gen=rsync-$version/patches";
|
||||
print(f"Updating the other files in {dest} ...")
|
||||
md_files = 'README.md NEWS.md OLDNEWS.md'.split()
|
||||
html_files = [ fn for fn in gen_files if fn.endswith('.html') ]
|
||||
cmd_chk(['rsync', '-a', *md_files, *html_files, dest])
|
||||
cmd_chk(["packaging/md2html"] + [ dest +'/'+ fn for fn in md_files ])
|
||||
|
||||
print "Creating $pattar_file ...\n";
|
||||
system "fakeroot tar chzf $pattar_file rsync-$version/patches; rm -rf rsync-$version";
|
||||
for topfn, verfn in (('NEWS.md', news_file), ('NEWS.html', news_file.replace('.md', '.html'))):
|
||||
topfn = dest + '/' + topfn
|
||||
if os.path.lexists(verfn):
|
||||
os.unlink(verfn)
|
||||
os.link(topfn, verfn)
|
||||
|
||||
print "Updating the other files in $dest ...\n";
|
||||
system "rsync -a README NEWS OLDNEWS TODO $dest";
|
||||
unlink($news_file);
|
||||
link("$dest/NEWS", $news_file);
|
||||
system "git log --name-status | gzip -9 >$dest/ChangeLog.gz";
|
||||
cmd_chk(f"git log --name-status | gzip -9 >{dest}/ChangeLog.gz")
|
||||
|
||||
system "yodl2html -o $dest/rsync.html rsync.yo";
|
||||
system "yodl2html -o $dest/rsyncd.conf.html rsyncd.conf.yo";
|
||||
for fn in (srctar_file, pattar_file, diff_file):
|
||||
asc_fn = fn + '.asc'
|
||||
if os.path.lexists(asc_fn):
|
||||
os.unlink(asc_fn)
|
||||
res = cmd_run(['gpg', '--batch', '-ba', fn])
|
||||
if res.returncode != 0 and res.returncode != 2:
|
||||
die("gpg signing failed")
|
||||
|
||||
foreach my $fn ($srctar_file, $pattar_file, $diff_file) {
|
||||
unlink("$fn.asc");
|
||||
open(GPG, '|-', "gpg --batch --passphrase-fd=0 -ba $fn") or die $!;
|
||||
print GPG $passphrase, "\n";
|
||||
close GPG;
|
||||
}
|
||||
if not pre:
|
||||
for find in f'{dest}/rsync-*.gz {dest}/rsync-*.asc {dest}/rsync-*-NEWS.md {dest}/src-previews/rsync-*diffs.gz*'.split():
|
||||
for fn in glob.glob(find):
|
||||
os.unlink(fn)
|
||||
top_link = [
|
||||
srctar_file, f"{srctar_file}.asc",
|
||||
pattar_file, f"{pattar_file}.asc",
|
||||
diff_file, f"{diff_file}.asc",
|
||||
news_file,
|
||||
]
|
||||
for fn in top_link:
|
||||
os.link(fn, re.sub(r'/src(-\w+)?/', '/', fn))
|
||||
|
||||
if (!$pre) {
|
||||
system "rm $dest/rsync-*.gz $dest/rsync-*.asc $dest/rsync-*-NEWS $dest/src-previews/rsync-*diffs.gz*";
|
||||
|
||||
foreach my $fn ($srctar_file, "$srctar_file.asc",
|
||||
$pattar_file, "$pattar_file.asc",
|
||||
$diff_file, "$diff_file.asc", $news_file) {
|
||||
(my $top_fn = $fn) =~ s#/src(-\w+)?/#/#;
|
||||
link($fn, $top_fn);
|
||||
}
|
||||
}
|
||||
|
||||
print $break, <<'EOT';
|
||||
print(f"""\
|
||||
{dash_line}
|
||||
|
||||
Local changes are done. When you're satisfied, push the git repository
|
||||
and rsync the release files. Remember to announce the release on *BOTH*
|
||||
rsync-announce@lists.samba.org and rsync@lists.samba.org (and the web)!
|
||||
EOT
|
||||
""")
|
||||
|
||||
exit;
|
||||
|
||||
sub get_subprotocol_version
|
||||
{
|
||||
my($subver) = @_;
|
||||
if ($pre && $proto_changed eq 'changed') {
|
||||
return $subver == 0 ? 1 : $subver;
|
||||
}
|
||||
0;
|
||||
}
|
||||
def replace_or_die(regex, repl, txt, die_msg):
|
||||
m = regex.search(txt)
|
||||
if not m:
|
||||
die(die_msg)
|
||||
return regex.sub(repl, txt, 1)
|
||||
|
||||
sub usage
|
||||
{
|
||||
die <<EOT;
|
||||
Usage: release-rsync [OPTIONS]
|
||||
|
||||
-b, --branch=BRANCH The branch to release (default: master)
|
||||
-h, --help Display this help message
|
||||
EOT
|
||||
}
|
||||
def signal_handler(sig, frame):
|
||||
die("\nAborting due to SIGINT.")
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
parser = argparse.ArgumentParser(description="Prepare a new release of rsync in the git repo & ftp dir.", add_help=False)
|
||||
parser.add_argument('--branch', '-b', dest='master_branch', default='master', help="The branch to release. Default: master.")
|
||||
parser.add_argument("--help", "-h", action="help", help="Output this help message and exit.")
|
||||
args = parser.parse_args()
|
||||
main()
|
||||
|
||||
# vim: sw=4 et
|
||||
|
||||
@@ -41,7 +41,7 @@ mkdir -p $FAKE_ROOT/man/man5
|
||||
cp ../../../rsync $FAKE_ROOT/bin/rsync
|
||||
cp ../../../rsync.1 $FAKE_ROOT/man/man1/rsync.1
|
||||
cp ../../../rsyncd.conf.5 $FAKE_ROOT/man/man5/rsyncd.conf.5
|
||||
cp ../../../README $FAKE_ROOT/doc/rsync/README
|
||||
cp ../../../README.md $FAKE_ROOT/doc/rsync/README.md
|
||||
cp ../../../COPYING $FAKE_ROOT/doc/rsync/COPYING
|
||||
cp ../../../tech_report.pdf $FAKE_ROOT/doc/rsync/tech_report.pdf
|
||||
cp ../../../COPYING $FAKE_ROOT/COPYING
|
||||
@@ -68,7 +68,7 @@ d none bin 0755 bin bin
|
||||
f none bin/rsync 0755 bin bin
|
||||
d none doc 0755 bin bin
|
||||
d none doc/$NAME 0755 bin bin
|
||||
f none doc/$NAME/README 0644 bin bin
|
||||
f none doc/$NAME/README.md 0644 bin bin
|
||||
f none doc/$NAME/COPYING 0644 bin bin
|
||||
f none doc/$NAME/tech_report.pdf 0644 bin bin
|
||||
d none man 0755 bin bin
|
||||
|
||||
@@ -1,83 +1,87 @@
|
||||
#!/usr/bin/perl
|
||||
#!/usr/bin/python3 -B
|
||||
|
||||
# This script checks the *.c files for extraneous "extern" variables,
|
||||
# for vars that are defined but not used, and for inconsistent array
|
||||
# sizes. Run it from inside the main rsync directory.
|
||||
|
||||
use strict;
|
||||
use warnings;
|
||||
import re, argparse, glob
|
||||
|
||||
my %add_syscall_c = map { $_ => 1 } qw( t_stub.c t_unsafe.c tls.c trimslash.c );
|
||||
my %add_compat_c = map { $_ => 1 } qw( t_stub.c tls.c trimslash.c wildtest.c );
|
||||
my %add_util_c = map { $_ => 1 } qw( t_stub.c t_unsafe.c );
|
||||
my %sizes;
|
||||
VARS_RE = re.compile(r'^(?!(?:extern|enum)\s)([a-zA-Z]\S*\s+.*);', re.M)
|
||||
EXTERNS_RE = re.compile(r'^extern\s+(.*);', re.M)
|
||||
|
||||
open(IN, '<', 'syscall.c') or die $!;
|
||||
undef $/; my $syscall_c = <IN>; $/ = "\n";
|
||||
close IN;
|
||||
$syscall_c =~ s/^extern\s.*//mg;
|
||||
sizes = { }
|
||||
|
||||
open(IN, '<', 'lib/compat.c') or die $!;
|
||||
undef $/; my $compat_c = <IN>; $/ = "\n";
|
||||
close IN;
|
||||
$compat_c =~ s/^extern\s.*//mg;
|
||||
def main():
|
||||
add_syscall_c = set('t_stub.c t_unsafe.c tls.c trimslash.c'.split())
|
||||
add_util_c = set('t_stub.c t_unsafe.c'.split())
|
||||
|
||||
open(IN, '<', 'util.c') or die $!;
|
||||
undef $/; my $util_c = <IN>; $/ = "\n";
|
||||
close IN;
|
||||
$util_c =~ s/^extern\s.*//mg;
|
||||
syscall_c = slurp_file('syscall.c', True)
|
||||
util_c = slurp_file('util.c', True)
|
||||
|
||||
my @files = glob('*.c');
|
||||
for fn in sorted(glob.glob('*.c')):
|
||||
txt = slurp_file(fn)
|
||||
|
||||
foreach my $fn (@files) {
|
||||
open(IN, '<', $fn) or die $!;
|
||||
undef $/; $_ = <IN>; $/ = "\n";
|
||||
close IN;
|
||||
var_list = parse_vars(fn, VARS_RE.findall(txt))
|
||||
extern_list = parse_vars(fn, EXTERNS_RE.findall(txt))
|
||||
if not var_list and not extern_list:
|
||||
continue
|
||||
|
||||
my @vars = /^(?!(?:extern|enum)\s)([a-zA-Z]\S*\s+.*);/mg;
|
||||
my @externs = /^extern\s+(.*);/mg;
|
||||
if fn in add_syscall_c:
|
||||
txt += syscall_c
|
||||
if fn in add_util_c:
|
||||
txt += util_c
|
||||
|
||||
$_ .= $syscall_c if $add_syscall_c{$fn};
|
||||
$_ .= $compat_c if $add_compat_c{$fn};
|
||||
$_ .= $util_c if $add_util_c{$fn};
|
||||
s/INFO_GTE/info_levels/g;
|
||||
s/DEBUG_GTE/debug_levels/g;
|
||||
txt = re.sub(r'INFO_GTE', 'info_levels ', txt)
|
||||
txt = re.sub(r'DEBUG_GTE', 'debug_levels ', txt)
|
||||
txt = re.sub(r'SIGACTION\(', 'sigact (', txt)
|
||||
|
||||
check_vars($fn, 'var', @vars);
|
||||
check_vars($fn, 'extern', @externs);
|
||||
}
|
||||
find = '|'.join([ re.escape(x) for x in var_list + extern_list ])
|
||||
var_re = re.compile(r'(?<!\sstruct )\b(%s)(?!\w)' % find)
|
||||
|
||||
exit;
|
||||
found = { x: 0 for x in var_list + extern_list }
|
||||
for var in var_re.findall(txt):
|
||||
found[var] += 1
|
||||
|
||||
# The file's contents are in $_.
|
||||
sub check_vars
|
||||
{
|
||||
my $fn = shift;
|
||||
my $type = shift;
|
||||
for var in sorted(var_list + extern_list):
|
||||
if found[var] == 1:
|
||||
vtype = 'var' if var in var_list else 'extern'
|
||||
print(fn, f'has extraneous {vtype}: "{var}"')
|
||||
|
||||
foreach my $line (@_) {
|
||||
$line =~ s/\s*\{.*\}//;
|
||||
$line =~ s/\s*\(.*\)//;
|
||||
foreach my $item (split(/\s*,\s*/, $line)) {
|
||||
$item =~ s/\s*=.*//;
|
||||
my $sz = $item =~ s/(\[.*?\])// ? $1 : '';
|
||||
my($var) = $item =~ /([^*\s]+)$/;
|
||||
if (!defined $var) {
|
||||
print "Bogus match? ($item)\n";
|
||||
next;
|
||||
}
|
||||
if ($sz) {
|
||||
if (defined $sizes{$var}) {
|
||||
if ($sizes{$var} ne $sz) {
|
||||
print $fn, ' has inconsistent size for "', $var,
|
||||
"\": $sizes{$var} vs $sz\n";
|
||||
}
|
||||
} else {
|
||||
$sizes{$var} = $sz;
|
||||
}
|
||||
}
|
||||
my @matches = /(?<!\sstruct )\b(\Q$var\E)(?!\w)/g;
|
||||
push(@matches, /(\QSIGACTION(\E)/g) if $var eq 'sigact';
|
||||
print $fn, " has extraneous $type: \"", $var, "\"\n" if @matches == 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
def slurp_file(fn, drop_externs=False):
|
||||
with open(fn, 'r', encoding='utf-8') as fh:
|
||||
txt = fh.read()
|
||||
if drop_externs:
|
||||
txt = EXTERNS_RE.sub('', txt)
|
||||
return txt
|
||||
|
||||
|
||||
def parse_vars(fn, lines):
|
||||
ret = [ ]
|
||||
for line in lines:
|
||||
line = re.sub(r'\s*\{.*\}', '', line)
|
||||
line = re.sub(r'\s*\(.*\)', '', line)
|
||||
for item in re.split(r'\s*,\s*', line):
|
||||
item = re.sub(r'\s*=.*', '', item)
|
||||
m = re.search(r'(?P<var>\w+)(?P<sz>\[.*?\])?$', item)
|
||||
if not m:
|
||||
print(f"Bogus match? ({item})")
|
||||
continue
|
||||
if m['sz']:
|
||||
if m['var'] in sizes:
|
||||
if sizes[m['var']] != m['sz']:
|
||||
var = m['var']
|
||||
print(fn, f'has inconsistent size for "{var}":', m['sz'], 'vs', sizes[var])
|
||||
else:
|
||||
sizes[m['var']] = m['sz']
|
||||
ret.append(m['var'])
|
||||
return ret
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
parser = argparse.ArgumentParser(description='Check the *.c files for extraneous extern vars.', add_help=False)
|
||||
parser.add_argument("--help", "-h", action="help", help="Output this help message and exit.")
|
||||
args = parser.parse_args()
|
||||
main()
|
||||
|
||||
# vim: sw=4 et
|
||||
|
||||
94
packaging/year-tweak
Executable file
94
packaging/year-tweak
Executable file
@@ -0,0 +1,94 @@
|
||||
#!/usr/bin/python3
|
||||
|
||||
# This uses the output from "support/git-set-file-times --list" to discern
|
||||
# the last-modified year of each *.c & *.h file and updates the copyright
|
||||
# year if it isn't set right.
|
||||
|
||||
import sys, os, re, argparse, subprocess
|
||||
from datetime import datetime
|
||||
|
||||
MAINTAINER_NAME = 'Wayne Davison'
|
||||
MAINTAINER_SUF = ' ' + MAINTAINER_NAME + "\n"
|
||||
|
||||
def main():
|
||||
latest_year = '2000'
|
||||
|
||||
proc = subprocess.Popen('support/git-set-file-times --list'.split(), stdout=subprocess.PIPE, encoding='utf-8')
|
||||
for line in proc.stdout:
|
||||
m = re.match(r'^\S\s+(?P<year>\d\d\d\d)\S+\s+\S+\s+(?P<fn>.+)', line)
|
||||
if not m:
|
||||
print("Failed to parse line from git-set-file-times:", line)
|
||||
sys.exit(1)
|
||||
m = argparse.Namespace(**m.groupdict())
|
||||
if m.year > latest_year:
|
||||
latest_year = m.year
|
||||
if m.fn.startswith('zlib/') or m.fn.startswith('popt/'):
|
||||
continue
|
||||
if re.search(r'\.(c|h|sh|test)$', m.fn):
|
||||
maybe_edit_copyright_year(m.fn, m.year)
|
||||
proc.communicate()
|
||||
|
||||
fn = 'latest-year.h'
|
||||
with open(fn, 'r', encoding='utf-8') as fh:
|
||||
old_txt = fh.read()
|
||||
|
||||
txt = f'#define LATEST_YEAR "{latest_year}"\n'
|
||||
if txt != old_txt:
|
||||
print(f"Updating {fn} with year {latest_year}")
|
||||
with open(fn, 'w', encoding='utf-8') as fh:
|
||||
fh.write(txt)
|
||||
|
||||
|
||||
def maybe_edit_copyright_year(fn, year):
|
||||
opening_lines = [ ]
|
||||
copyright_line = None
|
||||
|
||||
with open(fn, 'r', encoding='utf-8') as fh:
|
||||
for lineno, line in enumerate(fh):
|
||||
opening_lines.append(line)
|
||||
if lineno > 3 and not re.search(r'\S', line):
|
||||
break
|
||||
m = re.match(r'^(?P<pre>.*Copyright\s+\S+\s+)(?P<year>\d\d\d\d(?:-\d\d\d\d)?(,\s+\d\d\d\d)*)(?P<suf>.+)', line)
|
||||
if not m:
|
||||
continue
|
||||
copyright_line = argparse.Namespace(**m.groupdict())
|
||||
copyright_line.lineno = len(opening_lines)
|
||||
copyright_line.is_maintainer_line = MAINTAINER_NAME in copyright_line.suf
|
||||
copyright_line.txt = line
|
||||
if copyright_line.is_maintainer_line:
|
||||
break
|
||||
|
||||
if not copyright_line:
|
||||
return
|
||||
|
||||
if copyright_line.is_maintainer_line:
|
||||
cyears = copyright_line.year.split('-')
|
||||
if year == cyears[0]:
|
||||
cyears = [ year ]
|
||||
else:
|
||||
cyears = [ cyears[0], year ]
|
||||
txt = copyright_line.pre + '-'.join(cyears) + MAINTAINER_SUF
|
||||
if txt == copyright_line.txt:
|
||||
return
|
||||
opening_lines[copyright_line.lineno - 1] = txt
|
||||
else:
|
||||
if fn.startswith('lib/') or fn.startswith('testsuite/'):
|
||||
return
|
||||
txt = copyright_line.pre + year + MAINTAINER_SUF
|
||||
opening_lines[copyright_line.lineno - 1] += txt
|
||||
|
||||
remaining_txt = fh.read()
|
||||
|
||||
print(f"Updating {fn} with year {year}")
|
||||
|
||||
with open(fn, 'w', encoding='utf-8') as fh:
|
||||
fh.write(''.join(opening_lines))
|
||||
fh.write(remaining_txt)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
parser = argparse.ArgumentParser(description="Grab the year of last mod for our c & h files and make sure the Copyright comment is up-to-date.")
|
||||
args = parser.parse_args()
|
||||
main()
|
||||
|
||||
# vim: sw=4 et
|
||||
6
params.c
6
params.c
@@ -1,5 +1,5 @@
|
||||
/* This modules is based on the params.c module from Samba, written by Karl Auer
|
||||
and much modifed by Christopher Hertel. */
|
||||
and much modified by Christopher Hertel. */
|
||||
|
||||
/*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
@@ -59,7 +59,7 @@
|
||||
* beginning with either a semicolon (';') or a pound sign ('#').
|
||||
*
|
||||
* All whitespace in section names and parameter names is compressed
|
||||
* to single spaces. Leading and trailing whitespace is stipped from
|
||||
* to single spaces. Leading and trailing whitespace is stripped from
|
||||
* both names and values.
|
||||
*
|
||||
* Only the first equals sign in a parameter line is significant.
|
||||
@@ -153,7 +153,7 @@ static int EatComment( FILE *InFile )
|
||||
|
||||
static int Continuation( char *line, int pos )
|
||||
/* ------------------------------------------------------------------------ **
|
||||
* Scan backards within a string to discover if the last non-whitespace
|
||||
* Scan backwards within a string to discover if the last non-whitespace
|
||||
* character is a line-continuation character ('\\').
|
||||
*
|
||||
* Input: line - A pointer to a buffer containing the string to be
|
||||
|
||||
24
pipe.c
24
pipe.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) 2004-2014 Wayne Davison
|
||||
* Copyright (C) 2004-2020 Wayne Davison
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
@@ -66,10 +66,10 @@ pid_t piped_child(char **command, int *f_in, int *f_out)
|
||||
}
|
||||
|
||||
if (pid == 0) {
|
||||
if (dup2(to_child_pipe[0], STDIN_FILENO) < 0 ||
|
||||
close(to_child_pipe[1]) < 0 ||
|
||||
close(from_child_pipe[0]) < 0 ||
|
||||
dup2(from_child_pipe[1], STDOUT_FILENO) < 0) {
|
||||
if (dup2(to_child_pipe[0], STDIN_FILENO) < 0
|
||||
|| close(to_child_pipe[1]) < 0
|
||||
|| close(from_child_pipe[0]) < 0
|
||||
|| dup2(from_child_pipe[1], STDOUT_FILENO) < 0) {
|
||||
rsyserr(FERROR, errno, "Failed to dup/close");
|
||||
exit_cleanup(RERR_IPC);
|
||||
}
|
||||
@@ -116,8 +116,7 @@ pid_t local_child(int argc, char **argv, int *f_in, int *f_out,
|
||||
/* The parent process is always the sender for a local rsync. */
|
||||
assert(am_sender);
|
||||
|
||||
if (fd_pair(to_child_pipe) < 0 ||
|
||||
fd_pair(from_child_pipe) < 0) {
|
||||
if (fd_pair(to_child_pipe) < 0 || fd_pair(from_child_pipe) < 0) {
|
||||
rsyserr(FERROR, errno, "pipe");
|
||||
exit_cleanup(RERR_IPC);
|
||||
}
|
||||
@@ -150,10 +149,10 @@ pid_t local_child(int argc, char **argv, int *f_in, int *f_out,
|
||||
}
|
||||
}
|
||||
|
||||
if (dup2(to_child_pipe[0], STDIN_FILENO) < 0 ||
|
||||
close(to_child_pipe[1]) < 0 ||
|
||||
close(from_child_pipe[0]) < 0 ||
|
||||
dup2(from_child_pipe[1], STDOUT_FILENO) < 0) {
|
||||
if (dup2(to_child_pipe[0], STDIN_FILENO) < 0
|
||||
|| close(to_child_pipe[1]) < 0
|
||||
|| close(from_child_pipe[0]) < 0
|
||||
|| dup2(from_child_pipe[1], STDOUT_FILENO) < 0) {
|
||||
rsyserr(FERROR, errno, "Failed to dup/close");
|
||||
exit_cleanup(RERR_IPC);
|
||||
}
|
||||
@@ -167,8 +166,7 @@ pid_t local_child(int argc, char **argv, int *f_in, int *f_out,
|
||||
child_main(argc, argv);
|
||||
}
|
||||
|
||||
if (close(from_child_pipe[1]) < 0 ||
|
||||
close(to_child_pipe[0]) < 0) {
|
||||
if (close(from_child_pipe[1]) < 0 || close(to_child_pipe[0]) < 0) {
|
||||
rsyserr(FERROR, errno, "Failed to close");
|
||||
exit_cleanup(RERR_IPC);
|
||||
}
|
||||
|
||||
@@ -626,7 +626,7 @@ expandNextArg(/*@special@*/ poptContext con, const char * s)
|
||||
pos = te - t;
|
||||
t = realloc(t, tn);
|
||||
te = t + pos;
|
||||
strncpy(te, a, alen); te += alen;
|
||||
memcpy(te, a, alen+1); te += alen;
|
||||
continue;
|
||||
/*@notreached@*/ /*@switchbreak@*/ break;
|
||||
default:
|
||||
|
||||
@@ -12,8 +12,8 @@
|
||||
# The script stops after the first successful action.
|
||||
|
||||
dir=`dirname $0`
|
||||
if test x"$dir" != x -a x"$dir" != x.; then
|
||||
cd "$dir"
|
||||
if test x"$dir" = x; then
|
||||
dir=.
|
||||
fi
|
||||
|
||||
if test $# = 0; then
|
||||
@@ -23,21 +23,20 @@ fi
|
||||
for action in "${@}"; do
|
||||
case "$action" in
|
||||
build|make)
|
||||
make -f prepare-source.mak
|
||||
(cd $dir && make -f prepare-source.mak)
|
||||
;;
|
||||
fetch)
|
||||
if perl --version >/dev/null 2>/dev/null; then
|
||||
files='c*'
|
||||
else
|
||||
files='[cp]*'
|
||||
$dir/rsync-ssl -iip --no-motd rsync://download.samba.org/rsyncftp/generated-files/'[ca]*' $dir
|
||||
if ! perl --version >/dev/null 2>/dev/null; then
|
||||
$dir/rsync-ssl -iip --no-motd rsync://download.samba.org/rsyncftp/generated-files/'p*' .
|
||||
fi
|
||||
rsync -pvz rsync://rsync.samba.org/rsyncftp/generated-files/"$files" .
|
||||
;;
|
||||
fetchgen)
|
||||
rsync -pvz rsync://rsync.samba.org/rsyncftp/generated-files/'*' .
|
||||
$dir/rsync-ssl -iip --no-motd rsync://download.samba.org/rsyncftp/generated-files/'[ca]*' $dir
|
||||
$dir/rsync-ssl -iip --no-motd rsync://download.samba.org/rsyncftp/generated-files/'[^ca]*' .
|
||||
;;
|
||||
fetchSRC)
|
||||
rsync -pvrz --exclude=/.git/ rsync://rsync.samba.org/ftp/pub/unpacked/rsync/ .
|
||||
./rsync-ssl -iipr --no-motd --exclude=/.git/ rsync://download.samba.org/ftp/pub/unpacked/rsync/ .
|
||||
;;
|
||||
*)
|
||||
echo "Unknown action: $action"
|
||||
|
||||
@@ -1,5 +1,8 @@
|
||||
conf: configure.sh config.h.in
|
||||
|
||||
aclocal.m4: m4/*.m4
|
||||
aclocal -I m4
|
||||
|
||||
configure.sh: configure.ac aclocal.m4
|
||||
autoconf -o configure.sh
|
||||
|
||||
|
||||
38
progress.c
38
progress.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-2014 Wayne Davison
|
||||
* Copyright (C) 2003-2020 Wayne Davison
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
@@ -25,11 +25,15 @@
|
||||
|
||||
extern int am_server;
|
||||
extern int flist_eof;
|
||||
extern int quiet;
|
||||
extern int need_unsorted_flist;
|
||||
extern int output_needs_newline;
|
||||
extern int stdout_format_has_i;
|
||||
extern struct stats stats;
|
||||
extern struct file_list *cur_flist;
|
||||
|
||||
BOOL want_progress_now = False;
|
||||
|
||||
#define PROGRESS_HISTORY_SECS 5
|
||||
|
||||
#ifdef GETPGRP_VOID
|
||||
@@ -62,8 +66,7 @@ static unsigned long msdiff(struct timeval *t1, struct timeval *t2)
|
||||
* printed for this file, so we should output a newline. (Not
|
||||
* necessarily the same as all bytes being received.)
|
||||
**/
|
||||
static void rprint_progress(OFF_T ofs, OFF_T size, struct timeval *now,
|
||||
int is_last)
|
||||
static void rprint_progress(OFF_T ofs, OFF_T size, struct timeval *now, int is_last)
|
||||
{
|
||||
char rembuf[64], eol[128];
|
||||
const char *units;
|
||||
@@ -88,8 +91,7 @@ static void rprint_progress(OFF_T ofs, OFF_T size, struct timeval *now,
|
||||
is_last = 0;
|
||||
}
|
||||
/* Compute stats based on the starting info. */
|
||||
if (!ph_start.time.tv_sec
|
||||
|| !(diff = msdiff(&ph_start.time, now)))
|
||||
if (!ph_start.time.tv_sec || !(diff = msdiff(&ph_start.time, now)))
|
||||
diff = 1;
|
||||
rate = (double) (ofs - ph_start.ofs) * 1000.0 / diff / 1024.0;
|
||||
/* Switch to total time taken for our last update. */
|
||||
@@ -99,8 +101,7 @@ static void rprint_progress(OFF_T ofs, OFF_T size, struct timeval *now,
|
||||
/* Compute stats based on recent progress. */
|
||||
if (!(diff = msdiff(&ph_list[oldest_hpos].time, now)))
|
||||
diff = 1;
|
||||
rate = (double) (ofs - ph_list[oldest_hpos].ofs) * 1000.0
|
||||
/ diff / 1024.0;
|
||||
rate = (double) (ofs - ph_list[oldest_hpos].ofs) * 1000.0 / diff / 1024.0;
|
||||
remain = rate ? (double) (size - ofs) / rate / 1000.0 : 0.0;
|
||||
}
|
||||
|
||||
@@ -127,12 +128,22 @@ static void rprint_progress(OFF_T ofs, OFF_T size, struct timeval *now,
|
||||
pct = ofs == size ? 100 : (int) (100.0 * ofs / size);
|
||||
rprintf(FCLIENT, "\r%15s %3d%% %7.2f%s %s%s",
|
||||
human_num(ofs), pct, rate, units, rembuf, eol);
|
||||
if (!is_last) {
|
||||
if (!is_last && !quiet) {
|
||||
output_needs_newline = 1;
|
||||
rflush(FCLIENT);
|
||||
}
|
||||
}
|
||||
|
||||
void progress_init(void)
|
||||
{
|
||||
if (!am_server && !INFO_GTE(PROGRESS, 1)) {
|
||||
struct timeval now;
|
||||
gettimeofday(&now, NULL);
|
||||
ph_start.time.tv_sec = now.tv_sec;
|
||||
ph_start.time.tv_usec = now.tv_usec;
|
||||
}
|
||||
}
|
||||
|
||||
void set_current_file_index(struct file_struct *file, int ndx)
|
||||
{
|
||||
if (!file)
|
||||
@@ -144,12 +155,21 @@ void set_current_file_index(struct file_struct *file, int ndx)
|
||||
current_file_index -= cur_flist->flist_num;
|
||||
}
|
||||
|
||||
void instant_progress(const char *fname)
|
||||
{
|
||||
/* We only get here if want_progress_now is True */
|
||||
if (!stdout_format_has_i && !INFO_GTE(NAME, 1))
|
||||
rprintf(FINFO, "%s\n", fname);
|
||||
end_progress(0);
|
||||
want_progress_now = False;
|
||||
}
|
||||
|
||||
void end_progress(OFF_T size)
|
||||
{
|
||||
if (!am_server) {
|
||||
struct timeval now;
|
||||
gettimeofday(&now, NULL);
|
||||
if (INFO_GTE(PROGRESS, 2)) {
|
||||
if (INFO_GTE(PROGRESS, 2) || want_progress_now) {
|
||||
rprint_progress(stats.total_transferred_size,
|
||||
stats.total_size, &now, True);
|
||||
} else {
|
||||
|
||||
191
receiver.c
191
receiver.c
@@ -3,7 +3,7 @@
|
||||
*
|
||||
* Copyright (C) 1996-2000 Andrew Tridgell
|
||||
* Copyright (C) 1996 Paul Mackerras
|
||||
* Copyright (C) 2003-2014 Wayne Davison
|
||||
* Copyright (C) 2003-2020 Wayne Davison
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
@@ -30,6 +30,7 @@ extern int inc_recurse;
|
||||
extern int log_before_transfer;
|
||||
extern int stdout_format_has_i;
|
||||
extern int logfile_format_has_i;
|
||||
extern int want_xattr_optim;
|
||||
extern int csum_length;
|
||||
extern int read_batch;
|
||||
extern int write_batch;
|
||||
@@ -38,6 +39,7 @@ extern int protocol_version;
|
||||
extern int relative_paths;
|
||||
extern int preserve_hard_links;
|
||||
extern int preserve_perms;
|
||||
extern int write_devices;
|
||||
extern int preserve_xattrs;
|
||||
extern int basis_dir_cnt;
|
||||
extern int make_backups;
|
||||
@@ -47,11 +49,14 @@ extern int append_mode;
|
||||
extern int sparse_files;
|
||||
extern int preallocate_files;
|
||||
extern int keep_partial;
|
||||
extern int checksum_len;
|
||||
extern int checksum_seed;
|
||||
extern int whole_file;
|
||||
extern int inplace;
|
||||
extern int inplace_partial;
|
||||
extern int allowed_lull;
|
||||
extern int delay_updates;
|
||||
extern int xfersum_type;
|
||||
extern BOOL want_progress_now;
|
||||
extern mode_t orig_umask;
|
||||
extern struct stats stats;
|
||||
extern char *tmpdir;
|
||||
@@ -60,11 +65,12 @@ extern char *basis_dir[MAX_BASIS_DIRS+1];
|
||||
extern char sender_file_sum[MAX_DIGEST_LEN];
|
||||
extern struct file_list *cur_flist, *first_flist, *dir_flist;
|
||||
extern filter_rule_list daemon_filter_list;
|
||||
extern OFF_T preallocated_len;
|
||||
|
||||
static struct bitbag *delayed_bits = NULL;
|
||||
static int phase = 0, redoing = 0;
|
||||
static flist_ndx_list batch_redo_list;
|
||||
/* We're either updating the basis file or an identical copy: */
|
||||
/* This is non-0 when we are updating the basis file or an identical copy: */
|
||||
static int updating_basis_or_equiv;
|
||||
|
||||
#define TMPNAME_SUFFIX ".XXXXXX"
|
||||
@@ -228,33 +234,38 @@ int open_tmpfile(char *fnametmp, const char *fname, struct file_struct *file)
|
||||
}
|
||||
|
||||
static int receive_data(int f_in, char *fname_r, int fd_r, OFF_T size_r,
|
||||
const char *fname, int fd, OFF_T total_size)
|
||||
const char *fname, int fd, struct file_struct *file, int inplace_sizing)
|
||||
{
|
||||
static char file_sum1[MAX_DIGEST_LEN];
|
||||
struct map_struct *mapbuf;
|
||||
struct sum_struct sum;
|
||||
int sum_len;
|
||||
int32 len;
|
||||
OFF_T total_size = F_LENGTH(file);
|
||||
OFF_T offset = 0;
|
||||
OFF_T offset2;
|
||||
char *data;
|
||||
int32 i;
|
||||
char *map = NULL;
|
||||
#ifdef SUPPORT_PREALLOCATION
|
||||
#ifdef PREALLOCATE_NEEDS_TRUNCATE
|
||||
OFF_T preallocated_len = 0;
|
||||
#endif
|
||||
|
||||
if (preallocate_files && fd != -1 && total_size > 0 && (!inplace || total_size > size_r)) {
|
||||
#ifdef SUPPORT_PREALLOCATION
|
||||
if (preallocate_files && fd != -1 && total_size > 0 && (!inplace_sizing || total_size > size_r)) {
|
||||
/* Try to preallocate enough space for file's eventual length. Can
|
||||
* reduce fragmentation on filesystems like ext4, xfs, and NTFS. */
|
||||
if (do_fallocate(fd, 0, total_size) == 0) {
|
||||
#ifdef PREALLOCATE_NEEDS_TRUNCATE
|
||||
preallocated_len = total_size;
|
||||
#endif
|
||||
} else
|
||||
if ((preallocated_len = do_fallocate(fd, 0, total_size)) < 0)
|
||||
rsyserr(FWARNING, errno, "do_fallocate %s", full_fname(fname));
|
||||
}
|
||||
} else
|
||||
#endif
|
||||
if (inplace_sizing) {
|
||||
#ifdef HAVE_FTRUNCATE
|
||||
/* The most compatible way to create a sparse file is to start with no length. */
|
||||
if (sparse_files > 0 && whole_file && fd >= 0 && do_ftruncate(fd, 0) == 0)
|
||||
preallocated_len = 0;
|
||||
else
|
||||
#endif
|
||||
preallocated_len = size_r;
|
||||
} else
|
||||
preallocated_len = 0;
|
||||
|
||||
read_sum_head(f_in, &sum);
|
||||
|
||||
@@ -268,7 +279,7 @@ static int receive_data(int f_in, char *fname_r, int fd_r, OFF_T size_r,
|
||||
} else
|
||||
mapbuf = NULL;
|
||||
|
||||
sum_init(checksum_seed);
|
||||
sum_init(xfersum_type, checksum_seed);
|
||||
|
||||
if (append_mode > 0) {
|
||||
OFF_T j;
|
||||
@@ -316,7 +327,7 @@ static int receive_data(int f_in, char *fname_r, int fd_r, OFF_T size_r,
|
||||
|
||||
sum_update(data, i);
|
||||
|
||||
if (fd != -1 && write_file(fd,data,i) != i)
|
||||
if (fd != -1 && write_file(fd, 0, offset, data, i) != i)
|
||||
goto report_write_error;
|
||||
offset += i;
|
||||
continue;
|
||||
@@ -346,70 +357,58 @@ static int receive_data(int f_in, char *fname_r, int fd_r, OFF_T size_r,
|
||||
|
||||
if (updating_basis_or_equiv) {
|
||||
if (offset == offset2 && fd != -1) {
|
||||
OFF_T pos;
|
||||
if (flush_write_file(fd) < 0)
|
||||
if (skip_matched(fd, offset, map, len) < 0)
|
||||
goto report_write_error;
|
||||
offset += len;
|
||||
if ((pos = do_lseek(fd, len, SEEK_CUR)) != offset) {
|
||||
rsyserr(FERROR_XFER, errno,
|
||||
"lseek of %s returned %s, not %s",
|
||||
full_fname(fname),
|
||||
big_num(pos), big_num(offset));
|
||||
exit_cleanup(RERR_FILEIO);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
}
|
||||
if (fd != -1 && map && write_file(fd, map, len) != (int)len)
|
||||
if (fd != -1 && map && write_file(fd, 0, offset, map, len) != (int)len)
|
||||
goto report_write_error;
|
||||
offset += len;
|
||||
}
|
||||
|
||||
if (flush_write_file(fd) < 0)
|
||||
goto report_write_error;
|
||||
if (fd != -1 && offset > 0) {
|
||||
if (sparse_files > 0) {
|
||||
if (sparse_end(fd, offset) != 0)
|
||||
goto report_write_error;
|
||||
} else if (flush_write_file(fd) < 0) {
|
||||
report_write_error:
|
||||
rsyserr(FERROR_XFER, errno, "write failed on %s", full_fname(fname));
|
||||
exit_cleanup(RERR_FILEIO);
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef HAVE_FTRUNCATE
|
||||
/* inplace: New data could be shorter than old data.
|
||||
* preallocate_files: total_size could have been an overestimate.
|
||||
* Cut off any extra preallocated zeros from dest file. */
|
||||
if ((inplace
|
||||
#ifdef PREALLOCATE_NEEDS_TRUNCATE
|
||||
|| preallocated_len > offset
|
||||
#endif
|
||||
) && fd != -1 && do_ftruncate(fd, offset) < 0) {
|
||||
rsyserr(FERROR_XFER, errno, "ftruncate failed on %s",
|
||||
full_fname(fname));
|
||||
if ((inplace_sizing || preallocated_len > offset) && fd != -1 && !IS_DEVICE(file->mode)) {
|
||||
if (do_ftruncate(fd, offset) < 0)
|
||||
rsyserr(FERROR_XFER, errno, "ftruncate failed on %s", full_fname(fname));
|
||||
}
|
||||
#endif
|
||||
|
||||
if (INFO_GTE(PROGRESS, 1))
|
||||
end_progress(total_size);
|
||||
|
||||
if (fd != -1 && offset > 0 && sparse_end(fd, offset) != 0) {
|
||||
report_write_error:
|
||||
rsyserr(FERROR_XFER, errno, "write failed on %s",
|
||||
full_fname(fname));
|
||||
exit_cleanup(RERR_FILEIO);
|
||||
}
|
||||
|
||||
if (sum_end(file_sum1) != checksum_len)
|
||||
overflow_exit("checksum_len"); /* Impossible... */
|
||||
sum_len = sum_end(file_sum1);
|
||||
|
||||
if (mapbuf)
|
||||
unmap_file(mapbuf);
|
||||
|
||||
read_buf(f_in, sender_file_sum, checksum_len);
|
||||
read_buf(f_in, sender_file_sum, sum_len);
|
||||
if (DEBUG_GTE(DELTASUM, 2))
|
||||
rprintf(FINFO,"got file_sum\n");
|
||||
if (fd != -1 && memcmp(file_sum1, sender_file_sum, checksum_len) != 0)
|
||||
if (fd != -1 && memcmp(file_sum1, sender_file_sum, sum_len) != 0)
|
||||
return 0;
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
static void discard_receive_data(int f_in, OFF_T length)
|
||||
static void discard_receive_data(int f_in, struct file_struct *file)
|
||||
{
|
||||
receive_data(f_in, NULL, -1, 0, NULL, -1, length);
|
||||
receive_data(f_in, NULL, -1, 0, NULL, -1, file, 0);
|
||||
}
|
||||
|
||||
static void handle_delayed_updates(char *local_name)
|
||||
@@ -520,7 +519,7 @@ int recv_files(int f_in, int f_out, char *local_name)
|
||||
int iflags, xlen;
|
||||
char *fname, fbuf[MAXPATHLEN];
|
||||
char xname[MAXPATHLEN];
|
||||
char fnametmp[MAXPATHLEN];
|
||||
char *fnametmp, fnametmpbuf[MAXPATHLEN];
|
||||
char *fnamecmp, *partialptr;
|
||||
char fnamecmpbuf[MAXPATHLEN];
|
||||
uchar fnamecmp_type;
|
||||
@@ -532,7 +531,7 @@ int recv_files(int f_in, int f_out, char *local_name)
|
||||
#ifdef SUPPORT_ACLS
|
||||
const char *parent_dirname = "";
|
||||
#endif
|
||||
int ndx, recv_ok;
|
||||
int ndx, recv_ok, one_inplace;
|
||||
|
||||
if (DEBUG_GTE(RECV, 1))
|
||||
rprintf(FINFO, "recv_files(%d) starting\n", cur_flist->used);
|
||||
@@ -540,6 +539,8 @@ int recv_files(int f_in, int f_out, char *local_name)
|
||||
if (delay_updates)
|
||||
delayed_bits = bitbag_create(cur_flist->used + 1);
|
||||
|
||||
progress_init();
|
||||
|
||||
while (1) {
|
||||
cleanup_disable();
|
||||
|
||||
@@ -547,9 +548,10 @@ int recv_files(int f_in, int f_out, char *local_name)
|
||||
ndx = read_ndx_and_attrs(f_in, f_out, &iflags, &fnamecmp_type,
|
||||
xname, &xlen);
|
||||
if (ndx == NDX_DONE) {
|
||||
if (!am_server && INFO_GTE(PROGRESS, 2) && cur_flist) {
|
||||
if (!am_server && cur_flist) {
|
||||
set_current_file_index(NULL, 0);
|
||||
end_progress(0);
|
||||
if (INFO_GTE(PROGRESS, 2))
|
||||
end_progress(0);
|
||||
}
|
||||
if (inc_recurse && first_flist) {
|
||||
if (read_batch) {
|
||||
@@ -582,15 +584,23 @@ int recv_files(int f_in, int f_out, char *local_name)
|
||||
if (DEBUG_GTE(RECV, 1))
|
||||
rprintf(FINFO, "recv_files(%s)\n", fname);
|
||||
|
||||
if (daemon_filter_list.head && (*fname != '.' || fname[1] != '\0')
|
||||
&& check_filter(&daemon_filter_list, FLOG, fname, 0) < 0) {
|
||||
rprintf(FERROR, "attempt to hack rsync failed.\n");
|
||||
exit_cleanup(RERR_PROTOCOL);
|
||||
}
|
||||
|
||||
#ifdef SUPPORT_XATTRS
|
||||
if (preserve_xattrs && iflags & ITEM_REPORT_XATTR && do_xfers)
|
||||
if (preserve_xattrs && iflags & ITEM_REPORT_XATTR && do_xfers
|
||||
&& !(want_xattr_optim && BITS_SET(iflags, ITEM_XNAME_FOLLOWS|ITEM_LOCAL_CHANGE)))
|
||||
recv_xattr_request(file, f_in);
|
||||
#endif
|
||||
|
||||
if (!(iflags & ITEM_TRANSFER)) {
|
||||
maybe_log_item(file, iflags, itemizing, xname);
|
||||
#ifdef SUPPORT_XATTRS
|
||||
if (preserve_xattrs && iflags & ITEM_REPORT_XATTR && do_xfers)
|
||||
if (preserve_xattrs && iflags & ITEM_REPORT_XATTR && do_xfers
|
||||
&& !BITS_SET(iflags, ITEM_XNAME_FOLLOWS|ITEM_LOCAL_CHANGE))
|
||||
set_file_attrs(fname, file, NULL, fname, 0);
|
||||
#endif
|
||||
if (iflags & ITEM_IS_NEW) {
|
||||
@@ -641,19 +651,13 @@ int recv_files(int f_in, int f_out, char *local_name)
|
||||
stats.created_files++;
|
||||
}
|
||||
|
||||
if (!am_server && INFO_GTE(PROGRESS, 1))
|
||||
if (!am_server)
|
||||
set_current_file_index(file, ndx);
|
||||
stats.xferred_files++;
|
||||
stats.total_transferred_size += F_LENGTH(file);
|
||||
|
||||
cleanup_got_literal = 0;
|
||||
|
||||
if (daemon_filter_list.head
|
||||
&& check_filter(&daemon_filter_list, FLOG, fname, 0) < 0) {
|
||||
rprintf(FERROR, "attempt to hack rsync failed.\n");
|
||||
exit_cleanup(RERR_PROTOCOL);
|
||||
}
|
||||
|
||||
if (read_batch) {
|
||||
int wanted = redoing
|
||||
? we_want_redo(ndx)
|
||||
@@ -663,25 +667,24 @@ int recv_files(int f_in, int f_out, char *local_name)
|
||||
"(Skipping batched update for%s \"%s\")\n",
|
||||
redoing ? " resend of" : "",
|
||||
fname);
|
||||
discard_receive_data(f_in, F_LENGTH(file));
|
||||
discard_receive_data(f_in, file);
|
||||
file->flags |= FLAG_FILE_SENT;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
if (!log_before_transfer)
|
||||
remember_initial_stats();
|
||||
remember_initial_stats();
|
||||
|
||||
if (!do_xfers) { /* log the transfer */
|
||||
log_item(FCLIENT, file, iflags, NULL);
|
||||
if (read_batch)
|
||||
discard_receive_data(f_in, F_LENGTH(file));
|
||||
discard_receive_data(f_in, file);
|
||||
continue;
|
||||
}
|
||||
if (write_batch < 0) {
|
||||
log_item(FCLIENT, file, iflags, NULL);
|
||||
if (!am_server)
|
||||
discard_receive_data(f_in, F_LENGTH(file));
|
||||
discard_receive_data(f_in, file);
|
||||
if (inc_recurse)
|
||||
send_msg_int(MSG_SUCCESS, ndx);
|
||||
continue;
|
||||
@@ -726,7 +729,7 @@ int recv_files(int f_in, int f_out, char *local_name)
|
||||
break;
|
||||
}
|
||||
if (!fnamecmp || (daemon_filter_list.head
|
||||
&& check_filter(&daemon_filter_list, FLOG, fname, 0) < 0)) {
|
||||
&& check_filter(&daemon_filter_list, FLOG, fnamecmp, 0) < 0)) {
|
||||
fnamecmp = fname;
|
||||
fnamecmp_type = FNAMECMP_FNAME;
|
||||
}
|
||||
@@ -750,6 +753,7 @@ int recv_files(int f_in, int f_out, char *local_name)
|
||||
if (fd1 == -1 && protocol_version < 29) {
|
||||
if (fnamecmp != fname) {
|
||||
fnamecmp = fname;
|
||||
fnamecmp_type = FNAMECMP_FNAME;
|
||||
fd1 = do_open(fnamecmp, O_RDONLY, 0);
|
||||
}
|
||||
|
||||
@@ -758,12 +762,14 @@ int recv_files(int f_in, int f_out, char *local_name)
|
||||
pathjoin(fnamecmpbuf, sizeof fnamecmpbuf,
|
||||
basis_dir[0], fname);
|
||||
fnamecmp = fnamecmpbuf;
|
||||
fnamecmp_type = FNAMECMP_BASIS_DIR_LOW;
|
||||
fd1 = do_open(fnamecmp, O_RDONLY, 0);
|
||||
}
|
||||
}
|
||||
|
||||
updating_basis_or_equiv = inplace
|
||||
&& (fnamecmp == fname || fnamecmp_type == FNAMECMP_BACKUP);
|
||||
one_inplace = inplace_partial && fnamecmp_type == FNAMECMP_PARTIAL_DIR;
|
||||
updating_basis_or_equiv = one_inplace
|
||||
|| (inplace && (fnamecmp == fname || fnamecmp_type == FNAMECMP_BACKUP));
|
||||
|
||||
if (fd1 == -1) {
|
||||
st.st_mode = 0;
|
||||
@@ -771,7 +777,7 @@ int recv_files(int f_in, int f_out, char *local_name)
|
||||
} else if (do_fstat(fd1,&st) != 0) {
|
||||
rsyserr(FERROR_XFER, errno, "fstat %s failed",
|
||||
full_fname(fnamecmp));
|
||||
discard_receive_data(f_in, F_LENGTH(file));
|
||||
discard_receive_data(f_in, file);
|
||||
close(fd1);
|
||||
if (inc_recurse)
|
||||
send_msg_int(MSG_NO_SEND, ndx);
|
||||
@@ -786,18 +792,21 @@ int recv_files(int f_in, int f_out, char *local_name)
|
||||
*/
|
||||
rprintf(FERROR_XFER, "recv_files: %s is a directory\n",
|
||||
full_fname(fnamecmp));
|
||||
discard_receive_data(f_in, F_LENGTH(file));
|
||||
discard_receive_data(f_in, file);
|
||||
close(fd1);
|
||||
if (inc_recurse)
|
||||
send_msg_int(MSG_NO_SEND, ndx);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (fd1 != -1 && !S_ISREG(st.st_mode)) {
|
||||
if (fd1 != -1 && !(S_ISREG(st.st_mode) || (write_devices && IS_DEVICE(st.st_mode)))) {
|
||||
close(fd1);
|
||||
fd1 = -1;
|
||||
}
|
||||
|
||||
if (fd1 != -1 && IS_DEVICE(st.st_mode) && st.st_size == 0)
|
||||
st.st_size = get_device_size(fd1, fname);
|
||||
|
||||
/* If we're not preserving permissions, change the file-list's
|
||||
* mode based on the local permissions and some heuristics. */
|
||||
if (!preserve_perms) {
|
||||
@@ -810,26 +819,27 @@ int recv_files(int f_in, int f_out, char *local_name)
|
||||
parent_dirname = dn;
|
||||
}
|
||||
#endif
|
||||
file->mode = dest_mode(file->mode, st.st_mode,
|
||||
dflt_perms, exists);
|
||||
file->mode = dest_mode(file->mode, st.st_mode, dflt_perms, exists);
|
||||
}
|
||||
|
||||
/* We now check to see if we are writing the file "inplace" */
|
||||
if (inplace) {
|
||||
fd2 = do_open(fname, O_WRONLY|O_CREAT, 0600);
|
||||
if (inplace || one_inplace) {
|
||||
fnametmp = one_inplace ? partialptr : fname;
|
||||
fd2 = do_open(fnametmp, O_WRONLY|O_CREAT, 0600);
|
||||
if (fd2 == -1) {
|
||||
rsyserr(FERROR_XFER, errno, "open %s failed",
|
||||
full_fname(fname));
|
||||
full_fname(fnametmp));
|
||||
} else if (updating_basis_or_equiv)
|
||||
cleanup_set(NULL, NULL, file, fd1, fd2);
|
||||
} else {
|
||||
fnametmp = fnametmpbuf;
|
||||
fd2 = open_tmpfile(fnametmp, fname, file);
|
||||
if (fd2 != -1)
|
||||
cleanup_set(fnametmp, partialptr, file, fd1, fd2);
|
||||
}
|
||||
|
||||
if (fd2 == -1) {
|
||||
discard_receive_data(f_in, F_LENGTH(file));
|
||||
discard_receive_data(f_in, file);
|
||||
if (fd1 != -1)
|
||||
close(fd1);
|
||||
if (inc_recurse)
|
||||
@@ -844,10 +854,11 @@ int recv_files(int f_in, int f_out, char *local_name)
|
||||
rprintf(FINFO, "%s\n", fname);
|
||||
|
||||
/* recv file data */
|
||||
recv_ok = receive_data(f_in, fnamecmp, fd1, st.st_size,
|
||||
fname, fd2, F_LENGTH(file));
|
||||
recv_ok = receive_data(f_in, fnamecmp, fd1, st.st_size, fname, fd2, file, inplace || one_inplace);
|
||||
|
||||
log_item(log_code, file, iflags, NULL);
|
||||
if (want_progress_now)
|
||||
instant_progress(fname);
|
||||
|
||||
if (fd1 != -1)
|
||||
close(fd1);
|
||||
@@ -860,19 +871,19 @@ int recv_files(int f_in, int f_out, char *local_name)
|
||||
if ((recv_ok && (!delay_updates || !partialptr)) || inplace) {
|
||||
if (partialptr == fname)
|
||||
partialptr = NULL;
|
||||
if (!finish_transfer(fname, fnametmp, fnamecmp,
|
||||
partialptr, file, recv_ok, 1))
|
||||
if (!finish_transfer(fname, fnametmp, fnamecmp, partialptr, file, recv_ok, 1))
|
||||
recv_ok = -1;
|
||||
else if (fnamecmp == partialptr) {
|
||||
do_unlink(partialptr);
|
||||
if (!one_inplace)
|
||||
do_unlink(partialptr);
|
||||
handle_partial_dir(partialptr, PDIR_DELETE);
|
||||
}
|
||||
} else if (keep_partial && partialptr) {
|
||||
} else if (keep_partial && partialptr && !one_inplace) {
|
||||
if (!handle_partial_dir(partialptr, PDIR_CREATE)) {
|
||||
rprintf(FERROR,
|
||||
"Unable to create partial-dir for %s -- discarding %s.\n",
|
||||
local_name ? local_name : f_name(file, NULL),
|
||||
recv_ok ? "completed file" : "partial file");
|
||||
"Unable to create partial-dir for %s -- discarding %s.\n",
|
||||
local_name ? local_name : f_name(file, NULL),
|
||||
recv_ok ? "completed file" : "partial file");
|
||||
do_unlink(fnametmp);
|
||||
recv_ok = -1;
|
||||
} else if (!finish_transfer(partialptr, fnametmp, fnamecmp, NULL,
|
||||
@@ -883,7 +894,7 @@ int recv_files(int f_in, int f_out, char *local_name)
|
||||
recv_ok = 2;
|
||||
} else
|
||||
partialptr = NULL;
|
||||
} else
|
||||
} else if (!one_inplace)
|
||||
do_unlink(fnametmp);
|
||||
|
||||
cleanup_disable();
|
||||
@@ -930,7 +941,7 @@ int recv_files(int f_in, int f_out, char *local_name)
|
||||
} else if (inc_recurse)
|
||||
send_msg_int(MSG_NO_SEND, ndx);
|
||||
break;
|
||||
}
|
||||
}
|
||||
case -1:
|
||||
if (inc_recurse)
|
||||
send_msg_int(MSG_NO_SEND, ndx);
|
||||
|
||||
12
rounding.c
12
rounding.c
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* A pre-compilation helper program to aid in the creation of rounding.h.
|
||||
*
|
||||
* Copyright (C) 2007-2014 Wayne Davison
|
||||
* Copyright (C) 2007-2020 Wayne Davison
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
@@ -23,8 +23,8 @@
|
||||
#define SIZEOF(x) ((long int)sizeof (x))
|
||||
|
||||
struct test {
|
||||
union file_extras extras[ARRAY_LEN];
|
||||
struct file_struct file;
|
||||
union file_extras extras[ARRAY_LEN];
|
||||
struct file_struct file;
|
||||
};
|
||||
|
||||
#define ACTUAL_SIZE SIZEOF(struct test)
|
||||
@@ -32,7 +32,7 @@ struct test {
|
||||
|
||||
int main(UNUSED(int argc), UNUSED(char *argv[]))
|
||||
{
|
||||
static int test_array[1 - 2 * (ACTUAL_SIZE != EXPECTED_SIZE)];
|
||||
test_array[0] = 0;
|
||||
return 0;
|
||||
static int test_array[1 - 2 * (ACTUAL_SIZE != EXPECTED_SIZE)];
|
||||
test_array[0] = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
190
rsync-ssl
Executable file
190
rsync-ssl
Executable file
@@ -0,0 +1,190 @@
|
||||
#!/bin/bash
|
||||
|
||||
# This script uses openssl, gnutls, or stunnel to secure an rsync daemon connection.
|
||||
|
||||
# By default this script takes rsync args and hands them off to the actual
|
||||
# rsync command with an --rsh option that makes it open an SSL connection to an
|
||||
# rsync daemon. See the rsync-ssl manpage for usage details and env variables.
|
||||
|
||||
# When the first arg is --HELPER, we are being used by rsync as an --rsh helper
|
||||
# script, and the args are (note the trailing dot):
|
||||
#
|
||||
# rsync-ssl --HELPER HOSTNAME rsync --server --daemon .
|
||||
#
|
||||
# --HELPER is not a user-facing option, so it is not documented in the manpage.
|
||||
|
||||
# The first SSL setup was based on: http://dozzie.jarowit.net/trac/wiki/RsyncSSL
|
||||
# Note that an stunnel connection requires at least version 4.x of stunnel.
|
||||
|
||||
function rsync_ssl_run {
|
||||
case "$*" in
|
||||
*rsync://*) ;;
|
||||
*::*) ;;
|
||||
*)
|
||||
echo "You must use rsync-ssl with a daemon-style hostname." 1>&2
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
|
||||
exec rsync --rsh="$0 --HELPER" "${@}"
|
||||
}
|
||||
|
||||
function rsync_ssl_helper {
|
||||
if [[ -z "$RSYNC_SSL_TYPE" ]]; then
|
||||
found=`path_search openssl stunnel4 stunnel` || exit 1
|
||||
if [[ "$found" == */openssl ]]; then
|
||||
RSYNC_SSL_TYPE=openssl
|
||||
RSYNC_SSL_OPENSSL="$found"
|
||||
elif [[ "$found" == */gnutls-cli ]]; then
|
||||
RSYNC_SSL_TYPE=gnutls
|
||||
RSYNC_SSL_GNUTLS="$found"
|
||||
else
|
||||
RSYNC_SSL_TYPE=stunnel
|
||||
RSYNC_SSL_STUNNEL="$found"
|
||||
fi
|
||||
fi
|
||||
|
||||
case "$RSYNC_SSL_TYPE" in
|
||||
openssl)
|
||||
if [[ -z "$RSYNC_SSL_OPENSSL" ]]; then
|
||||
RSYNC_SSL_OPENSSL=`path_search openssl` || exit 1
|
||||
fi
|
||||
optsep=' '
|
||||
;;
|
||||
gnutls)
|
||||
if [[ -z "$RSYNC_SSL_GNUTLS" ]]; then
|
||||
RSYNC_SSL_GNUTLS=`path_search gnutls-cli` || exit 1
|
||||
fi
|
||||
optsep=' '
|
||||
;;
|
||||
stunnel)
|
||||
if [[ -z "$RSYNC_SSL_STUNNEL" ]]; then
|
||||
RSYNC_SSL_STUNNEL=`path_search stunnel4 stunnel` || exit 1
|
||||
fi
|
||||
optsep=' = '
|
||||
;;
|
||||
*)
|
||||
echo "The RSYNC_SSL_TYPE specifies an unknown type: $RSYNC_SSL_TYPE" 1>&2
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
|
||||
if [[ -z "$RSYNC_SSL_CERT" ]]; then
|
||||
certopt=""
|
||||
gnutls_cert_opt=""
|
||||
else
|
||||
certopt="cert$optsep$RSYNC_SSL_CERT"
|
||||
gnutls_cert_opt="--x509keyfile=$RSYNC_SSL_CERT"
|
||||
fi
|
||||
|
||||
if [[ -z ${RSYNC_SSL_CA_CERT+x} ]]; then
|
||||
# RSYNC_SSL_CA_CERT unset - default CA set AND verify:
|
||||
# openssl:
|
||||
caopt="-verify_return_error -verify 4"
|
||||
# gnutls:
|
||||
gnutls_opts=""
|
||||
# stunnel:
|
||||
# Since there is no way of using the default CA certificate collection,
|
||||
# we cannot do any verification. Thus, stunnel should really only be
|
||||
# used if nothing else is available.
|
||||
cafile=""
|
||||
verify=""
|
||||
elif [[ "$RSYNC_SSL_CA_CERT" == "" ]]; then
|
||||
# RSYNC_SSL_CA_CERT set but empty -do NO verifications:
|
||||
# openssl:
|
||||
caopt="-verify 1"
|
||||
# gnutls:
|
||||
gnutls_opts="--insecure"
|
||||
# stunnel:
|
||||
cafile=""
|
||||
verify="verifyChain = no"
|
||||
else
|
||||
# RSYNC_SSL_CA_CERT set - use CA AND verify:
|
||||
# openssl:
|
||||
caopt="-CAfile $RSYNC_SSL_CA_CERT -verify_return_error -verify 4"
|
||||
# gnutls:
|
||||
gnutls_opts="--x509cafile=$RSYNC_SSL_CA_CERT"
|
||||
# stunnel:
|
||||
cafile="CAfile = $RSYNC_SSL_CA_CERT"
|
||||
verify="verifyChain = yes"
|
||||
fi
|
||||
|
||||
port="${RSYNC_PORT:-0}"
|
||||
if [[ "$port" == 0 ]]; then
|
||||
port="${RSYNC_SSL_PORT:-874}"
|
||||
fi
|
||||
|
||||
# If the user specified USER@HOSTNAME::module, then rsync passes us
|
||||
# the -l USER option too, so we must be prepared to ignore it.
|
||||
if [[ "$1" == "-l" ]]; then
|
||||
shift 2
|
||||
fi
|
||||
|
||||
hostname="$1"
|
||||
shift
|
||||
|
||||
if [[ -z "$hostname" || "$1" != rsync || "$2" != --server || "$3" != --daemon ]]; then
|
||||
echo "Usage: rsync-ssl --HELPER HOSTNAME rsync --server --daemon ." 1>&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [[ $RSYNC_SSL_TYPE == openssl ]]; then
|
||||
exec $RSYNC_SSL_OPENSSL s_client $caopt $certopt -quiet -verify_quiet -servername $hostname -connect $hostname:$port
|
||||
elif [[ $RSYNC_SSL_TYPE == gnutls ]]; then
|
||||
exec $RSYNC_SSL_GNUTLS --logfile=/dev/null $gnutls_cert_opt $gnutls_opts $hostname:$port
|
||||
else
|
||||
# devzero@web.de came up with this no-tmpfile calling syntax:
|
||||
exec $RSYNC_SSL_STUNNEL -fd 10 11<&0 <<EOF 10<&0 0<&11 11<&-
|
||||
foreground = yes
|
||||
debug = crit
|
||||
connect = $hostname:$port
|
||||
client = yes
|
||||
TIMEOUTclose = 0
|
||||
$verify
|
||||
$certopt
|
||||
$cafile
|
||||
EOF
|
||||
fi
|
||||
}
|
||||
|
||||
function path_search {
|
||||
IFS_SAVE="$IFS"
|
||||
IFS=:
|
||||
for prog in "${@}"; do
|
||||
for dir in $PATH; do
|
||||
[[ -z "$dir" ]] && dir=.
|
||||
if [[ -f "$dir/$prog" && -x "$dir/$prog" ]]; then
|
||||
echo "$dir/$prog"
|
||||
IFS="$IFS_SAVE"
|
||||
return 0
|
||||
fi
|
||||
done
|
||||
done
|
||||
|
||||
IFS="$IFS_SAVE"
|
||||
echo "Failed to find on your path: $*" 1>&2
|
||||
echo "See the rsync-ssl manpage for configuration assistance." 1>&2
|
||||
return 1
|
||||
}
|
||||
|
||||
if [[ "$#" == 0 ]]; then
|
||||
echo "Usage: rsync-ssl [--type=SSL_TYPE] RSYNC_ARG [...]" 1>&2
|
||||
echo "The SSL_TYPE can be openssl or stunnel"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [[ "$1" = --help || "$1" = -h ]]; then
|
||||
exec rsync --help
|
||||
fi
|
||||
|
||||
if [[ "$1" == --HELPER ]]; then
|
||||
shift
|
||||
rsync_ssl_helper "${@}"
|
||||
fi
|
||||
|
||||
if [[ "$1" == --type=* ]]; then
|
||||
export RSYNC_SSL_TYPE="${1/--type=/}"
|
||||
shift
|
||||
fi
|
||||
|
||||
rsync_ssl_run "${@}"
|
||||
98
rsync-ssl.1.md
Normal file
98
rsync-ssl.1.md
Normal file
@@ -0,0 +1,98 @@
|
||||
# NAME
|
||||
|
||||
rsync-ssl - a helper script for connecting to an ssl rsync daemon
|
||||
|
||||
# SYNOPSIS
|
||||
|
||||
```
|
||||
rsync-ssl [--type=SSL_TYPE] RSYNC_ARGS
|
||||
```
|
||||
|
||||
# DESCRIPTION
|
||||
|
||||
The rsync-ssl script helps you to run an rsync copy to/from an rsync daemon
|
||||
that requires ssl connections.
|
||||
|
||||
# OPTIONS
|
||||
|
||||
If the **first** arg is a `--type=SSL_TYPE` option, the script will only use
|
||||
that particular program to open an ssl connection instead of trying to find an
|
||||
openssl or stunnel executable via a simple heuristic (assuming that the
|
||||
`RSYNC_SSL_TYPE` environment variable is not set as well -- see below). This
|
||||
option must specify one of `openssl` or `stunnel`. The equal sign is
|
||||
required for this particular option.
|
||||
|
||||
All the other options are passed through to the rsync command, so consult the
|
||||
**rsync** manpage for more information on how it works.
|
||||
|
||||
# ENVIRONMENT VARIABLES
|
||||
|
||||
The ssl helper scripts are affected by the following environment variables:
|
||||
|
||||
0. `RSYNC_SSL_TYPE` Specifies the program type that should be used to open the
|
||||
ssl connection. It must be one of `openssl` or `stunnel`. The
|
||||
`--type=SSL_TYPE` option overrides this, when specified.
|
||||
0. `RSYNC_SSL_PORT` If specified, the value is the port number that is used as
|
||||
the default when the user does not specify a port in their rsync command.
|
||||
When not specified, the default port number is 874. (Note that older rsync
|
||||
versions (prior to 3.2.0) did not communicate an overriding port number
|
||||
value to the helper script.)
|
||||
0. `RSYNC_SSL_CERT` If specified, the value is a filename that contains a
|
||||
certificate to use for the connection.
|
||||
0. `RSYNC_SSL_CA_CERT` If specified, the value is a filename that contains a
|
||||
certificate authority certificate that is used to validate the connection.
|
||||
0. `RSYNC_SSL_OPENSSL` Specifies the openssl executable to run when the
|
||||
connection type is set to openssl. If unspecified, the $PATH is searched
|
||||
for "openssl".
|
||||
0. `RSYNC_SSL_GNUTLS` Specifies the gnutls-cli executable to run when the
|
||||
connection type is set to gnutls. If unspecified, the $PATH is searched
|
||||
for "gnutls-cli".
|
||||
0. `RSYNC_SSL_STUNNEL` Specifies the stunnel executable to run when the
|
||||
connection type is set to stunnel. If unspecified, the $PATH is searched
|
||||
first for "stunnel4" and then for "stunnel".
|
||||
|
||||
# EXAMPLES
|
||||
|
||||
> rsync-ssl -aiv example.com::src/ dest
|
||||
|
||||
> rsync-ssl --type=openssl -aiv example.com::src/ dest
|
||||
|
||||
# SEE ALSO
|
||||
|
||||
**rsync**(1), **rsyncd.conf**(5)
|
||||
|
||||
# CAVEATS
|
||||
|
||||
Note that using an stunnel connection requires at least version 4 of stunnel,
|
||||
which should be the case on modern systems. Also, it does not verify a
|
||||
connection against the CA certificate collection, so it only encrypts the
|
||||
connection without any cert validation unless you have specified the
|
||||
certificate environment options.
|
||||
|
||||
This script also supports a `--type=gnutls` option, but at the time of this
|
||||
release the gnutls-cli command was dropping output, making it unusable. If
|
||||
that bug has been fixed in your version, feel free to put gnutls into an
|
||||
exported RSYNC_SSL_TYPE environment variable to make its use the default.
|
||||
|
||||
# BUGS
|
||||
|
||||
Please report bugs! See the web site at <http://rsync.samba.org/>.
|
||||
|
||||
# VERSION
|
||||
|
||||
This man page is current for version @VERSION@ of rsync.
|
||||
|
||||
# CREDITS
|
||||
|
||||
rsync is distributed under the GNU General Public License. See the file
|
||||
COPYING for details.
|
||||
|
||||
A web site is available at <http://rsync.samba.org/>. The site includes an
|
||||
FAQ-O-Matic which may cover questions unanswered by this manual page.
|
||||
|
||||
# AUTHOR
|
||||
|
||||
This manpage was written by Wayne Davison.
|
||||
|
||||
Mailing lists for support and development are available at
|
||||
<http://lists.samba.org/>.
|
||||
12
rsync-ssl.in
12
rsync-ssl.in
@@ -1,12 +0,0 @@
|
||||
#!/bin/bash
|
||||
# This script supports using stunnel to secure an rsync daemon connection.
|
||||
# Note that this requires at least version 4.x of stunnel.
|
||||
case "$@" in
|
||||
*rsync://*) ;;
|
||||
*::*) ;;
|
||||
*)
|
||||
echo "You must use rsync-ssl with a daemon-style hostname." 0>&1
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
exec @bindir@/rsync --rsh=@bindir@/stunnel-rsync "${@}"
|
||||
3935
rsync.1.md
Normal file
3935
rsync.1.md
Normal file
File diff suppressed because it is too large
Load Diff
98
rsync.c
98
rsync.c
@@ -3,7 +3,7 @@
|
||||
*
|
||||
* Copyright (C) 1996 Andrew Tridgell
|
||||
* Copyright (C) 1996 Paul Mackerras
|
||||
* Copyright (C) 2003-2014 Wayne Davison
|
||||
* Copyright (C) 2003-2020 Wayne Davison
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
@@ -43,12 +43,14 @@ extern int am_starting_up;
|
||||
extern int allow_8bit_chars;
|
||||
extern int protocol_version;
|
||||
extern int got_kill_signal;
|
||||
extern int called_from_signal_handler;
|
||||
extern int inc_recurse;
|
||||
extern int inplace;
|
||||
extern int flist_eof;
|
||||
extern int file_old_total;
|
||||
extern int keep_dirlinks;
|
||||
extern int make_backups;
|
||||
extern int sanitize_paths;
|
||||
extern struct file_list *cur_flist, *first_flist, *dir_flist;
|
||||
extern struct chmod_mode_struct *daemon_chmod_modes;
|
||||
#ifdef ICONV_OPTION
|
||||
@@ -61,6 +63,15 @@ iconv_t ic_chck = (iconv_t)-1;
|
||||
iconv_t ic_send = (iconv_t)-1, ic_recv = (iconv_t)-1;
|
||||
# endif
|
||||
|
||||
#define UPDATED_OWNER (1<<0)
|
||||
#define UPDATED_GROUP (1<<1)
|
||||
#define UPDATED_MTIME (1<<2)
|
||||
#define UPDATED_ATIME (1<<3)
|
||||
#define UPDATED_ACLS (1<<4)
|
||||
#define UPDATED_MODE (1<<5)
|
||||
|
||||
#define UPDATED_TIMES (UPDATED_MTIME|UPDATED_ATIME)
|
||||
|
||||
static const char *default_charset(void)
|
||||
{
|
||||
# if defined HAVE_LIBCHARSET_H && defined HAVE_LOCALE_CHARSET
|
||||
@@ -307,8 +318,7 @@ void send_protected_args(int fd, char *args[])
|
||||
#endif
|
||||
}
|
||||
|
||||
int read_ndx_and_attrs(int f_in, int f_out, int *iflag_ptr, uchar *type_ptr,
|
||||
char *buf, int *len_ptr)
|
||||
int read_ndx_and_attrs(int f_in, int f_out, int *iflag_ptr, uchar *type_ptr, char *buf, int *len_ptr)
|
||||
{
|
||||
int len, iflags = 0;
|
||||
struct file_list *flist;
|
||||
@@ -364,7 +374,7 @@ int read_ndx_and_attrs(int f_in, int f_out, int *iflag_ptr, uchar *type_ptr,
|
||||
}
|
||||
/* Send all the data we read for this flist to the generator. */
|
||||
start_flist_forward(ndx);
|
||||
flist = recv_file_list(f_in);
|
||||
flist = recv_file_list(f_in, ndx);
|
||||
flist->parent_ndx = ndx;
|
||||
stop_flist_forward();
|
||||
}
|
||||
@@ -396,6 +406,11 @@ int read_ndx_and_attrs(int f_in, int f_out, int *iflag_ptr, uchar *type_ptr,
|
||||
if (iflags & ITEM_XNAME_FOLLOWS) {
|
||||
if ((len = read_vstring(f_in, buf, MAXPATHLEN)) < 0)
|
||||
exit_cleanup(RERR_PROTOCOL);
|
||||
|
||||
if (sanitize_paths) {
|
||||
sanitize_path(buf, buf, "", 0, SP_DEFAULT);
|
||||
len = strlen(buf);
|
||||
}
|
||||
} else {
|
||||
*buf = '\0';
|
||||
len = -1;
|
||||
@@ -452,6 +467,21 @@ mode_t dest_mode(mode_t flist_mode, mode_t stat_mode, int dflt_perms,
|
||||
return new_mode;
|
||||
}
|
||||
|
||||
static int same_mtime(struct file_struct *file, STRUCT_STAT *st, int extra_accuracy)
|
||||
{
|
||||
#ifdef ST_MTIME_NSEC
|
||||
uint32 f1_nsec = F_MOD_NSEC_or_0(file);
|
||||
uint32 f2_nsec = (uint32)st->ST_MTIME_NSEC;
|
||||
#else
|
||||
uint32 f1_nsec = 0, f2_nsec = 0;
|
||||
#endif
|
||||
|
||||
if (extra_accuracy) /* ignore modify_window when setting the time after a transfer or checksum check */
|
||||
return file->modtime == st->st_mtime && f1_nsec == f2_nsec;
|
||||
|
||||
return same_time(file->modtime, f1_nsec, st->st_mtime , f2_nsec);
|
||||
}
|
||||
|
||||
int set_file_attrs(const char *fname, struct file_struct *file, stat_x *sxp,
|
||||
const char *fnamecmp, int flags)
|
||||
{
|
||||
@@ -517,8 +547,8 @@ int set_file_attrs(const char *fname, struct file_struct *file, stat_x *sxp,
|
||||
/* We shouldn't have attempted to change uid
|
||||
* or gid unless have the privilege. */
|
||||
rsyserr(FERROR_XFER, errno, "%s %s failed",
|
||||
change_uid ? "chown" : "chgrp",
|
||||
full_fname(fname));
|
||||
change_uid ? "chown" : "chgrp",
|
||||
full_fname(fname));
|
||||
goto cleanup;
|
||||
}
|
||||
if (uid == (uid_t)-1 && sxp->st.st_uid != (uid_t)-1)
|
||||
@@ -533,7 +563,10 @@ int set_file_attrs(const char *fname, struct file_struct *file, stat_x *sxp,
|
||||
keep_dirlinks && S_ISDIR(sxp->st.st_mode));
|
||||
}
|
||||
}
|
||||
updated = 1;
|
||||
if (change_uid)
|
||||
updated |= UPDATED_OWNER;
|
||||
if (change_gid)
|
||||
updated |= UPDATED_GROUP;
|
||||
}
|
||||
|
||||
#ifdef SUPPORT_XATTRS
|
||||
@@ -546,19 +579,39 @@ int set_file_attrs(const char *fname, struct file_struct *file, stat_x *sxp,
|
||||
if (!preserve_times
|
||||
|| (!(preserve_times & PRESERVE_DIR_TIMES) && S_ISDIR(sxp->st.st_mode))
|
||||
|| (!(preserve_times & PRESERVE_LINK_TIMES) && S_ISLNK(sxp->st.st_mode)))
|
||||
flags |= ATTRS_SKIP_MTIME;
|
||||
if (!(flags & ATTRS_SKIP_MTIME)
|
||||
&& cmp_time(sxp->st.st_mtime, file->modtime) != 0) {
|
||||
int ret = set_modtime(fname, file->modtime, F_MOD_NSEC(file), sxp->st.st_mode);
|
||||
flags |= ATTRS_SKIP_MTIME | ATTRS_SKIP_ATIME;
|
||||
else if (sxp != &sx2)
|
||||
memcpy(&sx2.st, &sxp->st, sizeof (sx2.st));
|
||||
if (!atimes_ndx || S_ISDIR(sxp->st.st_mode))
|
||||
flags |= ATTRS_SKIP_ATIME;
|
||||
if (!(flags & ATTRS_SKIP_MTIME) && !same_mtime(file, &sxp->st, flags & ATTRS_ACCURATE_TIME)) {
|
||||
sx2.st.st_mtime = file->modtime;
|
||||
#ifdef ST_MTIME_NSEC
|
||||
sx2.st.ST_MTIME_NSEC = F_MOD_NSEC_or_0(file);
|
||||
#endif
|
||||
updated |= UPDATED_MTIME;
|
||||
}
|
||||
if (!(flags & ATTRS_SKIP_ATIME)) {
|
||||
time_t file_atime = F_ATIME(file);
|
||||
if (flags & ATTRS_ACCURATE_TIME || !same_time(sxp->st.st_atime, 0, file_atime, 0)) {
|
||||
sx2.st.st_atime = file_atime;
|
||||
#ifdef ST_ATIME_NSEC
|
||||
sx2.st.ST_ATIME_NSEC = 0;
|
||||
#endif
|
||||
updated |= UPDATED_ATIME;
|
||||
}
|
||||
}
|
||||
if (updated & UPDATED_TIMES) {
|
||||
int ret = set_times(fname, &sx2.st);
|
||||
if (ret < 0) {
|
||||
rsyserr(FERROR_XFER, errno, "failed to set times on %s",
|
||||
full_fname(fname));
|
||||
goto cleanup;
|
||||
}
|
||||
if (ret == 0) /* ret == 1 if symlink could not be set */
|
||||
updated = 1;
|
||||
else
|
||||
if (ret > 0) { /* ret == 1 if symlink could not be set */
|
||||
updated &= ~UPDATED_TIMES;
|
||||
file->flags |= FLAG_TIME_FAILED;
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef SUPPORT_ACLS
|
||||
@@ -570,7 +623,7 @@ int set_file_attrs(const char *fname, struct file_struct *file, stat_x *sxp,
|
||||
* need to chmod(). */
|
||||
if (preserve_acls && !S_ISLNK(new_mode)) {
|
||||
if (set_acl(fname, file, sxp, new_mode) > 0)
|
||||
updated = 1;
|
||||
updated |= UPDATED_ACLS;
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -584,7 +637,7 @@ int set_file_attrs(const char *fname, struct file_struct *file, stat_x *sxp,
|
||||
goto cleanup;
|
||||
}
|
||||
if (ret == 0) /* ret == 1 if symlink could not be set */
|
||||
updated = 1;
|
||||
updated |= UPDATED_MODE;
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -601,8 +654,10 @@ int set_file_attrs(const char *fname, struct file_struct *file, stat_x *sxp,
|
||||
}
|
||||
|
||||
/* This is only called for SIGINT, SIGHUP, and SIGTERM. */
|
||||
RETSIGTYPE sig_int(int sig_num)
|
||||
void sig_int(int sig_num)
|
||||
{
|
||||
called_from_signal_handler = 1;
|
||||
|
||||
/* KLUGE: if the user hits Ctrl-C while ssh is prompting
|
||||
* for a password, then our cleanup's sending of a SIGUSR1
|
||||
* signal to all our children may kill ssh before it has a
|
||||
@@ -626,6 +681,7 @@ RETSIGTYPE sig_int(int sig_num)
|
||||
* we didn't already set the flag. */
|
||||
if (!got_kill_signal && (am_server || am_receiver)) {
|
||||
got_kill_signal = sig_num;
|
||||
called_from_signal_handler = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -636,7 +692,7 @@ RETSIGTYPE sig_int(int sig_num)
|
||||
* attributes (e.g. permissions, ownership, etc.). If the robust_rename()
|
||||
* call is forced to copy the temp file and partialptr is both non-NULL and
|
||||
* not an absolute path, we stage the file into the partial-dir and then
|
||||
* rename it into place. This returns 1 on succcess or 0 on failure. */
|
||||
* rename it into place. This returns 1 on success or 0 on failure. */
|
||||
int finish_transfer(const char *fname, const char *fnametmp,
|
||||
const char *fnamecmp, const char *partialptr,
|
||||
struct file_struct *file, int ok_to_set_time,
|
||||
@@ -655,14 +711,14 @@ int finish_transfer(const char *fname, const char *fnametmp,
|
||||
if (make_backups > 0 && overwriting_basis) {
|
||||
int ok = make_backup(fname, False);
|
||||
if (!ok)
|
||||
return 1;
|
||||
exit_cleanup(RERR_FILEIO);
|
||||
if (ok == 1 && fnamecmp == fname)
|
||||
fnamecmp = get_backup_name(fname);
|
||||
}
|
||||
|
||||
/* Change permissions before putting the file into place. */
|
||||
set_file_attrs(fnametmp, file, NULL, fnamecmp,
|
||||
ok_to_set_time ? 0 : ATTRS_SKIP_MTIME);
|
||||
ok_to_set_time ? ATTRS_ACCURATE_TIME : ATTRS_SKIP_MTIME | ATTRS_SKIP_ATIME);
|
||||
|
||||
/* move tmp file over real file */
|
||||
if (DEBUG_GTE(RECV, 1))
|
||||
@@ -687,7 +743,7 @@ int finish_transfer(const char *fname, const char *fnametmp,
|
||||
|
||||
do_set_file_attrs:
|
||||
set_file_attrs(fnametmp, file, NULL, fnamecmp,
|
||||
ok_to_set_time ? 0 : ATTRS_SKIP_MTIME);
|
||||
ok_to_set_time ? ATTRS_ACCURATE_TIME : ATTRS_SKIP_MTIME | ATTRS_SKIP_ATIME);
|
||||
|
||||
if (temp_copy_name) {
|
||||
if (do_rename(fnametmp, fname) < 0) {
|
||||
|
||||
119
rsync.h
119
rsync.h
@@ -2,7 +2,7 @@
|
||||
* Copyright (C) 1996, 2000 Andrew Tridgell
|
||||
* Copyright (C) 1996 Paul Mackerras
|
||||
* Copyright (C) 2001, 2002 Martin Pool <mbp@samba.org>
|
||||
* Copyright (C) 2003-2014 Wayne Davison
|
||||
* Copyright (C) 2003-2020 Wayne Davison
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
@@ -52,16 +52,24 @@
|
||||
#define XMIT_SAME_NAME (1<<5)
|
||||
#define XMIT_LONG_NAME (1<<6)
|
||||
#define XMIT_SAME_TIME (1<<7)
|
||||
|
||||
#define XMIT_SAME_RDEV_MAJOR (1<<8) /* protocols 28 - now (devices only) */
|
||||
#define XMIT_NO_CONTENT_DIR (1<<8) /* protocols 30 - now (dirs only) */
|
||||
#define XMIT_HLINKED (1<<9) /* protocols 28 - now */
|
||||
#define XMIT_HLINKED (1<<9) /* protocols 28 - now (non-dirs) */
|
||||
#define XMIT_SAME_DEV_pre30 (1<<10) /* protocols 28 - 29 */
|
||||
#define XMIT_USER_NAME_FOLLOWS (1<<10) /* protocols 30 - now */
|
||||
#define XMIT_RDEV_MINOR_8_pre30 (1<<11) /* protocols 28 - 29 */
|
||||
#define XMIT_RDEV_MINOR_8_pre30 (1<<11) /* protocols 28 - 29 */
|
||||
#define XMIT_GROUP_NAME_FOLLOWS (1<<11) /* protocols 30 - now */
|
||||
#define XMIT_HLINK_FIRST (1<<12) /* protocols 30 - now (HLINKED files only) */
|
||||
#define XMIT_IO_ERROR_ENDLIST (1<<12) /* protocols 31*- now (w/XMIT_EXTENDED_FLAGS) (also protocol 30 w/'f' compat flag) */
|
||||
#define XMIT_MOD_NSEC (1<<13) /* protocols 31 - now */
|
||||
#define XMIT_SAME_ATIME (1<<14) /* any protocol - restricted by command-line option */
|
||||
#define XMIT_UNUSED_15 (1<<15) /* unused flag bit */
|
||||
|
||||
/* The following XMIT flags require an rsync that uses a varint for the flag values */
|
||||
|
||||
#define XMIT_RESERVED_16 (1<<16) /* reserved for future fileflags use */
|
||||
#define XMIT_RESERVED_17 (1<<17) /* reserved for future crtimes use */
|
||||
|
||||
/* These flags are used in the live flist data. */
|
||||
|
||||
@@ -87,9 +95,11 @@
|
||||
/* These flags are passed to functions but not stored. */
|
||||
|
||||
#define FLAG_DIVERT_DIRS (1<<16) /* sender, but must be unique */
|
||||
#define FLAG_PERHAPS_DIR (1<<17) /* generator */
|
||||
|
||||
/* These flags are for get_dirlist(). */
|
||||
#define GDL_IGNORE_FILTER_RULES (1<<0)
|
||||
#define GDL_PERHAPS_DIR (1<<1)
|
||||
|
||||
/* Some helper macros for matching bits. */
|
||||
#define BITS_SET(val,bits) (((val) & (bits)) == (bits))
|
||||
@@ -151,6 +161,10 @@
|
||||
#define MAX_BASIS_DIRS 20
|
||||
#define MAX_SERVER_ARGS (MAX_BASIS_DIRS*2 + 100)
|
||||
|
||||
#define COMPARE_DEST 1
|
||||
#define COPY_DEST 2
|
||||
#define LINK_DEST 3
|
||||
|
||||
#define MPLEX_BASE 7
|
||||
|
||||
#define NO_FILTERS 0
|
||||
@@ -165,7 +179,10 @@
|
||||
|
||||
#define ATTRS_REPORT (1<<0)
|
||||
#define ATTRS_SKIP_MTIME (1<<1)
|
||||
#define ATTRS_ACCURATE_TIME (1<<2)
|
||||
#define ATTRS_SKIP_ATIME (1<<3)
|
||||
|
||||
#define MSG_FLUSH 2
|
||||
#define FULL_FLUSH 1
|
||||
#define NORMAL_FLUSH 0
|
||||
|
||||
@@ -372,7 +389,7 @@ enum delret {
|
||||
#include <utime.h>
|
||||
#endif
|
||||
|
||||
#if defined HAVE_UTIMENSAT || defined HAVE_LUTIMES
|
||||
#if defined HAVE_UTIMENSAT || defined HAVE_LUTIMES || defined HAVE_SETATTRLIST
|
||||
#define CAN_SET_SYMLINK_TIMES 1
|
||||
#endif
|
||||
|
||||
@@ -384,11 +401,20 @@ enum delret {
|
||||
#define CAN_CHMOD_SYMLINK 1
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_UTIMENSAT
|
||||
#if defined HAVE_UTIMENSAT || defined HAVE_SETATTRLIST
|
||||
#define CAN_SET_NSEC 1
|
||||
#endif
|
||||
|
||||
#ifdef CAN_SET_NSEC
|
||||
#ifdef HAVE_STRUCT_STAT_ST_MTIM_TV_NSEC
|
||||
#define ST_MTIME_NSEC st_mtim.tv_nsec
|
||||
#define ST_ATIME_NSEC st_atim.tv_nsec
|
||||
#elif defined(HAVE_STRUCT_STAT_ST_MTIMENSEC)
|
||||
#define ST_MTIME_NSEC st_mtimensec
|
||||
#define ST_ATIME_NSEC st_atimensec
|
||||
#elif defined(HAVE_STRUCT_STAT_ST_MTIMESPEC_TV_NSEC)
|
||||
#define ST_MTIME_NSEC st_mtimespec.tv_nsec
|
||||
#define ST_ATIME_NSEC st_atimespec.tv_nsec
|
||||
#endif
|
||||
#endif
|
||||
|
||||
@@ -609,6 +635,9 @@ typedef unsigned int size_t;
|
||||
# define SIZEOF_INT64 SIZEOF_OFF_T
|
||||
#endif
|
||||
|
||||
#define HT_KEY32 0
|
||||
#define HT_KEY64 1
|
||||
|
||||
struct hashtable {
|
||||
void *nodes;
|
||||
int32 size, entries;
|
||||
@@ -691,9 +720,29 @@ struct ht_int64_node {
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if SIZEOF_CHARP == 4
|
||||
# define PTRS_ARE_32 1
|
||||
# define PTR_EXTRA_CNT 1
|
||||
#elif SIZEOF_CHARP == 8
|
||||
# define PTRS_ARE_64 1
|
||||
# define PTR_EXTRA_CNT EXTRA64_CNT
|
||||
#else
|
||||
# error Character pointers are not 4 or 8 bytes.
|
||||
#endif
|
||||
|
||||
union file_extras {
|
||||
int32 num;
|
||||
uint32 unum;
|
||||
#ifdef PTRS_ARE_32
|
||||
const char* ptr;
|
||||
#endif
|
||||
};
|
||||
|
||||
union file_extras64 {
|
||||
int64 num;
|
||||
#ifdef PTRS_ARE_64
|
||||
const char* ptr;
|
||||
#endif
|
||||
};
|
||||
|
||||
struct file_struct {
|
||||
@@ -707,6 +756,9 @@ struct file_struct {
|
||||
|
||||
extern int file_extra_cnt;
|
||||
extern int inc_recurse;
|
||||
extern int atimes_ndx;
|
||||
extern int pathname_ndx;
|
||||
extern int depth_ndx;
|
||||
extern int uid_ndx;
|
||||
extern int gid_ndx;
|
||||
extern int acls_ndx;
|
||||
@@ -714,14 +766,18 @@ extern int xattrs_ndx;
|
||||
|
||||
#define FILE_STRUCT_LEN (offsetof(struct file_struct, basename))
|
||||
#define EXTRA_LEN (sizeof (union file_extras))
|
||||
#define PTR_EXTRA_CNT ((sizeof (char *) + EXTRA_LEN - 1) / EXTRA_LEN)
|
||||
#define DEV_EXTRA_CNT 2
|
||||
#define DIRNODE_EXTRA_CNT 3
|
||||
#define EXTRA64_CNT ((sizeof (union file_extras64) + EXTRA_LEN - 1) / EXTRA_LEN)
|
||||
#define SUM_EXTRA_CNT ((MAX_DIGEST_LEN + EXTRA_LEN - 1) / EXTRA_LEN)
|
||||
|
||||
#define REQ_EXTRA(f,ndx) ((union file_extras*)(f) - (ndx))
|
||||
#define OPT_EXTRA(f,bump) ((union file_extras*)(f) - file_extra_cnt - 1 - (bump))
|
||||
|
||||
/* These are guaranteed to be allocated first in the array so that they
|
||||
* are aligned for direct int64-pointer access. */
|
||||
#define REQ_EXTRA64(f,ndx) ((union file_extras64*)REQ_EXTRA(f,ndx))
|
||||
|
||||
#define NSEC_BUMP(f) ((f)->flags & FLAG_MOD_NSEC ? 1 : 0)
|
||||
#define LEN64_BUMP(f) ((f)->flags & FLAG_LENGTH64 ? 1 : 0)
|
||||
#define START_BUMP(f) (NSEC_BUMP(f) + LEN64_BUMP(f))
|
||||
@@ -732,20 +788,25 @@ extern int xattrs_ndx;
|
||||
#if SIZEOF_INT64 < 8
|
||||
#define F_LENGTH(f) ((int64)(f)->len32)
|
||||
#else
|
||||
#define F_LENGTH(f) ((int64)(f)->len32 + ((f)->flags & FLAG_LENGTH64 \
|
||||
? (int64)OPT_EXTRA(f, NSEC_BUMP(f))->unum << 32 : 0))
|
||||
#define F_HIGH_LEN(f) (OPT_EXTRA(f, NSEC_BUMP(f))->unum)
|
||||
#define F_LENGTH(f) ((int64)(f)->len32 + ((f)->flags & FLAG_LENGTH64 ? (int64)F_HIGH_LEN(f) << 32 : 0))
|
||||
#endif
|
||||
|
||||
#define F_MOD_NSEC(f) ((f)->flags & FLAG_MOD_NSEC ? OPT_EXTRA(f, 0)->unum : 0)
|
||||
#define F_MOD_NSEC(f) OPT_EXTRA(f, 0)->unum
|
||||
#define F_MOD_NSEC_or_0(f) ((f)->flags & FLAG_MOD_NSEC ? F_MOD_NSEC(f) : 0)
|
||||
|
||||
/* If there is a symlink string, it is always right after the basename */
|
||||
#define F_SYMLINK(f) ((f)->basename + strlen((f)->basename) + 1)
|
||||
|
||||
/* The sending side always has this available: */
|
||||
#define F_PATHNAME(f) (*(const char**)REQ_EXTRA(f, PTR_EXTRA_CNT))
|
||||
#ifdef PTRS_ARE_32
|
||||
#define F_PATHNAME(f) REQ_EXTRA(f, pathname_ndx)->ptr
|
||||
#else
|
||||
#define F_PATHNAME(f) REQ_EXTRA64(f, pathname_ndx)->ptr
|
||||
#endif
|
||||
|
||||
/* The receiving side always has this available: */
|
||||
#define F_DEPTH(f) REQ_EXTRA(f, 1)->num
|
||||
#define F_DEPTH(f) REQ_EXTRA(f, depth_ndx)->num
|
||||
|
||||
/* When the associated option is on, all entries will have these present: */
|
||||
#define F_OWNER(f) REQ_EXTRA(f, uid_ndx)->unum
|
||||
@@ -753,6 +814,7 @@ extern int xattrs_ndx;
|
||||
#define F_ACL(f) REQ_EXTRA(f, acls_ndx)->num
|
||||
#define F_XATTR(f) REQ_EXTRA(f, xattrs_ndx)->num
|
||||
#define F_NDX(f) REQ_EXTRA(f, unsort_ndx)->num
|
||||
#define F_ATIME(f) REQ_EXTRA64(f, atimes_ndx)->num
|
||||
|
||||
/* These items are per-entry optional: */
|
||||
#define F_HL_GNUM(f) OPT_EXTRA(f, START_BUMP(f))->num /* non-dirs */
|
||||
@@ -856,6 +918,10 @@ struct map_struct {
|
||||
int status; /* first errno from read errors */
|
||||
};
|
||||
|
||||
#define NAME_IS_FILE (0) /* filter name as a file */
|
||||
#define NAME_IS_DIR (1<<0) /* filter name as a dir */
|
||||
#define NAME_IS_XATTR (1<<2) /* filter name as an xattr */
|
||||
|
||||
#define FILTRULE_WILD (1<<0) /* pattern has '*', '[', and/or '?' */
|
||||
#define FILTRULE_WILD2 (1<<1) /* pattern has '**' */
|
||||
#define FILTRULE_WILD2_PREFIX (1<<2) /* pattern starts with "**" */
|
||||
@@ -876,6 +942,7 @@ struct map_struct {
|
||||
#define FILTRULE_RECEIVER_SIDE (1<<17)/* rule applies to the receiving side */
|
||||
#define FILTRULE_CLEAR_LIST (1<<18)/* this item is the "!" token */
|
||||
#define FILTRULE_PERISHABLE (1<<19)/* perishable if parent dir goes away */
|
||||
#define FILTRULE_XATTR (1<<20)/* rule only applies to xattr names */
|
||||
|
||||
#define FILTRULES_SIDES (FILTRULE_SENDER_SIDE | FILTRULE_RECEIVER_SIDE)
|
||||
|
||||
@@ -892,7 +959,6 @@ typedef struct filter_struct {
|
||||
typedef struct filter_list_struct {
|
||||
filter_rule *head;
|
||||
filter_rule *tail;
|
||||
filter_rule *parent_dirscan_head;
|
||||
char *debug_type;
|
||||
} filter_rule_list;
|
||||
|
||||
@@ -1003,7 +1069,32 @@ typedef struct {
|
||||
#define ACL_READY(sx) ((sx).acc_acl != NULL)
|
||||
#define XATTR_READY(sx) ((sx).xattr != NULL)
|
||||
|
||||
#define CLVL_NOT_SPECIFIED INT_MIN
|
||||
|
||||
#define CPRES_AUTO (-1)
|
||||
#define CPRES_NONE 0
|
||||
#define CPRES_ZLIB 1
|
||||
#define CPRES_ZLIBX 2
|
||||
#define CPRES_LZ4 3
|
||||
#define CPRES_ZSTD 4
|
||||
|
||||
struct name_num_item {
|
||||
int num;
|
||||
const char *name, *main_name;
|
||||
};
|
||||
|
||||
struct name_num_obj {
|
||||
const char *type;
|
||||
const char *negotiated_name;
|
||||
uchar *saw;
|
||||
int saw_len;
|
||||
int negotiated_num;
|
||||
struct name_num_item list[];
|
||||
};
|
||||
|
||||
#ifndef __cplusplus
|
||||
#include "proto.h"
|
||||
#endif
|
||||
|
||||
#ifndef SUPPORT_XATTRS
|
||||
#define x_stat(fn,fst,xst) do_stat(fn,fst)
|
||||
@@ -1030,7 +1121,6 @@ int vsnprintf(char *str, size_t count, const char *fmt, va_list args);
|
||||
int snprintf(char *str, size_t count, const char *fmt,...);
|
||||
#endif
|
||||
|
||||
|
||||
#ifndef HAVE_STRERROR
|
||||
extern char *sys_errlist[];
|
||||
#define strerror(i) sys_errlist[i]
|
||||
@@ -1269,7 +1359,8 @@ extern short info_levels[], debug_levels[];
|
||||
#define DEBUG_HLINK (DEBUG_HASH+1)
|
||||
#define DEBUG_ICONV (DEBUG_HLINK+1)
|
||||
#define DEBUG_IO (DEBUG_ICONV+1)
|
||||
#define DEBUG_OWN (DEBUG_IO+1)
|
||||
#define DEBUG_NSTR (DEBUG_IO+1)
|
||||
#define DEBUG_OWN (DEBUG_NSTR+1)
|
||||
#define DEBUG_PROTO (DEBUG_OWN+1)
|
||||
#define DEBUG_RECV (DEBUG_PROTO+1)
|
||||
#define DEBUG_SEND (DEBUG_RECV+1)
|
||||
|
||||
1208
rsyncd.conf.5.md
Normal file
1208
rsyncd.conf.5.md
Normal file
File diff suppressed because it is too large
Load Diff
934
rsyncd.conf.yo
934
rsyncd.conf.yo
@@ -1,934 +0,0 @@
|
||||
mailto(rsync-bugs@samba.org)
|
||||
manpage(rsyncd.conf)(5)(26 May 2014)()()
|
||||
manpagename(rsyncd.conf)(configuration file for rsync in daemon mode)
|
||||
manpagesynopsis()
|
||||
|
||||
rsyncd.conf
|
||||
|
||||
manpagedescription()
|
||||
|
||||
The rsyncd.conf file is the runtime configuration file for rsync when
|
||||
run as an rsync daemon.
|
||||
|
||||
The rsyncd.conf file controls authentication, access, logging and
|
||||
available modules.
|
||||
|
||||
manpagesection(FILE FORMAT)
|
||||
|
||||
The file consists of modules and parameters. A module begins with the
|
||||
name of the module in square brackets and continues until the next
|
||||
module begins. Modules contain parameters of the form "name = value".
|
||||
|
||||
The file is line-based -- that is, each newline-terminated line represents
|
||||
either a comment, a module name or a parameter.
|
||||
|
||||
Only the first equals sign in a parameter is significant. Whitespace before
|
||||
or after the first equals sign is discarded. Leading, trailing and internal
|
||||
whitespace in module and parameter names is irrelevant. Leading and
|
||||
trailing whitespace in a parameter value is discarded. Internal whitespace
|
||||
within a parameter value is retained verbatim.
|
||||
|
||||
Any line bf(beginning) with a hash (#) is ignored, as are lines containing
|
||||
only whitespace. (If a hash occurs after anything other than leading
|
||||
whitespace, it is considered a part of the line's content.)
|
||||
|
||||
Any line ending in a \ is "continued" on the next line in the
|
||||
customary UNIX fashion.
|
||||
|
||||
The values following the equals sign in parameters are all either a string
|
||||
(no quotes needed) or a boolean, which may be given as yes/no, 0/1 or
|
||||
true/false. Case is not significant in boolean values, but is preserved
|
||||
in string values.
|
||||
|
||||
manpagesection(LAUNCHING THE RSYNC DAEMON)
|
||||
|
||||
The rsync daemon is launched by specifying the bf(--daemon) option to
|
||||
rsync.
|
||||
|
||||
The daemon must run with root privileges if you wish to use chroot, to
|
||||
bind to a port numbered under 1024 (as is the default 873), or to set
|
||||
file ownership. Otherwise, it must just have permission to read and
|
||||
write the appropriate data, log, and lock files.
|
||||
|
||||
You can launch it either via inetd, as a stand-alone daemon, or from
|
||||
an rsync client via a remote shell. If run as a stand-alone daemon then
|
||||
just run the command "bf(rsync --daemon)" from a suitable startup script.
|
||||
|
||||
When run via inetd you should add a line like this to /etc/services:
|
||||
|
||||
verb( rsync 873/tcp)
|
||||
|
||||
and a single line something like this to /etc/inetd.conf:
|
||||
|
||||
verb( rsync stream tcp nowait root /usr/bin/rsync rsyncd --daemon)
|
||||
|
||||
Replace "/usr/bin/rsync" with the path to where you have rsync installed on
|
||||
your system. You will then need to send inetd a HUP signal to tell it to
|
||||
reread its config file.
|
||||
|
||||
Note that you should bf(not) send the rsync daemon a HUP signal to force
|
||||
it to reread the tt(rsyncd.conf) file. The file is re-read on each client
|
||||
connection.
|
||||
|
||||
manpagesection(GLOBAL PARAMETERS)
|
||||
|
||||
The first parameters in the file (before a [module] header) are the
|
||||
global parameters.
|
||||
|
||||
You may also include any module parameters in the global part of the
|
||||
config file in which case the supplied value will override the
|
||||
default for that parameter.
|
||||
|
||||
You may use references to environment variables in the values of parameters.
|
||||
String parameters will have %VAR% references expanded as late as possible (when
|
||||
the string is used in the program), allowing for the use of variables that
|
||||
rsync sets at connection time, such as RSYNC_USER_NAME. Non-string parameters
|
||||
(such as true/false settings) are expanded when read from the config file. If
|
||||
a variable does not exist in the environment, or if a sequence of characters is
|
||||
not a valid reference (such as an un-paired percent sign), the raw characters
|
||||
are passed through unchanged. This helps with backward compatibility and
|
||||
safety (e.g. expanding a non-existent %VAR% to an empty string in a path could
|
||||
result in a very unsafe path). The safest way to insert a literal % into a
|
||||
value is to use %%.
|
||||
|
||||
startdit()
|
||||
dit(bf(motd file)) This parameter allows you to specify a
|
||||
"message of the day" to display to clients on each connect. This
|
||||
usually contains site information and any legal notices. The default
|
||||
is no motd file.
|
||||
This can be overridden by the bf(--dparam=motdfile=FILE)
|
||||
command-line option when starting the daemon.
|
||||
|
||||
dit(bf(pid file)) This parameter tells the rsync daemon to write
|
||||
its process ID to that file. If the file already exists, the rsync
|
||||
daemon will abort rather than overwrite the file.
|
||||
This can be overridden by the bf(--dparam=pidfile=FILE)
|
||||
command-line option when starting the daemon.
|
||||
|
||||
dit(bf(port)) You can override the default port the daemon will listen on
|
||||
by specifying this value (defaults to 873). This is ignored if the daemon
|
||||
is being run by inetd, and is superseded by the bf(--port) command-line option.
|
||||
|
||||
dit(bf(address)) You can override the default IP address the daemon
|
||||
will listen on by specifying this value. This is ignored if the daemon is
|
||||
being run by inetd, and is superseded by the bf(--address) command-line option.
|
||||
|
||||
dit(bf(socket options)) This parameter can provide endless fun for people
|
||||
who like to tune their systems to the utmost degree. You can set all
|
||||
sorts of socket options which may make transfers faster (or
|
||||
slower!). Read the man page for the code(setsockopt()) system call for
|
||||
details on some of the options you may be able to set. By default no
|
||||
special socket options are set. These settings can also be specified
|
||||
via the bf(--sockopts) command-line option.
|
||||
|
||||
dit(bf(listen backlog)) You can override the default backlog value when the
|
||||
daemon listens for connections. It defaults to 5.
|
||||
|
||||
enddit()
|
||||
|
||||
manpagesection(MODULE PARAMETERS)
|
||||
|
||||
After the global parameters you should define a number of modules, each
|
||||
module exports a directory tree as a symbolic name. Modules are
|
||||
exported by specifying a module name in square brackets [module]
|
||||
followed by the parameters for that module.
|
||||
The module name cannot contain a slash or a closing square bracket. If the
|
||||
name contains whitespace, each internal sequence of whitespace will be
|
||||
changed into a single space, while leading or trailing whitespace will be
|
||||
discarded.
|
||||
|
||||
As with GLOBAL PARAMETERS, you may use references to environment variables in
|
||||
the values of parameters. See the GLOBAL PARAMETERS section for more details.
|
||||
|
||||
startdit()
|
||||
|
||||
dit(bf(comment)) This parameter specifies a description string
|
||||
that is displayed next to the module name when clients obtain a list
|
||||
of available modules. The default is no comment.
|
||||
|
||||
dit(bf(path)) This parameter specifies the directory in the daemon's
|
||||
filesystem to make available in this module. You must specify this parameter
|
||||
for each module in tt(rsyncd.conf).
|
||||
|
||||
You may base the path's value off of an environment variable by surrounding
|
||||
the variable name with percent signs. You can even reference a variable
|
||||
that is set by rsync when the user connects.
|
||||
For example, this would use the authorizing user's name in the path:
|
||||
|
||||
verb( path = /home/%RSYNC_USER_NAME% )
|
||||
|
||||
It is fine if the path includes internal spaces -- they will be retained
|
||||
verbatim (which means that you shouldn't try to escape them). If your final
|
||||
directory has a trailing space (and this is somehow not something you wish to
|
||||
fix), append a trailing slash to the path to avoid losing the trailing
|
||||
whitespace.
|
||||
|
||||
dit(bf(use chroot)) If "use chroot" is true, the rsync daemon will chroot
|
||||
to the "path" before starting the file transfer with the client. This has
|
||||
the advantage of extra protection against possible implementation security
|
||||
holes, but it has the disadvantages of requiring super-user privileges,
|
||||
of not being able to follow symbolic links that are either absolute or outside
|
||||
of the new root path, and of complicating the preservation of users and groups
|
||||
by name (see below).
|
||||
|
||||
As an additional safety feature, you can specify a dot-dir in the module's
|
||||
"path" to indicate the point where the chroot should occur. This allows rsync
|
||||
to run in a chroot with a non-"/" path for the top of the transfer hierarchy.
|
||||
Doing this guards against unintended library loading (since those absolute
|
||||
paths will not be inside the transfer hierarchy unless you have used an unwise
|
||||
pathname), and lets you setup libraries for the chroot that are outside of the
|
||||
transfer. For example, specifying "/var/rsync/./module1" will chroot to the
|
||||
"/var/rsync" directory and set the inside-chroot path to "/module1". If you
|
||||
had omitted the dot-dir, the chroot would have used the whole path, and the
|
||||
inside-chroot path would have been "/".
|
||||
|
||||
When "use chroot" is false or the inside-chroot path is not "/", rsync will:
|
||||
(1) munge symlinks by
|
||||
default for security reasons (see "munge symlinks" for a way to turn this
|
||||
off, but only if you trust your users), (2) substitute leading slashes in
|
||||
absolute paths with the module's path (so that options such as
|
||||
bf(--backup-dir), bf(--compare-dest), etc. interpret an absolute path as
|
||||
rooted in the module's "path" dir), and (3) trim ".." path elements from
|
||||
args if rsync believes they would escape the module hierarchy.
|
||||
The default for "use chroot" is true, and is the safer choice (especially
|
||||
if the module is not read-only).
|
||||
|
||||
When this parameter is enabled, rsync will not attempt to map users and groups
|
||||
by name (by default), but instead copy IDs as though bf(--numeric-ids) had
|
||||
been specified. In order to enable name-mapping, rsync needs to be able to
|
||||
use the standard library functions for looking up names and IDs (i.e.
|
||||
code(getpwuid()), code(getgrgid()), code(getpwname()), and code(getgrnam())).
|
||||
This means the rsync
|
||||
process in the chroot hierarchy will need to have access to the resources
|
||||
used by these library functions (traditionally /etc/passwd and
|
||||
/etc/group, but perhaps additional dynamic libraries as well).
|
||||
|
||||
If you copy the necessary resources into the module's chroot area, you
|
||||
should protect them through your OS's normal user/group or ACL settings (to
|
||||
prevent the rsync module's user from being able to change them), and then
|
||||
hide them from the user's view via "exclude" (see how in the discussion of
|
||||
that parameter). At that point it will be safe to enable the mapping of users
|
||||
and groups by name using the "numeric ids" daemon parameter (see below).
|
||||
|
||||
Note also that you are free to setup custom user/group information in the
|
||||
chroot area that is different from your normal system. For example, you
|
||||
could abbreviate the list of users and groups.
|
||||
|
||||
dit(bf(numeric ids)) Enabling this parameter disables the mapping
|
||||
of users and groups by name for the current daemon module. This prevents
|
||||
the daemon from trying to load any user/group-related files or libraries.
|
||||
This enabling makes the transfer behave as if the client had passed
|
||||
the bf(--numeric-ids) command-line option. By default, this parameter is
|
||||
enabled for chroot modules and disabled for non-chroot modules.
|
||||
|
||||
A chroot-enabled module should not have this parameter enabled unless you've
|
||||
taken steps to ensure that the module has the necessary resources it needs
|
||||
to translate names, and that it is not possible for a user to change those
|
||||
resources.
|
||||
|
||||
dit(bf(munge symlinks)) This parameter tells rsync to modify
|
||||
all symlinks in the same way as the (non-daemon-affecting)
|
||||
bf(--munge-links) command-line option (using a method described below).
|
||||
This should help protect your files from user trickery when
|
||||
your daemon module is writable. The default is disabled when "use chroot"
|
||||
is on and the inside-chroot path is "/", otherwise it is enabled.
|
||||
|
||||
If you disable this parameter on a daemon that is not read-only, there
|
||||
are tricks that a user can play with uploaded symlinks to access
|
||||
daemon-excluded items (if your module has any), and, if "use chroot"
|
||||
is off, rsync can even be tricked into showing or changing data that
|
||||
is outside the module's path (as access-permissions allow).
|
||||
|
||||
The way rsync disables the use of symlinks is to prefix each one with
|
||||
the string "/rsyncd-munged/". This prevents the links from being used
|
||||
as long as that directory does not exist. When this parameter is enabled,
|
||||
rsync will refuse to run if that path is a directory or a symlink to
|
||||
a directory. When using the "munge symlinks" parameter in a chroot area
|
||||
that has an inside-chroot path of "/", you should add "/rsyncd-munged/"
|
||||
to the exclude setting for the module so that
|
||||
a user can't try to create it.
|
||||
|
||||
Note: rsync makes no attempt to verify that any pre-existing symlinks in
|
||||
the module's hierarchy are as safe as you want them to be (unless, of
|
||||
course, it just copied in the whole hierarchy). If you setup an rsync
|
||||
daemon on a new area or locally add symlinks, you can manually protect your
|
||||
symlinks from being abused by prefixing "/rsyncd-munged/" to the start of
|
||||
every symlink's value. There is a perl script in the support directory
|
||||
of the source code named "munge-symlinks" that can be used to add or remove
|
||||
this prefix from your symlinks.
|
||||
|
||||
When this parameter is disabled on a writable module and "use chroot" is off
|
||||
(or the inside-chroot path is not "/"),
|
||||
incoming symlinks will be modified to drop a leading slash and to remove ".."
|
||||
path elements that rsync believes will allow a symlink to escape the module's
|
||||
hierarchy. There are tricky ways to work around this, though, so you had
|
||||
better trust your users if you choose this combination of parameters.
|
||||
|
||||
dit(bf(charset)) This specifies the name of the character set in which the
|
||||
module's filenames are stored. If the client uses an bf(--iconv) option,
|
||||
the daemon will use the value of the "charset" parameter regardless of the
|
||||
character set the client actually passed. This allows the daemon to
|
||||
support charset conversion in a chroot module without extra files in the
|
||||
chroot area, and also ensures that name-translation is done in a consistent
|
||||
manner. If the "charset" parameter is not set, the bf(--iconv) option is
|
||||
refused, just as if "iconv" had been specified via "refuse options".
|
||||
|
||||
If you wish to force users to always use bf(--iconv) for a particular
|
||||
module, add "no-iconv" to the "refuse options" parameter. Keep in mind
|
||||
that this will restrict access to your module to very new rsync clients.
|
||||
|
||||
dit(bf(max connections)) This parameter allows you to
|
||||
specify the maximum number of simultaneous connections you will allow.
|
||||
Any clients connecting when the maximum has been reached will receive a
|
||||
message telling them to try later. The default is 0, which means no limit.
|
||||
A negative value disables the module.
|
||||
See also the "lock file" parameter.
|
||||
|
||||
dit(bf(log file)) When the "log file" parameter is set to a non-empty
|
||||
string, the rsync daemon will log messages to the indicated file rather
|
||||
than using syslog. This is particularly useful on systems (such as AIX)
|
||||
where code(syslog()) doesn't work for chrooted programs. The file is
|
||||
opened before code(chroot()) is called, allowing it to be placed outside
|
||||
the transfer. If this value is set on a per-module basis instead of
|
||||
globally, the global log will still contain any authorization failures
|
||||
or config-file error messages.
|
||||
|
||||
If the daemon fails to open the specified file, it will fall back to
|
||||
using syslog and output an error about the failure. (Note that the
|
||||
failure to open the specified log file used to be a fatal error.)
|
||||
|
||||
This setting can be overridden by using the bf(--log-file=FILE) or
|
||||
bf(--dparam=logfile=FILE) command-line options. The former overrides
|
||||
all the log-file parameters of the daemon and all module settings.
|
||||
The latter sets the daemon's log file and the default for all the
|
||||
modules, which still allows modules to override the default setting.
|
||||
|
||||
dit(bf(syslog facility)) This parameter allows you to
|
||||
specify the syslog facility name to use when logging messages from the
|
||||
rsync daemon. You may use any standard syslog facility name which is
|
||||
defined on your system. Common names are auth, authpriv, cron, daemon,
|
||||
ftp, kern, lpr, mail, news, security, syslog, user, uucp, local0,
|
||||
local1, local2, local3, local4, local5, local6 and local7. The default
|
||||
is daemon. This setting has no effect if the "log file" setting is a
|
||||
non-empty string (either set in the per-modules settings, or inherited
|
||||
from the global settings).
|
||||
|
||||
dit(bf(max verbosity)) This parameter allows you to control
|
||||
the maximum amount of verbose information that you'll allow the daemon to
|
||||
generate (since the information goes into the log file). The default is 1,
|
||||
which allows the client to request one level of verbosity.
|
||||
|
||||
This also affects the user's ability to request higher levels of bf(--info) and
|
||||
bf(--debug) logging. If the max value is 2, then no info and/or debug value
|
||||
that is higher than what would be set by bf(-vv) will be honored by the daemon
|
||||
in its logging. To see how high of a verbosity level you need to accept for a
|
||||
particular info/debug level, refer to "rsync --info=help" and "rsync --debug=help".
|
||||
For instance, it takes max-verbosity 4 to be able to output debug TIME2 and FLIST3.
|
||||
|
||||
dit(bf(lock file)) This parameter specifies the file to use to
|
||||
support the "max connections" parameter. The rsync daemon uses record
|
||||
locking on this file to ensure that the max connections limit is not
|
||||
exceeded for the modules sharing the lock file.
|
||||
The default is tt(/var/run/rsyncd.lock).
|
||||
|
||||
dit(bf(read only)) This parameter determines whether clients
|
||||
will be able to upload files or not. If "read only" is true then any
|
||||
attempted uploads will fail. If "read only" is false then uploads will
|
||||
be possible if file permissions on the daemon side allow them. The default
|
||||
is for all modules to be read only.
|
||||
|
||||
Note that "auth users" can override this setting on a per-user basis.
|
||||
|
||||
dit(bf(write only)) This parameter determines whether clients
|
||||
will be able to download files or not. If "write only" is true then any
|
||||
attempted downloads will fail. If "write only" is false then downloads
|
||||
will be possible if file permissions on the daemon side allow them. The
|
||||
default is for this parameter to be disabled.
|
||||
|
||||
dit(bf(list)) This parameter determines whether this module is
|
||||
listed when the client asks for a listing of available modules. In addition,
|
||||
if this is false, the daemon will pretend the module does not exist
|
||||
when a client denied by "hosts allow" or "hosts deny" attempts to access it.
|
||||
Realize that if "reverse lookup" is disabled globally but enabled for the
|
||||
module, the resulting reverse lookup to a potentially client-controlled DNS
|
||||
server may still reveal to the client that it hit an existing module.
|
||||
The default is for modules to be listable.
|
||||
|
||||
dit(bf(uid)) This parameter specifies the user name or user ID that
|
||||
file transfers to and from that module should take place as when the daemon
|
||||
was run as root. In combination with the "gid" parameter this determines what
|
||||
file permissions are available. The default when run by a super-user is to
|
||||
switch to the system's "nobody" user. The default for a non-super-user is to
|
||||
not try to change the user. See also the "gid" parameter.
|
||||
|
||||
The RSYNC_USER_NAME environment variable may be used to request that rsync run
|
||||
as the authorizing user. For example, if you want a rsync to run as the same
|
||||
user that was received for the rsync authentication, this setup is useful:
|
||||
|
||||
verb( uid = %RSYNC_USER_NAME%
|
||||
gid = * )
|
||||
|
||||
dit(bf(gid)) This parameter specifies one or more group names/IDs that will be
|
||||
used when accessing the module. The first one will be the default group, and
|
||||
any extra ones be set as supplemental groups. You may also specify a "*" as
|
||||
the first gid in the list, which will be replaced by all the normal groups for
|
||||
the transfer's user (see "uid"). The default when run by a super-user is to
|
||||
switch to your OS's "nobody" (or perhaps "nogroup") group with no other
|
||||
supplementary groups. The default for a non-super-user is to not change any
|
||||
group attributes (and indeed, your OS may not allow a non-super-user to try to
|
||||
change their group settings).
|
||||
|
||||
dit(bf(fake super)) Setting "fake super = yes" for a module causes the
|
||||
daemon side to behave as if the bf(--fake-super) command-line option had
|
||||
been specified. This allows the full attributes of a file to be stored
|
||||
without having to have the daemon actually running as root.
|
||||
|
||||
dit(bf(filter)) The daemon has its own filter chain that determines what files
|
||||
it will let the client access. This chain is not sent to the client and is
|
||||
independent of any filters the client may have specified. Files excluded by
|
||||
the daemon filter chain (bf(daemon-excluded) files) are treated as non-existent
|
||||
if the client tries to pull them, are skipped with an error message if the
|
||||
client tries to push them (triggering exit code 23), and are never deleted from
|
||||
the module. You can use daemon filters to prevent clients from downloading or
|
||||
tampering with private administrative files, such as files you may add to
|
||||
support uid/gid name translations.
|
||||
|
||||
The daemon filter chain is built from the "filter", "include from", "include",
|
||||
"exclude from", and "exclude" parameters, in that order of priority. Anchored
|
||||
patterns are anchored at the root of the module. To prevent access to an
|
||||
entire subtree, for example, "/secret", you em(must) exclude everything in the
|
||||
subtree; the easiest way to do this is with a triple-star pattern like
|
||||
"/secret/***".
|
||||
|
||||
The "filter" parameter takes a space-separated list of daemon filter rules,
|
||||
though it is smart enough to know not to split a token at an internal space in
|
||||
a rule (e.g. "- /foo - /bar" is parsed as two rules). You may specify one or
|
||||
more merge-file rules using the normal syntax. Only one "filter" parameter can
|
||||
apply to a given module in the config file, so put all the rules you want in a
|
||||
single parameter. Note that per-directory merge-file rules do not provide as
|
||||
much protection as global rules, but they can be used to make bf(--delete) work
|
||||
better during a client download operation if the per-dir merge files are
|
||||
included in the transfer and the client requests that they be used.
|
||||
|
||||
dit(bf(exclude)) This parameter takes a space-separated list of daemon
|
||||
exclude patterns. As with the client bf(--exclude) option, patterns can be
|
||||
qualified with "- " or "+ " to explicitly indicate exclude/include. Only one
|
||||
"exclude" parameter can apply to a given module. See the "filter" parameter
|
||||
for a description of how excluded files affect the daemon.
|
||||
|
||||
dit(bf(include)) Use an "include" to override the effects of the "exclude"
|
||||
parameter. Only one "include" parameter can apply to a given module. See the
|
||||
"filter" parameter for a description of how excluded files affect the daemon.
|
||||
|
||||
dit(bf(exclude from)) This parameter specifies the name of a file
|
||||
on the daemon that contains daemon exclude patterns, one per line. Only one
|
||||
"exclude from" parameter can apply to a given module; if you have multiple
|
||||
exclude-from files, you can specify them as a merge file in the "filter"
|
||||
parameter. See the "filter" parameter for a description of how excluded files
|
||||
affect the daemon.
|
||||
|
||||
dit(bf(include from)) Analogue of "exclude from" for a file of daemon include
|
||||
patterns. Only one "include from" parameter can apply to a given module. See
|
||||
the "filter" parameter for a description of how excluded files affect the
|
||||
daemon.
|
||||
|
||||
dit(bf(incoming chmod)) This parameter allows you to specify a set of
|
||||
comma-separated chmod strings that will affect the permissions of all
|
||||
incoming files (files that are being received by the daemon). These
|
||||
changes happen after all other permission calculations, and this will
|
||||
even override destination-default and/or existing permissions when the
|
||||
client does not specify bf(--perms).
|
||||
See the description of the bf(--chmod) rsync option and the bf(chmod)(1)
|
||||
manpage for information on the format of this string.
|
||||
|
||||
dit(bf(outgoing chmod)) This parameter allows you to specify a set of
|
||||
comma-separated chmod strings that will affect the permissions of all
|
||||
outgoing files (files that are being sent out from the daemon). These
|
||||
changes happen first, making the sent permissions appear to be different
|
||||
than those stored in the filesystem itself. For instance, you could
|
||||
disable group write permissions on the server while having it appear to
|
||||
be on to the clients.
|
||||
See the description of the bf(--chmod) rsync option and the bf(chmod)(1)
|
||||
manpage for information on the format of this string.
|
||||
|
||||
dit(bf(auth users)) This parameter specifies a comma and/or space-separated
|
||||
list of authorization rules. In its simplest form, you list the usernames
|
||||
that will be allowed to connect to
|
||||
this module. The usernames do not need to exist on the local
|
||||
system. The rules may contain shell wildcard characters that will be matched
|
||||
against the username provided by the client for authentication. If
|
||||
"auth users" is set then the client will be challenged to supply a
|
||||
username and password to connect to the module. A challenge response
|
||||
authentication protocol is used for this exchange. The plain text
|
||||
usernames and passwords are stored in the file specified by the
|
||||
"secrets file" parameter. The default is for all users to be able to
|
||||
connect without a password (this is called "anonymous rsync").
|
||||
|
||||
In addition to username matching, you can specify groupname matching via a '@'
|
||||
prefix. When using groupname matching, the authenticating username must be a
|
||||
real user on the system, or it will be assumed to be a member of no groups.
|
||||
For example, specifying "@rsync" will match the authenticating user if the
|
||||
named user is a member of the rsync group.
|
||||
|
||||
Finally, options may be specified after a colon (:). The options allow you to
|
||||
"deny" a user or a group, set the access to "ro" (read-only), or set the access
|
||||
to "rw" (read/write). Setting an auth-rule-specific ro/rw setting overrides
|
||||
the module's "read only" setting.
|
||||
|
||||
Be sure to put the rules in the order you want them to be matched, because the
|
||||
checking stops at the first matching user or group, and that is the only auth
|
||||
that is checked. For example:
|
||||
|
||||
verb( auth users = joe:deny @guest:deny admin:rw @rsync:ro susan joe sam )
|
||||
|
||||
In the above rule, user joe will be denied access no matter what. Any user
|
||||
that is in the group "guest" is also denied access. The user "admin" gets
|
||||
access in read/write mode, but only if the admin user is not in group "guest"
|
||||
(because the admin user-matching rule would never be reached if the user is in
|
||||
group "guest"). Any other user who is in group "rsync" will get read-only
|
||||
access. Finally, users susan, joe, and sam get the ro/rw setting of the
|
||||
module, but only if the user didn't match an earlier group-matching rule.
|
||||
|
||||
See the description of the secrets file for how you can have per-user passwords
|
||||
as well as per-group passwords. It also explains how a user can authenticate
|
||||
using their user password or (when applicable) a group password, depending on
|
||||
what rule is being authenticated.
|
||||
|
||||
See also the section entitled "USING RSYNC-DAEMON FEATURES VIA A REMOTE
|
||||
SHELL CONNECTION" in bf(rsync)(1) for information on how handle an
|
||||
rsyncd.conf-level username that differs from the remote-shell-level
|
||||
username when using a remote shell to connect to an rsync daemon.
|
||||
|
||||
dit(bf(secrets file)) This parameter specifies the name of a file that contains
|
||||
the username:password and/or @groupname:password pairs used for authenticating
|
||||
this module. This file is only consulted if the "auth users" parameter is
|
||||
specified. The file is line-based and contains one name:password pair per
|
||||
line. Any line has a hash (#) as the very first character on the line is
|
||||
considered a comment and is skipped. The passwords can contain any characters
|
||||
but be warned that many operating systems limit the length of passwords that
|
||||
can be typed at the client end, so you may find that passwords longer than 8
|
||||
characters don't work.
|
||||
|
||||
The use of group-specific lines are only relevant when the module is being
|
||||
authorized using a matching "@groupname" rule. When that happens, the user
|
||||
can be authorized via either their "username:password" line or the
|
||||
"@groupname:password" line for the group that triggered the authentication.
|
||||
|
||||
It is up to you what kind of password entries you want to include, either
|
||||
users, groups, or both. The use of group rules in "auth users" does not
|
||||
require that you specify a group password if you do not want to use shared
|
||||
passwords.
|
||||
|
||||
There is no default for the "secrets file" parameter, you must choose a name
|
||||
(such as tt(/etc/rsyncd.secrets)). The file must normally not be readable
|
||||
by "other"; see "strict modes". If the file is not found or is rejected, no
|
||||
logins for a "user auth" module will be possible.
|
||||
|
||||
dit(bf(strict modes)) This parameter determines whether or not
|
||||
the permissions on the secrets file will be checked. If "strict modes" is
|
||||
true, then the secrets file must not be readable by any user ID other
|
||||
than the one that the rsync daemon is running under. If "strict modes" is
|
||||
false, the check is not performed. The default is true. This parameter
|
||||
was added to accommodate rsync running on the Windows operating system.
|
||||
|
||||
dit(bf(hosts allow)) This parameter allows you to specify a
|
||||
list of patterns that are matched against a connecting clients
|
||||
hostname and IP address. If none of the patterns match then the
|
||||
connection is rejected.
|
||||
|
||||
Each pattern can be in one of five forms:
|
||||
|
||||
quote(itemization(
|
||||
it() a dotted decimal IPv4 address of the form a.b.c.d, or an IPv6 address
|
||||
of the form a:b:c::d:e:f. In this case the incoming machine's IP address
|
||||
must match exactly.
|
||||
it() an address/mask in the form ipaddr/n where ipaddr is the IP address
|
||||
and n is the number of one bits in the netmask. All IP addresses which
|
||||
match the masked IP address will be allowed in.
|
||||
it() an address/mask in the form ipaddr/maskaddr where ipaddr is the
|
||||
IP address and maskaddr is the netmask in dotted decimal notation for IPv4,
|
||||
or similar for IPv6, e.g. ffff:ffff:ffff:ffff:: instead of /64. All IP
|
||||
addresses which match the masked IP address will be allowed in.
|
||||
it() a hostname pattern using wildcards. If the hostname of the connecting IP
|
||||
(as determined by a reverse lookup) matches the wildcarded name (using the
|
||||
same rules as normal unix filename matching), the client is allowed in. This
|
||||
only works if "reverse lookup" is enabled (the default).
|
||||
it() a hostname. A plain hostname is matched against the reverse DNS of the
|
||||
connecting IP (if "reverse lookup" is enabled), and/or the IP of the given
|
||||
hostname is matched against the connecting IP (if "forward lookup" is
|
||||
enabled, as it is by default). Any match will be allowed in.
|
||||
))
|
||||
|
||||
Note IPv6 link-local addresses can have a scope in the address specification:
|
||||
|
||||
quote(
|
||||
tt( fe80::1%link1)nl()
|
||||
tt( fe80::%link1/64)nl()
|
||||
tt( fe80::%link1/ffff:ffff:ffff:ffff::)nl()
|
||||
)
|
||||
|
||||
You can also combine "hosts allow" with a separate "hosts deny"
|
||||
parameter. If both parameters are specified then the "hosts allow" parameter is
|
||||
checked first and a match results in the client being able to
|
||||
connect. The "hosts deny" parameter is then checked and a match means
|
||||
that the host is rejected. If the host does not match either the
|
||||
"hosts allow" or the "hosts deny" patterns then it is allowed to
|
||||
connect.
|
||||
|
||||
The default is no "hosts allow" parameter, which means all hosts can connect.
|
||||
|
||||
dit(bf(hosts deny)) This parameter allows you to specify a
|
||||
list of patterns that are matched against a connecting clients
|
||||
hostname and IP address. If the pattern matches then the connection is
|
||||
rejected. See the "hosts allow" parameter for more information.
|
||||
|
||||
The default is no "hosts deny" parameter, which means all hosts can connect.
|
||||
|
||||
dit(bf(reverse lookup)) Controls whether the daemon performs a reverse lookup
|
||||
on the client's IP address to determine its hostname, which is used for
|
||||
"hosts allow"/"hosts deny" checks and the "%h" log escape. This is enabled by
|
||||
default, but you may wish to disable it to save time if you know the lookup will
|
||||
not return a useful result, in which case the daemon will use the name
|
||||
"UNDETERMINED" instead.
|
||||
|
||||
If this parameter is enabled globally (even by default), rsync performs the
|
||||
lookup as soon as a client connects, so disabling it for a module will not
|
||||
avoid the lookup. Thus, you probably want to disable it globally and then
|
||||
enable it for modules that need the information.
|
||||
|
||||
dit(bf(forward lookup)) Controls whether the daemon performs a forward lookup
|
||||
on any hostname specified in an hosts allow/deny setting. By default this is
|
||||
enabled, allowing the use of an explicit hostname that would not be returned
|
||||
by reverse DNS of the connecting IP.
|
||||
|
||||
dit(bf(ignore errors)) This parameter tells rsyncd to
|
||||
ignore I/O errors on the daemon when deciding whether to run the delete
|
||||
phase of the transfer. Normally rsync skips the bf(--delete) step if any
|
||||
I/O errors have occurred in order to prevent disastrous deletion due
|
||||
to a temporary resource shortage or other I/O error. In some cases this
|
||||
test is counter productive so you can use this parameter to turn off this
|
||||
behavior.
|
||||
|
||||
dit(bf(ignore nonreadable)) This tells the rsync daemon to completely
|
||||
ignore files that are not readable by the user. This is useful for
|
||||
public archives that may have some non-readable files among the
|
||||
directories, and the sysadmin doesn't want those files to be seen at all.
|
||||
|
||||
dit(bf(transfer logging)) This parameter enables per-file
|
||||
logging of downloads and uploads in a format somewhat similar to that
|
||||
used by ftp daemons. The daemon always logs the transfer at the end, so
|
||||
if a transfer is aborted, no mention will be made in the log file.
|
||||
|
||||
If you want to customize the log lines, see the "log format" parameter.
|
||||
|
||||
dit(bf(log format)) This parameter allows you to specify the
|
||||
format used for logging file transfers when transfer logging is enabled.
|
||||
The format is a text string containing embedded single-character escape
|
||||
sequences prefixed with a percent (%) character. An optional numeric
|
||||
field width may also be specified between the percent and the escape
|
||||
letter (e.g. "bf(%-50n %8l %07p)").
|
||||
In addition, one or more apostrophes may be specified prior to a numerical
|
||||
escape to indicate that the numerical value should be made more human-readable.
|
||||
The 3 supported levels are the same as for the bf(--human-readable)
|
||||
command-line option, though the default is for human-readability to be off.
|
||||
Each added apostrophe increases the level (e.g. "bf(%''l %'b %f)").
|
||||
|
||||
The default log format is "%o %h [%a] %m (%u) %f %l", and a "%t [%p] "
|
||||
is always prefixed when using the "log file" parameter.
|
||||
(A perl script that will summarize this default log format is included
|
||||
in the rsync source code distribution in the "support" subdirectory:
|
||||
rsyncstats.)
|
||||
|
||||
The single-character escapes that are understood are as follows:
|
||||
|
||||
quote(itemization(
|
||||
it() %a the remote IP address (only available for a daemon)
|
||||
it() %b the number of bytes actually transferred
|
||||
it() %B the permission bits of the file (e.g. rwxrwxrwt)
|
||||
it() %c the total size of the block checksums received for the basis file (only when sending)
|
||||
it() %C the full-file MD5 checksum if bf(--checksum) is enabled or a file was transferred (only for protocol 30 or above).
|
||||
it() %f the filename (long form on sender; no trailing "/")
|
||||
it() %G the gid of the file (decimal) or "DEFAULT"
|
||||
it() %h the remote host name (only available for a daemon)
|
||||
it() %i an itemized list of what is being updated
|
||||
it() %l the length of the file in bytes
|
||||
it() %L the string " -> SYMLINK", " => HARDLINK", or "" (where bf(SYMLINK) or bf(HARDLINK) is a filename)
|
||||
it() %m the module name
|
||||
it() %M the last-modified time of the file
|
||||
it() %n the filename (short form; trailing "/" on dir)
|
||||
it() %o the operation, which is "send", "recv", or "del." (the latter includes the trailing period)
|
||||
it() %p the process ID of this rsync session
|
||||
it() %P the module path
|
||||
it() %t the current date time
|
||||
it() %u the authenticated username or an empty string
|
||||
it() %U the uid of the file (decimal)
|
||||
))
|
||||
|
||||
For a list of what the characters mean that are output by "%i", see the
|
||||
bf(--itemize-changes) option in the rsync manpage.
|
||||
|
||||
Note that some of the logged output changes when talking with older
|
||||
rsync versions. For instance, deleted files were only output as verbose
|
||||
messages prior to rsync 2.6.4.
|
||||
|
||||
dit(bf(timeout)) This parameter allows you to override the
|
||||
clients choice for I/O timeout for this module. Using this parameter you
|
||||
can ensure that rsync won't wait on a dead client forever. The timeout
|
||||
is specified in seconds. A value of zero means no timeout and is the
|
||||
default. A good choice for anonymous rsync daemons may be 600 (giving
|
||||
a 10 minute timeout).
|
||||
|
||||
dit(bf(refuse options)) This parameter allows you to
|
||||
specify a space-separated list of rsync command line options that will
|
||||
be refused by your rsync daemon.
|
||||
You may specify the full option name, its one-letter abbreviation, or a
|
||||
wild-card string that matches multiple options.
|
||||
For example, this would refuse bf(--checksum) (bf(-c)) and all the various
|
||||
delete options:
|
||||
|
||||
quote(tt( refuse options = c delete))
|
||||
|
||||
The reason the above refuses all delete options is that the options imply
|
||||
bf(--delete), and implied options are refused just like explicit options.
|
||||
As an additional safety feature, the refusal of "delete" also refuses
|
||||
bf(remove-source-files) when the daemon is the sender; if you want the latter
|
||||
without the former, instead refuse "delete-*" -- that refuses all the
|
||||
delete modes without affecting bf(--remove-source-files).
|
||||
|
||||
When an option is refused, the daemon prints an error message and exits.
|
||||
To prevent all compression when serving files,
|
||||
you can use "dont compress = *" (see below)
|
||||
instead of "refuse options = compress" to avoid returning an error to a
|
||||
client that requests compression.
|
||||
|
||||
dit(bf(dont compress)) This parameter allows you to select
|
||||
filenames based on wildcard patterns that should not be compressed
|
||||
when pulling files from the daemon (no analogous parameter exists to
|
||||
govern the pushing of files to a daemon).
|
||||
Compression is expensive in terms of CPU usage, so it
|
||||
is usually good to not try to compress files that won't compress well,
|
||||
such as already compressed files.
|
||||
|
||||
The "dont compress" parameter takes a space-separated list of
|
||||
case-insensitive wildcard patterns. Any source filename matching one
|
||||
of the patterns will not be compressed during transfer.
|
||||
|
||||
See the bf(--skip-compress) parameter in the bf(rsync)(1) manpage for the list
|
||||
of file suffixes that are not compressed by default. Specifying a value
|
||||
for the "dont compress" parameter changes the default when the daemon is
|
||||
the sender.
|
||||
|
||||
dit(bf(pre-xfer exec), bf(post-xfer exec)) You may specify a command to be run
|
||||
before and/or after the transfer. If the bf(pre-xfer exec) command fails, the
|
||||
transfer is aborted before it begins. Any output from the script on stdout (up
|
||||
to several KB) will be displayed to the user when aborting, but is NOT
|
||||
displayed if the script returns success. Any output from the script on stderr
|
||||
goes to the daemon's stderr, which is typically discarded (though see
|
||||
--no-detatch option for a way to see the stderr output, which can assist with
|
||||
debugging).
|
||||
|
||||
The following environment variables will be set, though some are
|
||||
specific to the pre-xfer or the post-xfer environment:
|
||||
|
||||
quote(itemization(
|
||||
it() bf(RSYNC_MODULE_NAME): The name of the module being accessed.
|
||||
it() bf(RSYNC_MODULE_PATH): The path configured for the module.
|
||||
it() bf(RSYNC_HOST_ADDR): The accessing host's IP address.
|
||||
it() bf(RSYNC_HOST_NAME): The accessing host's name.
|
||||
it() bf(RSYNC_USER_NAME): The accessing user's name (empty if no user).
|
||||
it() bf(RSYNC_PID): A unique number for this transfer.
|
||||
it() bf(RSYNC_REQUEST): (pre-xfer only) The module/path info specified
|
||||
by the user. Note that the user can specify multiple source files,
|
||||
so the request can be something like "mod/path1 mod/path2", etc.
|
||||
it() bf(RSYNC_ARG#): (pre-xfer only) The pre-request arguments are set
|
||||
in these numbered values. RSYNC_ARG0 is always "rsyncd", followed by
|
||||
the options that were used in RSYNC_ARG1, and so on. There will be a
|
||||
value of "." indicating that the options are done and the path args
|
||||
are beginning -- these contain similar information to RSYNC_REQUEST,
|
||||
but with values separated and the module name stripped off.
|
||||
it() bf(RSYNC_EXIT_STATUS): (post-xfer only) the server side's exit value.
|
||||
This will be 0 for a successful run, a positive value for an error that the
|
||||
server generated, or a -1 if rsync failed to exit properly. Note that an
|
||||
error that occurs on the client side does not currently get sent to the
|
||||
server side, so this is not the final exit status for the whole transfer.
|
||||
it() bf(RSYNC_RAW_STATUS): (post-xfer only) the raw exit value from code(waitpid()).
|
||||
))
|
||||
|
||||
Even though the commands can be associated with a particular module, they
|
||||
are run using the permissions of the user that started the daemon (not the
|
||||
module's uid/gid setting) without any chroot restrictions.
|
||||
|
||||
enddit()
|
||||
|
||||
manpagesection(CONFIG DIRECTIVES)
|
||||
|
||||
There are currently two config directives available that allow a config file to
|
||||
incorporate the contents of other files: bf(&include) and bf(&merge). Both
|
||||
allow a reference to either a file or a directory. They differ in how
|
||||
segregated the file's contents are considered to be.
|
||||
|
||||
The bf(&include) directive treats each file as more distinct, with each one
|
||||
inheriting the defaults of the parent file, starting the parameter parsing
|
||||
as globals/defaults, and leaving the defaults unchanged for the parsing of
|
||||
the rest of the parent file.
|
||||
|
||||
The bf(&merge) directive, on the other hand, treats the file's contents as
|
||||
if it were simply inserted in place of the directive, and thus it can set
|
||||
parameters in a module started in another file, can affect the defaults for
|
||||
other files, etc.
|
||||
|
||||
When an bf(&include) or bf(&merge) directive refers to a directory, it will read
|
||||
in all the bf(*.conf) or bf(*.inc) files (respectively) that are contained inside
|
||||
that directory (without any
|
||||
recursive scanning), with the files sorted into alpha order. So, if you have a
|
||||
directory named "rsyncd.d" with the files "foo.conf", "bar.conf", and
|
||||
"baz.conf" inside it, this directive:
|
||||
|
||||
verb( &include /path/rsyncd.d )
|
||||
|
||||
would be the same as this set of directives:
|
||||
|
||||
verb( &include /path/rsyncd.d/bar.conf
|
||||
&include /path/rsyncd.d/baz.conf
|
||||
&include /path/rsyncd.d/foo.conf )
|
||||
|
||||
except that it adjusts as files are added and removed from the directory.
|
||||
|
||||
The advantage of the bf(&include) directive is that you can define one or more
|
||||
modules in a separate file without worrying about unintended side-effects
|
||||
between the self-contained module files.
|
||||
|
||||
The advantage of the bf(&merge) directive is that you can load config snippets
|
||||
that can be included into multiple module definitions, and you can also set
|
||||
global values that will affect connections (such as bf(motd file)), or globals
|
||||
that will affect other include files.
|
||||
|
||||
For example, this is a useful /etc/rsyncd.conf file:
|
||||
|
||||
verb( port = 873
|
||||
log file = /var/log/rsync.log
|
||||
pid file = /var/lock/rsync.lock
|
||||
|
||||
&merge /etc/rsyncd.d
|
||||
&include /etc/rsyncd.d )
|
||||
|
||||
This would merge any /etc/rsyncd.d/*.inc files (for global values that should
|
||||
stay in effect), and then include any /etc/rsyncd.d/*.conf files (defining
|
||||
modules without any global-value cross-talk).
|
||||
|
||||
manpagesection(AUTHENTICATION STRENGTH)
|
||||
|
||||
The authentication protocol used in rsync is a 128 bit MD4 based
|
||||
challenge response system. This is fairly weak protection, though (with
|
||||
at least one brute-force hash-finding algorithm publicly available), so
|
||||
if you want really top-quality security, then I recommend that you run
|
||||
rsync over ssh. (Yes, a future version of rsync will switch over to a
|
||||
stronger hashing method.)
|
||||
|
||||
Also note that the rsync daemon protocol does not currently provide any
|
||||
encryption of the data that is transferred over the connection. Only
|
||||
authentication is provided. Use ssh as the transport if you want
|
||||
encryption.
|
||||
|
||||
Future versions of rsync may support SSL for better authentication and
|
||||
encryption, but that is still being investigated.
|
||||
|
||||
manpagesection(EXAMPLES)
|
||||
|
||||
A simple rsyncd.conf file that allow anonymous rsync to a ftp area at
|
||||
tt(/home/ftp) would be:
|
||||
|
||||
verb(
|
||||
[ftp]
|
||||
path = /home/ftp
|
||||
comment = ftp export area
|
||||
)
|
||||
|
||||
A more sophisticated example would be:
|
||||
|
||||
verb(
|
||||
uid = nobody
|
||||
gid = nobody
|
||||
use chroot = yes
|
||||
max connections = 4
|
||||
syslog facility = local5
|
||||
pid file = /var/run/rsyncd.pid
|
||||
|
||||
[ftp]
|
||||
path = /var/ftp/./pub
|
||||
comment = whole ftp area (approx 6.1 GB)
|
||||
|
||||
[sambaftp]
|
||||
path = /var/ftp/./pub/samba
|
||||
comment = Samba ftp area (approx 300 MB)
|
||||
|
||||
[rsyncftp]
|
||||
path = /var/ftp/./pub/rsync
|
||||
comment = rsync ftp area (approx 6 MB)
|
||||
|
||||
[sambawww]
|
||||
path = /public_html/samba
|
||||
comment = Samba WWW pages (approx 240 MB)
|
||||
|
||||
[cvs]
|
||||
path = /data/cvs
|
||||
comment = CVS repository (requires authentication)
|
||||
auth users = tridge, susan
|
||||
secrets file = /etc/rsyncd.secrets
|
||||
)
|
||||
|
||||
The /etc/rsyncd.secrets file would look something like this:
|
||||
|
||||
quote(
|
||||
tt(tridge:mypass)nl()
|
||||
tt(susan:herpass)nl()
|
||||
)
|
||||
|
||||
manpagefiles()
|
||||
|
||||
/etc/rsyncd.conf or rsyncd.conf
|
||||
|
||||
manpageseealso()
|
||||
|
||||
bf(rsync)(1)
|
||||
|
||||
manpagediagnostics()
|
||||
|
||||
manpagebugs()
|
||||
|
||||
Please report bugs! The rsync bug tracking system is online at
|
||||
url(http://rsync.samba.org/)(http://rsync.samba.org/)
|
||||
|
||||
manpagesection(VERSION)
|
||||
|
||||
This man page is current for version 3.1.1pre2 of rsync.
|
||||
|
||||
manpagesection(CREDITS)
|
||||
|
||||
rsync is distributed under the GNU General Public License. See the file
|
||||
COPYING for details.
|
||||
|
||||
The primary ftp site for rsync is
|
||||
url(ftp://rsync.samba.org/pub/rsync)(ftp://rsync.samba.org/pub/rsync).
|
||||
|
||||
A WEB site is available at
|
||||
url(http://rsync.samba.org/)(http://rsync.samba.org/)
|
||||
|
||||
We would be delighted to hear from you if you like this program.
|
||||
|
||||
This program uses the zlib compression library written by Jean-loup
|
||||
Gailly and Mark Adler.
|
||||
|
||||
manpagesection(THANKS)
|
||||
|
||||
Thanks to Warren Stanley for his original idea and patch for the rsync
|
||||
daemon. Thanks to Karsten Thygesen for his many suggestions and
|
||||
documentation!
|
||||
|
||||
manpageauthor()
|
||||
|
||||
rsync was written by Andrew Tridgell and Paul Mackerras.
|
||||
Many people have later contributed to it.
|
||||
|
||||
Mailing lists for support and development are available at
|
||||
url(http://lists.samba.org)(lists.samba.org)
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user