mirror of
https://github.com/RsyncProject/rsync.git
synced 2026-05-24 23:05:52 -04:00
Compare commits
398 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
618c8a73db | ||
|
|
aa0ea373cd | ||
|
|
6c3fda83ba | ||
|
|
a3571c6cce | ||
|
|
6fcedb7dbe | ||
|
|
18882701d2 | ||
|
|
30c041f9ad | ||
|
|
be7cf82299 | ||
|
|
fde045cd77 | ||
|
|
183150b741 | ||
|
|
a2570930e8 | ||
|
|
fdb6716c0f | ||
|
|
a20a88d235 | ||
|
|
48d3ff94c9 | ||
|
|
a33857da09 | ||
|
|
13791b1eeb | ||
|
|
9a5e37fca8 | ||
|
|
3e976df0fb | ||
|
|
42afed9c1a | ||
|
|
37c36e2692 | ||
|
|
7fbc7031f4 | ||
|
|
9f004a9ea9 | ||
|
|
23f4587f2b | ||
|
|
4d8f5b0ae7 | ||
|
|
89389a29ef | ||
|
|
29fe3961ab | ||
|
|
4e8a085ac9 | ||
|
|
fb22c2774d | ||
|
|
7d059d4c37 | ||
|
|
9715c5899a | ||
|
|
cc07f21211 | ||
|
|
b4d1e854ef | ||
|
|
075aa18fd4 | ||
|
|
e0204f5621 | ||
|
|
a9ac4411e5 | ||
|
|
50b31539c2 | ||
|
|
56194bcd95 | ||
|
|
eb8ffa9040 | ||
|
|
a7a1cc2c75 | ||
|
|
ab217f7ffa | ||
|
|
a20c9893e4 | ||
|
|
3bb400ca14 | ||
|
|
cd6aa5b5c0 | ||
|
|
dc55d7bdab | ||
|
|
8b115ac8dc | ||
|
|
c94e4afbfa | ||
|
|
6566d205e2 | ||
|
|
e484f0cc04 | ||
|
|
bd397b8cba | ||
|
|
f8c8ef9eac | ||
|
|
72c19bb3de | ||
|
|
89f7eff382 | ||
|
|
b90a6d9ff6 | ||
|
|
584ba4ebae | ||
|
|
ba3db4795e | ||
|
|
59d73bf3d2 | ||
|
|
919ca3a3cc | ||
|
|
5886edfac2 | ||
|
|
d414962af4 | ||
|
|
8fb7db245a | ||
|
|
6f0fc27e33 | ||
|
|
9c54ad58f8 | ||
|
|
f55c2dfc03 | ||
|
|
675ef1aa3a | ||
|
|
ef57235623 | ||
|
|
d66d07e883 | ||
|
|
b92693daba | ||
|
|
58b1999e08 | ||
|
|
8e5f029e02 | ||
|
|
2d41264e9e | ||
|
|
82c6be7edf | ||
|
|
0219d4dfba | ||
|
|
391516da51 | ||
|
|
1d6b8f9ad2 | ||
|
|
10796f4b6e | ||
|
|
33ffd7c37d | ||
|
|
21d1e929a0 | ||
|
|
d0bc3520de | ||
|
|
9f18657889 | ||
|
|
c16d69b292 | ||
|
|
ebeacb36fb | ||
|
|
6558854dbe | ||
|
|
7d9d5d9478 | ||
|
|
630f548ff4 | ||
|
|
100b62bb69 | ||
|
|
e012b94f21 | ||
|
|
3104620cf0 | ||
|
|
ebdd24d6d0 | ||
|
|
7cd72c79ec | ||
|
|
84a6379565 | ||
|
|
0a5f12720e | ||
|
|
73f7af0e88 | ||
|
|
e5a96f0f54 | ||
|
|
d73e7f6edd | ||
|
|
61542c41de | ||
|
|
bd1a581bee | ||
|
|
6e8a1782ab | ||
|
|
96d910c770 | ||
|
|
7560c17adc | ||
|
|
9cd339eb39 | ||
|
|
f310029387 | ||
|
|
3ed8eb3f9c | ||
|
|
007351494d | ||
|
|
6dcb93208d | ||
|
|
84e1a698bf | ||
|
|
0d7638eafd | ||
|
|
86e2f445f7 | ||
|
|
093e816c37 | ||
|
|
1cb0a3edc6 | ||
|
|
06a5054273 | ||
|
|
acd0299243 | ||
|
|
dca68b0aad | ||
|
|
c3ea09906d | ||
|
|
bf4679e8a0 | ||
|
|
c4054610c8 | ||
|
|
f6c0d3d70b | ||
|
|
ef855d198e | ||
|
|
81b07870c8 | ||
|
|
bb6721dce6 | ||
|
|
446a2987cd | ||
|
|
4de2a17409 | ||
|
|
99d24f77ed | ||
|
|
c0422cea9f | ||
|
|
8b6ad0193d | ||
|
|
33eff8bfd6 | ||
|
|
65af3dab03 | ||
|
|
065a605270 | ||
|
|
a7260c4037 | ||
|
|
44cad59f2b | ||
|
|
c52461f911 | ||
|
|
7f459268d9 | ||
|
|
9eeb3b9c88 | ||
|
|
d1b31da71e | ||
|
|
89e540e638 | ||
|
|
fab65a5bc2 | ||
|
|
e7d13fe532 | ||
|
|
ecc81fce17 | ||
|
|
b4afd23c30 | ||
|
|
af1a3f9b6e | ||
|
|
820b6c9aa0 | ||
|
|
3cb22c204c | ||
|
|
7432ccf4ed | ||
|
|
6a48e792c1 | ||
|
|
9459290ae7 | ||
|
|
741d654495 | ||
|
|
d3e182af09 | ||
|
|
d9b4d267c7 | ||
|
|
58c5c24555 | ||
|
|
341c9a137f | ||
|
|
871446fc98 | ||
|
|
0abda1b176 | ||
|
|
394bcdb5e3 | ||
|
|
28deecca55 | ||
|
|
4db88e5b8f | ||
|
|
75b243a51d | ||
|
|
9bccfc429c | ||
|
|
077e59b769 | ||
|
|
007e3c0e9a | ||
|
|
e2bc412669 | ||
|
|
e344209582 | ||
|
|
e76ca1458c | ||
|
|
16cc9ca2c9 | ||
|
|
8c90957ff5 | ||
|
|
c0d8e84c9d | ||
|
|
b0ad542928 | ||
|
|
727b35f665 | ||
|
|
aa4343211f | ||
|
|
3611989355 | ||
|
|
3381b77d71 | ||
|
|
dce70db374 | ||
|
|
2adbcdc7ea | ||
|
|
7e5fa372cf | ||
|
|
6e45e1dd86 | ||
|
|
7f290d5c82 | ||
|
|
b6609cafae | ||
|
|
efa95a1842 | ||
|
|
51bd4f0f3a | ||
|
|
562b61695e | ||
|
|
98f51bfb56 | ||
|
|
73f0ce69e7 | ||
|
|
cf338ab1be | ||
|
|
66a9dc9639 | ||
|
|
8ed9d849dc | ||
|
|
5ebab6c10c | ||
|
|
e7a69008e6 | ||
|
|
73e015683c | ||
|
|
b462781fd0 | ||
|
|
93095cbe99 | ||
|
|
399371e7b5 | ||
|
|
d7142e2328 | ||
|
|
1f75bb1066 | ||
|
|
088adfacc1 | ||
|
|
da3478b2a7 | ||
|
|
5126ed1ef0 | ||
|
|
61fb21ad28 | ||
|
|
a3221d2ac1 | ||
|
|
2c713fcdfa | ||
|
|
afd8bdb907 | ||
|
|
efd5ee5786 | ||
|
|
510b4cd4d5 | ||
|
|
de584c658c | ||
|
|
6eb770bbcc | ||
|
|
c7e11bfdc0 | ||
|
|
94327ff0c2 | ||
|
|
4602eafa87 | ||
|
|
bb3edc3b47 | ||
|
|
c769702fe5 | ||
|
|
dbbab0c4d2 | ||
|
|
9b3318b0df | ||
|
|
0fac7fe8b8 | ||
|
|
b9f592fbf5 | ||
|
|
c7b1a56b3d | ||
|
|
3896bca4d8 | ||
|
|
9774cc3344 | ||
|
|
d3979b025d | ||
|
|
01966df4f7 | ||
|
|
f38bd4a072 | ||
|
|
b1df18d76f | ||
|
|
7daccb8e72 | ||
|
|
bb91a624f1 | ||
|
|
a04d77bcbc | ||
|
|
25bd99451c | ||
|
|
ed43d0a76d | ||
|
|
066a844c4e | ||
|
|
5e252dea4b | ||
|
|
d2a918b454 | ||
|
|
da38e779ea | ||
|
|
8186ae6bc0 | ||
|
|
e1f67417d7 | ||
|
|
fd322eef82 | ||
|
|
d3a4375f78 | ||
|
|
78112d305b | ||
|
|
f7c3ee9932 | ||
|
|
e7a392c77c | ||
|
|
887e553f05 | ||
|
|
beb227ddf1 | ||
|
|
84acca07ae | ||
|
|
cc1e997dcd | ||
|
|
a7026ba90a | ||
|
|
3a69fad0f6 | ||
|
|
40564811ee | ||
|
|
dcd08dc51c | ||
|
|
fdf57ede8c | ||
|
|
bd717af8ab | ||
|
|
c54f5170bf | ||
|
|
eae4e1f9f0 | ||
|
|
9c513d678d | ||
|
|
d16c245fc4 | ||
|
|
ec8290c897 | ||
|
|
b293a7f62c | ||
|
|
d67c8bdfc3 | ||
|
|
e2ccd3578c | ||
|
|
4e834af140 | ||
|
|
7e5614383d | ||
|
|
eb84a83b47 | ||
|
|
2c2898a388 | ||
|
|
1732b6c037 | ||
|
|
314f459161 | ||
|
|
83926d3cae | ||
|
|
6218c7bf42 | ||
|
|
566fce3237 | ||
|
|
373ef16010 | ||
|
|
ea76e76104 | ||
|
|
9fd62d1588 | ||
|
|
b7061c82b4 | ||
|
|
6fb812f747 | ||
|
|
40e8d11e64 | ||
|
|
73042aae5b | ||
|
|
e5ce3bcf2c | ||
|
|
c399d22a19 | ||
|
|
1ea087a794 | ||
|
|
00bdf89977 | ||
|
|
0bb4d17634 | ||
|
|
f9c6b3e7d6 | ||
|
|
9e5a5ddb4c | ||
|
|
8c0d6a8432 | ||
|
|
553f93758a | ||
|
|
a4a7e64c19 | ||
|
|
22832c30a0 | ||
|
|
1a21666286 | ||
|
|
4033b80b51 | ||
|
|
99218d821b | ||
|
|
e626b29e10 | ||
|
|
f89b936801 | ||
|
|
17f59e818d | ||
|
|
b5bd5542eb | ||
|
|
2e94e70e2b | ||
|
|
4e1f385711 | ||
|
|
716e73d483 | ||
|
|
5b36173d11 | ||
|
|
b2ef4f6134 | ||
|
|
c7be6dec11 | ||
|
|
bd1574b208 | ||
|
|
f376e67420 | ||
|
|
ef0bc0abff | ||
|
|
71e586304b | ||
|
|
3c74c3a358 | ||
|
|
edad5898f2 | ||
|
|
fa0c1939ed | ||
|
|
9a5ade185c | ||
|
|
f1dd0f27cb | ||
|
|
f9e5a0cde2 | ||
|
|
ead751c62b | ||
|
|
0058c58edd | ||
|
|
221ddb9456 | ||
|
|
65e2487096 | ||
|
|
0501f36390 | ||
|
|
96981b9cff | ||
|
|
f51e87f5ad | ||
|
|
cb213f1c1b | ||
|
|
c8d895de26 | ||
|
|
e51094b721 | ||
|
|
b03bded70b | ||
|
|
ee1df1ccae | ||
|
|
bc6ebcd248 | ||
|
|
ba582f753a | ||
|
|
cbd85b472e | ||
|
|
7a92ded39a | ||
|
|
831f05df51 | ||
|
|
0d94a6a66c | ||
|
|
3e35c34b6b | ||
|
|
03a9ca0a97 | ||
|
|
6f481bb0e0 | ||
|
|
f98cc5685d | ||
|
|
9135621ff9 | ||
|
|
8624daa7f8 | ||
|
|
3051c46dc3 | ||
|
|
e920830ec5 | ||
|
|
7892e5ac77 | ||
|
|
b0e9bafc78 | ||
|
|
44aa070770 | ||
|
|
97f9dcae6a | ||
|
|
8cbf495a57 | ||
|
|
c1b29492c5 | ||
|
|
669a31924e | ||
|
|
5e972dcf34 | ||
|
|
8fcdc444df | ||
|
|
619d21ffc9 | ||
|
|
d62bcc17f3 | ||
|
|
982e05bbd5 | ||
|
|
a3c8b36863 | ||
|
|
630e3c408b | ||
|
|
1082b52bd4 | ||
|
|
914f3066bb | ||
|
|
de91e75724 | ||
|
|
384431886a | ||
|
|
82b302d928 | ||
|
|
4ecc9e6b64 | ||
|
|
55e50d890b | ||
|
|
6e86c951d7 | ||
|
|
c41b52c487 | ||
|
|
5c6fc4a6a3 | ||
|
|
edecdad54d | ||
|
|
5291364f1d | ||
|
|
41cc97ae64 | ||
|
|
bf2b7ddfc5 | ||
|
|
eb0cbdaa90 | ||
|
|
0d0142e812 | ||
|
|
a43e21e05c | ||
|
|
4135d091a6 | ||
|
|
534407b1f4 | ||
|
|
18cc8c7ef1 | ||
|
|
58c9b4b7f6 | ||
|
|
cde719f49f | ||
|
|
38cab94d9a | ||
|
|
6ed6d7f5a8 | ||
|
|
e40a46de71 | ||
|
|
c5bf99a1c2 | ||
|
|
2c7d63c765 | ||
|
|
3dd22903ac | ||
|
|
d8d36af452 | ||
|
|
e610e50f9c | ||
|
|
935c64173f | ||
|
|
377dbd2075 | ||
|
|
93272700d2 | ||
|
|
d508258ad8 | ||
|
|
f57b2e6150 | ||
|
|
af45f9e27e | ||
|
|
4c4d61b046 | ||
|
|
7561c3e132 | ||
|
|
1514ad2a80 | ||
|
|
d8195637d4 | ||
|
|
c8d771a0fb | ||
|
|
9130776c4e | ||
|
|
9eac94a4dd | ||
|
|
6e06d2f31a | ||
|
|
6a6d21136a | ||
|
|
f28bd83346 | ||
|
|
96fb478eae | ||
|
|
8752b3fcd8 | ||
|
|
55ffed7e42 | ||
|
|
e00df64bae | ||
|
|
080ddf58ae | ||
|
|
4ce48a5bfd | ||
|
|
20bf7f847f | ||
|
|
b66d00853b | ||
|
|
8b602edda4 | ||
|
|
9f27cd8ca6 |
@@ -21,3 +21,4 @@ tls
|
||||
trimslash
|
||||
t_unsafe
|
||||
wildtest
|
||||
getfsdev
|
||||
|
||||
39
Makefile.in
39
Makefile.in
@@ -44,11 +44,11 @@ OBJS=$(OBJS1) $(OBJS2) $(OBJS3) $(DAEMON_OBJ) $(LIBOBJ) $(ZLIBOBJ) @BUILD_POPT@
|
||||
TLS_OBJ = tls.o syscall.o lib/permstring.o
|
||||
|
||||
# Programs we must have to run the test cases
|
||||
CHECK_PROGS = rsync$(EXEEXT) tls$(EXEEXT) getgroups$(EXEEXT) \
|
||||
CHECK_PROGS = rsync$(EXEEXT) tls$(EXEEXT) getgroups$(EXEEXT) getfsdev$(EXEEXT) \
|
||||
trimslash$(EXEEXT) t_unsafe$(EXEEXT) wildtest$(EXEEXT)
|
||||
|
||||
# Objects for CHECK_PROGS to clean
|
||||
CHECK_OBJS=getgroups.o t_stub.o t_unsafe.o trimslash.o wildtest.o
|
||||
CHECK_OBJS=getgroups.o getfsdev.o t_stub.o t_unsafe.o trimslash.o wildtest.o
|
||||
|
||||
# note that the -I. is needed to handle config.h when using VPATH
|
||||
.c.o:
|
||||
@@ -58,18 +58,16 @@ CHECK_OBJS=getgroups.o t_stub.o t_unsafe.o trimslash.o wildtest.o
|
||||
|
||||
all: rsync$(EXEEXT)
|
||||
|
||||
man: rsync.1 rsyncd.conf.5
|
||||
|
||||
install: all
|
||||
-mkdir -p ${DESTDIR}${bindir}
|
||||
${INSTALLCMD} ${STRIP} -m 755 rsync$(EXEEXT) ${DESTDIR}${bindir}
|
||||
${INSTALLCMD} ${INSTALL_STRIP} -m 755 rsync$(EXEEXT) ${DESTDIR}${bindir}
|
||||
-mkdir -p ${DESTDIR}${mandir}/man1
|
||||
-mkdir -p ${DESTDIR}${mandir}/man5
|
||||
${INSTALLMAN} -m 644 $(srcdir)/rsync.1 ${DESTDIR}${mandir}/man1
|
||||
${INSTALLMAN} -m 644 $(srcdir)/rsyncd.conf.5 ${DESTDIR}${mandir}/man5
|
||||
|
||||
install-strip:
|
||||
$(MAKE) STRIP='-s' install
|
||||
$(MAKE) INSTALL_STRIP='-s' install
|
||||
|
||||
rsync$(EXEEXT): $(OBJS)
|
||||
$(CC) $(CFLAGS) $(LDFLAGS) -o $@ $(OBJS) $(LIBS)
|
||||
@@ -82,6 +80,9 @@ tls$(EXEEXT): $(TLS_OBJ)
|
||||
getgroups$(EXEEXT): getgroups.o
|
||||
$(CC) $(CFLAGS) $(LDFLAGS) -o $@ getgroups.o $(LIBS)
|
||||
|
||||
getfsdev$(EXEEXT): getfsdev.o
|
||||
$(CC) $(CFLAGS) $(LDFLAGS) -o $@ getfsdev.o $(LIBS)
|
||||
|
||||
TRIMSLASH_OBJ = trimslash.o syscall.o
|
||||
trimslash$(EXEEXT): $(TRIMSLASH_OBJ)
|
||||
$(CC) $(CFLAGS) $(LDFLAGS) -o $@ $(TRIMSLASH_OBJ) $(LIBS)
|
||||
@@ -90,17 +91,15 @@ T_UNSAFE_OBJ = t_unsafe.o syscall.o util.o t_stub.o lib/compat.o lib/snprintf.o
|
||||
t_unsafe$(EXEEXT): $(T_UNSAFE_OBJ)
|
||||
$(CC) $(CFLAGS) $(LDFLAGS) -o $@ $(T_UNSAFE_OBJ) $(LIBS)
|
||||
|
||||
# I don't like these rules because CVS can skew the timestamps and
|
||||
# produce spurious warnings, and also make "make install" fail if the
|
||||
# source directory can no longer be found. Since we don't rebuild
|
||||
# automatically they're kind of lame anyhow.
|
||||
gen: $(srcdir)/configure $(srcdir)/config.h.in proto man
|
||||
|
||||
#Makefile: Makefile.in configure config.status
|
||||
# echo "WARNING: You need to run ./config.status --recheck"
|
||||
man: $(srcdir)/rsync.1 $(srcdir)/rsyncd.conf.5
|
||||
|
||||
# don't actually run autoconf, just issue a warning
|
||||
#configure: configure.in
|
||||
# echo "WARNING: you need to rerun autoconf"
|
||||
$(srcdir)/configure: $(srcdir)/configure.in $(srcdir)/aclocal.m4
|
||||
cd $(srcdir); autoconf
|
||||
|
||||
$(srcdir)/config.h.in: $(srcdir)/configure.in $(srcdir)/aclocal.m4
|
||||
cd $(srcdir); autoheader
|
||||
|
||||
$(srcdir)/rsync.1: $(srcdir)/rsync.yo
|
||||
yodl2man -o $(srcdir)/rsync.1 $(srcdir)/rsync.yo
|
||||
@@ -109,7 +108,12 @@ $(srcdir)/rsyncd.conf.5: $(srcdir)/rsyncd.conf.yo
|
||||
yodl2man -o $(srcdir)/rsyncd.conf.5 $(srcdir)/rsyncd.conf.yo
|
||||
|
||||
proto:
|
||||
cat $(srcdir)/*.c $(srcdir)/lib/compat.c | awk -f $(srcdir)/mkproto.awk > $(srcdir)/proto.h
|
||||
cat $(srcdir)/*.c $(srcdir)/lib/compat.c | awk -f $(srcdir)/mkproto.awk >$(srcdir)/proto.h.new
|
||||
if diff $(srcdir)/proto.h $(srcdir)/proto.h.new >/dev/null; then \
|
||||
rm $(srcdir)/proto.h.new; \
|
||||
else \
|
||||
mv $(srcdir)/proto.h.new $(srcdir)/proto.h; \
|
||||
fi
|
||||
|
||||
clean: cleantests
|
||||
rm -f *~ $(OBJS) $(TLS_OBJ) $(CHECK_PROGS) $(CHECK_OBJS)
|
||||
@@ -146,9 +150,6 @@ test: check
|
||||
# There seems to be no standard way to specify some variables as
|
||||
# exported from a Makefile apart from listing them like this.
|
||||
|
||||
# TODO: Tests that depend on built test aide programs like tls need to
|
||||
# know where the build directory is.
|
||||
|
||||
# This depends on building rsync; if we need any helper programs it
|
||||
# should depend on them too.
|
||||
|
||||
|
||||
350
NEWS
350
NEWS
@@ -1,190 +1,252 @@
|
||||
NEWS for rsync 2.6.1 (26 Apr 2004)
|
||||
Protocol: 28 (changed)
|
||||
Changes since 2.6.0:
|
||||
NEWS for rsync 2.6.3 (30 Sep 2004)
|
||||
Protocol: 28 (unchanged)
|
||||
Changes since 2.6.2:
|
||||
|
||||
SECURITY FIXES:
|
||||
|
||||
- Paths sent to an rsync daemon are more thoroughly sanitized when
|
||||
chroot is not used. If you're running a non-read-only rsync
|
||||
daemon with chroot disabled, *please upgrade*, ESPECIALLY if the
|
||||
user privs you run rsync under is anything above "nobody".
|
||||
- A bug in the sanitize_path routine (which affects a non-chrooted
|
||||
rsync daemon) could allow a user to craft a pathname that would get
|
||||
transformed into an absolute path for certain options (but not for
|
||||
file-transfer names). If you're running an rsync daemon with chroot
|
||||
disabled, *please upgrade*, ESPECIALLY if the user privs you run
|
||||
rsync under is anything above "nobody".
|
||||
|
||||
ENHANCEMENTS:
|
||||
OUTPUT CHANGES (ATTN: those using a script to parse the verbose output):
|
||||
|
||||
- Lower memory use, more optimal transfer of data over the socket,
|
||||
and lower CPU usage (see the INTERNAL section for details).
|
||||
- Please note that the 2-line footer (output when verbose) now uses the
|
||||
term "sent" instead of "wrote" and "received" instead of "read". If
|
||||
you are not parsing the numeric values out of this footer, a script
|
||||
would be better off using the empty line prior to the footer as the
|
||||
indicator that the verbose output is over.
|
||||
|
||||
- The output from the --stats option was similarly affected to change
|
||||
"written" to "sent" and "read" to "received".
|
||||
|
||||
- The RSYNC_PROXY environment variable can now contain a
|
||||
"USER:PASS@" prefix before the "HOST:PORT" information.
|
||||
(Bardur Arantsson)
|
||||
- Rsync ensures that a filename that contains a newline gets mentioned
|
||||
with each newline transformed into a question mark (which prevents a
|
||||
filename from causing an empty line to be output).
|
||||
|
||||
- The --progress output now mentions how far along in the transfer
|
||||
we are, including both a count of files transferred and a
|
||||
percentage of the total file-count that we've processed. It also
|
||||
shows better current-rate-of-transfer and remaining-transfer-time
|
||||
values.
|
||||
|
||||
- The configure script now accepts --with-rsyncd-conf=PATH to
|
||||
override the default value of the /etc/rsyncd.conf file.
|
||||
|
||||
- Added a couple extra diffs in the "patches" dir, removed the ones
|
||||
that got applied, and rebuilt the rest.
|
||||
|
||||
- Documentation changes now attempt to describe some often mis-
|
||||
understood features more clearly.
|
||||
- The "backed up ..." message that is output when at least 2 --verbose
|
||||
options are specified is now the same both with and without the
|
||||
--backup-dir option.
|
||||
|
||||
BUG FIXES:
|
||||
|
||||
- When -x (--one-file-system) is combined with -L (--copy-links) or
|
||||
--copy-unsafe-links, no symlinked files are skipped, even if the
|
||||
referent file is on a different filesystem.
|
||||
- Fixed a crash bug that might appear when --delete was used and
|
||||
multiple source directories were specified.
|
||||
|
||||
- The --link-dest code now works properly for a non-root user when
|
||||
(1) the UIDs of the source and destination differ and -o was
|
||||
specified, or (2) when the group of the source can't be used on
|
||||
the destination and -g was specified.
|
||||
- Fixed a 32-bit truncation of the file length when generating the
|
||||
checksums.
|
||||
|
||||
- Fixed a bug in the handling of -H (hard-links) that might cause
|
||||
the expanded PATH/NAME value of the current item to get
|
||||
overwritten (due to an expanded-name caching bug).
|
||||
|
||||
- We now reset the "new data has been sent" flag at the start of
|
||||
each file we send. This makes sure that an interrupted transfer
|
||||
with the --partial option set doesn't keep a shorter temp file
|
||||
than the current basis file when no new data has been transfered
|
||||
over the wire for that file.
|
||||
- The --backup code no longer attempts to create some directories
|
||||
over and over again (generating warnings along the way).
|
||||
|
||||
- Fixed a byte-order problem in --batch-mode on big-endian machines.
|
||||
(Jay Fenlason)
|
||||
- Fixed a bug in the reading of the secrets file (by the daemon) and
|
||||
the password file (by the client): the files no longer need to be
|
||||
terminated by a newline for their content to be read in.
|
||||
|
||||
- Fixed configure bug when running "./configure --disable-ipv6".
|
||||
- If a file has a read error on the sending side or the reconstructed
|
||||
data doesn't match the expected checksum (perhaps due to the basis
|
||||
file changing during the transfer), the receiver will no longer
|
||||
retain the resulting file unless the --partial option was specified.
|
||||
(Note: for the read-error detection to work, neither side can be
|
||||
older than 2.6.3 -- older receivers will always retain the file, and
|
||||
older senders don't tell the receiver that the file had a read
|
||||
error.)
|
||||
|
||||
- Fixed "make test" bug when build dir is not the source dir.
|
||||
- If a file gets resent in a single transfer and the --backup option
|
||||
is enabled, rsync no longer performs a duplicate backup (it used to
|
||||
overwrite the original file in the backup area).
|
||||
|
||||
- When using --cvs-exclude, the exclude items we get from a
|
||||
per-directory's .cvsignore file once again only affect that one
|
||||
directory (not all following directories too). The items are also
|
||||
now properly word-split and parsed without any +/- prefix parsing.
|
||||
- Files specified in the daemon's "exclude" or "exclude from" config
|
||||
items are now excluded from being uploaded (assuming that the module
|
||||
allows uploading at all) in addition to the old download exclusion.
|
||||
|
||||
- When specifying the USER@HOST: prefix for a file, the USER part
|
||||
can now contain an '@', if needed (i.e. the last '@' is used to
|
||||
find the HOST, not the first).
|
||||
- Got rid of a potential hang in the receiver when near the end of a
|
||||
phase.
|
||||
|
||||
- Fixed some bugs in the handling of group IDs for non-root users:
|
||||
(1) It properly handles a group that the sender didn't have a name
|
||||
for (it would previously skip changing the group on any files in
|
||||
that group). (2) If --numeric-ids is used, rsync no longer
|
||||
attempts to set groups that the user doesn't have the permission
|
||||
to set.
|
||||
- When using --backup without a --backup-dir, rsync no longer preserves
|
||||
the modify time on directories. This avoids confusing NFS.
|
||||
|
||||
- Fixed the "refuse options" setting in the rsyncd.conf file.
|
||||
- When --copy-links (-L) is specified, we now output a separate error
|
||||
for a symlink that has no referent instead of claiming that a file
|
||||
"vanished".
|
||||
|
||||
- Improved the -x (--one-file-system) flag's handling of any mount-
|
||||
point directories we encounter. It is both more optimal (in that
|
||||
it no longer does a useless scan of the contents of the mount-
|
||||
point dirs) and also fixes a bug where a remapped mount of the
|
||||
original filesystem could get discovered in a subdir we should be
|
||||
ignoring.
|
||||
- The --copy-links (-L) option no longer has the side-effect of telling
|
||||
the receiving side to follow symlinks. See the --keep-dirlinks
|
||||
option (mentioned below) for a way to specify that behavior.
|
||||
|
||||
- Rsync no longer discards a double-slash at the start of a filename
|
||||
when trying to open the file. It also no longer constructs names
|
||||
that start with a double slash (unless the user supplied them).
|
||||
- Error messages from the daemon server's option-parsing (such as
|
||||
refused options) are now successfully transferred back to the client
|
||||
(the server used to fail to send the message because the socket
|
||||
wasn't in the right state for the message to get through).
|
||||
|
||||
- Path-specifying options to a daemon should now work the same with
|
||||
or without chroot turned on. Previously, such a option (such as
|
||||
--link-dest) would get its absolute path munged into a relative
|
||||
one if chroot was not on, making that setting fairly useless.
|
||||
Rsync now transforms the path into one that is based on the
|
||||
module's base dir when chroot is not enabled.
|
||||
- Most transfer errors that occur during a daemon transfer are now
|
||||
returned to the user in addition to being logged (some messages are
|
||||
intended to be daemon-only and are not affected by this).
|
||||
|
||||
- Fixed compilation problem on Tru64 Unix (having to do with
|
||||
sockaddr.sa_len and sockaddr.sin_len).
|
||||
- Fixed a bug in the daemon authentication code when using one of the
|
||||
batch-processing options.
|
||||
|
||||
- Fixed a compatibility problem interacting with older rsync
|
||||
versions that might send us an empty --suffix value without
|
||||
telling us that --backup-dir was specified.
|
||||
- We try to work around some buggy IPv6 implementations that fail to
|
||||
implement IPV6_V6ONLY. This should fix the "address in use" error
|
||||
that some daemons get when running on an OS with a buggy IPv6
|
||||
implementation. Also, if the new code gets this error, we might
|
||||
suggest that the user specify --ipv4 or --ipv6 (if we think it will
|
||||
help).
|
||||
|
||||
- The "hosts allow" option for a daemon-over-remote-shell process
|
||||
now has improved support for IPv6 addresses and a fix for systems
|
||||
that have a length field in their socket structs.
|
||||
- When the remote rsync dies, make a better effort to recover any error
|
||||
messages it may have sent before dying (the local rsync used to just
|
||||
die with a socket-write error).
|
||||
|
||||
- Fixed the ability to request an empty backup --suffix when sending
|
||||
files to an rsync daemon.
|
||||
- When using --delete and a --backup-dir that contains files that are
|
||||
hard-linked to their destination equivalents, rsync now makes sure
|
||||
that removed files really get removed (avoids a really weird rename()
|
||||
behavior).
|
||||
|
||||
- Avoid a bogus run-time complaint about a lack of 64-bit integers when
|
||||
the int64 type is defined as an off_t and it actually has 64-bits.
|
||||
|
||||
- Added a configure check for open64() without mkstemp64() so that we
|
||||
can avoid using mkstemp() when such a combination is encountered.
|
||||
This bypasses a problem writing out large temp files on OSes such as
|
||||
AIX and HP-UX.
|
||||
|
||||
- Fixed an age-old crash problem with --read-batch on a local copy
|
||||
(rsync was improperly assuming --whole-file for the local copy).
|
||||
|
||||
- When --dry-run (-n) is used and the destination directory does not
|
||||
exist, rsync now produces a correct report of files that would be
|
||||
sent instead of dying with a chdir() error.
|
||||
|
||||
- Fixed a bug that could cause a slow-to-connect rsync daemon to die
|
||||
with an error instead of waiting for the connection to finish.
|
||||
|
||||
- Fixed an ssh interaction that could cause output to be lost when the
|
||||
user chose to combine the output of rsync's stdout and stderr (e.g.
|
||||
using the "2>&1").
|
||||
|
||||
ENHANCEMENTS:
|
||||
|
||||
- Added the --partial-dir=DIR option that lets you specify where to
|
||||
(temporarily) put a partially transferred file (instead of over-
|
||||
writing the destination file). E.g. --partial-dir=.rsync-partial
|
||||
Also added support for the RSYNC_PARTIAL_DIR environment variable
|
||||
that, when found, transforms a regular --partial option (such as
|
||||
the convenient -P option) into one that also specifies a directory.
|
||||
|
||||
- Added --keep-dirlinks (-K), which allows you to symlink a directory
|
||||
onto another partition on the receiving side and have rsync treat it
|
||||
as matching a normal directory from the sender.
|
||||
|
||||
- Added the --inplace option that tells rsync to write each destination
|
||||
file without using a temporary file. The matching of existing data
|
||||
in the destination file can be severely limited by this, but there
|
||||
are also cases where this is more efficient (such as appending data).
|
||||
Use only when needed (see the man page for more details).
|
||||
|
||||
- Added the "write only" option for the daemon's config file.
|
||||
|
||||
- Added long-option names for -4 and -6 (namely --ipv4 and --ipv6)
|
||||
and documented all these options in the man page.
|
||||
|
||||
- Improved the handling of the --bwlimit option so that it's less
|
||||
bursty, more accurate, and works properly over a larger range of
|
||||
values.
|
||||
|
||||
- The rsync daemon-over-ssh code now looks for SSH_CONNECTION and
|
||||
SSH2_CLIENT in addition to SSH_CLIENT to figure out the IP address.
|
||||
|
||||
- Added the --checksum-seed=N option for advanced users.
|
||||
|
||||
- Batch writing/reading has a brand-new implementation that is simpler,
|
||||
fixes a few weird problems with the old code (such as no longer
|
||||
sprinkling the batch files into different dirs or even onto different
|
||||
systems), and is much less intrusive into the code (making it easier
|
||||
to maintain for the future). The new code generates just one data
|
||||
file instead of three, which makes it possible to read the batch on
|
||||
stdin via a remote shell. Also, the old requirement of forcing the
|
||||
same fixed checksum-seed for all batch processing has been removed.
|
||||
|
||||
- If an rsync daemon has a module set with "list = no" (which hides its
|
||||
presence in the list of available modules), a user that fails to
|
||||
authenticate gets the same "unknown module" error that they would get
|
||||
if the module were actually unknown (while still logging the real
|
||||
error to the daemon's log file). This prevents fishing for module
|
||||
names.
|
||||
|
||||
- The daemon's "refuse options" config item now allows you to match
|
||||
option names using wildcards and/or the single-letter option names.
|
||||
|
||||
- Each transferred file now gets its permissions and modified-time
|
||||
updated before the temp-file gets moved into place. Previously, the
|
||||
finished file would have a very brief window where its permissions
|
||||
disallowed all group and world access.
|
||||
|
||||
- Added the ability to parse a literal IPv6 address in an "rsync:" URL
|
||||
(e.g. rsync://[2001:638:500:101::21]:873/module/dir).
|
||||
|
||||
- The daemon's wildcard expanding code can now handle more than 1000
|
||||
filenames (it's now limited by memory instead of having a hard-wired
|
||||
limit).
|
||||
|
||||
INTERNAL:
|
||||
|
||||
- Most of the I/O is now buffered, which results in a pretty large
|
||||
speedup when running under MS Windows. (Craig Barratt)
|
||||
- Some cleanup in the exclude code has saved some per-exclude memory
|
||||
and made the code easier to maintain.
|
||||
|
||||
- Optimizations to the name-handling/comparing code have made some
|
||||
significant reductions in user-CPU time for large file sets.
|
||||
- Improved the argv-overflow checking for a remote command that has a
|
||||
lot of args.
|
||||
|
||||
- Some cleanup of the variable types make the code more consistent.
|
||||
- Use rsyserr() in the various places that were still calling rprintf()
|
||||
with strerror() as an arg.
|
||||
|
||||
- Reduced memory requirements of hard link preservation.
|
||||
(J.W. Schultz)
|
||||
- If an rsync daemon is listening on multiple sockets (to handle both
|
||||
IPv4 and IPv6 to a single port), we now close all the unneeded file
|
||||
handles after we accept a connection (we used to close just one of
|
||||
them).
|
||||
|
||||
- Implemented a new algorithm for hard-link handling that speeds up
|
||||
the code significantly. (J.W. Schultz and Wayne Davison)
|
||||
- Optimized the handling of larger block sizes (rsync used to slow to a
|
||||
crawl if the block size got too large).
|
||||
|
||||
- The --hard-link option now uses the first existing file in the
|
||||
group of linked files as the basis for the transfer. This
|
||||
prevents the sub-optimal transfer of a file's data when a new
|
||||
hardlink is added on the sending side and it sorts alphabetically
|
||||
earlier in the list than the files that are already present on the
|
||||
receiving side.
|
||||
- Optimized away a loop in hash_search().
|
||||
|
||||
- Dropped support for protocol versions less than 20 (2.3.0 released
|
||||
15 Mar 1999) and activated warnings for protocols less than 25
|
||||
(2.5.0 released 23 Aug 2001). (Wayne Davison and J.W. Schultz,
|
||||
severally)
|
||||
- Some improvements to the sanitize_path() and clean_fname() functions
|
||||
makes them more efficient and produce better results (while still
|
||||
being compatible with the file-name cleaning that gets done on both
|
||||
sides when sending the file-list).
|
||||
|
||||
- More optimal data transmission for --hard-links (protocol 28).
|
||||
- Got rid of alloc_sanitize_path() after adding a destination-buffer
|
||||
arg to sanitize_path() made it possible to put all the former's
|
||||
functionality into the latter.
|
||||
|
||||
- More optimal data transmission for --checksum (protocol 28).
|
||||
- The file-list that is output when at least 4 verbose options are
|
||||
specified reports the uid value on the sender even when rsync is
|
||||
not running as root (since we might be sending to a root receiver).
|
||||
|
||||
- Less memory is used when --checksum is specified.
|
||||
BUILD CHANGES:
|
||||
|
||||
- Less memory is used in the file list (a per-file savings).
|
||||
- Added a "gen" target to rebuild most of the generated files,
|
||||
including configure, config.h.in, the man pages, and proto.h.
|
||||
|
||||
- The generator is now better about not modifying the file list
|
||||
during the transfer in order to avoid a copy-on-write memory
|
||||
bifurcation (on systems where fork() uses shared memory).
|
||||
Previously, rsync's shared memory would slowly become unshared,
|
||||
resulting in real memory usage nearly doubling on the receiving
|
||||
side by the end of the transfer. Now, as long as permissions
|
||||
are being preserved, the shared memory should remain that way
|
||||
for the entire transfer.
|
||||
- If "make proto" doesn't find some changes in the prototypes, the
|
||||
proto.h file is left untouched (its time-stamp used to always be
|
||||
updated).
|
||||
|
||||
- Changed hardlink info and file_struct + strings to use allocation
|
||||
pools. This reduces memory use for large file-sets and permits
|
||||
freeing memory to the OS. (J.W. Schultz)
|
||||
- The variable $STRIP (that is optionally set by the install-strip
|
||||
target's rule) was changed to $INSTALL_STRIP because some systems
|
||||
have $STRIP already set in the environment.
|
||||
|
||||
- The 2 pipes used between the receiver and generator processes
|
||||
(which are forked on the same machine) were reduced to 1 pipe and
|
||||
the protocol improved so that (1) it is now impossible to have the
|
||||
"redo" pipe fill up and hang rsync, and (2) trailing messages from
|
||||
the receiver don't get lost on their way through the generator
|
||||
over to the sender (which mainly affected hard-link messages and
|
||||
verbose --stats output).
|
||||
- Fixed a build problem when SUPPORT_HARD_LINKS isn't defined.
|
||||
|
||||
- Improved the internal uid/gid code to be more portable and a
|
||||
little more optimized.
|
||||
- When cross-compiling, the gettimeofday() function is now assumed to
|
||||
be a modern version that takes two-args (since we can't test it).
|
||||
|
||||
- The device numbers sent when using --devices are now sent as
|
||||
separate major/minor values with 32-bit accuracy (protocol 28).
|
||||
Previously, the copied devices were sent as a single 32-bit
|
||||
number. This will make inter-operation of 64-bit binaries more
|
||||
compatible with their 32-bit brethren (with both ends of the
|
||||
connection are using protocol 28). Note that optimizations in the
|
||||
binary protocol for sending the device numbers often results in
|
||||
fewer bytes being used than before, even though more precision is
|
||||
now available.
|
||||
DEVELOPER RELATED:
|
||||
|
||||
- Some cleanup of the exclude/include structures and its code made
|
||||
things clearer (internally), simpler, and more efficient.
|
||||
- The scripts in the testsuite dir were cleaned up a bit and a few
|
||||
new tests added.
|
||||
|
||||
- Some new diffs were added to the patches dir, and some accepted
|
||||
ones were removed.
|
||||
|
||||
- The reading & writing of the file-list in batch-mode is now
|
||||
handled by the same code that sends & receives the list over the
|
||||
wire. This makes it much easier to maintain. (Note that the
|
||||
batch code is still considered to be experimental.)
|
||||
|
||||
240
OLDNEWS
240
OLDNEWS
@@ -1,3 +1,240 @@
|
||||
NEWS for rsync 2.6.2 (30 Apr 2004)
|
||||
Protocol: 28 (unchanged)
|
||||
Changes since 2.6.1:
|
||||
|
||||
BUG FIXES:
|
||||
|
||||
- Fixed a major bug in the sorting of the filenames when --relative
|
||||
is used for some sources (just sources such as "/" and "/*" were
|
||||
affected). This fix ensures that we ask for the right file-list
|
||||
item when requesting changes from the sender.
|
||||
|
||||
- Rsync now checks the return value of the close() function to
|
||||
better report disk-full problems on an NFS file system.
|
||||
|
||||
- Restored the old daemon-server behavior of logging error messages
|
||||
rather than returning them to the user. (A better long-term fix
|
||||
will be sought in the future.)
|
||||
|
||||
- An obscure uninitialized-variable bug was fixed in the uid/gid
|
||||
code. (This bug probably had no ill effects.)
|
||||
|
||||
BUILD CHANGES:
|
||||
|
||||
- Got rid of the configure check for sys/sysctl.h (it wasn't used
|
||||
and was causing a problem on some systems). Also improved the
|
||||
broken-largefile-locking test to try to avoid failure due to an
|
||||
NFS build-dir.
|
||||
|
||||
- Fixed a compile problem on systems that don't define
|
||||
AI_NUMERICHOST.
|
||||
|
||||
- Fixed a compile problem in the popt source for compilers that
|
||||
don't support __attribute__.
|
||||
|
||||
DEVELOPER RELATED:
|
||||
|
||||
- Improved the testsuite's "merge" test to work on OSF1.
|
||||
|
||||
- Two new diffs were added to the patches dir.
|
||||
|
||||
|
||||
NEWS for rsync 2.6.1 (26 Apr 2004)
|
||||
Protocol: 28 (changed)
|
||||
Changes since 2.6.0:
|
||||
|
||||
SECURITY FIXES:
|
||||
|
||||
- Paths sent to an rsync daemon are more thoroughly sanitized when
|
||||
chroot is not used. If you're running a non-read-only rsync
|
||||
daemon with chroot disabled, *please upgrade*, ESPECIALLY if the
|
||||
user privs you run rsync under is anything above "nobody".
|
||||
|
||||
ENHANCEMENTS:
|
||||
|
||||
- Lower memory use, more optimal transfer of data over the socket,
|
||||
and lower CPU usage (see the INTERNAL section for details).
|
||||
|
||||
- The RSYNC_PROXY environment variable can now contain a
|
||||
"USER:PASS@" prefix before the "HOST:PORT" information.
|
||||
(Bardur Arantsson)
|
||||
|
||||
- The --progress output now mentions how far along in the transfer
|
||||
we are, including both a count of files transferred and a
|
||||
percentage of the total file-count that we've processed. It also
|
||||
shows better current-rate-of-transfer and remaining-transfer-time
|
||||
values.
|
||||
|
||||
- Documentation changes now attempt to describe some often mis-
|
||||
understood features more clearly.
|
||||
|
||||
BUG FIXES:
|
||||
|
||||
- When -x (--one-file-system) is combined with -L (--copy-links) or
|
||||
--copy-unsafe-links, no symlinked files are skipped, even if the
|
||||
referent file is on a different filesystem.
|
||||
|
||||
- The --link-dest code now works properly for a non-root user when
|
||||
(1) the UIDs of the source and destination differ and -o was
|
||||
specified, or (2) when the group of the source can't be used on
|
||||
the destination and -g was specified.
|
||||
|
||||
- Fixed a bug in the handling of -H (hard-links) that might cause
|
||||
the expanded PATH/NAME value of the current item to get
|
||||
overwritten (due to an expanded-name caching bug).
|
||||
|
||||
- We now reset the "new data has been sent" flag at the start of
|
||||
each file we send. This makes sure that an interrupted transfer
|
||||
with the --partial option set doesn't keep a shorter temp file
|
||||
than the current basis file when no new data has been transfered
|
||||
over the wire for that file.
|
||||
|
||||
- Fixed a byte-order problem in --batch-mode on big-endian machines.
|
||||
(Jay Fenlason)
|
||||
|
||||
- When using --cvs-exclude, the exclude items we get from a
|
||||
per-directory's .cvsignore file once again only affect that one
|
||||
directory (not all following directories too). The items are also
|
||||
now properly word-split and parsed without any +/- prefix parsing.
|
||||
|
||||
- When specifying the USER@HOST: prefix for a file, the USER part
|
||||
can now contain an '@', if needed (i.e. the last '@' is used to
|
||||
find the HOST, not the first).
|
||||
|
||||
- Fixed some bugs in the handling of group IDs for non-root users:
|
||||
(1) It properly handles a group that the sender didn't have a name
|
||||
for (it would previously skip changing the group on any files in
|
||||
that group). (2) If --numeric-ids is used, rsync no longer
|
||||
attempts to set groups that the user doesn't have the permission
|
||||
to set.
|
||||
|
||||
- Fixed the "refuse options" setting in the rsyncd.conf file.
|
||||
|
||||
- Improved the -x (--one-file-system) flag's handling of any mount-
|
||||
point directories we encounter. It is both more optimal (in that
|
||||
it no longer does a useless scan of the contents of the mount-
|
||||
point dirs) and also fixes a bug where a remapped mount of the
|
||||
original filesystem could get discovered in a subdir we should be
|
||||
ignoring.
|
||||
|
||||
- Rsync no longer discards a double-slash at the start of a filename
|
||||
when trying to open the file. It also no longer constructs names
|
||||
that start with a double slash (unless the user supplied them).
|
||||
|
||||
- Path-specifying options to a daemon should now work the same with
|
||||
or without chroot turned on. Previously, such a option (such as
|
||||
--link-dest) would get its absolute path munged into a relative
|
||||
one if chroot was not on, making that setting fairly useless.
|
||||
Rsync now transforms the path into one that is based on the
|
||||
module's base dir when chroot is not enabled.
|
||||
|
||||
- Fixed a compatibility problem interacting with older rsync
|
||||
versions that might send us an empty --suffix value without
|
||||
telling us that --backup-dir was specified.
|
||||
|
||||
- The "hosts allow" option for a daemon-over-remote-shell process
|
||||
now has improved support for IPv6 addresses and a fix for systems
|
||||
that have a length field in their socket structs.
|
||||
|
||||
- Fixed the ability to request an empty backup --suffix when sending
|
||||
files to an rsync daemon.
|
||||
|
||||
INTERNAL:
|
||||
|
||||
- Most of the I/O is now buffered, which results in a pretty large
|
||||
speedup when running under MS Windows. (Craig Barratt)
|
||||
|
||||
- Optimizations to the name-handling/comparing code have made some
|
||||
significant reductions in user-CPU time for large file sets.
|
||||
|
||||
- Some cleanup of the variable types make the code more consistent.
|
||||
|
||||
- Reduced memory requirements of hard link preservation.
|
||||
(J.W. Schultz)
|
||||
|
||||
- Implemented a new algorithm for hard-link handling that speeds up
|
||||
the code significantly. (J.W. Schultz and Wayne Davison)
|
||||
|
||||
- The --hard-link option now uses the first existing file in the
|
||||
group of linked files as the basis for the transfer. This
|
||||
prevents the sub-optimal transfer of a file's data when a new
|
||||
hardlink is added on the sending side and it sorts alphabetically
|
||||
earlier in the list than the files that are already present on the
|
||||
receiving side.
|
||||
|
||||
- Dropped support for protocol versions less than 20 (2.3.0 released
|
||||
15 Mar 1999) and activated warnings for protocols less than 25
|
||||
(2.5.0 released 23 Aug 2001). (Wayne Davison and J.W. Schultz,
|
||||
severally)
|
||||
|
||||
- More optimal data transmission for --hard-links (protocol 28).
|
||||
|
||||
- More optimal data transmission for --checksum (protocol 28).
|
||||
|
||||
- Less memory is used when --checksum is specified.
|
||||
|
||||
- Less memory is used in the file list (a per-file savings).
|
||||
|
||||
- The generator is now better about not modifying the file list
|
||||
during the transfer in order to avoid a copy-on-write memory
|
||||
bifurcation (on systems where fork() uses shared memory).
|
||||
Previously, rsync's shared memory would slowly become unshared,
|
||||
resulting in real memory usage nearly doubling on the receiving
|
||||
side by the end of the transfer. Now, as long as permissions
|
||||
are being preserved, the shared memory should remain that way
|
||||
for the entire transfer.
|
||||
|
||||
- Changed hardlink info and file_struct + strings to use allocation
|
||||
pools. This reduces memory use for large file-sets and permits
|
||||
freeing memory to the OS. (J.W. Schultz)
|
||||
|
||||
- The 2 pipes used between the receiver and generator processes
|
||||
(which are forked on the same machine) were reduced to 1 pipe and
|
||||
the protocol improved so that (1) it is now impossible to have the
|
||||
"redo" pipe fill up and hang rsync, and (2) trailing messages from
|
||||
the receiver don't get lost on their way through the generator
|
||||
over to the sender (which mainly affected hard-link messages and
|
||||
verbose --stats output).
|
||||
|
||||
- Improved the internal uid/gid code to be more portable and a
|
||||
little more optimized.
|
||||
|
||||
- The device numbers sent when using --devices are now sent as
|
||||
separate major/minor values with 32-bit accuracy (protocol 28).
|
||||
Previously, the copied devices were sent as a single 32-bit
|
||||
number. This will make inter-operation of 64-bit binaries more
|
||||
compatible with their 32-bit brethren (with both ends of the
|
||||
connection are using protocol 28). Note that optimizations in the
|
||||
binary protocol for sending the device numbers often results in
|
||||
fewer bytes being used than before, even though more precision is
|
||||
now available.
|
||||
|
||||
- Some cleanup of the exclude/include structures and its code made
|
||||
things clearer (internally), simpler, and more efficient.
|
||||
|
||||
- The reading & writing of the file-list in batch-mode is now
|
||||
handled by the same code that sends & receives the list over the
|
||||
wire. This makes it much easier to maintain. (Note that the
|
||||
batch code is still considered to be experimental.)
|
||||
|
||||
BUILD CHANGES:
|
||||
|
||||
- The configure script now accepts --with-rsyncd-conf=PATH to
|
||||
override the default value of the /etc/rsyncd.conf file.
|
||||
|
||||
- Fixed configure bug when running "./configure --disable-ipv6".
|
||||
|
||||
- Fixed compilation problem on Tru64 Unix (having to do with
|
||||
sockaddr.sa_len and sockaddr.sin_len).
|
||||
|
||||
DEVELOPER RELATED:
|
||||
|
||||
- Fixed "make test" bug when build dir is not the source dir.
|
||||
|
||||
- Added a couple extra diffs in the "patches" dir, removed the ones
|
||||
that got applied, and rebuilt the rest.
|
||||
|
||||
|
||||
NEWS for rsync 2.6.0 (1 Jan 2004)
|
||||
Protocol: 27 (changed)
|
||||
Changes since 2.5.7:
|
||||
@@ -553,6 +790,9 @@ Changes since 2.4.6:
|
||||
|
||||
Partial Protocol History
|
||||
RELEASE DATE VER. DATE OF COMMIT PROTOCOL
|
||||
30 Sep 2004 2.6.3 28
|
||||
30 Apr 2004 2.6.2 28
|
||||
26 Apr 2004 2.6.1 08 Jan 2004 28
|
||||
01 Jan 2004 2.6.0 10 Apr 2003 27 (MAX=40)
|
||||
04 Dec 2003 2.5.7 26
|
||||
26 Jan 2003 2.5.6 26
|
||||
|
||||
11
README
11
README
@@ -29,9 +29,9 @@ and see the manual for more information.
|
||||
SETUP
|
||||
-----
|
||||
|
||||
Rsync normally uses rsh or ssh for communication. It does not need to
|
||||
Rsync normally uses ssh or rsh for communication. It does not need to
|
||||
be setuid and requires no special privileges for installation. You
|
||||
must, however, have a working rsh or ssh system. Using ssh is
|
||||
must, however, have a working ssh or rsh system. Using ssh is
|
||||
recommended for its security features.
|
||||
|
||||
Alternatively, rsync can run in `daemon' mode, listening on a socket.
|
||||
@@ -77,7 +77,7 @@ BUG REPORTS
|
||||
|
||||
If you have web access then please look at
|
||||
|
||||
http://rsync.samba.org
|
||||
http://rsync.samba.org/
|
||||
|
||||
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
|
||||
@@ -86,9 +86,8 @@ mailing list archives at
|
||||
|
||||
http://mail-archive.com/rsync@lists.samba.org/
|
||||
|
||||
Please send bug reports to
|
||||
|
||||
rsync@lists.samba.org
|
||||
To send a bug report, follow the instructions on the bug-tracking
|
||||
page of the web site.
|
||||
|
||||
|
||||
CVS TREE
|
||||
|
||||
14
TODO
14
TODO
@@ -21,13 +21,12 @@ SOCKS 2002/01/23
|
||||
FAT support
|
||||
Allow forcing arbitrary permissions 2002/03/12
|
||||
--diff david.e.sewell 2002/03/15
|
||||
Add daemon --no-detach and --no-fork options
|
||||
Add daemon --no-fork option
|
||||
Create more granular verbosity jw 2003/05/15
|
||||
|
||||
DOCUMENTATION --------------------------------------------------------
|
||||
Update README
|
||||
Keep list of open issues and todos on the web site
|
||||
Update web site from CVS
|
||||
Perhaps redo manual as SGML
|
||||
|
||||
LOGGING --------------------------------------------------------------
|
||||
@@ -326,7 +325,7 @@ Allow forcing arbitrary permissions 2002/03/12
|
||||
-- --
|
||||
|
||||
|
||||
Add daemon --no-detach and --no-fork options
|
||||
Add daemon --no-fork option
|
||||
|
||||
Very useful for debugging. Also good when running under a
|
||||
daemon-monitoring process that tries to restart the service when the
|
||||
@@ -362,11 +361,6 @@ Keep list of open issues and todos on the web site
|
||||
-- --
|
||||
|
||||
|
||||
Update web site from CVS
|
||||
|
||||
-- --
|
||||
|
||||
|
||||
Perhaps redo manual as SGML
|
||||
|
||||
The man page is getting rather large, and there is more information
|
||||
@@ -425,7 +419,9 @@ Improve error messages
|
||||
our load? (Debian #28416) Probably fixed now, but a test case would
|
||||
be good.
|
||||
|
||||
|
||||
When running as a daemon, some errors should both be returned to the
|
||||
user and logged. This will make interacting with a daemon less
|
||||
cryptic.
|
||||
|
||||
-- --
|
||||
|
||||
|
||||
31
access.c
31
access.c
@@ -88,9 +88,13 @@ static int match_address(char *addr, char *tok)
|
||||
/* Fail quietly if tok is a hostname (not an address) */
|
||||
if (strspn(tok, ".0123456789") != len
|
||||
#ifdef INET6
|
||||
&& !strchr(tok, ':')
|
||||
&& strchr(tok, ':') == NULL
|
||||
#endif
|
||||
) return 0;
|
||||
) {
|
||||
if (p)
|
||||
*p = '/';
|
||||
return 0;
|
||||
}
|
||||
|
||||
memset(&hints, 0, sizeof(hints));
|
||||
hints.ai_family = PF_UNSPEC;
|
||||
@@ -99,17 +103,18 @@ static int match_address(char *addr, char *tok)
|
||||
hints.ai_flags = AI_NUMERICHOST;
|
||||
#endif
|
||||
|
||||
gai = getaddrinfo(addr, NULL, &hints, &resa);
|
||||
if (gai) return 0;
|
||||
if (getaddrinfo(addr, NULL, &hints, &resa) != 0) {
|
||||
if (p)
|
||||
*p = '/';
|
||||
return 0;
|
||||
}
|
||||
|
||||
gai = getaddrinfo(tok, NULL, &hints, &rest);
|
||||
if (p)
|
||||
*p++ = '/';
|
||||
if (gai) {
|
||||
rprintf(FERROR,
|
||||
"error matching address %s: %s\n",
|
||||
tok,
|
||||
gai_strerror(gai));
|
||||
if (gai != 0) {
|
||||
rprintf(FLOG, "error matching address %s: %s\n",
|
||||
tok, gai_strerror(gai));
|
||||
freeaddrinfo(resa);
|
||||
return 0;
|
||||
}
|
||||
@@ -152,7 +157,7 @@ static int match_address(char *addr, char *tok)
|
||||
}
|
||||
#endif
|
||||
default:
|
||||
rprintf(FERROR,"unknown family %u\n", rest->ai_family);
|
||||
rprintf(FLOG, "unknown family %u\n", rest->ai_family);
|
||||
ret = 0;
|
||||
goto out;
|
||||
}
|
||||
@@ -169,14 +174,14 @@ static int match_address(char *addr, char *tok)
|
||||
#ifdef HAVE_STRTOL
|
||||
bits = strtol(p, &ep, 10);
|
||||
if (!*p || *ep) {
|
||||
rprintf(FERROR,"malformed mask in %s\n", tok);
|
||||
rprintf(FLOG, "malformed mask in %s\n", tok);
|
||||
ret = 0;
|
||||
goto out;
|
||||
}
|
||||
#else
|
||||
for (pp = (unsigned char *)p; *pp; pp++) {
|
||||
if (!isascii(*pp) || !isdigit(*pp)) {
|
||||
rprintf(FERROR,"malformed mask in %s\n", tok);
|
||||
rprintf(FLOG, "malformed mask in %s\n", tok);
|
||||
ret = 0;
|
||||
goto out;
|
||||
}
|
||||
@@ -188,7 +193,7 @@ static int match_address(char *addr, char *tok)
|
||||
goto out;
|
||||
}
|
||||
if (bits < 0 || bits > (addrlen << 3)) {
|
||||
rprintf(FERROR,"malformed mask in %s\n", tok);
|
||||
rprintf(FLOG, "malformed mask in %s\n", tok);
|
||||
ret = 0;
|
||||
goto out;
|
||||
}
|
||||
|
||||
207
authenticate.c
207
authenticate.c
@@ -1,17 +1,17 @@
|
||||
/* -*- c-file-style: "linux"; -*-
|
||||
|
||||
Copyright (C) 1998-2000 by Andrew Tridgell
|
||||
|
||||
|
||||
Copyright (C) 1998-2000 by Andrew Tridgell
|
||||
|
||||
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 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
@@ -20,6 +20,9 @@
|
||||
/* support rsync authentication */
|
||||
#include "rsync.h"
|
||||
|
||||
extern char *password_file;
|
||||
extern int am_root;
|
||||
|
||||
/***************************************************************************
|
||||
encode a buffer using base64 - simple and slow algorithm. null terminates
|
||||
the result.
|
||||
@@ -54,7 +57,7 @@ static void gen_challenge(char *addr, char *challenge)
|
||||
char input[32];
|
||||
struct timeval tv;
|
||||
|
||||
memset(input, 0, sizeof(input));
|
||||
memset(input, 0, sizeof input);
|
||||
|
||||
strlcpy((char *)input, addr, 17);
|
||||
sys_gettimeofday(&tv);
|
||||
@@ -62,121 +65,131 @@ static void gen_challenge(char *addr, char *challenge)
|
||||
SIVAL(input, 20, tv.tv_usec);
|
||||
SIVAL(input, 24, getpid());
|
||||
|
||||
sum_init();
|
||||
sum_update(input, sizeof(input));
|
||||
sum_init(0);
|
||||
sum_update(input, sizeof input);
|
||||
sum_end(challenge);
|
||||
}
|
||||
|
||||
|
||||
/* return the secret for a user from the sercret file. maximum length
|
||||
is len. null terminate it */
|
||||
/* Return the secret for a user from the secret file, null terminated.
|
||||
* Maximum length is len (not counting the null). */
|
||||
static int get_secret(int module, char *user, char *secret, int len)
|
||||
{
|
||||
char *fname = lp_secrets_file(module);
|
||||
int fd, found=0;
|
||||
char line[MAXPATHLEN];
|
||||
char *p, *pass=NULL;
|
||||
STRUCT_STAT st;
|
||||
int ok = 1;
|
||||
extern int am_root;
|
||||
int fd, ok = 1;
|
||||
char ch, *p;
|
||||
|
||||
if (!fname || !*fname) return 0;
|
||||
if (!fname || !*fname)
|
||||
return 0;
|
||||
|
||||
fd = open(fname,O_RDONLY);
|
||||
if (fd == -1) return 0;
|
||||
if ((fd = open(fname, O_RDONLY)) < 0)
|
||||
return 0;
|
||||
|
||||
if (do_stat(fname, &st) == -1) {
|
||||
rsyserr(FERROR, errno, "stat(%s)", fname);
|
||||
rsyserr(FLOG, errno, "stat(%s)", fname);
|
||||
ok = 0;
|
||||
} else if (lp_strict_modes(module)) {
|
||||
if ((st.st_mode & 06) != 0) {
|
||||
rprintf(FERROR,"secrets file must not be other-accessible (see strict modes option)\n");
|
||||
rprintf(FLOG, "secrets file must not be other-accessible (see strict modes option)\n");
|
||||
ok = 0;
|
||||
} else if (am_root && (st.st_uid != 0)) {
|
||||
rprintf(FERROR,"secrets file must be owned by root when running as root (see strict modes)\n");
|
||||
rprintf(FLOG, "secrets file must be owned by root when running as root (see strict modes)\n");
|
||||
ok = 0;
|
||||
}
|
||||
}
|
||||
if (!ok) {
|
||||
rprintf(FERROR,"continuing without secrets file\n");
|
||||
rprintf(FLOG, "continuing without secrets file\n");
|
||||
close(fd);
|
||||
return 0;
|
||||
}
|
||||
|
||||
while (!found) {
|
||||
int i = 0;
|
||||
memset(line, 0, sizeof line);
|
||||
while ((size_t) i < (sizeof(line)-1)) {
|
||||
if (read(fd, &line[i], 1) != 1) {
|
||||
memset(line, 0, sizeof(line));
|
||||
close(fd);
|
||||
return 0;
|
||||
}
|
||||
if (line[i] == '\r') continue;
|
||||
if (line[i] == '\n') break;
|
||||
i++;
|
||||
}
|
||||
line[i] = 0;
|
||||
if (line[0] == '#') continue;
|
||||
p = strchr(line,':');
|
||||
if (!p) continue;
|
||||
*p = 0;
|
||||
if (strcmp(user, line)) continue;
|
||||
pass = p+1;
|
||||
found = 1;
|
||||
if (*user == '#') {
|
||||
/* Reject attempt to match a comment. */
|
||||
close(fd);
|
||||
return 0;
|
||||
}
|
||||
|
||||
close(fd);
|
||||
if (!found) return 0;
|
||||
/* Try to find a line that starts with the user name and a ':'. */
|
||||
p = user;
|
||||
while (1) {
|
||||
if (read(fd, &ch, 1) != 1) {
|
||||
close(fd);
|
||||
return 0;
|
||||
}
|
||||
if (ch == '\n')
|
||||
p = user;
|
||||
else if (p) {
|
||||
if (*p == ch)
|
||||
p++;
|
||||
else if (!*p && ch == ':')
|
||||
break;
|
||||
else
|
||||
p = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
/* Slurp the secret into the "secret" buffer. */
|
||||
p = secret;
|
||||
while (len > 0) {
|
||||
if (read(fd, p, 1) != 1 || *p == '\n')
|
||||
break;
|
||||
if (*p == '\r')
|
||||
continue;
|
||||
p++;
|
||||
len--;
|
||||
}
|
||||
*p = '\0';
|
||||
close(fd);
|
||||
|
||||
strlcpy(secret, pass, len);
|
||||
return 1;
|
||||
}
|
||||
|
||||
static char *getpassf(char *filename)
|
||||
{
|
||||
char buffer[100];
|
||||
int fd=0;
|
||||
STRUCT_STAT st;
|
||||
int ok = 1;
|
||||
extern int am_root;
|
||||
char *envpw=getenv("RSYNC_PASSWORD");
|
||||
char buffer[512], *p;
|
||||
int fd, n, ok = 1;
|
||||
char *envpw = getenv("RSYNC_PASSWORD");
|
||||
|
||||
if (!filename) return NULL;
|
||||
if (!filename)
|
||||
return NULL;
|
||||
|
||||
if ( (fd=open(filename,O_RDONLY)) == -1) {
|
||||
if ((fd = open(filename,O_RDONLY)) < 0) {
|
||||
rsyserr(FERROR, errno, "could not open password file \"%s\"",filename);
|
||||
if (envpw) rprintf(FERROR,"falling back to RSYNC_PASSWORD environment variable.\n");
|
||||
if (envpw)
|
||||
rprintf(FERROR, "falling back to RSYNC_PASSWORD environment variable.\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
if (do_stat(filename, &st) == -1) {
|
||||
rsyserr(FERROR, errno, "stat(%s)", filename);
|
||||
ok = 0;
|
||||
} else if ((st.st_mode & 06) != 0) {
|
||||
rprintf(FERROR,"password file must not be other-accessible\n");
|
||||
ok = 0;
|
||||
} else if (am_root && (st.st_uid != 0)) {
|
||||
} else if (am_root && st.st_uid != 0) {
|
||||
rprintf(FERROR,"password file must be owned by root when running as root\n");
|
||||
ok = 0;
|
||||
}
|
||||
if (!ok) {
|
||||
rprintf(FERROR,"continuing without password file\n");
|
||||
if (envpw) rprintf(FERROR,"using RSYNC_PASSWORD environment variable.\n");
|
||||
if (envpw)
|
||||
rprintf(FERROR, "using RSYNC_PASSWORD environment variable.\n");
|
||||
close(fd);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (envpw) rprintf(FERROR,"RSYNC_PASSWORD environment variable ignored\n");
|
||||
if (envpw)
|
||||
rprintf(FERROR, "RSYNC_PASSWORD environment variable ignored\n");
|
||||
|
||||
buffer[sizeof(buffer)-1]='\0';
|
||||
if (read(fd,buffer,sizeof(buffer)-1) > 0)
|
||||
{
|
||||
char *p = strtok(buffer,"\n\r");
|
||||
close(fd);
|
||||
if (p) p = strdup(p);
|
||||
return p;
|
||||
}
|
||||
n = read(fd, buffer, sizeof buffer - 1);
|
||||
close(fd);
|
||||
if (n > 0) {
|
||||
buffer[n] = '\0';
|
||||
if ((p = strtok(buffer, "\n\r")) != NULL)
|
||||
return strdup(p);
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
@@ -186,7 +199,7 @@ static void generate_hash(char *in, char *challenge, char *out)
|
||||
{
|
||||
char buf[16];
|
||||
|
||||
sum_init();
|
||||
sum_init(0);
|
||||
sum_update(in, strlen(in));
|
||||
sum_update(challenge, strlen(challenge));
|
||||
sum_end(buf);
|
||||
@@ -194,15 +207,12 @@ static void generate_hash(char *in, char *challenge, char *out)
|
||||
base64_encode(buf, 16, out);
|
||||
}
|
||||
|
||||
/* possible negotiate authentication with the client. Use "leader" to
|
||||
start off the auth if necessary
|
||||
|
||||
return NULL if authentication failed
|
||||
|
||||
return "" if anonymous access
|
||||
|
||||
otherwise return username
|
||||
*/
|
||||
/* Possibly negotiate authentication with the client. Use "leader" to
|
||||
* start off the auth if necessary.
|
||||
*
|
||||
* Return NULL if authentication failed. Return "" if anonymous access.
|
||||
* Otherwise return username.
|
||||
*/
|
||||
char *auth_server(int f_in, int f_out, int module, char *addr, char *leader)
|
||||
{
|
||||
char *users = lp_auth_users(module);
|
||||
@@ -216,46 +226,46 @@ char *auth_server(int f_in, int f_out, int module, char *addr, char *leader)
|
||||
char *tok;
|
||||
|
||||
/* if no auth list then allow anyone in! */
|
||||
if (!users || !*users) return "";
|
||||
if (!users || !*users)
|
||||
return "";
|
||||
|
||||
gen_challenge(addr, challenge);
|
||||
|
||||
|
||||
base64_encode(challenge, 16, b64_challenge);
|
||||
|
||||
io_printf(f_out, "%s%s\n", leader, b64_challenge);
|
||||
|
||||
if (!read_line(f_in, line, sizeof(line)-1)) {
|
||||
if (!read_line(f_in, line, sizeof line - 1))
|
||||
return NULL;
|
||||
}
|
||||
|
||||
memset(user, 0, sizeof(user));
|
||||
memset(pass, 0, sizeof(pass));
|
||||
memset(user, 0, sizeof user);
|
||||
memset(pass, 0, sizeof pass);
|
||||
|
||||
if (sscanf(line,"%99s %29s", user, pass) != 2) {
|
||||
if (sscanf(line,"%99s %29s", user, pass) != 2)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
users = strdup(users);
|
||||
if (!users) return NULL;
|
||||
if (!users)
|
||||
return NULL;
|
||||
|
||||
for (tok=strtok(users," ,\t"); tok; tok = strtok(NULL," ,\t")) {
|
||||
if (wildmatch(tok, user)) break;
|
||||
if (wildmatch(tok, user))
|
||||
break;
|
||||
}
|
||||
free(users);
|
||||
|
||||
if (!tok) {
|
||||
if (!tok)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
memset(secret, 0, sizeof(secret));
|
||||
if (!get_secret(module, user, secret, sizeof(secret)-1)) {
|
||||
memset(secret, 0, sizeof(secret));
|
||||
|
||||
memset(secret, 0, sizeof secret);
|
||||
if (!get_secret(module, user, secret, sizeof secret - 1)) {
|
||||
memset(secret, 0, sizeof secret);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
generate_hash(secret, b64_challenge, pass2);
|
||||
memset(secret, 0, sizeof(secret));
|
||||
|
||||
memset(secret, 0, sizeof secret);
|
||||
|
||||
if (strcmp(pass, pass2) == 0)
|
||||
return user;
|
||||
|
||||
@@ -267,12 +277,12 @@ void auth_client(int fd, char *user, char *challenge)
|
||||
{
|
||||
char *pass;
|
||||
char pass2[30];
|
||||
extern char *password_file;
|
||||
|
||||
if (!user || !*user)
|
||||
user = "nobody";
|
||||
|
||||
if (!(pass=getpassf(password_file)) && !(pass=getenv("RSYNC_PASSWORD"))) {
|
||||
if (!(pass = getpassf(password_file))
|
||||
&& !(pass = getenv("RSYNC_PASSWORD"))) {
|
||||
/* XXX: cyeoh says that getpass is deprecated, because
|
||||
* it may return a truncated password on some systems,
|
||||
* and it is not in the LSB.
|
||||
@@ -285,9 +295,8 @@ void auth_client(int fd, char *user, char *challenge)
|
||||
pass = getpass("Password: ");
|
||||
}
|
||||
|
||||
if (!pass || !*pass) {
|
||||
if (!pass)
|
||||
pass = "";
|
||||
}
|
||||
|
||||
generate_hash(pass, challenge, pass2);
|
||||
io_printf(fd, "%s %s\n", user, pass2);
|
||||
|
||||
115
backup.c
115
backup.c
@@ -33,22 +33,38 @@ extern int preserve_devices;
|
||||
extern int preserve_links;
|
||||
extern int preserve_hard_links;
|
||||
extern int orig_umask;
|
||||
extern int safe_symlinks;
|
||||
|
||||
/* make a complete pathname for backup file */
|
||||
char *get_backup_name(char *fname)
|
||||
{
|
||||
if (backup_dir) {
|
||||
if (stringjoin(backup_dir_buf + backup_dir_len, backup_dir_remainder,
|
||||
fname, backup_suffix, NULL) < backup_dir_remainder)
|
||||
return backup_dir_buf;
|
||||
} else {
|
||||
if (stringjoin(backup_dir_buf, MAXPATHLEN,
|
||||
fname, backup_suffix, NULL) < MAXPATHLEN)
|
||||
return backup_dir_buf;
|
||||
}
|
||||
|
||||
rprintf(FERROR, "backup filename too long\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* simple backup creates a backup with a suffix in the same directory */
|
||||
static int make_simple_backup(char *fname)
|
||||
{
|
||||
char fnamebak[MAXPATHLEN];
|
||||
char *fnamebak = get_backup_name(fname);
|
||||
|
||||
if (stringjoin(fnamebak, sizeof fnamebak, fname, backup_suffix, NULL)
|
||||
>= sizeof fnamebak) {
|
||||
rprintf(FERROR, "backup filename too long\n");
|
||||
if (!fnamebak)
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (do_rename(fname, fnamebak) != 0) {
|
||||
/* cygwin (at least version b19) reports EINVAL */
|
||||
if (errno != ENOENT && errno != EINVAL) {
|
||||
rsyserr(FERROR, errno, "rename %s to backup %s", fname, fnamebak);
|
||||
rsyserr(FERROR, errno,
|
||||
"rename %s to backup %s", fname, fnamebak);
|
||||
return 0;
|
||||
}
|
||||
} else if (verbose > 1) {
|
||||
@@ -83,9 +99,9 @@ static int make_bak_dir(char *fullpath)
|
||||
if (do_mkdir(fullpath, 0777 & ~orig_umask) == 0)
|
||||
break;
|
||||
if (errno != ENOENT) {
|
||||
rprintf(FERROR,
|
||||
"make_bak_dir mkdir %s failed: %s\n",
|
||||
full_fname(fullpath), strerror(errno));
|
||||
rsyserr(FERROR, errno,
|
||||
"make_bak_dir mkdir %s failed",
|
||||
full_fname(fullpath));
|
||||
goto failure;
|
||||
}
|
||||
}
|
||||
@@ -96,12 +112,11 @@ static int make_bak_dir(char *fullpath)
|
||||
if (p >= rel) {
|
||||
/* Try to transfer the directory settings of the
|
||||
* actual dir that the files are coming from. */
|
||||
if (do_lstat(rel, &st) != 0) {
|
||||
rprintf(FERROR,
|
||||
"make_bak_dir stat %s failed: %s\n",
|
||||
full_fname(rel), strerror(errno));
|
||||
if (do_stat(rel, &st) < 0) {
|
||||
rsyserr(FERROR, errno,
|
||||
"make_bak_dir stat %s failed",
|
||||
full_fname(rel));
|
||||
} else {
|
||||
set_modtime(fullpath, st.st_mtime);
|
||||
do_lchown(fullpath, st.st_uid, st.st_gid);
|
||||
do_chmod(fullpath, st.st_mode);
|
||||
}
|
||||
@@ -111,9 +126,8 @@ static int make_bak_dir(char *fullpath)
|
||||
if (p == end)
|
||||
break;
|
||||
if (do_mkdir(fullpath, 0777 & ~orig_umask) < 0) {
|
||||
rprintf(FERROR,
|
||||
"make_bak_dir mkdir %s failed: %s\n",
|
||||
full_fname(fullpath), strerror(errno));
|
||||
rsyserr(FERROR, errno, "make_bak_dir mkdir %s failed",
|
||||
full_fname(fullpath));
|
||||
goto failure;
|
||||
}
|
||||
}
|
||||
@@ -143,36 +157,34 @@ static int keep_backup(char *fname)
|
||||
{
|
||||
STRUCT_STAT st;
|
||||
struct file_struct *file;
|
||||
char *buf;
|
||||
int kept = 0;
|
||||
int ret_code;
|
||||
|
||||
/* return if no file to keep */
|
||||
#if SUPPORT_LINKS
|
||||
if (do_lstat(fname, &st)) return 1;
|
||||
ret_code = do_lstat(fname, &st);
|
||||
#else
|
||||
if (do_stat(fname, &st)) return 1;
|
||||
ret_code = do_stat(fname, &st);
|
||||
#endif
|
||||
if (ret_code < 0)
|
||||
return 1;
|
||||
|
||||
file = make_file(fname, NULL, NO_EXCLUDES);
|
||||
if (!(file = make_file(fname, NULL, NO_EXCLUDES)))
|
||||
return 1; /* the file could have disappeared */
|
||||
|
||||
/* the file could have disappeared */
|
||||
if (!file) return 1;
|
||||
|
||||
/* make a complete pathname for backup file */
|
||||
if (stringjoin(backup_dir_buf + backup_dir_len, backup_dir_remainder,
|
||||
fname, backup_suffix, NULL) >= backup_dir_remainder) {
|
||||
rprintf(FERROR, "keep_backup filename too long\n");
|
||||
if (!(buf = get_backup_name(fname)))
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef HAVE_MKNOD
|
||||
/* Check to see if this is a device file, or link */
|
||||
if (IS_DEVICE(file->mode)) {
|
||||
if (am_root && preserve_devices) {
|
||||
make_bak_dir(backup_dir_buf);
|
||||
if (do_mknod(backup_dir_buf, file->mode, file->u.rdev) != 0) {
|
||||
rprintf(FERROR, "mknod %s failed: %s\n",
|
||||
full_fname(backup_dir_buf), strerror(errno));
|
||||
if (do_mknod(buf, file->mode, file->u.rdev) < 0
|
||||
&& (errno != ENOENT || make_bak_dir(buf) < 0
|
||||
|| do_mknod(buf, file->mode, file->u.rdev) < 0)) {
|
||||
rsyserr(FERROR, errno, "mknod %s failed",
|
||||
full_fname(buf));
|
||||
} else if (verbose > 2) {
|
||||
rprintf(FINFO,
|
||||
"make_backup: DEVICE %s successful.\n",
|
||||
@@ -186,10 +198,14 @@ static int keep_backup(char *fname)
|
||||
|
||||
if (!kept && S_ISDIR(file->mode)) {
|
||||
/* make an empty directory */
|
||||
make_bak_dir(backup_dir_buf);
|
||||
do_mkdir(backup_dir_buf, file->mode);
|
||||
ret_code = do_rmdir(fname);
|
||||
if (do_mkdir(buf, file->mode) < 0
|
||||
&& (errno != ENOENT || make_bak_dir(buf) < 0
|
||||
|| do_mkdir(buf, file->mode) < 0)) {
|
||||
rsyserr(FINFO, errno, "mkdir %s failed",
|
||||
full_fname(buf));
|
||||
}
|
||||
|
||||
ret_code = do_rmdir(fname);
|
||||
if (verbose > 2) {
|
||||
rprintf(FINFO, "make_backup: RMDIR %s returns %i\n",
|
||||
full_fname(fname), ret_code);
|
||||
@@ -199,18 +215,18 @@ static int keep_backup(char *fname)
|
||||
|
||||
#if SUPPORT_LINKS
|
||||
if (!kept && preserve_links && S_ISLNK(file->mode)) {
|
||||
extern int safe_symlinks;
|
||||
if (safe_symlinks && unsafe_symlink(file->u.link, backup_dir_buf)) {
|
||||
if (safe_symlinks && unsafe_symlink(file->u.link, buf)) {
|
||||
if (verbose) {
|
||||
rprintf(FINFO, "ignoring unsafe symlink %s -> %s\n",
|
||||
full_fname(backup_dir_buf), file->u.link);
|
||||
full_fname(buf), file->u.link);
|
||||
}
|
||||
kept = 1;
|
||||
}
|
||||
make_bak_dir(backup_dir_buf);
|
||||
if (do_symlink(file->u.link, backup_dir_buf) != 0) {
|
||||
rprintf(FERROR, "link %s -> %s : %s\n",
|
||||
full_fname(backup_dir_buf), file->u.link, strerror(errno));
|
||||
if (do_symlink(file->u.link, buf) < 0
|
||||
&& (errno != ENOENT || make_bak_dir(buf) < 0
|
||||
|| do_symlink(file->u.link, buf) < 0)) {
|
||||
rsyserr(FERROR, errno, "link %s -> \"%s\"",
|
||||
full_fname(buf), file->u.link);
|
||||
}
|
||||
do_unlink(fname);
|
||||
kept = 1;
|
||||
@@ -220,20 +236,25 @@ static int keep_backup(char *fname)
|
||||
if (!kept && !S_ISREG(file->mode)) {
|
||||
rprintf(FINFO, "make_bak: skipping non-regular file %s\n",
|
||||
fname);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* move to keep tree if a file */
|
||||
if (!kept) {
|
||||
if (robust_move(fname, backup_dir_buf) != 0) {
|
||||
rprintf(FERROR, "keep_backup failed: %s -> \"%s\": %s\n",
|
||||
full_fname(fname), backup_dir_buf, strerror(errno));
|
||||
if (robust_move(fname, buf) != 0) {
|
||||
rsyserr(FERROR, errno, "keep_backup failed: %s -> \"%s\"",
|
||||
full_fname(fname), buf);
|
||||
} else if (st.st_nlink > 1) {
|
||||
/* If someone has hard-linked the file into the backup
|
||||
* dir, rename() might return success but do nothing! */
|
||||
robust_unlink(fname); /* Just in case... */
|
||||
}
|
||||
}
|
||||
set_perms(backup_dir_buf, file, NULL, 0);
|
||||
set_perms(buf, file, NULL, 0);
|
||||
free(file);
|
||||
|
||||
if (verbose > 1)
|
||||
rprintf(FINFO, "keep_backup %s -> %s\n", fname, backup_dir_buf);
|
||||
rprintf(FINFO, "backed up %s to %s\n", fname, buf);
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
448
batch.c
448
batch.c
@@ -8,329 +8,171 @@
|
||||
#include "rsync.h"
|
||||
#include <time.h>
|
||||
|
||||
extern char *batch_prefix;
|
||||
extern int csum_length;
|
||||
extern int protocol_version;
|
||||
extern struct stats stats;
|
||||
extern char *batch_name;
|
||||
extern int eol_nulls;
|
||||
extern int recurse;
|
||||
extern int preserve_links;
|
||||
extern int preserve_hard_links;
|
||||
extern int preserve_devices;
|
||||
extern int preserve_uid;
|
||||
extern int preserve_gid;
|
||||
extern int always_checksum;
|
||||
|
||||
struct file_list *batch_flist;
|
||||
extern struct exclude_list_struct exclude_list;
|
||||
|
||||
static char rsync_flist_file[] = ".rsync_flist";
|
||||
static char rsync_csums_file[] = ".rsync_csums";
|
||||
static char rsync_delta_file[] = ".rsync_delta";
|
||||
static char rsync_argvs_file[] = ".rsync_argvs";
|
||||
static int *flag_ptr[] = {
|
||||
&recurse,
|
||||
&preserve_uid,
|
||||
&preserve_gid,
|
||||
&preserve_links,
|
||||
&preserve_devices,
|
||||
&preserve_hard_links,
|
||||
&always_checksum,
|
||||
NULL
|
||||
};
|
||||
|
||||
static int f_csums = -1;
|
||||
static int f_delta = -1;
|
||||
static char *flag_name[] = {
|
||||
"--recurse (-r)",
|
||||
"--owner (-o)",
|
||||
"--group (-g)",
|
||||
"--links (-l)",
|
||||
"--devices (-D)",
|
||||
"--hard-links (-H)",
|
||||
"--checksum (-c)",
|
||||
NULL
|
||||
};
|
||||
|
||||
void write_batch_flist_info(int flist_count, struct file_struct **files)
|
||||
void write_stream_flags(int fd)
|
||||
{
|
||||
char filename[MAXPATHLEN];
|
||||
int i, f, save_pv;
|
||||
int64 save_written;
|
||||
int i, flags;
|
||||
|
||||
stringjoin(filename, sizeof filename,
|
||||
batch_prefix, rsync_flist_file, NULL);
|
||||
|
||||
f = do_open(filename, O_WRONLY | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR);
|
||||
if (f < 0) {
|
||||
rprintf(FERROR, "Batch file %s open error: %s\n",
|
||||
filename, strerror(errno));
|
||||
exit_cleanup(1);
|
||||
/* Start the batch file with a bitmap of data-stream-affecting
|
||||
* flags. */
|
||||
for (i = 0, flags = 0; flag_ptr[i]; i++) {
|
||||
if (*flag_ptr[i])
|
||||
flags |= 1 << i;
|
||||
}
|
||||
|
||||
save_written = stats.total_written;
|
||||
save_pv = protocol_version;
|
||||
protocol_version = PROTOCOL_VERSION;
|
||||
write_int(f, protocol_version);
|
||||
write_int(f, flist_count);
|
||||
|
||||
for (i = 0; i < flist_count; i++) {
|
||||
send_file_entry(files[i], f,
|
||||
files[i]->flags & FLAG_TOP_DIR ? XMIT_TOP_DIR : 0);
|
||||
}
|
||||
send_file_entry(NULL, f, 0);
|
||||
|
||||
protocol_version = save_pv;
|
||||
stats.total_written = save_written;
|
||||
|
||||
close(f);
|
||||
write_int(fd, flags);
|
||||
}
|
||||
|
||||
|
||||
void write_batch_argvs_file(int argc, char *argv[])
|
||||
void read_stream_flags(int fd)
|
||||
{
|
||||
int f;
|
||||
int i;
|
||||
char buff[256]; /* XXX */
|
||||
char buff2[MAXPATHLEN + 6];
|
||||
char filename[MAXPATHLEN];
|
||||
int i, flags;
|
||||
|
||||
for (i = 0, flags = read_int(fd); flag_ptr[i]; i++) {
|
||||
int set = flags & (1 << i) ? 1 : 0;
|
||||
if (*flag_ptr[i] != set) {
|
||||
if (verbose) {
|
||||
rprintf(FINFO,
|
||||
"%sing the %s option to match the batchfile.\n",
|
||||
set ? "Sett" : "Clear", flag_name[i]);
|
||||
}
|
||||
*flag_ptr[i] = set;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void write_arg(int fd, char *arg)
|
||||
{
|
||||
char *x, *s;
|
||||
|
||||
if (*arg == '-' && (x = strchr(arg, '=')) != NULL) {
|
||||
write(fd, arg, x - arg + 1);
|
||||
arg += x - arg + 1;
|
||||
}
|
||||
|
||||
if (strpbrk(arg, " \"'&;|[]()$#!*?^\\") != NULL) {
|
||||
write(fd, "'", 1);
|
||||
for (s = arg; (x = strchr(s, '\'')) != NULL; s = x + 1) {
|
||||
write(fd, s, x - s + 1);
|
||||
write(fd, "'", 1);
|
||||
}
|
||||
write(fd, s, strlen(s));
|
||||
write(fd, "'", 1);
|
||||
return;
|
||||
}
|
||||
|
||||
write(fd, arg, strlen(arg));
|
||||
}
|
||||
|
||||
static void write_excludes(int fd)
|
||||
{
|
||||
struct exclude_struct *ent;
|
||||
|
||||
write_sbuf(fd, " <<'#E#'\n");
|
||||
for (ent = exclude_list.head; ent; ent = ent->next) {
|
||||
char *p = ent->pattern;
|
||||
if (ent->match_flags & MATCHFLG_INCLUDE)
|
||||
write_buf(fd, "+ ", 2);
|
||||
else if (((*p == '-' || *p == '+') && p[1] == ' ')
|
||||
|| *p == '#' || *p == ';')
|
||||
write_buf(fd, "- ", 2);
|
||||
write_sbuf(fd, p);
|
||||
if (ent->match_flags & MATCHFLG_DIRECTORY)
|
||||
write_byte(fd, '/');
|
||||
write_byte(fd, eol_nulls ? 0 : '\n');
|
||||
}
|
||||
if (eol_nulls)
|
||||
write_sbuf(fd, ";\n");
|
||||
write_sbuf(fd, "#E#");
|
||||
}
|
||||
|
||||
/* 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)
|
||||
{
|
||||
int fd, i;
|
||||
char *p, filename[MAXPATHLEN];
|
||||
|
||||
stringjoin(filename, sizeof filename,
|
||||
batch_prefix, rsync_argvs_file, NULL);
|
||||
|
||||
f = do_open(filename, O_WRONLY | O_CREAT | O_TRUNC,
|
||||
S_IRUSR | S_IWUSR | S_IEXEC);
|
||||
if (f < 0) {
|
||||
rprintf(FERROR, "Batch file %s open error: %s\n",
|
||||
filename, strerror(errno));
|
||||
batch_name, ".sh", NULL);
|
||||
fd = do_open(filename, O_WRONLY | O_CREAT | O_TRUNC,
|
||||
S_IRUSR | S_IWUSR | S_IEXEC);
|
||||
if (fd < 0) {
|
||||
rsyserr(FERROR, errno, "Batch file %s open error", filename);
|
||||
exit_cleanup(1);
|
||||
}
|
||||
buff[0] = '\0';
|
||||
|
||||
/* Write argvs info to batch file */
|
||||
|
||||
for (i = 0; i < argc; ++i) {
|
||||
if (i == argc - 2) /* Skip source directory on cmdline */
|
||||
/* Write argvs info to BATCH.sh file */
|
||||
write_arg(fd, argv[0]);
|
||||
if (exclude_list.head)
|
||||
write_sbuf(fd, " --exclude-from=-");
|
||||
for (i = 1; i < argc - file_arg_cnt; i++) {
|
||||
p = argv[i];
|
||||
if (strncmp(p, "--files-from", 12) == 0
|
||||
|| strncmp(p, "--include", 9) == 0
|
||||
|| strncmp(p, "--exclude", 9) == 0) {
|
||||
if (strchr(p, '=') == NULL)
|
||||
i++;
|
||||
continue;
|
||||
/*
|
||||
* FIXME:
|
||||
* I think directly manipulating argv[] is probably bogus
|
||||
*/
|
||||
if (!strncmp(argv[i], "--write-batch",
|
||||
strlen("--write-batch"))) {
|
||||
/* Safer to change it here than script */
|
||||
/*
|
||||
* Change to --read-batch=prefix
|
||||
* to get ready for remote
|
||||
*/
|
||||
strlcat(buff, "--read-batch=", sizeof buff);
|
||||
strlcat(buff, batch_prefix, sizeof buff);
|
||||
}
|
||||
write(fd, " ", 1);
|
||||
if (strncmp(p, "--write-batch", 13) == 0) {
|
||||
write(fd, "--read-batch", 12);
|
||||
if (p[13] == '=') {
|
||||
write(fd, "=", 1);
|
||||
write_arg(fd, p + 14);
|
||||
}
|
||||
} else
|
||||
if (i == argc - 1) {
|
||||
snprintf(buff2, sizeof buff2, "${1:-%s}", argv[i]);
|
||||
strlcat(buff, buff2, sizeof buff);
|
||||
}
|
||||
else {
|
||||
strlcat(buff, argv[i], sizeof buff);
|
||||
}
|
||||
|
||||
if (i < (argc - 1)) {
|
||||
strlcat(buff, " ", sizeof buff);
|
||||
}
|
||||
write_arg(fd, p);
|
||||
}
|
||||
strlcat(buff, "\n", sizeof buff);
|
||||
if (!write(f, buff, strlen(buff))) {
|
||||
rprintf(FERROR, "Batch file %s write error: %s\n",
|
||||
filename, strerror(errno));
|
||||
close(f);
|
||||
if ((p = find_colon(argv[argc - 1])) != NULL) {
|
||||
if (*++p == ':')
|
||||
p++;
|
||||
} else
|
||||
p = argv[argc - 1];
|
||||
write(fd, " ${1:-", 6);
|
||||
write_arg(fd, p);
|
||||
write_byte(fd, '}');
|
||||
if (exclude_list.head)
|
||||
write_excludes(fd);
|
||||
if (write(fd, "\n", 1) != 1 || close(fd) < 0) {
|
||||
rsyserr(FERROR, errno, "Batch file %s write error", filename);
|
||||
exit_cleanup(1);
|
||||
}
|
||||
close(f);
|
||||
}
|
||||
|
||||
struct file_list *create_flist_from_batch(void)
|
||||
{
|
||||
char filename[MAXPATHLEN];
|
||||
unsigned short flags;
|
||||
int i, f, save_pv;
|
||||
int64 save_read;
|
||||
|
||||
stringjoin(filename, sizeof filename,
|
||||
batch_prefix, rsync_flist_file, NULL);
|
||||
|
||||
f = do_open(filename, O_RDONLY, 0);
|
||||
if (f < 0) {
|
||||
rprintf(FERROR, "Batch file %s open error: %s\n",
|
||||
filename, strerror(errno));
|
||||
exit_cleanup(1);
|
||||
}
|
||||
|
||||
batch_flist = flist_new(WITH_HLINK, "create_flist_from_batch");
|
||||
|
||||
save_read = stats.total_read;
|
||||
save_pv = protocol_version;
|
||||
protocol_version = read_int(f);
|
||||
|
||||
batch_flist->count = read_int(f);
|
||||
flist_expand(batch_flist);
|
||||
|
||||
for (i = 0; (flags = read_byte(f)) != 0; i++) {
|
||||
if (protocol_version >= 28 && (flags & XMIT_EXTENDED_FLAGS))
|
||||
flags |= read_byte(f) << 8;
|
||||
receive_file_entry(&batch_flist->files[i], flags, batch_flist, f);
|
||||
}
|
||||
receive_file_entry(NULL, 0, NULL, 0); /* Signal that we're done. */
|
||||
|
||||
protocol_version = save_pv;
|
||||
stats.total_read = save_read;
|
||||
|
||||
return batch_flist;
|
||||
}
|
||||
|
||||
void write_batch_csums_file(void *buff, int bytes_to_write)
|
||||
{
|
||||
if (write(f_csums, buff, bytes_to_write) < 0) {
|
||||
rprintf(FERROR, "Batch file write error: %s\n",
|
||||
strerror(errno));
|
||||
close(f_csums);
|
||||
exit_cleanup(1);
|
||||
}
|
||||
}
|
||||
|
||||
void close_batch_csums_file(void)
|
||||
{
|
||||
close(f_csums);
|
||||
f_csums = -1;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Write csum info to batch file
|
||||
*
|
||||
* @todo This will break if s->count is ever larger than maxint. The
|
||||
* batch code should probably be changed to consistently use the
|
||||
* variable-length integer routines, which is probably a compatible
|
||||
* change.
|
||||
**/
|
||||
void write_batch_csum_info(int *flist_entry, struct sum_struct *s)
|
||||
{
|
||||
size_t i;
|
||||
int int_count;
|
||||
char filename[MAXPATHLEN];
|
||||
|
||||
if (f_csums < 0) {
|
||||
stringjoin(filename, sizeof filename,
|
||||
batch_prefix, rsync_csums_file, NULL);
|
||||
|
||||
f_csums = do_open(filename, O_WRONLY | O_CREAT | O_TRUNC,
|
||||
S_IRUSR | S_IWUSR);
|
||||
if (f_csums < 0) {
|
||||
rprintf(FERROR, "Batch file %s open error: %s\n",
|
||||
filename, strerror(errno));
|
||||
close(f_csums);
|
||||
exit_cleanup(1);
|
||||
}
|
||||
}
|
||||
|
||||
write_batch_csums_file(flist_entry, sizeof (int));
|
||||
int_count = s ? (int) s->count : 0;
|
||||
write_batch_csums_file(&int_count, sizeof int_count);
|
||||
|
||||
if (s) {
|
||||
for (i = 0; i < s->count; i++) {
|
||||
write_batch_csums_file(&s->sums[i].sum1,
|
||||
sizeof (uint32));
|
||||
write_batch_csums_file(s->sums[i].sum2, csum_length);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int read_batch_csums_file(char *buff, int len)
|
||||
{
|
||||
int bytes_read;
|
||||
|
||||
if ((bytes_read = read(f_csums, buff, len)) < 0) {
|
||||
rprintf(FERROR, "Batch file read error: %s\n", strerror(errno));
|
||||
close(f_csums);
|
||||
exit_cleanup(1);
|
||||
}
|
||||
return bytes_read;
|
||||
}
|
||||
|
||||
void read_batch_csum_info(int flist_entry, struct sum_struct *s,
|
||||
int *checksums_match)
|
||||
{
|
||||
int i;
|
||||
int file_flist_entry;
|
||||
int file_chunk_ct;
|
||||
uint32 file_sum1;
|
||||
char file_sum2[SUM_LENGTH];
|
||||
char filename[MAXPATHLEN];
|
||||
|
||||
if (f_csums < 0) {
|
||||
stringjoin(filename, sizeof filename,
|
||||
batch_prefix, rsync_csums_file, NULL);
|
||||
|
||||
f_csums = do_open(filename, O_RDONLY, 0);
|
||||
if (f_csums < 0) {
|
||||
rprintf(FERROR, "Batch file %s open error: %s\n",
|
||||
filename, strerror(errno));
|
||||
close(f_csums);
|
||||
exit_cleanup(1);
|
||||
}
|
||||
}
|
||||
|
||||
read_batch_csums_file((char *) &file_flist_entry, sizeof (int));
|
||||
if (file_flist_entry != flist_entry) {
|
||||
rprintf(FINFO, "file_flist_entry (%d) != flist_entry (%d)\n",
|
||||
file_flist_entry, flist_entry);
|
||||
close(f_csums);
|
||||
exit_cleanup(1);
|
||||
|
||||
} else {
|
||||
read_batch_csums_file((char *) &file_chunk_ct, sizeof (int));
|
||||
*checksums_match = 1;
|
||||
for (i = 0; i < file_chunk_ct; i++) {
|
||||
read_batch_csums_file((char *) &file_sum1,
|
||||
sizeof (uint32));
|
||||
read_batch_csums_file(file_sum2, csum_length);
|
||||
|
||||
if ((s->sums[i].sum1 != file_sum1)
|
||||
|| memcmp(s->sums[i].sum2, file_sum2, csum_length))
|
||||
*checksums_match = 0;
|
||||
} /* end for */
|
||||
}
|
||||
}
|
||||
|
||||
void write_batch_delta_file(char *buff, int bytes_to_write)
|
||||
{
|
||||
char filename[MAXPATHLEN];
|
||||
|
||||
if (f_delta < 0) {
|
||||
stringjoin(filename, sizeof filename,
|
||||
batch_prefix, rsync_delta_file, NULL);
|
||||
|
||||
f_delta = do_open(filename, O_WRONLY | O_CREAT | O_TRUNC,
|
||||
S_IRUSR | S_IWUSR);
|
||||
if (f_delta < 0) {
|
||||
rprintf(FERROR, "Batch file %s open error: %s\n",
|
||||
filename, strerror(errno));
|
||||
exit_cleanup(1);
|
||||
}
|
||||
}
|
||||
|
||||
if (write(f_delta, buff, bytes_to_write) < 0) {
|
||||
rprintf(FERROR, "Batch file %s write error: %s\n",
|
||||
filename, strerror(errno));
|
||||
close(f_delta);
|
||||
exit_cleanup(1);
|
||||
}
|
||||
}
|
||||
|
||||
void close_batch_delta_file(void)
|
||||
{
|
||||
close(f_delta);
|
||||
f_delta = -1;
|
||||
}
|
||||
|
||||
int read_batch_delta_file(char *buff, int len)
|
||||
{
|
||||
int bytes_read;
|
||||
char filename[MAXPATHLEN];
|
||||
|
||||
if (f_delta < 0) {
|
||||
stringjoin(filename, sizeof filename,
|
||||
batch_prefix, rsync_delta_file, NULL);
|
||||
|
||||
f_delta = do_open(filename, O_RDONLY, 0);
|
||||
if (f_delta < 0) {
|
||||
rprintf(FERROR, "Batch file %s open error: %s\n",
|
||||
filename, strerror(errno));
|
||||
close(f_delta);
|
||||
exit_cleanup(1);
|
||||
}
|
||||
}
|
||||
|
||||
bytes_read = read(f_delta, buff, len);
|
||||
if (bytes_read < 0) {
|
||||
rprintf(FERROR, "Batch file %s read error: %s\n",
|
||||
filename, strerror(errno));
|
||||
close(f_delta);
|
||||
exit_cleanup(1);
|
||||
}
|
||||
|
||||
return bytes_read;
|
||||
}
|
||||
|
||||
void show_flist(int index, struct file_struct **fptr)
|
||||
|
||||
62
checksum.c
62
checksum.c
@@ -1,17 +1,17 @@
|
||||
/*
|
||||
/*
|
||||
Copyright (C) Andrew Tridgell 1996
|
||||
Copyright (C) Paul Mackerras 1996
|
||||
|
||||
|
||||
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 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
@@ -38,9 +38,9 @@ uint32 get_checksum1(char *buf1,int len)
|
||||
|
||||
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] +
|
||||
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);
|
||||
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;
|
||||
@@ -62,15 +62,15 @@ void get_checksum2(char *buf,int len,char *sum)
|
||||
len1 = len;
|
||||
if (!buf1) out_of_memory("get_checksum2");
|
||||
}
|
||||
|
||||
|
||||
mdfour_begin(&m);
|
||||
|
||||
|
||||
memcpy(buf1,buf,len);
|
||||
if (checksum_seed) {
|
||||
SIVAL(buf1,len,checksum_seed);
|
||||
len += 4;
|
||||
}
|
||||
|
||||
|
||||
for(i = 0; i + CSUM_CHUNK <= len; i += CSUM_CHUNK) {
|
||||
mdfour_update(&m, (uchar *)(buf1+i), CSUM_CHUNK);
|
||||
}
|
||||
@@ -83,7 +83,7 @@ void get_checksum2(char *buf,int len,char *sum)
|
||||
if (len - i > 0 || protocol_version >= 27) {
|
||||
mdfour_update(&m, (uchar *)(buf1+i), (len-i));
|
||||
}
|
||||
|
||||
|
||||
mdfour_result(&m, (uchar *)sum);
|
||||
}
|
||||
|
||||
@@ -94,35 +94,29 @@ void file_checksum(char *fname,char *sum,OFF_T size)
|
||||
struct map_struct *buf;
|
||||
int fd;
|
||||
OFF_T len = size;
|
||||
char tmpchunk[CSUM_CHUNK];
|
||||
struct mdfour m;
|
||||
|
||||
|
||||
memset(sum,0,MD4_SUM_LENGTH);
|
||||
|
||||
|
||||
fd = do_open(fname, O_RDONLY, 0);
|
||||
if (fd == -1) return;
|
||||
|
||||
buf = map_file(fd,size);
|
||||
|
||||
if (fd == -1)
|
||||
return;
|
||||
|
||||
buf = map_file(fd, size, MAX_MAP_SIZE, CSUM_CHUNK);
|
||||
|
||||
mdfour_begin(&m);
|
||||
|
||||
for(i = 0; i + CSUM_CHUNK <= len; i += CSUM_CHUNK) {
|
||||
memcpy(tmpchunk, map_ptr(buf,i,CSUM_CHUNK), CSUM_CHUNK);
|
||||
mdfour_update(&m, (uchar *)tmpchunk, CSUM_CHUNK);
|
||||
mdfour_update(&m, (uchar *)map_ptr(buf, i, CSUM_CHUNK),
|
||||
CSUM_CHUNK);
|
||||
}
|
||||
|
||||
/*
|
||||
* Prior to version 27 an incorrect MD4 checksum was computed
|
||||
/* 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.
|
||||
*/
|
||||
if (len - i > 0) {
|
||||
memcpy(tmpchunk, map_ptr(buf,i,len-i), len-i);
|
||||
}
|
||||
if (len - i > 0 || protocol_version >= 27) {
|
||||
mdfour_update(&m, (uchar *)tmpchunk, (len-i));
|
||||
}
|
||||
* even when there are no more bytes. */
|
||||
if (len - i > 0 || protocol_version >= 27)
|
||||
mdfour_update(&m, (uchar *)map_ptr(buf, i, len-i), len-i);
|
||||
|
||||
mdfour_result(&m, (uchar *)sum);
|
||||
|
||||
@@ -135,13 +129,13 @@ static int sumresidue;
|
||||
static char sumrbuf[CSUM_CHUNK];
|
||||
static struct mdfour md;
|
||||
|
||||
void sum_init(void)
|
||||
void sum_init(int seed)
|
||||
{
|
||||
char s[4];
|
||||
mdfour_begin(&md);
|
||||
sumresidue=0;
|
||||
SIVAL(s,0,checksum_seed);
|
||||
sum_update(s,4);
|
||||
sumresidue = 0;
|
||||
SIVAL(s, 0, seed);
|
||||
sum_update(s, 4);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -178,7 +172,7 @@ void sum_update(char *p, int len)
|
||||
sumresidue = len-i;
|
||||
memcpy(sumrbuf,p+i,sumresidue);
|
||||
} else {
|
||||
sumresidue = 0;
|
||||
sumresidue = 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
64
cleanup.c
64
cleanup.c
@@ -1,19 +1,19 @@
|
||||
/* -*- c-file-style: "linux" -*-
|
||||
|
||||
|
||||
Copyright (C) 1996-2000 by Andrew Tridgell
|
||||
Copyright (C) Paul Mackerras 1996
|
||||
Copyright (C) 2002 by Martin Pool
|
||||
|
||||
|
||||
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 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
@@ -21,6 +21,10 @@
|
||||
|
||||
#include "rsync.h"
|
||||
|
||||
extern int io_error;
|
||||
extern int keep_partial;
|
||||
extern int log_got_error;
|
||||
|
||||
/**
|
||||
* Close all open sockets and files, allowing a (somewhat) graceful
|
||||
* shutdown() of socket connections. This eliminates the abortive
|
||||
@@ -38,9 +42,8 @@ void close_all(void)
|
||||
for (fd = max_fd; fd >= 0; fd--) {
|
||||
ret = fstat(fd,&st);
|
||||
if (fstat(fd,&st) == 0) {
|
||||
if (is_a_socket(fd)) {
|
||||
if (is_a_socket(fd))
|
||||
ret = shutdown(fd, 2);
|
||||
}
|
||||
ret = close(fd);
|
||||
}
|
||||
}
|
||||
@@ -65,15 +68,13 @@ void close_all(void)
|
||||
* --partial is selected. We need to ensure that the partial file is
|
||||
* kept if any real data has been transferred.
|
||||
**/
|
||||
int cleanup_got_literal=0;
|
||||
int cleanup_got_literal = 0;
|
||||
|
||||
static char *cleanup_fname;
|
||||
static char *cleanup_new_fname;
|
||||
static struct file_struct *cleanup_file;
|
||||
static int cleanup_fd1, cleanup_fd2;
|
||||
static struct map_struct *cleanup_buf;
|
||||
static int cleanup_fd_r, cleanup_fd_w;
|
||||
static pid_t cleanup_pid = 0;
|
||||
extern int io_error;
|
||||
|
||||
pid_t cleanup_child_pid = -1;
|
||||
|
||||
@@ -85,8 +86,6 @@ pid_t cleanup_child_pid = -1;
|
||||
void _exit_cleanup(int code, const char *file, int line)
|
||||
{
|
||||
int ocode = code;
|
||||
extern int keep_partial;
|
||||
extern int log_got_error;
|
||||
static int inside_cleanup = 0;
|
||||
|
||||
if (inside_cleanup > 10) {
|
||||
@@ -98,37 +97,39 @@ void _exit_cleanup(int code, const char *file, int line)
|
||||
signal(SIGUSR1, SIG_IGN);
|
||||
signal(SIGUSR2, SIG_IGN);
|
||||
|
||||
if (verbose > 3)
|
||||
rprintf(FINFO,"_exit_cleanup(code=%d, file=%s, line=%d): entered\n",
|
||||
if (verbose > 3) {
|
||||
rprintf(FINFO,"_exit_cleanup(code=%d, file=%s, line=%d): entered\n",
|
||||
code, file, line);
|
||||
}
|
||||
|
||||
if (cleanup_child_pid != -1) {
|
||||
int status;
|
||||
if (waitpid(cleanup_child_pid, &status, WNOHANG) == cleanup_child_pid) {
|
||||
status = WEXITSTATUS(status);
|
||||
if (status > code) code = status;
|
||||
if (status > code)
|
||||
code = status;
|
||||
}
|
||||
}
|
||||
|
||||
if (cleanup_got_literal && cleanup_fname && keep_partial) {
|
||||
if (cleanup_got_literal && cleanup_fname && keep_partial
|
||||
&& handle_partial_dir(cleanup_new_fname, PDIR_CREATE)) {
|
||||
char *fname = cleanup_fname;
|
||||
cleanup_fname = NULL;
|
||||
if (cleanup_buf) unmap_file(cleanup_buf);
|
||||
if (cleanup_fd1 != -1) close(cleanup_fd1);
|
||||
if (cleanup_fd2 != -1) close(cleanup_fd2);
|
||||
finish_transfer(cleanup_new_fname, fname, cleanup_file);
|
||||
if (cleanup_fd_r != -1)
|
||||
close(cleanup_fd_r);
|
||||
if (cleanup_fd_w != -1)
|
||||
close(cleanup_fd_w);
|
||||
finish_transfer(cleanup_new_fname, fname, cleanup_file, 0);
|
||||
}
|
||||
io_flush(FULL_FLUSH);
|
||||
if (cleanup_fname)
|
||||
do_unlink(cleanup_fname);
|
||||
if (code) {
|
||||
if (code)
|
||||
kill_all(SIGUSR1);
|
||||
}
|
||||
if (cleanup_pid && cleanup_pid == getpid()) {
|
||||
char *pidf = lp_pid_file();
|
||||
if (pidf && *pidf) {
|
||||
if (pidf && *pidf)
|
||||
unlink(lp_pid_file());
|
||||
}
|
||||
}
|
||||
|
||||
if (code == 0) {
|
||||
@@ -138,11 +139,13 @@ void _exit_cleanup(int code, const char *file, int line)
|
||||
code = RERR_VANISHED;
|
||||
}
|
||||
|
||||
if (code) log_exit(code, file, line);
|
||||
if (code)
|
||||
log_exit(code, file, line);
|
||||
|
||||
if (verbose > 2)
|
||||
rprintf(FINFO,"_exit_cleanup(code=%d, file=%s, line=%d): about to call exit(%d)\n",
|
||||
if (verbose > 2) {
|
||||
rprintf(FINFO,"_exit_cleanup(code=%d, file=%s, line=%d): about to call exit(%d)\n",
|
||||
ocode, file, line, code);
|
||||
}
|
||||
|
||||
close_all();
|
||||
exit(code);
|
||||
@@ -156,14 +159,13 @@ void cleanup_disable(void)
|
||||
|
||||
|
||||
void cleanup_set(char *fnametmp, char *fname, struct file_struct *file,
|
||||
struct map_struct *buf, int fd1, int fd2)
|
||||
int fd_r, int fd_w)
|
||||
{
|
||||
cleanup_fname = fnametmp;
|
||||
cleanup_new_fname = fname;
|
||||
cleanup_file = file;
|
||||
cleanup_buf = buf;
|
||||
cleanup_fd1 = fd1;
|
||||
cleanup_fd2 = fd2;
|
||||
cleanup_fd_r = fd_r;
|
||||
cleanup_fd_w = fd_w;
|
||||
}
|
||||
|
||||
void cleanup_set_pid(pid_t pid)
|
||||
|
||||
61
clientname.c
61
clientname.c
@@ -43,12 +43,11 @@ extern int am_server;
|
||||
**/
|
||||
char *client_addr(int fd)
|
||||
{
|
||||
struct sockaddr_storage ss;
|
||||
socklen_t length = sizeof ss;
|
||||
char *ssh_client, *p;
|
||||
int len;
|
||||
static char addr_buf[100];
|
||||
static int initialised;
|
||||
struct sockaddr_storage ss;
|
||||
socklen_t length = sizeof ss;
|
||||
char *ssh_info, *p;
|
||||
|
||||
if (initialised)
|
||||
return addr_buf;
|
||||
@@ -57,14 +56,13 @@ char *client_addr(int fd)
|
||||
|
||||
if (am_server) { /* daemon over --rsh mode */
|
||||
strcpy(addr_buf, "0.0.0.0");
|
||||
if ((ssh_client = getenv("SSH_CLIENT")) != NULL) {
|
||||
/* truncate SSH_CLIENT to just IP address */
|
||||
if ((p = strchr(ssh_client, ' ')) != NULL) {
|
||||
len = MIN((unsigned int) (p - ssh_client),
|
||||
sizeof addr_buf - 1);
|
||||
strncpy(addr_buf, ssh_client, len);
|
||||
*(addr_buf + len) = '\0';
|
||||
}
|
||||
if ((ssh_info = getenv("SSH_CONNECTION")) != NULL
|
||||
|| (ssh_info = getenv("SSH_CLIENT")) != NULL
|
||||
|| (ssh_info = getenv("SSH2_CLIENT")) != NULL) {
|
||||
strlcpy(addr_buf, ssh_info, sizeof addr_buf);
|
||||
/* Truncate the value to just the IP address. */
|
||||
if ((p = strchr(addr_buf, ' ')) != NULL)
|
||||
*p = '\0';
|
||||
}
|
||||
} else {
|
||||
client_sockaddr(fd, &ss, &length);
|
||||
@@ -118,11 +116,13 @@ char *client_name(int fd)
|
||||
|
||||
memset(&hint, 0, sizeof hint);
|
||||
|
||||
#ifdef AI_NUMERICHOST
|
||||
hint.ai_flags = AI_NUMERICHOST;
|
||||
#endif
|
||||
hint.ai_socktype = SOCK_STREAM;
|
||||
|
||||
if ((err = getaddrinfo(addr, NULL, &hint, &answer)) != 0) {
|
||||
rprintf(FERROR, RSYNC_NAME ": malformed address %s: %s\n",
|
||||
rprintf(FLOG, "malformed address %s: %s\n",
|
||||
addr, gai_strerror(err));
|
||||
return name_buf;
|
||||
}
|
||||
@@ -145,8 +145,8 @@ char *client_name(int fd)
|
||||
client_sockaddr(fd, &ss, &ss_len);
|
||||
}
|
||||
|
||||
if (!lookup_name(fd, &ss, ss_len, name_buf, sizeof name_buf,
|
||||
port_buf, sizeof port_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);
|
||||
|
||||
return name_buf;
|
||||
@@ -168,8 +168,7 @@ void client_sockaddr(int fd,
|
||||
|
||||
if (getpeername(fd, (struct sockaddr *) ss, ss_len)) {
|
||||
/* FIXME: Can we really not continue? */
|
||||
rprintf(FERROR, RSYNC_NAME ": getpeername on fd%d failed: %s\n",
|
||||
fd, strerror(errno));
|
||||
rsyserr(FLOG, errno, "getpeername on fd%d failed", fd);
|
||||
exit_cleanup(RERR_SOCKETIO);
|
||||
}
|
||||
|
||||
@@ -224,9 +223,8 @@ int lookup_name(int fd, const struct sockaddr_storage *ss,
|
||||
NI_NAMEREQD | NI_NUMERICSERV);
|
||||
if (name_err != 0) {
|
||||
strcpy(name_buf, default_name);
|
||||
rprintf(FERROR, RSYNC_NAME ": name lookup failed for %s: %s\n",
|
||||
client_addr(fd),
|
||||
gai_strerror(name_err));
|
||||
rprintf(FLOG, "name lookup failed for %s: %s\n",
|
||||
client_addr(fd), gai_strerror(name_err));
|
||||
return name_err;
|
||||
}
|
||||
|
||||
@@ -247,8 +245,7 @@ int compare_addrinfo_sockaddr(const struct addrinfo *ai,
|
||||
const char fn[] = "compare_addrinfo_sockaddr";
|
||||
|
||||
if (ai->ai_family != ss_family) {
|
||||
rprintf(FERROR,
|
||||
"%s: response family %d != %d\n",
|
||||
rprintf(FLOG, "%s: response family %d != %d\n",
|
||||
fn, ai->ai_family, ss_family);
|
||||
return 1;
|
||||
}
|
||||
@@ -272,8 +269,7 @@ int compare_addrinfo_sockaddr(const struct addrinfo *ai,
|
||||
sin2 = (const struct sockaddr_in6 *) ai->ai_addr;
|
||||
|
||||
if (ai->ai_addrlen < sizeof (struct sockaddr_in6)) {
|
||||
rprintf(FERROR,
|
||||
"%s: too short sockaddr_in6; length=%d\n",
|
||||
rprintf(FLOG, "%s: too short sockaddr_in6; length=%d\n",
|
||||
fn, ai->ai_addrlen);
|
||||
return 1;
|
||||
}
|
||||
@@ -319,8 +315,7 @@ int check_name(int fd,
|
||||
hints.ai_socktype = SOCK_STREAM;
|
||||
error = getaddrinfo(name_buf, NULL, &hints, &res0);
|
||||
if (error) {
|
||||
rprintf(FERROR,
|
||||
RSYNC_NAME ": forward name lookup for %s failed: %s\n",
|
||||
rprintf(FLOG, "forward name lookup for %s failed: %s\n",
|
||||
name_buf, gai_strerror(error));
|
||||
strcpy(name_buf, default_name);
|
||||
return error;
|
||||
@@ -337,23 +332,17 @@ int check_name(int fd,
|
||||
if (!res0) {
|
||||
/* We hit the end of the list without finding an
|
||||
* address that was the same as ss. */
|
||||
rprintf(FERROR, RSYNC_NAME
|
||||
": no known address for \"%s\": "
|
||||
"spoofed address?\n",
|
||||
name_buf);
|
||||
rprintf(FLOG, "no known address for \"%s\": "
|
||||
"spoofed address?\n", name_buf);
|
||||
strcpy(name_buf, default_name);
|
||||
} else if (res == NULL) {
|
||||
/* We hit the end of the list without finding an
|
||||
* address that was the same as ss. */
|
||||
rprintf(FERROR, RSYNC_NAME
|
||||
": %s is not a known address for \"%s\": "
|
||||
"spoofed address?\n",
|
||||
client_addr(fd),
|
||||
name_buf);
|
||||
rprintf(FLOG, "%s is not a known address for \"%s\": "
|
||||
"spoofed address?\n", client_addr(fd), name_buf);
|
||||
strcpy(name_buf, default_name);
|
||||
}
|
||||
|
||||
freeaddrinfo(res0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
222
clientserver.c
222
clientserver.c
@@ -50,6 +50,7 @@ extern char *bind_address;
|
||||
extern struct exclude_list_struct server_exclude_list;
|
||||
extern char *exclude_path_prefix;
|
||||
extern char *config_file;
|
||||
extern char *files_from;
|
||||
|
||||
char *auth_user;
|
||||
|
||||
@@ -70,21 +71,21 @@ char *auth_user;
|
||||
int start_socket_client(char *host, char *path, int argc, char *argv[])
|
||||
{
|
||||
int fd, ret;
|
||||
char *p, *user=NULL;
|
||||
char *p, *user = NULL;
|
||||
|
||||
/* this is redundant with code in start_inband_exchange(), but
|
||||
* this short-circuits a problem before we open a socket, and
|
||||
* the extra check won't hurt */
|
||||
/* This is redundant with code in start_inband_exchange(), but this
|
||||
* short-circuits a problem in the client before we open a socket,
|
||||
* and the extra check won't hurt. */
|
||||
if (*path == '/') {
|
||||
rprintf(FERROR,"ERROR: The remote path must start with a module name not a /\n");
|
||||
rprintf(FERROR,
|
||||
"ERROR: The remote path must start with a module name not a /\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
p = strchr(host, '@');
|
||||
if (p) {
|
||||
if ((p = strchr(host, '@')) != NULL) {
|
||||
user = host;
|
||||
host = p+1;
|
||||
*p = 0;
|
||||
*p = '\0';
|
||||
}
|
||||
|
||||
fd = open_socket_out_wrapped(host, rsync_port, bind_address,
|
||||
@@ -97,7 +98,8 @@ int start_socket_client(char *host, char *path, int argc, char *argv[])
|
||||
return ret < 0? ret : client_run(fd, fd, -1, argc, argv);
|
||||
}
|
||||
|
||||
int start_inband_exchange(char *user, char *path, int f_in, int f_out, int argc)
|
||||
int start_inband_exchange(char *user, char *path, int f_in, int f_out,
|
||||
int argc)
|
||||
{
|
||||
int i;
|
||||
char *sargs[MAX_ARGS];
|
||||
@@ -109,12 +111,15 @@ int start_inband_exchange(char *user, char *path, int f_in, int f_out, int argc)
|
||||
list_only = 1;
|
||||
|
||||
if (*path == '/') {
|
||||
rprintf(FERROR, "ERROR: The remote path must start with a module name\n");
|
||||
rprintf(FERROR,
|
||||
"ERROR: The remote path must start with a module name\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (!user) user = getenv("USER");
|
||||
if (!user) user = getenv("LOGNAME");
|
||||
if (!user)
|
||||
user = getenv("USER");
|
||||
if (!user)
|
||||
user = getenv("LOGNAME");
|
||||
|
||||
/* set daemon_over_rsh to false since we need to build the
|
||||
* true set of args passed through the rsh/ssh connection;
|
||||
@@ -131,7 +136,7 @@ int start_inband_exchange(char *user, char *path, int f_in, int f_out, int argc)
|
||||
|
||||
io_printf(f_out, "@RSYNCD: %d\n", protocol_version);
|
||||
|
||||
if (!read_line(f_in, line, sizeof(line)-1)) {
|
||||
if (!read_line(f_in, line, sizeof line - 1)) {
|
||||
rprintf(FERROR, "rsync: did not see server greeting\n");
|
||||
return -1;
|
||||
}
|
||||
@@ -155,7 +160,7 @@ int start_inband_exchange(char *user, char *path, int f_in, int f_out, int argc)
|
||||
kludge_around_eof = list_only && (protocol_version < 25);
|
||||
|
||||
while (1) {
|
||||
if (!read_line(f_in, line, sizeof(line)-1)) {
|
||||
if (!read_line(f_in, line, sizeof line - 1)) {
|
||||
rprintf(FERROR, "rsync: didn't get server startup line\n");
|
||||
return -1;
|
||||
}
|
||||
@@ -165,7 +170,8 @@ int start_inband_exchange(char *user, char *path, int f_in, int f_out, int argc)
|
||||
continue;
|
||||
}
|
||||
|
||||
if (strcmp(line,"@RSYNCD: OK") == 0) break;
|
||||
if (strcmp(line,"@RSYNCD: OK") == 0)
|
||||
break;
|
||||
|
||||
if (strcmp(line,"@RSYNCD: EXIT") == 0) {
|
||||
/* This is sent by recent versions of the
|
||||
@@ -176,7 +182,7 @@ int start_inband_exchange(char *user, char *path, int f_in, int f_out, int argc)
|
||||
}
|
||||
|
||||
if (strncmp(line, "@ERROR", 6) == 0) {
|
||||
rprintf(FERROR,"%s\n", line);
|
||||
rprintf(FERROR, "%s\n", line);
|
||||
/* This is always fatal; the server will now
|
||||
* close the socket. */
|
||||
return RERR_STARTCLIENT;
|
||||
@@ -193,7 +199,7 @@ int start_inband_exchange(char *user, char *path, int f_in, int f_out, int argc)
|
||||
|
||||
if (protocol_version < 23) {
|
||||
if (protocol_version == 22 || !am_sender)
|
||||
io_start_multiplex_in(f_in);
|
||||
io_start_multiplex_in();
|
||||
}
|
||||
|
||||
return 0;
|
||||
@@ -203,8 +209,9 @@ int start_inband_exchange(char *user, char *path, int f_in, int f_out, int argc)
|
||||
|
||||
static int rsync_module(int f_in, int f_out, int i)
|
||||
{
|
||||
int argc=0;
|
||||
char *argv[MAX_ARGS];
|
||||
int argc = 0;
|
||||
int maxargs;
|
||||
char **argv;
|
||||
char **argp;
|
||||
char line[MAXPATHLEN];
|
||||
uid_t uid = (uid_t)-2; /* canonically "nobody" */
|
||||
@@ -214,31 +221,36 @@ static int rsync_module(int f_in, int f_out, int i)
|
||||
char *host = client_name(f_in);
|
||||
char *name = lp_name(i);
|
||||
int use_chroot = lp_use_chroot(i);
|
||||
int start_glob=0;
|
||||
int start_glob = 0;
|
||||
int ret;
|
||||
char *request=NULL;
|
||||
char *request = NULL;
|
||||
|
||||
if (!allow_access(addr, host, lp_hosts_allow(i), lp_hosts_deny(i))) {
|
||||
rprintf(FERROR,"rsync denied on module %s from %s (%s)\n",
|
||||
rprintf(FLOG, "rsync denied on module %s from %s (%s)\n",
|
||||
name, host, addr);
|
||||
io_printf(f_out, "@ERROR: access denied to %s from %s (%s)\n",
|
||||
name, host, addr);
|
||||
if (!lp_list(i))
|
||||
io_printf(f_out, "@ERROR: Unknown module '%s'\n", name);
|
||||
else {
|
||||
io_printf(f_out,
|
||||
"@ERROR: access denied to %s from %s (%s)\n",
|
||||
name, host, addr);
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (am_daemon && am_server) {
|
||||
rprintf(FINFO, "rsync allowed access on module %s from %s (%s)\n",
|
||||
rprintf(FLOG, "rsync allowed access on module %s from %s (%s)\n",
|
||||
name, host, addr);
|
||||
}
|
||||
|
||||
if (!claim_connection(lp_lock_file(i), lp_max_connections(i))) {
|
||||
if (errno) {
|
||||
rprintf(FERROR,"failed to open lock file %s : %s\n",
|
||||
lp_lock_file(i), strerror(errno));
|
||||
io_printf(f_out, "@ERROR: failed to open lock file %s : %s\n",
|
||||
lp_lock_file(i), strerror(errno));
|
||||
rsyserr(FLOG, errno, "failed to open lock file %s",
|
||||
lp_lock_file(i));
|
||||
io_printf(f_out, "@ERROR: failed to open lock file %s\n",
|
||||
lp_lock_file(i));
|
||||
} else {
|
||||
rprintf(FERROR,"max connections (%d) reached\n",
|
||||
rprintf(FLOG, "max connections (%d) reached\n",
|
||||
lp_max_connections(i));
|
||||
io_printf(f_out, "@ERROR: max connections (%d) reached - try again later\n",
|
||||
lp_max_connections(i));
|
||||
@@ -246,11 +258,10 @@ static int rsync_module(int f_in, int f_out, int i)
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
auth_user = auth_server(f_in, f_out, i, addr, "@RSYNCD: AUTHREQD ");
|
||||
|
||||
if (!auth_user) {
|
||||
rprintf(FERROR,"auth failed on module %s from %s (%s)\n",
|
||||
rprintf(FLOG, "auth failed on module %s from %s (%s)\n",
|
||||
name, host, addr);
|
||||
io_printf(f_out, "@ERROR: auth failed on module %s\n", name);
|
||||
return -1;
|
||||
@@ -263,8 +274,8 @@ static int rsync_module(int f_in, int f_out, int i)
|
||||
if (am_root) {
|
||||
p = lp_uid(i);
|
||||
if (!name_to_uid(p, &uid)) {
|
||||
if (!isdigit(* (unsigned char *) p)) {
|
||||
rprintf(FERROR,"Invalid uid %s\n", p);
|
||||
if (!isdigit(*(unsigned char *)p)) {
|
||||
rprintf(FLOG, "Invalid uid %s\n", p);
|
||||
io_printf(f_out, "@ERROR: invalid uid %s\n", p);
|
||||
return -1;
|
||||
}
|
||||
@@ -273,8 +284,8 @@ static int rsync_module(int f_in, int f_out, int i)
|
||||
|
||||
p = lp_gid(i);
|
||||
if (!name_to_gid(p, &gid)) {
|
||||
if (!isdigit(* (unsigned char *) p)) {
|
||||
rprintf(FERROR,"Invalid gid %s\n", p);
|
||||
if (!isdigit(*(unsigned char *)p)) {
|
||||
rprintf(FLOG, "Invalid gid %s\n", p);
|
||||
io_printf(f_out, "@ERROR: invalid gid %s\n", p);
|
||||
return -1;
|
||||
}
|
||||
@@ -326,20 +337,20 @@ static int rsync_module(int f_in, int f_out, int i)
|
||||
* in which case we fail.
|
||||
*/
|
||||
if (chroot(lp_path(i))) {
|
||||
rsyserr(FERROR, errno, "chroot %s failed", lp_path(i));
|
||||
rsyserr(FLOG, errno, "chroot %s failed", lp_path(i));
|
||||
io_printf(f_out, "@ERROR: chroot failed\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (!push_dir("/")) {
|
||||
rsyserr(FERROR, errno, "chdir %s failed\n", lp_path(i));
|
||||
rsyserr(FLOG, errno, "chdir %s failed\n", lp_path(i));
|
||||
io_printf(f_out, "@ERROR: chdir failed\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
} else {
|
||||
if (!push_dir(lp_path(i))) {
|
||||
rsyserr(FERROR, errno, "chdir %s failed\n", lp_path(i));
|
||||
rsyserr(FLOG, errno, "chdir %s failed\n", lp_path(i));
|
||||
io_printf(f_out, "@ERROR: chdir failed\n");
|
||||
return -1;
|
||||
}
|
||||
@@ -358,7 +369,7 @@ static int rsync_module(int f_in, int f_out, int i)
|
||||
* all their supplementary groups. */
|
||||
|
||||
if (setgid(gid)) {
|
||||
rsyserr(FERROR, errno, "setgid %d failed", (int) gid);
|
||||
rsyserr(FLOG, errno, "setgid %d failed", (int)gid);
|
||||
io_printf(f_out, "@ERROR: setgid failed\n");
|
||||
return -1;
|
||||
}
|
||||
@@ -366,14 +377,14 @@ static int rsync_module(int f_in, int f_out, int i)
|
||||
/* Get rid of any supplementary groups this process
|
||||
* might have inheristed. */
|
||||
if (setgroups(1, &gid)) {
|
||||
rsyserr(FERROR, errno, "setgroups failed");
|
||||
rsyserr(FLOG, errno, "setgroups failed");
|
||||
io_printf(f_out, "@ERROR: setgroups failed\n");
|
||||
return -1;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (setuid(uid)) {
|
||||
rsyserr(FERROR, errno, "setuid %d failed", (int) uid);
|
||||
rsyserr(FLOG, errno, "setuid %d failed", (int)uid);
|
||||
io_printf(f_out, "@ERROR: setuid failed\n");
|
||||
return -1;
|
||||
}
|
||||
@@ -383,39 +394,39 @@ static int rsync_module(int f_in, int f_out, int i)
|
||||
|
||||
io_printf(f_out, "@RSYNCD: OK\n");
|
||||
|
||||
maxargs = MAX_ARGS;
|
||||
if (!(argv = new_array(char *, maxargs)))
|
||||
out_of_memory("rsync_module");
|
||||
argv[argc++] = "rsyncd";
|
||||
|
||||
while (1) {
|
||||
if (!read_line(f_in, line, sizeof(line)-1)) {
|
||||
if (!read_line(f_in, line, sizeof line - 1))
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (!*line) break;
|
||||
if (!*line)
|
||||
break;
|
||||
|
||||
p = line;
|
||||
|
||||
argv[argc] = strdup(p);
|
||||
if (!argv[argc]) {
|
||||
return -1;
|
||||
if (argc == maxargs) {
|
||||
maxargs += MAX_ARGS;
|
||||
if (!(argv = realloc_array(argv, char *, maxargs)))
|
||||
out_of_memory("rsync_module");
|
||||
}
|
||||
if (!(argv[argc] = strdup(p)))
|
||||
out_of_memory("rsync_module");
|
||||
|
||||
if (start_glob) {
|
||||
if (start_glob == 1) {
|
||||
request = strdup(p);
|
||||
start_glob++;
|
||||
}
|
||||
glob_expand(name, argv, &argc, MAX_ARGS);
|
||||
} else {
|
||||
glob_expand(name, &argv, &argc, &maxargs);
|
||||
} else
|
||||
argc++;
|
||||
}
|
||||
|
||||
if (strcmp(line,".") == 0) {
|
||||
if (strcmp(line, ".") == 0)
|
||||
start_glob = 1;
|
||||
}
|
||||
|
||||
if (argc == MAX_ARGS) {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
argp = argv;
|
||||
@@ -426,12 +437,12 @@ static int rsync_module(int f_in, int f_out, int i)
|
||||
|
||||
if (request) {
|
||||
if (*auth_user) {
|
||||
rprintf(FINFO,"rsync %s %s from %s@%s (%s)\n",
|
||||
am_sender?"on":"to",
|
||||
rprintf(FLOG, "rsync %s %s from %s@%s (%s)\n",
|
||||
am_sender ? "on" : "to",
|
||||
request, auth_user, host, addr);
|
||||
} else {
|
||||
rprintf(FINFO,"rsync %s %s from %s (%s)\n",
|
||||
am_sender?"on":"to",
|
||||
rprintf(FLOG, "rsync %s %s from %s (%s)\n",
|
||||
am_sender ? "on" : "to",
|
||||
request, host, addr);
|
||||
}
|
||||
free(request);
|
||||
@@ -443,27 +454,27 @@ static int rsync_module(int f_in, int f_out, int i)
|
||||
verbose = lp_max_verbosity();
|
||||
#endif
|
||||
|
||||
if (protocol_version < 23) {
|
||||
if (protocol_version == 22 || am_sender)
|
||||
io_start_multiplex_out(f_out);
|
||||
if (protocol_version < 23
|
||||
&& (protocol_version == 22 || am_sender))
|
||||
io_start_multiplex_out();
|
||||
else if (!ret) {
|
||||
/* We have to get I/O multiplexing started so that we can
|
||||
* get the error back to the client. This means getting
|
||||
* the protocol setup finished first in later versions. */
|
||||
setup_protocol(f_out, f_in);
|
||||
if (files_from && !am_sender && strcmp(files_from, "-") != 0)
|
||||
write_byte(f_out, 0);
|
||||
io_start_multiplex_out();
|
||||
}
|
||||
|
||||
/* For later protocol versions, we don't start multiplexing
|
||||
* until we've configured nonblocking in start_server. That
|
||||
* means we're in a sticky situation now: there's no way to
|
||||
* convey errors to the client. */
|
||||
|
||||
/* FIXME: Hold off on reporting option processing errors until
|
||||
* we've set up nonblocking and multiplexed IO and can get the
|
||||
* message back to them. */
|
||||
if (!ret) {
|
||||
option_error();
|
||||
msleep(400);
|
||||
exit_cleanup(RERR_UNSUPPORTED);
|
||||
}
|
||||
|
||||
if (lp_timeout(i)) {
|
||||
if (lp_timeout(i))
|
||||
io_timeout = lp_timeout(i);
|
||||
}
|
||||
|
||||
start_server(f_in, f_out, argc, argp);
|
||||
|
||||
@@ -477,9 +488,10 @@ static void send_listing(int fd)
|
||||
int n = lp_numservices();
|
||||
int i;
|
||||
|
||||
for (i=0;i<n;i++)
|
||||
for (i = 0; i < n; i++) {
|
||||
if (lp_list(i))
|
||||
io_printf(fd, "%-15s\t%s\n", lp_name(i), lp_comment(i));
|
||||
}
|
||||
|
||||
if (protocol_version >= 25)
|
||||
io_printf(fd,"@RSYNCD: EXIT\n");
|
||||
@@ -492,11 +504,12 @@ int start_daemon(int f_in, int f_out)
|
||||
{
|
||||
char line[200];
|
||||
char *motd;
|
||||
int i = -1;
|
||||
int i;
|
||||
|
||||
if (!lp_load(config_file, 0)) {
|
||||
io_set_sock_fds(f_in, f_out);
|
||||
|
||||
if (!lp_load(config_file, 0))
|
||||
exit_cleanup(RERR_SYNTAX);
|
||||
}
|
||||
|
||||
log_init();
|
||||
|
||||
@@ -512,19 +525,19 @@ int start_daemon(int f_in, int f_out)
|
||||
if (motd && *motd) {
|
||||
FILE *f = fopen(motd,"r");
|
||||
while (f && !feof(f)) {
|
||||
int len = fread(line, 1, sizeof(line)-1, f);
|
||||
int len = fread(line, 1, sizeof line - 1, f);
|
||||
if (len > 0) {
|
||||
line[len] = 0;
|
||||
io_printf(f_out, "%s", line);
|
||||
}
|
||||
}
|
||||
if (f) fclose(f);
|
||||
if (f)
|
||||
fclose(f);
|
||||
io_printf(f_out, "\n");
|
||||
}
|
||||
|
||||
if (!read_line(f_in, line, sizeof(line)-1)) {
|
||||
if (!read_line(f_in, line, sizeof line - 1))
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (sscanf(line,"@RSYNCD: %d", &remote_protocol) != 1) {
|
||||
io_printf(f_out, "@ERROR: protocol startup error\n");
|
||||
@@ -533,28 +546,28 @@ int start_daemon(int f_in, int f_out)
|
||||
if (protocol_version > remote_protocol)
|
||||
protocol_version = remote_protocol;
|
||||
|
||||
while (i == -1) {
|
||||
line[0] = 0;
|
||||
if (!read_line(f_in, line, sizeof(line)-1)) {
|
||||
return -1;
|
||||
}
|
||||
line[0] = 0;
|
||||
if (!read_line(f_in, line, sizeof line - 1))
|
||||
return -1;
|
||||
|
||||
if (!*line || strcmp(line,"#list")==0) {
|
||||
send_listing(f_out);
|
||||
return -1;
|
||||
}
|
||||
if (!*line || strcmp(line, "#list") == 0) {
|
||||
send_listing(f_out);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (*line == '#') {
|
||||
/* it's some sort of command that I don't understand */
|
||||
io_printf(f_out, "@ERROR: Unknown command '%s'\n", line);
|
||||
return -1;
|
||||
}
|
||||
if (*line == '#') {
|
||||
/* it's some sort of command that I don't understand */
|
||||
io_printf(f_out, "@ERROR: Unknown command '%s'\n", line);
|
||||
return -1;
|
||||
}
|
||||
|
||||
i = lp_number(line);
|
||||
if (i == -1) {
|
||||
io_printf(f_out, "@ERROR: Unknown module '%s'\n", line);
|
||||
return -1;
|
||||
}
|
||||
if ((i = lp_number(line)) < 0) {
|
||||
char *addr = client_addr(f_in);
|
||||
char *host = client_name(f_in);
|
||||
rprintf(FLOG, "unknown module '%s' tried from %s (%s)\n",
|
||||
line, host, addr);
|
||||
io_printf(f_out, "@ERROR: Unknown module '%s'\n", line);
|
||||
return -1;
|
||||
}
|
||||
|
||||
return rsync_module(f_in, f_out, i);
|
||||
@@ -571,7 +584,7 @@ int daemon_main(void)
|
||||
/* we are running via inetd - close off stdout and
|
||||
* stderr so that library functions (and getopt) don't
|
||||
* try to use them. Redirect them to /dev/null */
|
||||
for (i=1;i<3;i++) {
|
||||
for (i = 1; i < 3; i++) {
|
||||
close(i);
|
||||
open("/dev/null", O_RDWR);
|
||||
}
|
||||
@@ -582,13 +595,12 @@ int daemon_main(void)
|
||||
if (!no_detach)
|
||||
become_daemon();
|
||||
|
||||
if (!lp_load(config_file, 1)) {
|
||||
if (!lp_load(config_file, 1))
|
||||
exit_cleanup(RERR_SYNTAX);
|
||||
}
|
||||
|
||||
log_init();
|
||||
|
||||
rprintf(FINFO, "rsyncd version %s starting, listening on port %d\n",
|
||||
rprintf(FLOG, "rsyncd version %s starting, listening on port %d\n",
|
||||
RSYNC_VERSION, rsync_port);
|
||||
/* TODO: If listening on a particular address, then show that
|
||||
* address too. In fact, why not just do inet_ntop on the
|
||||
|
||||
31
compat.c
31
compat.c
@@ -27,36 +27,27 @@
|
||||
|
||||
int remote_protocol = 0;
|
||||
|
||||
extern int am_server;
|
||||
|
||||
extern int preserve_links;
|
||||
extern int preserve_perms;
|
||||
extern int preserve_devices;
|
||||
extern int preserve_uid;
|
||||
extern int preserve_gid;
|
||||
extern int preserve_times;
|
||||
extern int always_checksum;
|
||||
extern int checksum_seed;
|
||||
|
||||
extern int protocol_version;
|
||||
extern int verbose;
|
||||
|
||||
extern int am_server;
|
||||
extern int am_sender;
|
||||
extern int read_batch;
|
||||
extern int write_batch;
|
||||
extern int checksum_seed;
|
||||
extern int protocol_version;
|
||||
|
||||
void setup_protocol(int f_out,int f_in)
|
||||
{
|
||||
if (remote_protocol == 0) {
|
||||
if (am_server) {
|
||||
remote_protocol = read_int(f_in);
|
||||
if (!read_batch)
|
||||
write_int(f_out, protocol_version);
|
||||
} else {
|
||||
write_int(f_out, protocol_version);
|
||||
remote_protocol = read_int(f_in);
|
||||
}
|
||||
remote_protocol = read_int(f_in);
|
||||
if (protocol_version > remote_protocol)
|
||||
protocol_version = remote_protocol;
|
||||
}
|
||||
if (read_batch && remote_protocol > protocol_version) {
|
||||
rprintf(FERROR, "The protocol version in the batch file is too new (%d > %d).\n",
|
||||
remote_protocol, protocol_version);
|
||||
exit_cleanup(RERR_PROTOCOL);
|
||||
}
|
||||
|
||||
if (verbose > 3) {
|
||||
rprintf(FINFO, "(%s) Protocol versions: remote=%d, negotiated=%d\n",
|
||||
|
||||
32
configure.in
32
configure.in
@@ -5,7 +5,7 @@ AC_CONFIG_SRCDIR([byteorder.h])
|
||||
AC_CONFIG_HEADER(config.h)
|
||||
AC_PREREQ(2.52)
|
||||
|
||||
RSYNC_VERSION=2.6.1
|
||||
RSYNC_VERSION=2.6.3
|
||||
AC_SUBST(RSYNC_VERSION)
|
||||
AC_MSG_NOTICE([Configuring rsync $RSYNC_VERSION])
|
||||
|
||||
@@ -146,21 +146,26 @@ AC_TRY_RUN([
|
||||
int main(void)
|
||||
{
|
||||
struct flock lock;
|
||||
int status;
|
||||
int fd = open("conftest.dat", O_CREAT|O_RDWR, 0600);
|
||||
int status;
|
||||
char tpl[32] = "/tmp/locktest.XXXXXX";
|
||||
int fd = mkstemp(tpl);
|
||||
if (fd < 0) {
|
||||
strcpy(tpl, "conftest.dat");
|
||||
fd = open(tpl, O_CREAT|O_RDWR, 0600);
|
||||
}
|
||||
|
||||
lock.l_type = F_WRLCK;
|
||||
lock.l_whence = SEEK_SET;
|
||||
lock.l_start = 0;
|
||||
lock.l_len = 1;
|
||||
lock.l_pid = 0;
|
||||
|
||||
fcntl(fd,F_SETLK,&lock);
|
||||
if (fork() == 0) {
|
||||
lock.l_start = 1;
|
||||
exit(fcntl(fd,F_SETLK,&lock) == 0);
|
||||
}
|
||||
wait(&status);
|
||||
unlink("conftest.dat");
|
||||
lock.l_start = 1;
|
||||
_exit(fcntl(fd,F_SETLK,&lock) == 0);
|
||||
}
|
||||
wait(&status);
|
||||
unlink(tpl);
|
||||
exit(WEXITSTATUS(status));
|
||||
}
|
||||
],
|
||||
@@ -282,7 +287,7 @@ AC_HEADER_SYS_WAIT
|
||||
AC_CHECK_HEADERS(sys/fcntl.h sys/select.h fcntl.h sys/time.h sys/unistd.h \
|
||||
unistd.h utime.h grp.h compat.h sys/param.h ctype.h sys/wait.h \
|
||||
sys/ioctl.h sys/filio.h string.h stdlib.h sys/socket.h sys/mode.h \
|
||||
sys/un.h glob.h mcheck.h sys/sysctl.h arpa/inet.h arpa/nameser.h \
|
||||
sys/un.h glob.h mcheck.h arpa/inet.h arpa/nameser.h \
|
||||
netdb.h malloc.h float.h)
|
||||
AC_HEADER_MAJOR
|
||||
|
||||
@@ -437,9 +442,10 @@ dnl AC_FUNC_MEMCMP
|
||||
AC_FUNC_UTIME_NULL
|
||||
AC_FUNC_ALLOCA
|
||||
AC_CHECK_FUNCS(waitpid wait4 getcwd strdup strerror chown chmod mknod mkfifo \
|
||||
fchmod fstat strchr readlink link utime utimes strftime mtrace \
|
||||
fchmod fstat strchr readlink link utime utimes strftime mtrace ftruncate \
|
||||
memmove lchown vsnprintf snprintf asprintf setsid glob strpbrk \
|
||||
strlcat strlcpy strtol mallinfo getgroups setgroups geteuid getegid)
|
||||
strlcat strlcpy strtol mallinfo getgroups setgroups geteuid getegid \
|
||||
open64 mkstemp64)
|
||||
|
||||
AC_CACHE_CHECK([for working socketpair],rsync_cv_HAVE_SOCKETPAIR,[
|
||||
AC_TRY_RUN([
|
||||
@@ -537,7 +543,7 @@ AC_TRY_RUN([
|
||||
#include <unistd.h>
|
||||
main() { struct timeval tv; exit(gettimeofday(&tv, NULL));}],
|
||||
rsync_cv_HAVE_GETTIMEOFDAY_TZ=yes,rsync_cv_HAVE_GETTIMEOFDAY_TZ=no,rsync_cv_HAVE_GETTIMEOFDAY_TZ=cross)])
|
||||
if test x"$rsync_cv_HAVE_GETTIMEOFDAY_TZ" = x"yes"; then
|
||||
if test x"$rsync_cv_HAVE_GETTIMEOFDAY_TZ" != x"no"; then
|
||||
AC_DEFINE(HAVE_GETTIMEOFDAY_TZ, 1, [ ])
|
||||
fi
|
||||
|
||||
|
||||
131
exclude.c
131
exclude.c
@@ -38,24 +38,23 @@ struct exclude_list_struct local_exclude_list = { 0, 0, "per-dir .cvsignore " };
|
||||
struct exclude_list_struct server_exclude_list = { 0, 0, "server " };
|
||||
char *exclude_path_prefix = NULL;
|
||||
|
||||
/** Build an exclude structure given a exclude pattern */
|
||||
static void make_exclude(struct exclude_list_struct *listp, const char *pattern,
|
||||
int pat_len, int include)
|
||||
/** Build an exclude structure given an exclude pattern. */
|
||||
static void make_exclude(struct exclude_list_struct *listp, const char *pat,
|
||||
unsigned int pat_len, unsigned int mflags)
|
||||
{
|
||||
struct exclude_struct *ret;
|
||||
const char *cp;
|
||||
int ex_len;
|
||||
unsigned int ex_len;
|
||||
|
||||
ret = new(struct exclude_struct);
|
||||
if (!ret)
|
||||
out_of_memory("make_exclude");
|
||||
|
||||
memset(ret, 0, sizeof ret[0]);
|
||||
ret->include = include;
|
||||
|
||||
if (exclude_path_prefix)
|
||||
ret->match_flags |= MATCHFLG_ABS_PATH;
|
||||
if (exclude_path_prefix && *pattern == '/')
|
||||
mflags |= MATCHFLG_ABS_PATH;
|
||||
if (exclude_path_prefix && *pat == '/')
|
||||
ex_len = strlen(exclude_path_prefix);
|
||||
else
|
||||
ex_len = 0;
|
||||
@@ -64,27 +63,29 @@ static void make_exclude(struct exclude_list_struct *listp, const char *pattern,
|
||||
out_of_memory("make_exclude");
|
||||
if (ex_len)
|
||||
memcpy(ret->pattern, exclude_path_prefix, ex_len);
|
||||
strlcpy(ret->pattern + ex_len, pattern, pat_len + 1);
|
||||
strlcpy(ret->pattern + ex_len, pat, pat_len + 1);
|
||||
pat_len += ex_len;
|
||||
|
||||
if (strpbrk(ret->pattern, "*[?")) {
|
||||
ret->match_flags |= MATCHFLG_WILD;
|
||||
mflags |= MATCHFLG_WILD;
|
||||
if ((cp = strstr(ret->pattern, "**")) != NULL) {
|
||||
ret->match_flags |= MATCHFLG_WILD2;
|
||||
mflags |= MATCHFLG_WILD2;
|
||||
/* If the pattern starts with **, note that. */
|
||||
if (cp == ret->pattern)
|
||||
ret->match_flags |= MATCHFLG_WILD2_PREFIX;
|
||||
mflags |= MATCHFLG_WILD2_PREFIX;
|
||||
}
|
||||
}
|
||||
|
||||
if (pat_len > 1 && ret->pattern[pat_len-1] == '/') {
|
||||
ret->pattern[pat_len-1] = 0;
|
||||
ret->directory = 1;
|
||||
mflags |= MATCHFLG_DIRECTORY;
|
||||
}
|
||||
|
||||
for (cp = ret->pattern; (cp = strchr(cp, '/')) != NULL; cp++)
|
||||
ret->slash_cnt++;
|
||||
|
||||
ret->match_flags = mflags;
|
||||
|
||||
if (!listp->tail)
|
||||
listp->head = listp->tail = ret;
|
||||
else {
|
||||
@@ -99,15 +100,10 @@ static void free_exclude(struct exclude_struct *ex)
|
||||
free(ex);
|
||||
}
|
||||
|
||||
void free_exclude_list(struct exclude_list_struct *listp)
|
||||
void clear_exclude_list(struct exclude_list_struct *listp)
|
||||
{
|
||||
struct exclude_struct *ent, *next;
|
||||
|
||||
if (verbose > 2) {
|
||||
rprintf(FINFO, "[%s] clearing %sexclude list\n",
|
||||
who_am_i(), listp->debug_type);
|
||||
}
|
||||
|
||||
for (ent = listp->head; ent; ent = next) {
|
||||
next = ent->next;
|
||||
free_exclude(ent);
|
||||
@@ -119,10 +115,13 @@ void free_exclude_list(struct exclude_list_struct *listp)
|
||||
static int check_one_exclude(char *name, struct exclude_struct *ex,
|
||||
int name_is_dir)
|
||||
{
|
||||
char *p;
|
||||
char *p, full_name[MAXPATHLEN];
|
||||
int match_start = 0;
|
||||
char *pattern = ex->pattern;
|
||||
|
||||
if (!*name)
|
||||
return 0;
|
||||
|
||||
/* If the pattern does not have any slashes AND it does not have
|
||||
* a "**" (which could match a slash), then we just match the
|
||||
* name portion of the path. */
|
||||
@@ -130,16 +129,14 @@ static int check_one_exclude(char *name, struct exclude_struct *ex,
|
||||
if ((p = strrchr(name,'/')) != NULL)
|
||||
name = p+1;
|
||||
}
|
||||
else if ((ex->match_flags & MATCHFLG_ABS_PATH) && *name != '/') {
|
||||
static char full_name[MAXPATHLEN];
|
||||
int plus = curr_dir[1] == '\0'? 1 : 0;
|
||||
pathjoin(full_name, sizeof full_name, curr_dir+plus, name);
|
||||
else if (ex->match_flags & MATCHFLG_ABS_PATH && *name != '/'
|
||||
&& curr_dir[1]) {
|
||||
pathjoin(full_name, sizeof full_name, curr_dir + 1, name);
|
||||
name = full_name;
|
||||
}
|
||||
|
||||
if (!name[0]) return 0;
|
||||
|
||||
if (ex->directory && !name_is_dir) return 0;
|
||||
if (ex->match_flags & MATCHFLG_DIRECTORY && !name_is_dir)
|
||||
return 0;
|
||||
|
||||
if (*pattern == '/') {
|
||||
match_start = 1;
|
||||
@@ -151,8 +148,8 @@ static int check_one_exclude(char *name, struct exclude_struct *ex,
|
||||
if (ex->match_flags & MATCHFLG_WILD) {
|
||||
/* A non-anchored match with an infix slash and no "**"
|
||||
* needs to match the last slash_cnt+1 name elements. */
|
||||
if (!match_start && ex->slash_cnt &&
|
||||
!(ex->match_flags & MATCHFLG_WILD2)) {
|
||||
if (!match_start && ex->slash_cnt
|
||||
&& !(ex->match_flags & MATCHFLG_WILD2)) {
|
||||
int cnt = ex->slash_cnt + 1;
|
||||
for (p = name + strlen(name) - 1; p >= name; p--) {
|
||||
if (*p == '/' && !--cnt)
|
||||
@@ -206,9 +203,11 @@ static void report_exclude_result(char const *name,
|
||||
|
||||
if (verbose >= 2) {
|
||||
rprintf(FINFO, "[%s] %scluding %s %s because of %spattern %s%s\n",
|
||||
who_am_i(), ent->include ? "in" : "ex",
|
||||
who_am_i(),
|
||||
ent->match_flags & MATCHFLG_INCLUDE ? "in" : "ex",
|
||||
name_is_dir ? "directory" : "file", name, type,
|
||||
ent->pattern, ent->directory ? "/" : "");
|
||||
ent->pattern,
|
||||
ent->match_flags & MATCHFLG_DIRECTORY ? "/" : "");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -225,7 +224,7 @@ int check_exclude(struct exclude_list_struct *listp, char *name, int name_is_dir
|
||||
if (check_one_exclude(name, ent, name_is_dir)) {
|
||||
report_exclude_result(name, ent, name_is_dir,
|
||||
listp->debug_type);
|
||||
return ent->include ? 1 : -1;
|
||||
return ent->match_flags & MATCHFLG_INCLUDE ? 1 : -1;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -236,16 +235,15 @@ int check_exclude(struct exclude_list_struct *listp, char *name, int name_is_dir
|
||||
/* Get the next include/exclude arg from the string. The token will not
|
||||
* be '\0' terminated, so use the returned length to limit the string.
|
||||
* Also, be sure to add this length to the returned pointer before passing
|
||||
* it back to ask for the next token. This routine will not parse the +/-
|
||||
* prefixes or the "!" token when xflags contains XFLG_WORDS_ONLY. The
|
||||
* *incl_ptr value will be 1 for an include, 0 for an exclude, and -1 for
|
||||
* the list-clearing "!" token.
|
||||
* it back to ask for the next token. This routine parses the +/- prefixes
|
||||
* and the "!" token unless xflags contains XFLG_WORDS_ONLY. The *flag_ptr
|
||||
* value will also be set to the MATCHFLG_* bits for the current token.
|
||||
*/
|
||||
static const char *get_exclude_tok(const char *p, int *len_ptr, int *incl_ptr,
|
||||
int xflags)
|
||||
static const char *get_exclude_tok(const char *p, unsigned int *len_ptr,
|
||||
unsigned int *flag_ptr, int xflags)
|
||||
{
|
||||
const unsigned char *s = (const unsigned char *)p;
|
||||
int len;
|
||||
unsigned int len, mflags = 0;
|
||||
|
||||
if (xflags & XFLG_WORD_SPLIT) {
|
||||
/* Skip over any initial whitespace. */
|
||||
@@ -258,10 +256,13 @@ static const char *get_exclude_tok(const char *p, int *len_ptr, int *incl_ptr,
|
||||
/* Is this a '+' or '-' followed by a space (not whitespace)? */
|
||||
if (!(xflags & XFLG_WORDS_ONLY)
|
||||
&& (*s == '-' || *s == '+') && s[1] == ' ') {
|
||||
*incl_ptr = *s == '+';
|
||||
if (*s == '+')
|
||||
mflags |= MATCHFLG_INCLUDE;
|
||||
s += 2;
|
||||
} else
|
||||
*incl_ptr = xflags & XFLG_DEF_INCLUDE;
|
||||
} else if (xflags & XFLG_DEF_INCLUDE)
|
||||
mflags |= MATCHFLG_INCLUDE;
|
||||
if (xflags & XFLG_DIRECTORY)
|
||||
mflags |= MATCHFLG_DIRECTORY;
|
||||
|
||||
if (xflags & XFLG_WORD_SPLIT) {
|
||||
const unsigned char *cp = s;
|
||||
@@ -273,9 +274,10 @@ static const char *get_exclude_tok(const char *p, int *len_ptr, int *incl_ptr,
|
||||
len = strlen(s);
|
||||
|
||||
if (*p == '!' && len == 1 && !(xflags & XFLG_WORDS_ONLY))
|
||||
*incl_ptr = -1;
|
||||
mflags |= MATCHFLG_CLEAR_LIST;
|
||||
|
||||
*len_ptr = len;
|
||||
*flag_ptr = mflags;
|
||||
return (const char *)s;
|
||||
}
|
||||
|
||||
@@ -283,7 +285,7 @@ static const char *get_exclude_tok(const char *p, int *len_ptr, int *incl_ptr,
|
||||
void add_exclude(struct exclude_list_struct *listp, const char *pattern,
|
||||
int xflags)
|
||||
{
|
||||
int pat_len, incl;
|
||||
unsigned int pat_len, mflags;
|
||||
const char *cp;
|
||||
|
||||
if (!pattern)
|
||||
@@ -292,21 +294,26 @@ void add_exclude(struct exclude_list_struct *listp, const char *pattern,
|
||||
cp = pattern;
|
||||
pat_len = 0;
|
||||
while (1) {
|
||||
cp = get_exclude_tok(cp + pat_len, &pat_len, &incl, xflags);
|
||||
cp = get_exclude_tok(cp + pat_len, &pat_len, &mflags, xflags);
|
||||
if (!pat_len)
|
||||
break;
|
||||
/* If we got the special "!" token, clear the list. */
|
||||
if (incl < 0)
|
||||
free_exclude_list(listp);
|
||||
else {
|
||||
make_exclude(listp, cp, pat_len, incl);
|
||||
|
||||
if (mflags & MATCHFLG_CLEAR_LIST) {
|
||||
if (verbose > 2) {
|
||||
rprintf(FINFO, "[%s] add_exclude(%.*s, %s%s)\n",
|
||||
who_am_i(), pat_len, cp,
|
||||
listp->debug_type,
|
||||
incl ? "include" : "exclude");
|
||||
rprintf(FINFO,
|
||||
"[%s] clearing %sexclude list\n",
|
||||
who_am_i(), listp->debug_type);
|
||||
}
|
||||
clear_exclude_list(listp);
|
||||
continue;
|
||||
}
|
||||
|
||||
make_exclude(listp, cp, pat_len, mflags);
|
||||
|
||||
if (verbose > 2) {
|
||||
rprintf(FINFO, "[%s] add_exclude(%.*s, %s%sclude)\n",
|
||||
who_am_i(), (int)pat_len, cp, listp->debug_type,
|
||||
mflags & MATCHFLG_INCLUDE ? "in" : "ex");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -316,8 +323,8 @@ void add_exclude_file(struct exclude_list_struct *listp, const char *fname,
|
||||
int xflags)
|
||||
{
|
||||
FILE *fp;
|
||||
char line[MAXPATHLEN];
|
||||
char *eob = line + MAXPATHLEN - 1;
|
||||
char line[MAXPATHLEN+3]; /* Room for "x " prefix and trailing slash. */
|
||||
char *eob = line + sizeof line - 1;
|
||||
int word_split = xflags & XFLG_WORD_SPLIT;
|
||||
|
||||
if (!fname || !*fname)
|
||||
@@ -340,7 +347,7 @@ void add_exclude_file(struct exclude_list_struct *listp, const char *fname,
|
||||
|
||||
while (1) {
|
||||
char *s = line;
|
||||
int ch;
|
||||
int ch, overflow = 0;
|
||||
while (1) {
|
||||
if ((ch = getc(fp)) == EOF) {
|
||||
if (ferror(fp) && errno == EINTR)
|
||||
@@ -353,6 +360,12 @@ void add_exclude_file(struct exclude_list_struct *listp, const char *fname,
|
||||
break;
|
||||
if (s < eob)
|
||||
*s++ = ch;
|
||||
else
|
||||
overflow = 1;
|
||||
}
|
||||
if (overflow) {
|
||||
rprintf(FERROR, "discarding over-long exclude: %s...\n", line);
|
||||
s = line;
|
||||
}
|
||||
*s = '\0';
|
||||
/* Skip an empty token and (when line parsing) comments. */
|
||||
@@ -383,12 +396,12 @@ void send_exclude_list(int f)
|
||||
l = strlcpy(p, ent->pattern, sizeof p);
|
||||
if (l == 0 || l >= MAXPATHLEN)
|
||||
continue;
|
||||
if (ent->directory) {
|
||||
if (ent->match_flags & MATCHFLG_DIRECTORY) {
|
||||
p[l++] = '/';
|
||||
p[l] = '\0';
|
||||
}
|
||||
|
||||
if (ent->include) {
|
||||
if (ent->match_flags & MATCHFLG_INCLUDE) {
|
||||
write_int(f, l + 2);
|
||||
write_buf(f, "+ ", 2);
|
||||
} else if ((*p == '-' || *p == '+') && p[1] == ' ') {
|
||||
@@ -405,7 +418,7 @@ void send_exclude_list(int f)
|
||||
|
||||
void recv_exclude_list(int f)
|
||||
{
|
||||
char line[MAXPATHLEN+1]; /* Allows a trailing slash on a max-len dir */
|
||||
char line[MAXPATHLEN+3]; /* Room for "x " prefix and trailing slash. */
|
||||
unsigned int l;
|
||||
|
||||
while ((l = read_int(f)) != 0) {
|
||||
|
||||
59
fileio.c
59
fileio.c
@@ -22,9 +22,10 @@
|
||||
*/
|
||||
#include "rsync.h"
|
||||
|
||||
extern int sparse_files;
|
||||
|
||||
static char last_byte;
|
||||
static int last_sparse;
|
||||
extern int sparse_files;
|
||||
|
||||
int sparse_end(int f)
|
||||
{
|
||||
@@ -91,6 +92,7 @@ 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.
|
||||
@@ -106,9 +108,9 @@ int write_file(int f,char *buf,size_t len)
|
||||
r1 = write_sparse(f, buf, len1);
|
||||
} else {
|
||||
if (!wf_writeBuf) {
|
||||
wf_writeBufSize = MAX_MAP_SIZE;
|
||||
wf_writeBufSize = WRITE_SIZE * 8;
|
||||
wf_writeBufCnt = 0;
|
||||
wf_writeBuf = new_array(char, MAX_MAP_SIZE);
|
||||
wf_writeBuf = new_array(char, wf_writeBufSize);
|
||||
if (!wf_writeBuf)
|
||||
out_of_memory("write_file");
|
||||
}
|
||||
@@ -125,7 +127,8 @@ int write_file(int f,char *buf,size_t len)
|
||||
}
|
||||
}
|
||||
if (r1 <= 0) {
|
||||
if (ret > 0) return ret;
|
||||
if (ret > 0)
|
||||
return ret;
|
||||
return r1;
|
||||
}
|
||||
len -= r1;
|
||||
@@ -136,29 +139,30 @@ int write_file(int f,char *buf,size_t len)
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* this provides functionality somewhat similar to mmap() but using
|
||||
read(). It gives sliding window access to a file. mmap() is not
|
||||
used because of the possibility of another program (such as a
|
||||
mailer) truncating the file thus giving us a SIGBUS */
|
||||
struct map_struct *map_file(int fd,OFF_T len)
|
||||
/* This provides functionality somewhat similar to mmap() but using read().
|
||||
* It gives sliding window access to a file. mmap() is not used because of
|
||||
* the possibility of another program (such as a mailer) truncating the
|
||||
* file thus giving us a SIGBUS. */
|
||||
struct map_struct *map_file(int fd, OFF_T len, OFF_T map_size,
|
||||
size_t block_size)
|
||||
{
|
||||
struct map_struct *map;
|
||||
map = new(struct map_struct);
|
||||
if (!map) out_of_memory("map_file");
|
||||
|
||||
if (!(map = new(struct map_struct)))
|
||||
out_of_memory("map_file");
|
||||
|
||||
if (block_size && (map_size % block_size))
|
||||
map_size += block_size - (map_size % block_size);
|
||||
|
||||
memset(map, 0, sizeof map[0]);
|
||||
map->fd = fd;
|
||||
map->file_size = len;
|
||||
map->p = NULL;
|
||||
map->p_size = 0;
|
||||
map->p_offset = 0;
|
||||
map->p_fd_offset = 0;
|
||||
map->p_len = 0;
|
||||
map->status = 0;
|
||||
map->def_window_size = map_size;
|
||||
|
||||
return map;
|
||||
}
|
||||
|
||||
|
||||
/* slide the read window in the file */
|
||||
char *map_ptr(struct map_struct *map,OFF_T offset,int len)
|
||||
{
|
||||
@@ -166,9 +170,8 @@ char *map_ptr(struct map_struct *map,OFF_T offset,int len)
|
||||
OFF_T window_start, read_start;
|
||||
int window_size, read_size, read_offset;
|
||||
|
||||
if (len == 0) {
|
||||
if (len == 0)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* can't go beyond the end of file */
|
||||
if (len > (map->file_size - offset)) {
|
||||
@@ -181,15 +184,9 @@ char *map_ptr(struct map_struct *map,OFF_T offset,int len)
|
||||
return (map->p + (offset - map->p_offset));
|
||||
}
|
||||
|
||||
|
||||
/* nope, we are going to have to do a read. Work out our desired window */
|
||||
if (offset > 2*CHUNK_SIZE) {
|
||||
window_start = offset - 2*CHUNK_SIZE;
|
||||
window_start &= ~((OFF_T)(CHUNK_SIZE-1)); /* assumes power of 2 */
|
||||
} else {
|
||||
window_start = 0;
|
||||
}
|
||||
window_size = MAX_MAP_SIZE;
|
||||
window_start = offset;
|
||||
window_size = map->def_window_size;
|
||||
if (window_start + window_size > map->file_size) {
|
||||
window_size = map->file_size - window_start;
|
||||
}
|
||||
@@ -200,7 +197,8 @@ char *map_ptr(struct map_struct *map,OFF_T offset,int len)
|
||||
/* make sure we have allocated enough memory for the window */
|
||||
if (window_size > map->p_size) {
|
||||
map->p = realloc_array(map->p, char, window_size);
|
||||
if (!map->p) out_of_memory("map_ptr");
|
||||
if (!map->p)
|
||||
out_of_memory("map_ptr");
|
||||
map->p_size = window_size;
|
||||
}
|
||||
|
||||
@@ -259,9 +257,8 @@ int unmap_file(struct map_struct *map)
|
||||
map->p = NULL;
|
||||
}
|
||||
ret = map->status;
|
||||
memset(map, 0, sizeof(*map));
|
||||
memset(map, 0, sizeof map[0]);
|
||||
free(map);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
220
flist.c
220
flist.c
@@ -34,6 +34,7 @@ extern int do_progress;
|
||||
extern int am_root;
|
||||
extern int am_server;
|
||||
extern int am_daemon;
|
||||
extern int am_sender;
|
||||
extern int always_checksum;
|
||||
extern int module_id;
|
||||
extern int ignore_errors;
|
||||
@@ -47,22 +48,22 @@ extern char *files_from;
|
||||
extern int filesfrom_fd;
|
||||
|
||||
extern int one_file_system;
|
||||
extern int keep_dirlinks;
|
||||
extern int preserve_links;
|
||||
extern int preserve_hard_links;
|
||||
extern int preserve_perms;
|
||||
extern int preserve_devices;
|
||||
extern int preserve_uid;
|
||||
extern int preserve_gid;
|
||||
extern int preserve_times;
|
||||
extern int relative_paths;
|
||||
extern int implied_dirs;
|
||||
extern int copy_links;
|
||||
extern int copy_unsafe_links;
|
||||
extern int protocol_version;
|
||||
extern int sanitize_paths;
|
||||
|
||||
extern int read_batch;
|
||||
extern int write_batch;
|
||||
extern int delete_excluded;
|
||||
extern int orig_umask;
|
||||
extern int list_only;
|
||||
|
||||
extern struct exclude_list_struct exclude_list;
|
||||
extern struct exclude_list_struct server_exclude_list;
|
||||
@@ -72,6 +73,7 @@ int io_error;
|
||||
|
||||
static char empty_sum[MD4_SUM_LENGTH];
|
||||
static unsigned int file_struct_len;
|
||||
static struct file_list *received_flist;
|
||||
|
||||
static void clean_flist(struct file_list *flist, int strip_root, int no_dups);
|
||||
static void output_flist(struct file_list *flist);
|
||||
@@ -93,7 +95,7 @@ static int show_filelist_p(void)
|
||||
static void start_filelist_progress(char *kind)
|
||||
{
|
||||
rprintf(FINFO, "%s ... ", kind);
|
||||
if ((verbose > 1) || do_progress)
|
||||
if (verbose > 1 || do_progress)
|
||||
rprintf(FINFO, "\n");
|
||||
rflush(FINFO);
|
||||
}
|
||||
@@ -107,7 +109,7 @@ static void emit_filelist_progress(const struct file_list *flist)
|
||||
|
||||
static void maybe_emit_filelist_progress(const struct file_list *flist)
|
||||
{
|
||||
if (do_progress && show_filelist_p() && ((flist->count % 100) == 0))
|
||||
if (do_progress && show_filelist_p() && (flist->count % 100) == 0)
|
||||
emit_filelist_progress(flist);
|
||||
}
|
||||
|
||||
@@ -132,9 +134,10 @@ static void list_file_entry(struct file_struct *f)
|
||||
{
|
||||
char perms[11];
|
||||
|
||||
if (!f->basename)
|
||||
if (!f->basename) {
|
||||
/* this can happen if duplicate names were removed */
|
||||
return;
|
||||
}
|
||||
|
||||
permstring(perms, f->mode);
|
||||
|
||||
@@ -142,14 +145,16 @@ static void list_file_entry(struct file_struct *f)
|
||||
if (preserve_links && S_ISLNK(f->mode)) {
|
||||
rprintf(FINFO, "%s %11.0f %s %s -> %s\n",
|
||||
perms,
|
||||
(double) f->length, timestring(f->modtime),
|
||||
(double)f->length, timestring(f->modtime),
|
||||
f_name(f), f->u.link);
|
||||
} else
|
||||
#endif
|
||||
{
|
||||
rprintf(FINFO, "%s %11.0f %s %s\n",
|
||||
perms,
|
||||
(double) f->length, timestring(f->modtime),
|
||||
(double)f->length, timestring(f->modtime),
|
||||
f_name(f));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -167,15 +172,15 @@ static void list_file_entry(struct file_struct *f)
|
||||
* @post @p buffer contains information about the link or the
|
||||
* referrent as appropriate, if they exist.
|
||||
**/
|
||||
int readlink_stat(const char *path, STRUCT_STAT *buffer, char *linkbuf)
|
||||
static int readlink_stat(const char *path, STRUCT_STAT *buffer, char *linkbuf)
|
||||
{
|
||||
#if SUPPORT_LINKS
|
||||
if (copy_links)
|
||||
return do_stat(path, buffer);
|
||||
if (do_lstat(path, buffer) == -1)
|
||||
if (link_stat(path, buffer, 0) < 0)
|
||||
return -1;
|
||||
if (S_ISLNK(buffer->st_mode)) {
|
||||
int l = readlink((char *) path, linkbuf, MAXPATHLEN - 1);
|
||||
int l = readlink((char *)path, linkbuf, MAXPATHLEN - 1);
|
||||
if (l == -1)
|
||||
return -1;
|
||||
linkbuf[l] = 0;
|
||||
@@ -193,12 +198,19 @@ int readlink_stat(const char *path, STRUCT_STAT *buffer, char *linkbuf)
|
||||
#endif
|
||||
}
|
||||
|
||||
int link_stat(const char *path, STRUCT_STAT * buffer)
|
||||
int link_stat(const char *path, STRUCT_STAT *buffer, int follow_dirlinks)
|
||||
{
|
||||
#if SUPPORT_LINKS
|
||||
if (copy_links)
|
||||
return do_stat(path, buffer);
|
||||
return do_lstat(path, buffer);
|
||||
if (do_lstat(path, buffer) < 0)
|
||||
return -1;
|
||||
if (follow_dirlinks && S_ISLNK(buffer->st_mode)) {
|
||||
STRUCT_STAT st;
|
||||
if (do_stat(path, &st) == 0 && S_ISDIR(st.st_mode))
|
||||
*buffer = st;
|
||||
}
|
||||
return 0;
|
||||
#else
|
||||
return do_stat(path, buffer);
|
||||
#endif
|
||||
@@ -248,7 +260,7 @@ static dev_t filesystem_dev;
|
||||
static void set_filesystem(char *fname)
|
||||
{
|
||||
STRUCT_STAT st;
|
||||
if (link_stat(fname, &st) != 0)
|
||||
if (do_stat(fname, &st) != 0)
|
||||
return;
|
||||
filesystem_dev = st.st_dev;
|
||||
}
|
||||
@@ -260,14 +272,14 @@ static int to_wire_mode(mode_t mode)
|
||||
if (S_ISLNK(mode) && (_S_IFLNK != 0120000))
|
||||
return (mode & ~(_S_IFMT)) | 0120000;
|
||||
#endif
|
||||
return (int) mode;
|
||||
return (int)mode;
|
||||
}
|
||||
|
||||
static mode_t from_wire_mode(int mode)
|
||||
{
|
||||
if ((mode & (_S_IFMT)) == 0120000 && (_S_IFLNK != 0120000))
|
||||
return (mode & ~(_S_IFMT)) | _S_IFLNK;
|
||||
return (mode_t) mode;
|
||||
return (mode_t)mode;
|
||||
}
|
||||
|
||||
|
||||
@@ -283,7 +295,7 @@ static int flist_dir_len;
|
||||
**/
|
||||
void flist_expand(struct file_list *flist)
|
||||
{
|
||||
void *new_ptr;
|
||||
struct file_struct **new_ptr;
|
||||
|
||||
if (flist->count < flist->malloced)
|
||||
return;
|
||||
@@ -302,21 +314,17 @@ void flist_expand(struct file_list *flist)
|
||||
if (flist->malloced < flist->count)
|
||||
flist->malloced = flist->count;
|
||||
|
||||
if (flist->files) {
|
||||
new_ptr = realloc_array(flist->files,
|
||||
struct file_struct *, flist->malloced);
|
||||
} else {
|
||||
new_ptr = new_array(struct file_struct *, flist->malloced);
|
||||
}
|
||||
new_ptr = realloc_array(flist->files, struct file_struct *,
|
||||
flist->malloced);
|
||||
|
||||
if (verbose >= 2) {
|
||||
rprintf(FINFO, "[%s] expand file_list to %.0f bytes, did%s move\n",
|
||||
who_am_i(),
|
||||
(double) sizeof flist->files[0] * flist->malloced,
|
||||
(double)sizeof flist->files[0] * flist->malloced,
|
||||
(new_ptr == flist->files) ? " not" : "");
|
||||
}
|
||||
|
||||
flist->files = (struct file_struct **) new_ptr;
|
||||
flist->files = new_ptr;
|
||||
|
||||
if (!flist->files)
|
||||
out_of_memory("flist_expand");
|
||||
@@ -333,7 +341,7 @@ void send_file_entry(struct file_struct *file, int f, unsigned short base_flags)
|
||||
static uid_t uid;
|
||||
static gid_t gid;
|
||||
static char lastname[MAXPATHLEN];
|
||||
char *fname, fbuf[MAXPATHLEN];
|
||||
char fname[MAXPATHLEN];
|
||||
int l1, l2;
|
||||
|
||||
if (f == -1)
|
||||
@@ -351,7 +359,7 @@ void send_file_entry(struct file_struct *file, int f, unsigned short base_flags)
|
||||
|
||||
io_write_phase = "send_file_entry";
|
||||
|
||||
fname = f_name_to(file, fbuf);
|
||||
f_name_to(file, fname);
|
||||
|
||||
flags = base_flags;
|
||||
|
||||
@@ -515,7 +523,7 @@ void send_file_entry(struct file_struct *file, int f, unsigned short base_flags)
|
||||
|
||||
|
||||
void receive_file_entry(struct file_struct **fptr, unsigned short flags,
|
||||
struct file_list *flist, int f)
|
||||
struct file_list *flist, int f)
|
||||
{
|
||||
static time_t modtime;
|
||||
static mode_t mode;
|
||||
@@ -525,7 +533,7 @@ void receive_file_entry(struct file_struct **fptr, unsigned short flags,
|
||||
static uid_t uid;
|
||||
static gid_t gid;
|
||||
static char lastname[MAXPATHLEN], *lastdir;
|
||||
static int lastdir_len = -1;
|
||||
static int lastdir_depth, lastdir_len = -1;
|
||||
char thisname[MAXPATHLEN];
|
||||
unsigned int l1 = 0, l2 = 0;
|
||||
int alloc_len, basename_len, dirname_len, linkname_len, sum_len;
|
||||
@@ -539,6 +547,7 @@ void receive_file_entry(struct file_struct **fptr, unsigned short flags,
|
||||
rdev_major = 0;
|
||||
uid = 0, gid = 0;
|
||||
*lastname = '\0';
|
||||
lastdir_len = -1;
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -563,10 +572,10 @@ void receive_file_entry(struct file_struct **fptr, unsigned short flags,
|
||||
|
||||
strlcpy(lastname, thisname, MAXPATHLEN);
|
||||
|
||||
clean_fname(thisname);
|
||||
clean_fname(thisname, 0);
|
||||
|
||||
if (sanitize_paths)
|
||||
sanitize_path(thisname, NULL);
|
||||
sanitize_path(thisname, thisname, "", 0);
|
||||
|
||||
if ((basename = strrchr(thisname, '/')) != NULL) {
|
||||
dirname_len = ++basename - thisname; /* counts future '\0' */
|
||||
@@ -649,6 +658,8 @@ void receive_file_entry(struct file_struct **fptr, unsigned short flags,
|
||||
memcpy(bp, dirname, dirname_len - 1);
|
||||
bp += dirname_len;
|
||||
bp[-1] = '\0';
|
||||
if (sanitize_paths)
|
||||
lastdir_depth = count_dir_elements(lastdir);
|
||||
} else if (dirname)
|
||||
file->dirname = dirname;
|
||||
|
||||
@@ -664,7 +675,7 @@ void receive_file_entry(struct file_struct **fptr, unsigned short flags,
|
||||
file->u.link = bp;
|
||||
read_sbuf(f, bp, linkname_len - 1);
|
||||
if (sanitize_paths)
|
||||
sanitize_path(bp, lastdir);
|
||||
sanitize_path(bp, bp, "", lastdir_depth);
|
||||
bp += linkname_len;
|
||||
}
|
||||
#endif
|
||||
@@ -708,7 +719,6 @@ void receive_file_entry(struct file_struct **fptr, unsigned short flags,
|
||||
}
|
||||
|
||||
if (!preserve_perms) {
|
||||
extern int orig_umask;
|
||||
/* set an appropriate set of permissions based on original
|
||||
* permissions and umask. This emulates what GNU cp does */
|
||||
file->mode &= ~orig_umask;
|
||||
@@ -731,8 +741,8 @@ void receive_file_entry(struct file_struct **fptr, unsigned short flags,
|
||||
* statting directories if we're not recursing, but this is not a very
|
||||
* important case. Some systems may not have d_type.
|
||||
**/
|
||||
struct file_struct *make_file(char *fname,
|
||||
struct file_list *flist, int exclude_level)
|
||||
struct file_struct *make_file(char *fname, struct file_list *flist,
|
||||
int exclude_level)
|
||||
{
|
||||
static char *lastdir;
|
||||
static int lastdir_len = -1;
|
||||
@@ -745,7 +755,7 @@ struct file_struct *make_file(char *fname,
|
||||
char *basename, *dirname, *bp;
|
||||
unsigned short flags = 0;
|
||||
|
||||
if (!flist) /* lastdir isn't valid if flist is NULL */
|
||||
if (!flist || !flist->count) /* Ignore lastdir when invalid. */
|
||||
lastdir_len = -1;
|
||||
|
||||
if (strlcpy(thisname, fname, sizeof thisname)
|
||||
@@ -753,33 +763,39 @@ struct file_struct *make_file(char *fname,
|
||||
rprintf(FINFO, "skipping overly long name: %s\n", fname);
|
||||
return NULL;
|
||||
}
|
||||
clean_fname(thisname);
|
||||
clean_fname(thisname, 0);
|
||||
if (sanitize_paths)
|
||||
sanitize_path(thisname, NULL);
|
||||
sanitize_path(thisname, thisname, "", 0);
|
||||
|
||||
memset(sum, 0, SUM_LENGTH);
|
||||
|
||||
if (readlink_stat(thisname, &st, linkname) != 0) {
|
||||
int save_errno = errno;
|
||||
if (errno == ENOENT) {
|
||||
enum logcode c = am_daemon && protocol_version < 28
|
||||
? FERROR : FINFO;
|
||||
/* either symlink pointing nowhere or file that
|
||||
* was removed during rsync run; see if excluded
|
||||
* before reporting an error */
|
||||
if (exclude_level != NO_EXCLUDES
|
||||
&& check_exclude_file(thisname, 0, exclude_level)) {
|
||||
/* file is excluded anyway, ignore silently */
|
||||
return NULL;
|
||||
/* See if file is excluded before reporting an error. */
|
||||
if (exclude_level != NO_EXCLUDES
|
||||
&& check_exclude_file(thisname, 0, exclude_level))
|
||||
return NULL;
|
||||
if (save_errno == ENOENT) {
|
||||
#if SUPPORT_LINKS
|
||||
/* Avoid "vanished" error if symlink points nowhere. */
|
||||
if (copy_links && do_lstat(thisname, &st) == 0
|
||||
&& S_ISLNK(st.st_mode)) {
|
||||
io_error |= IOERR_GENERAL;
|
||||
rprintf(FERROR, "symlink has no referent: %s\n",
|
||||
full_fname(thisname));
|
||||
} else
|
||||
#endif
|
||||
{
|
||||
enum logcode c = am_daemon && protocol_version < 28
|
||||
? FERROR : FINFO;
|
||||
io_error |= IOERR_VANISHED;
|
||||
rprintf(c, "file has vanished: %s\n",
|
||||
full_fname(thisname));
|
||||
}
|
||||
io_error |= IOERR_VANISHED;
|
||||
rprintf(c, "file has vanished: %s\n",
|
||||
full_fname(thisname));
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
io_error |= IOERR_GENERAL;
|
||||
rprintf(FERROR, "readlink %s failed: %s\n",
|
||||
full_fname(thisname), strerror(save_errno));
|
||||
rsyserr(FERROR, save_errno, "readlink %s failed",
|
||||
full_fname(thisname));
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
@@ -911,6 +927,26 @@ skip_excludes:
|
||||
|
||||
file->basedir = flist_dir;
|
||||
|
||||
/* This code is only used by the receiver when it is building
|
||||
* a list of files for a delete pass. */
|
||||
if (keep_dirlinks && linkname_len && flist) {
|
||||
STRUCT_STAT st2;
|
||||
int i = flist_find(received_flist, file);
|
||||
if (i >= 0 && S_ISDIR(received_flist->files[i]->mode)
|
||||
&& do_stat(thisname, &st2) == 0 && S_ISDIR(st2.st_mode)) {
|
||||
file->modtime = st2.st_mtime;
|
||||
file->length = st2.st_size;
|
||||
file->mode = st2.st_mode;
|
||||
file->uid = st2.st_uid;
|
||||
file->gid = st2.st_gid;
|
||||
file->u.link = NULL;
|
||||
if (file->link_u.idev) {
|
||||
pool_free(flist->hlink_pool, 0, file->link_u.idev);
|
||||
file->link_u.idev = NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!S_ISDIR(st.st_mode))
|
||||
stats.total_size += st.st_size;
|
||||
|
||||
@@ -923,7 +959,6 @@ void send_file_name(int f, struct file_list *flist, char *fname,
|
||||
{
|
||||
struct file_struct *file;
|
||||
char fbuf[MAXPATHLEN];
|
||||
extern int delete_excluded;
|
||||
|
||||
/* f is set to -1 when calculating deletion file list */
|
||||
file = make_file(fname, flist,
|
||||
@@ -936,9 +971,6 @@ void send_file_name(int f, struct file_list *flist, char *fname,
|
||||
|
||||
flist_expand(flist);
|
||||
|
||||
if (write_batch)
|
||||
file->flags |= FLAG_TOP_DIR;
|
||||
|
||||
if (file->basename[0]) {
|
||||
flist->files[flist->count++] = file;
|
||||
send_file_entry(file, f, base_flags);
|
||||
@@ -949,7 +981,11 @@ void send_file_name(int f, struct file_list *flist, char *fname,
|
||||
struct exclude_list_struct last_list = local_exclude_list;
|
||||
local_exclude_list.head = local_exclude_list.tail = NULL;
|
||||
send_directory(f, flist, f_name_to(file, fbuf));
|
||||
free_exclude_list(&local_exclude_list);
|
||||
if (verbose > 2) {
|
||||
rprintf(FINFO, "[%s] popping %sexclude list\n",
|
||||
who_am_i(), local_exclude_list.debug_type);
|
||||
}
|
||||
clear_exclude_list(&local_exclude_list);
|
||||
local_exclude_list = last_list;
|
||||
}
|
||||
}
|
||||
@@ -966,8 +1002,7 @@ static void send_directory(int f, struct file_list *flist, char *dir)
|
||||
d = opendir(dir);
|
||||
if (!d) {
|
||||
io_error |= IOERR_GENERAL;
|
||||
rprintf(FERROR, "opendir %s failed: %s\n",
|
||||
full_fname(dir), strerror(errno));
|
||||
rsyserr(FERROR, errno, "opendir %s failed", full_fname(dir));
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -1014,8 +1049,7 @@ static void send_directory(int f, struct file_list *flist, char *dir)
|
||||
}
|
||||
if (errno) {
|
||||
io_error |= IOERR_GENERAL;
|
||||
rprintf(FERROR, "readdir(%s): (%d) %s\n",
|
||||
dir, errno, strerror(errno));
|
||||
rsyserr(FERROR, errno, "readdir(%s)", dir);
|
||||
}
|
||||
|
||||
closedir(d);
|
||||
@@ -1023,6 +1057,8 @@ static void send_directory(int f, struct file_list *flist, char *dir)
|
||||
|
||||
|
||||
/**
|
||||
* This function is normally called by the sender, but the receiver also
|
||||
* uses it to construct its own file list if --delete has been specified.
|
||||
* The delete_files() function in receiver.c sets f to -1 so that we just
|
||||
* construct the file list in memory without sending it over the wire. It
|
||||
* also has the side-effect of ignoring user-excludes if delete_excluded
|
||||
@@ -1047,11 +1083,11 @@ struct file_list *send_file_list(int f, int argc, char *argv[])
|
||||
"send_file_list");
|
||||
|
||||
if (f != -1) {
|
||||
io_start_buffering_out(f);
|
||||
io_start_buffering_out();
|
||||
if (filesfrom_fd >= 0) {
|
||||
if (argv[0] && !push_dir(argv[0])) {
|
||||
rprintf(FERROR, "push_dir %s failed: %s\n",
|
||||
full_fname(argv[0]), strerror(errno));
|
||||
rsyserr(FERROR, errno, "push_dir %s failed",
|
||||
full_fname(argv[0]));
|
||||
exit_cleanup(RERR_FILESELECT);
|
||||
}
|
||||
use_ff_fd = 1;
|
||||
@@ -1065,13 +1101,13 @@ struct file_list *send_file_list(int f, int argc, char *argv[])
|
||||
if (use_ff_fd) {
|
||||
if (read_filesfrom_line(filesfrom_fd, fname) == 0)
|
||||
break;
|
||||
sanitize_path(fname, NULL);
|
||||
sanitize_path(fname, fname, "", 0);
|
||||
} else {
|
||||
if (argc-- == 0)
|
||||
break;
|
||||
strlcpy(fname, *argv++, MAXPATHLEN);
|
||||
if (sanitize_paths)
|
||||
sanitize_path(fname, NULL);
|
||||
sanitize_path(fname, fname, "", 0);
|
||||
}
|
||||
|
||||
l = strlen(fname);
|
||||
@@ -1085,11 +1121,11 @@ struct file_list *send_file_list(int f, int argc, char *argv[])
|
||||
}
|
||||
}
|
||||
|
||||
if (link_stat(fname, &st) != 0) {
|
||||
if (link_stat(fname, &st, keep_dirlinks) != 0) {
|
||||
if (f != -1) {
|
||||
io_error |= IOERR_GENERAL;
|
||||
rprintf(FERROR, "link_stat %s failed: %s\n",
|
||||
full_fname(fname), strerror(errno));
|
||||
rsyserr(FERROR, errno, "link_stat %s failed",
|
||||
full_fname(fname));
|
||||
}
|
||||
continue;
|
||||
}
|
||||
@@ -1158,8 +1194,8 @@ struct file_list *send_file_list(int f, int argc, char *argv[])
|
||||
|
||||
if (!push_dir(dir)) {
|
||||
io_error |= IOERR_GENERAL;
|
||||
rprintf(FERROR, "push_dir %s failed: %s\n",
|
||||
full_fname(dir), strerror(errno));
|
||||
rsyserr(FERROR, errno, "push_dir %s failed",
|
||||
full_fname(dir));
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -1181,8 +1217,8 @@ struct file_list *send_file_list(int f, int argc, char *argv[])
|
||||
flist_dir = NULL;
|
||||
flist_dir_len = 0;
|
||||
if (!pop_dir(olddir)) {
|
||||
rprintf(FERROR, "pop_dir %s failed: %s\n",
|
||||
full_fname(dir), strerror(errno));
|
||||
rsyserr(FERROR, errno, "pop_dir %s failed",
|
||||
full_fname(dir));
|
||||
exit_cleanup(RERR_FILESELECT);
|
||||
}
|
||||
}
|
||||
@@ -1213,8 +1249,6 @@ struct file_list *send_file_list(int f, int argc, char *argv[])
|
||||
io_end_buffering();
|
||||
stats.flist_size = stats.total_written - start_write;
|
||||
stats.num_files = flist->count;
|
||||
if (write_batch)
|
||||
write_batch_flist_info(flist->count, flist->files);
|
||||
}
|
||||
|
||||
if (verbose > 3)
|
||||
@@ -1232,7 +1266,6 @@ struct file_list *recv_file_list(int f)
|
||||
struct file_list *flist;
|
||||
unsigned short flags;
|
||||
int64 start_read;
|
||||
extern int list_only;
|
||||
|
||||
if (show_filelist_p())
|
||||
start_filelist_progress("receiving file list");
|
||||
@@ -1240,6 +1273,7 @@ struct file_list *recv_file_list(int f)
|
||||
start_read = stats.total_read;
|
||||
|
||||
flist = flist_new(WITH_HLINK, "recv_file_list");
|
||||
received_flist = flist;
|
||||
|
||||
flist->count = 0;
|
||||
flist->malloced = 1000;
|
||||
@@ -1284,13 +1318,11 @@ struct file_list *recv_file_list(int f)
|
||||
* protocol version 15 */
|
||||
recv_uid_list(f, flist);
|
||||
|
||||
if (!read_batch) {
|
||||
/* Recv the io_error flag */
|
||||
if (lp_ignore_errors(module_id) || ignore_errors)
|
||||
read_int(f);
|
||||
else
|
||||
io_error |= read_int(f);
|
||||
}
|
||||
/* Recv the io_error flag */
|
||||
if (lp_ignore_errors(module_id) || ignore_errors)
|
||||
read_int(f);
|
||||
else
|
||||
io_error |= read_int(f);
|
||||
}
|
||||
|
||||
if (verbose > 3)
|
||||
@@ -1422,7 +1454,7 @@ static void clean_flist(struct file_list *flist, int strip_root, int no_dups)
|
||||
return;
|
||||
|
||||
qsort(flist->files, flist->count,
|
||||
sizeof flist->files[0], (int (*)()) file_compare);
|
||||
sizeof flist->files[0], (int (*)())file_compare);
|
||||
|
||||
for (i = no_dups? 0 : flist->count; i < flist->count; i++) {
|
||||
if (flist->files[i]->basename) {
|
||||
@@ -1478,7 +1510,7 @@ static void output_flist(struct file_list *flist)
|
||||
|
||||
for (i = 0; i < flist->count; i++) {
|
||||
file = flist->files[i];
|
||||
if (am_root && preserve_uid)
|
||||
if ((am_root || am_sender) && preserve_uid)
|
||||
sprintf(uidbuf, " uid=%ld", (long)file->uid);
|
||||
else
|
||||
*uidbuf = '\0';
|
||||
@@ -1488,8 +1520,8 @@ static void output_flist(struct file_list *flist)
|
||||
*gidbuf = '\0';
|
||||
rprintf(FINFO, "[%s] i=%d %s %s %s mode=0%o len=%.0f%s%s\n",
|
||||
who_am_i(), i, NS(file->basedir), NS(file->dirname),
|
||||
NS(file->basename), (int) file->mode,
|
||||
(double) file->length, uidbuf, gidbuf);
|
||||
NS(file->basename), (int)file->mode,
|
||||
(double)file->length, uidbuf, gidbuf);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1517,11 +1549,17 @@ int f_name_cmp(struct file_struct *f1, struct file_struct *f2)
|
||||
if (!(c1 = (uchar*)f1->dirname)) {
|
||||
state1 = fnc_BASE;
|
||||
c1 = (uchar*)f1->basename;
|
||||
} else if (!*c1) {
|
||||
state1 = fnc_SLASH;
|
||||
c1 = (uchar*)"/";
|
||||
} else
|
||||
state1 = fnc_DIR;
|
||||
if (!(c2 = (uchar*)f2->dirname)) {
|
||||
state2 = fnc_BASE;
|
||||
c2 = (uchar*)f2->basename;
|
||||
} else if (!*c2) {
|
||||
state2 = fnc_SLASH;
|
||||
c2 = (uchar*)"/";
|
||||
} else
|
||||
state2 = fnc_DIR;
|
||||
|
||||
|
||||
348
generator.c
348
generator.c
@@ -26,6 +26,7 @@
|
||||
extern int verbose;
|
||||
extern int dry_run;
|
||||
extern int relative_paths;
|
||||
extern int keep_dirlinks;
|
||||
extern int preserve_links;
|
||||
extern int am_root;
|
||||
extern int preserve_devices;
|
||||
@@ -35,29 +36,34 @@ extern int preserve_uid;
|
||||
extern int preserve_gid;
|
||||
extern int update_only;
|
||||
extern int opt_ignore_existing;
|
||||
extern int inplace;
|
||||
extern int make_backups;
|
||||
extern int csum_length;
|
||||
extern int ignore_times;
|
||||
extern int size_only;
|
||||
extern int io_timeout;
|
||||
extern int protocol_version;
|
||||
extern int always_checksum;
|
||||
extern char *partial_dir;
|
||||
extern char *compare_dest;
|
||||
extern int link_dest;
|
||||
extern int whole_file;
|
||||
extern int local_server;
|
||||
extern int write_batch;
|
||||
extern int list_only;
|
||||
extern int read_batch;
|
||||
extern int only_existing;
|
||||
extern int orig_umask;
|
||||
extern int safe_symlinks;
|
||||
extern unsigned int block_size;
|
||||
|
||||
extern struct exclude_list_struct server_exclude_list;
|
||||
|
||||
|
||||
/* choose whether to skip a particular file */
|
||||
static int skip_file(char *fname, struct file_struct *file, STRUCT_STAT *st)
|
||||
{
|
||||
if (st->st_size != file->length) {
|
||||
if (st->st_size != file->length)
|
||||
return 0;
|
||||
}
|
||||
if (link_dest) {
|
||||
if (preserve_perms
|
||||
&& (st->st_mode & CHMOD_BITS) != (file->mode & CHMOD_BITS))
|
||||
@@ -75,29 +81,18 @@ static int skip_file(char *fname, struct file_struct *file, STRUCT_STAT *st)
|
||||
of the file time to determine whether to sync */
|
||||
if (always_checksum && S_ISREG(st->st_mode)) {
|
||||
char sum[MD4_SUM_LENGTH];
|
||||
char fnamecmpdest[MAXPATHLEN];
|
||||
|
||||
if (compare_dest != NULL) {
|
||||
if (access(fname, 0) != 0) {
|
||||
pathjoin(fnamecmpdest, sizeof fnamecmpdest,
|
||||
compare_dest, fname);
|
||||
fname = fnamecmpdest;
|
||||
}
|
||||
}
|
||||
file_checksum(fname,sum,st->st_size);
|
||||
return memcmp(sum, file->u.sum, protocol_version < 21 ? 2
|
||||
: MD4_SUM_LENGTH) == 0;
|
||||
}
|
||||
|
||||
if (size_only) {
|
||||
if (size_only)
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (ignore_times) {
|
||||
if (ignore_times)
|
||||
return 0;
|
||||
}
|
||||
|
||||
return (cmp_modtime(st->st_mtime,file->modtime) == 0);
|
||||
return cmp_modtime(st->st_mtime, file->modtime) == 0;
|
||||
}
|
||||
|
||||
|
||||
@@ -118,11 +113,11 @@ void write_sum_head(int f, struct sum_struct *sum)
|
||||
write_int(f, sum->remainder);
|
||||
}
|
||||
|
||||
/*
|
||||
/*
|
||||
* set (initialize) the size entries in the per-file sum_struct
|
||||
* calulating dynamic block ans checksum sizes.
|
||||
* calculating dynamic block and checksum sizes.
|
||||
*
|
||||
* This is only called from generate_and_send_sums() but is a seperate
|
||||
* This is only called from generate_and_send_sums() but is a separate
|
||||
* function to encapsulate the logic.
|
||||
*
|
||||
* The block size is a rounded square root of file length.
|
||||
@@ -138,7 +133,6 @@ void write_sum_head(int f, struct sum_struct *sum)
|
||||
|
||||
static void sum_sizes_sqroot(struct sum_struct *sum, uint64 len)
|
||||
{
|
||||
extern unsigned int block_size;
|
||||
unsigned int blength;
|
||||
int s2length;
|
||||
uint32 c;
|
||||
@@ -200,46 +194,37 @@ static void sum_sizes_sqroot(struct sum_struct *sum, uint64 len)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Perhaps we want to just send an empty checksum set for this file,
|
||||
* which will force the whole thing to be literally transferred.
|
||||
*
|
||||
* When do we do this? If the user's explicitly said they
|
||||
* want the whole thing, or if { they haven't explicitly
|
||||
* requested a delta, and it's local but not batch mode.}
|
||||
*
|
||||
* Whew. */
|
||||
static BOOL disable_deltas_p(void)
|
||||
{
|
||||
if (whole_file > 0)
|
||||
return True;
|
||||
if (whole_file == 0 || write_batch)
|
||||
return False;
|
||||
return local_server;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Generate and send a stream of signatures/checksums that describe a buffer
|
||||
*
|
||||
* Generate approximately one checksum every block_len bytes.
|
||||
*/
|
||||
static void generate_and_send_sums(struct map_struct *buf, size_t len, int f_out)
|
||||
static void generate_and_send_sums(int fd, OFF_T len, int f_out, int f_copy)
|
||||
{
|
||||
size_t i;
|
||||
struct map_struct *mapbuf;
|
||||
struct sum_struct sum;
|
||||
OFF_T offset = 0;
|
||||
|
||||
sum_sizes_sqroot(&sum, len);
|
||||
|
||||
if (len > 0)
|
||||
mapbuf = map_file(fd, len, MAX_MAP_SIZE, sum.blength);
|
||||
else
|
||||
mapbuf = NULL;
|
||||
|
||||
write_sum_head(f_out, &sum);
|
||||
|
||||
for (i = 0; i < sum.count; i++) {
|
||||
unsigned int n1 = MIN(len, sum.blength);
|
||||
char *map = map_ptr(buf, offset, n1);
|
||||
char *map = map_ptr(mapbuf, offset, n1);
|
||||
uint32 sum1 = get_checksum1(map, n1);
|
||||
char sum2[SUM_LENGTH];
|
||||
|
||||
if (f_copy >= 0)
|
||||
full_write(f_copy, map, n1);
|
||||
|
||||
get_checksum2(map, n1, sum2);
|
||||
|
||||
if (verbose > 3) {
|
||||
@@ -253,44 +238,67 @@ static void generate_and_send_sums(struct map_struct *buf, size_t len, int f_out
|
||||
len -= n1;
|
||||
offset += n1;
|
||||
}
|
||||
|
||||
if (mapbuf)
|
||||
unmap_file(mapbuf);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
/*
|
||||
* Acts on file number @p i from @p flist, whose name is @p fname.
|
||||
*
|
||||
* First fixes up permissions, then generates checksums for the file.
|
||||
*
|
||||
* @note This comment was added later by mbp who was trying to work it
|
||||
* out. It might be wrong.
|
||||
**/
|
||||
void recv_generator(char *fname, struct file_struct *file, int i, int f_out)
|
||||
*/
|
||||
static void recv_generator(char *fname, struct file_struct *file, int i,
|
||||
int f_out)
|
||||
{
|
||||
int fd;
|
||||
STRUCT_STAT st;
|
||||
struct map_struct *mapbuf;
|
||||
int statret;
|
||||
char *fnamecmp;
|
||||
int fd, f_copy;
|
||||
STRUCT_STAT st, partial_st;
|
||||
struct file_struct *back_file;
|
||||
int statret, stat_errno;
|
||||
char *fnamecmp, *partialptr, *backupptr;
|
||||
char fnamecmpbuf[MAXPATHLEN];
|
||||
|
||||
if (list_only)
|
||||
return;
|
||||
|
||||
if (verbose > 2)
|
||||
rprintf(FINFO,"recv_generator(%s,%d)\n",fname,i);
|
||||
rprintf(FINFO, "recv_generator(%s,%d)\n", safe_fname(fname), i);
|
||||
|
||||
statret = link_stat(fname,&st);
|
||||
|
||||
if (only_existing && statret == -1 && errno == ENOENT) {
|
||||
/* we only want to update existing files */
|
||||
if (verbose > 1) rprintf(FINFO, "not creating new file \"%s\"\n",fname);
|
||||
if (server_exclude_list.head
|
||||
&& check_exclude(&server_exclude_list, fname,
|
||||
S_ISDIR(file->mode)) < 0) {
|
||||
if (verbose) {
|
||||
rprintf(FINFO, "skipping server-excluded file \"%s\"\n",
|
||||
safe_fname(fname));
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (statret == 0 &&
|
||||
!preserve_perms &&
|
||||
(S_ISDIR(st.st_mode) == S_ISDIR(file->mode))) {
|
||||
if (dry_run > 1) {
|
||||
statret = -1;
|
||||
stat_errno = ENOENT;
|
||||
} else {
|
||||
statret = link_stat(fname, &st,
|
||||
keep_dirlinks && S_ISDIR(file->mode));
|
||||
stat_errno = errno;
|
||||
}
|
||||
|
||||
if (only_existing && statret == -1 && stat_errno == ENOENT) {
|
||||
/* we only want to update existing files */
|
||||
if (verbose > 1) {
|
||||
rprintf(FINFO, "not creating new file \"%s\"\n",
|
||||
safe_fname(fname));
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (statret == 0 && !preserve_perms
|
||||
&& S_ISDIR(st.st_mode) == S_ISDIR(file->mode)) {
|
||||
/* if the file exists already and we aren't perserving
|
||||
* permissions then act as though the remote end sent
|
||||
* us the file permissions we already have */
|
||||
@@ -305,28 +313,31 @@ void recv_generator(char *fname, struct file_struct *file, int i, int f_out)
|
||||
* we need to delete it. If it doesn't exist, then
|
||||
* recursively create it. */
|
||||
|
||||
if (dry_run) return; /* XXXX -- might cause inaccuracies?? -- mbp */
|
||||
if (dry_run)
|
||||
return; /* TODO: causes inaccuracies -- fix */
|
||||
if (statret == 0 && !S_ISDIR(st.st_mode)) {
|
||||
if (robust_unlink(fname) != 0) {
|
||||
rprintf(FERROR,
|
||||
"recv_generator: unlink %s to make room for directory: %s\n",
|
||||
full_fname(fname), strerror(errno));
|
||||
rsyserr(FERROR, errno,
|
||||
"recv_generator: unlink %s to make room for directory",
|
||||
full_fname(fname));
|
||||
return;
|
||||
}
|
||||
statret = -1;
|
||||
}
|
||||
if (statret != 0 && do_mkdir(fname,file->mode) != 0 && errno != EEXIST) {
|
||||
if (!(relative_paths && errno==ENOENT &&
|
||||
create_directory_path(fname, orig_umask)==0 &&
|
||||
do_mkdir(fname,file->mode)==0)) {
|
||||
rprintf(FERROR, "recv_generator: mkdir %s failed: %s\n",
|
||||
full_fname(fname), strerror(errno));
|
||||
if (!(relative_paths && errno == ENOENT
|
||||
&& create_directory_path(fname, orig_umask) == 0
|
||||
&& do_mkdir(fname, file->mode) == 0)) {
|
||||
rsyserr(FERROR, errno,
|
||||
"recv_generator: mkdir %s failed",
|
||||
full_fname(fname));
|
||||
}
|
||||
}
|
||||
/* f_out is set to -1 when doing final directory
|
||||
permission and modification time repair */
|
||||
if (set_perms(fname,file,NULL,0) && verbose && (f_out != -1))
|
||||
rprintf(FINFO,"%s/\n",fname);
|
||||
/* f_out is set to -1 when doing final directory-permission
|
||||
* and modification-time repair. */
|
||||
if (set_perms(fname, file, statret ? NULL : &st, 0)
|
||||
&& verbose && f_out != -1)
|
||||
rprintf(FINFO, "%s/\n", safe_fname(fname));
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -350,7 +361,8 @@ void recv_generator(char *fname, struct file_struct *file, int i, int f_out)
|
||||
* right place -- no further action
|
||||
* required. */
|
||||
if (strcmp(lnk,file->u.link) == 0) {
|
||||
set_perms(fname,file,&st,1);
|
||||
set_perms(fname, file, &st,
|
||||
PERMS_REPORT);
|
||||
return;
|
||||
}
|
||||
}
|
||||
@@ -360,12 +372,13 @@ void recv_generator(char *fname, struct file_struct *file, int i, int f_out)
|
||||
delete_file(fname);
|
||||
}
|
||||
if (do_symlink(file->u.link,fname) != 0) {
|
||||
rprintf(FERROR, "symlink %s -> \"%s\" failed: %s\n",
|
||||
full_fname(fname), file->u.link, strerror(errno));
|
||||
rsyserr(FERROR, errno, "symlink %s -> \"%s\" failed",
|
||||
full_fname(fname), safe_fname(file->u.link));
|
||||
} else {
|
||||
set_perms(fname,file,NULL,0);
|
||||
if (verbose) {
|
||||
rprintf(FINFO,"%s -> %s\n", fname,file->u.link);
|
||||
rprintf(FINFO, "%s -> %s\n", safe_fname(fname),
|
||||
safe_fname(file->u.link));
|
||||
}
|
||||
}
|
||||
#endif
|
||||
@@ -378,19 +391,23 @@ void recv_generator(char *fname, struct file_struct *file, int i, int f_out)
|
||||
st.st_mode != file->mode ||
|
||||
st.st_rdev != file->u.rdev) {
|
||||
delete_file(fname);
|
||||
if (verbose > 2)
|
||||
if (verbose > 2) {
|
||||
rprintf(FINFO,"mknod(%s,0%o,0x%x)\n",
|
||||
fname,(int)file->mode,(int)file->u.rdev);
|
||||
safe_fname(fname),
|
||||
(int)file->mode, (int)file->u.rdev);
|
||||
}
|
||||
if (do_mknod(fname,file->mode,file->u.rdev) != 0) {
|
||||
rprintf(FERROR, "mknod %s failed: %s\n",
|
||||
full_fname(fname), strerror(errno));
|
||||
rsyserr(FERROR, errno, "mknod %s failed",
|
||||
full_fname(fname));
|
||||
} else {
|
||||
set_perms(fname,file,NULL,0);
|
||||
if (verbose)
|
||||
rprintf(FINFO,"%s\n",fname);
|
||||
if (verbose) {
|
||||
rprintf(FINFO, "%s\n",
|
||||
safe_fname(fname));
|
||||
}
|
||||
}
|
||||
} else {
|
||||
set_perms(fname,file,&st,1);
|
||||
set_perms(fname, file, &st, PERMS_REPORT);
|
||||
}
|
||||
return;
|
||||
}
|
||||
@@ -400,7 +417,8 @@ void recv_generator(char *fname, struct file_struct *file, int i, int f_out)
|
||||
return;
|
||||
|
||||
if (!S_ISREG(file->mode)) {
|
||||
rprintf(FINFO, "skipping non-regular file \"%s\"\n",fname);
|
||||
rprintf(FINFO, "skipping non-regular file \"%s\"\n",
|
||||
safe_fname(fname));
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -408,91 +426,100 @@ void recv_generator(char *fname, struct file_struct *file, int i, int f_out)
|
||||
|
||||
if (statret == -1 && compare_dest != NULL) {
|
||||
/* try the file at compare_dest instead */
|
||||
int saveerrno = errno;
|
||||
pathjoin(fnamecmpbuf, sizeof fnamecmpbuf, compare_dest, fname);
|
||||
statret = link_stat(fnamecmpbuf,&st);
|
||||
if (!S_ISREG(st.st_mode))
|
||||
statret = -1;
|
||||
if (statret == -1)
|
||||
errno = saveerrno;
|
||||
if (link_stat(fnamecmpbuf, &st, 0) == 0
|
||||
&& S_ISREG(st.st_mode)) {
|
||||
#if HAVE_LINK
|
||||
else if (link_dest && !dry_run) {
|
||||
if (do_link(fnamecmpbuf, fname) != 0) {
|
||||
if (verbose > 0) {
|
||||
rprintf(FINFO,"link %s => %s : %s\n",
|
||||
fnamecmpbuf, fname,
|
||||
strerror(errno));
|
||||
if (link_dest && !dry_run) {
|
||||
if (do_link(fnamecmpbuf, fname) < 0) {
|
||||
if (verbose) {
|
||||
rsyserr(FINFO, errno,
|
||||
"link %s => %s",
|
||||
fnamecmpbuf,
|
||||
safe_fname(fname));
|
||||
}
|
||||
fnamecmp = fnamecmpbuf;
|
||||
}
|
||||
}
|
||||
fnamecmp = fnamecmpbuf;
|
||||
}
|
||||
} else
|
||||
#endif
|
||||
else
|
||||
fnamecmp = fnamecmpbuf;
|
||||
fnamecmp = fnamecmpbuf;
|
||||
statret = 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (statret == 0 && !S_ISREG(st.st_mode)) {
|
||||
if (delete_file(fname) != 0)
|
||||
return;
|
||||
statret = -1;
|
||||
stat_errno = ENOENT;
|
||||
}
|
||||
|
||||
if (partial_dir && (partialptr = partial_dir_fname(fname))
|
||||
&& link_stat(partialptr, &partial_st, 0) == 0
|
||||
&& S_ISREG(partial_st.st_mode)) {
|
||||
if (statret == -1)
|
||||
goto prepare_to_open;
|
||||
} else
|
||||
partialptr = NULL;
|
||||
|
||||
if (statret == -1) {
|
||||
if (preserve_hard_links && hard_link_check(file, HL_SKIP))
|
||||
return;
|
||||
if (errno == ENOENT) {
|
||||
if (stat_errno == ENOENT) {
|
||||
write_int(f_out,i);
|
||||
if (!dry_run) write_sum_head(f_out, NULL);
|
||||
if (!dry_run && !read_batch)
|
||||
write_sum_head(f_out, NULL);
|
||||
} else if (verbose > 1) {
|
||||
rprintf(FERROR,
|
||||
"recv_generator: failed to open %s: %s\n",
|
||||
full_fname(fname), strerror(errno));
|
||||
rsyserr(FERROR, stat_errno,
|
||||
"recv_generator: failed to stat %s",
|
||||
full_fname(fname));
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (!S_ISREG(st.st_mode)) {
|
||||
if (delete_file(fname) != 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
/* now pretend the file didn't exist */
|
||||
if (preserve_hard_links && hard_link_check(file, HL_SKIP))
|
||||
return;
|
||||
write_int(f_out,i);
|
||||
if (!dry_run) write_sum_head(f_out, NULL);
|
||||
return;
|
||||
}
|
||||
|
||||
if (opt_ignore_existing && fnamecmp == fname) {
|
||||
if (verbose > 1)
|
||||
rprintf(FINFO,"%s exists\n",fname);
|
||||
rprintf(FINFO, "%s exists\n", safe_fname(fname));
|
||||
return;
|
||||
}
|
||||
|
||||
if (update_only && cmp_modtime(st.st_mtime,file->modtime)>0 && fnamecmp == fname) {
|
||||
if (update_only && fnamecmp == fname
|
||||
&& cmp_modtime(st.st_mtime, file->modtime) > 0) {
|
||||
if (verbose > 1)
|
||||
rprintf(FINFO,"%s is newer\n",fname);
|
||||
rprintf(FINFO, "%s is newer\n", safe_fname(fname));
|
||||
return;
|
||||
}
|
||||
|
||||
if (skip_file(fname, file, &st)) {
|
||||
if (skip_file(fnamecmp, file, &st)) {
|
||||
if (fnamecmp == fname)
|
||||
set_perms(fname,file,&st,1);
|
||||
set_perms(fname, file, &st, PERMS_REPORT);
|
||||
return;
|
||||
}
|
||||
|
||||
if (dry_run) {
|
||||
prepare_to_open:
|
||||
if (dry_run || read_batch) {
|
||||
write_int(f_out,i);
|
||||
return;
|
||||
}
|
||||
|
||||
if (disable_deltas_p()) {
|
||||
if (whole_file > 0) {
|
||||
write_int(f_out,i);
|
||||
write_sum_head(f_out, NULL);
|
||||
return;
|
||||
}
|
||||
|
||||
if (partialptr) {
|
||||
st = partial_st;
|
||||
fnamecmp = partialptr;
|
||||
}
|
||||
|
||||
/* open the file */
|
||||
fd = do_open(fnamecmp, O_RDONLY, 0);
|
||||
|
||||
if (fd == -1) {
|
||||
rprintf(FERROR, "failed to open %s, continuing: %s\n",
|
||||
full_fname(fnamecmp), strerror(errno));
|
||||
rsyserr(FERROR, errno, "failed to open %s, continuing",
|
||||
full_fname(fnamecmp));
|
||||
pretend_missing:
|
||||
/* pretend the file didn't exist */
|
||||
if (preserve_hard_links && hard_link_check(file, HL_SKIP))
|
||||
return;
|
||||
@@ -501,31 +528,63 @@ void recv_generator(char *fname, struct file_struct *file, int i, int f_out)
|
||||
return;
|
||||
}
|
||||
|
||||
if (st.st_size > 0)
|
||||
mapbuf = map_file(fd,st.st_size);
|
||||
else
|
||||
mapbuf = NULL;
|
||||
if (inplace && make_backups) {
|
||||
if (!(backupptr = get_backup_name(fname))) {
|
||||
close(fd);
|
||||
return;
|
||||
}
|
||||
if (!(back_file = make_file(fname, NULL, NO_EXCLUDES))) {
|
||||
close(fd);
|
||||
goto pretend_missing;
|
||||
}
|
||||
if (robust_unlink(backupptr) && errno != ENOENT) {
|
||||
rsyserr(FERROR, errno, "unlink %s",
|
||||
full_fname(backupptr));
|
||||
free(back_file);
|
||||
close(fd);
|
||||
return;
|
||||
}
|
||||
if ((f_copy = do_open(backupptr,
|
||||
O_WRONLY | O_CREAT | O_TRUNC | O_EXCL, 0600)) < 0) {
|
||||
rsyserr(FERROR, errno, "open %s",
|
||||
full_fname(backupptr));
|
||||
free(back_file);
|
||||
close(fd);
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
backupptr = NULL;
|
||||
back_file = NULL;
|
||||
f_copy = -1;
|
||||
}
|
||||
|
||||
if (verbose > 3) {
|
||||
rprintf(FINFO,"gen mapped %s of size %.0f\n", fnamecmp,
|
||||
(double)st.st_size);
|
||||
rprintf(FINFO, "gen mapped %s of size %.0f\n",
|
||||
safe_fname(fnamecmp), (double)st.st_size);
|
||||
}
|
||||
|
||||
if (verbose > 2)
|
||||
rprintf(FINFO, "generating and sending sums for %d\n", i);
|
||||
|
||||
write_int(f_out,i);
|
||||
generate_and_send_sums(mapbuf, st.st_size, f_out);
|
||||
generate_and_send_sums(fd, st.st_size, f_out, f_copy);
|
||||
|
||||
if (f_copy >= 0) {
|
||||
close(f_copy);
|
||||
set_perms(backupptr, back_file, NULL, 0);
|
||||
if (verbose > 1)
|
||||
rprintf(FINFO, "backed up %s to %s\n", fname, backupptr);
|
||||
free(back_file);
|
||||
}
|
||||
|
||||
close(fd);
|
||||
if (mapbuf) unmap_file(mapbuf);
|
||||
}
|
||||
|
||||
|
||||
void generate_files(int f, struct file_list *flist, char *local_name)
|
||||
void generate_files(int f_out, struct file_list *flist, char *local_name)
|
||||
{
|
||||
int i;
|
||||
int phase=0;
|
||||
int phase = 0;
|
||||
char fbuf[MAXPATHLEN];
|
||||
|
||||
if (verbose > 2) {
|
||||
@@ -535,7 +594,7 @@ void generate_files(int f, struct file_list *flist, char *local_name)
|
||||
|
||||
if (verbose >= 2) {
|
||||
rprintf(FINFO,
|
||||
disable_deltas_p()
|
||||
whole_file > 0
|
||||
? "delta-transmission disabled for local transfer or --whole-file\n"
|
||||
: "delta transmission enabled\n");
|
||||
}
|
||||
@@ -563,31 +622,31 @@ void generate_files(int f, struct file_list *flist, char *local_name)
|
||||
}
|
||||
|
||||
recv_generator(local_name ? local_name : f_name_to(file, fbuf),
|
||||
file, i, f);
|
||||
file, i, f_out);
|
||||
}
|
||||
|
||||
phase++;
|
||||
csum_length = SUM_LENGTH;
|
||||
ignore_times=1;
|
||||
ignore_times = 1;
|
||||
|
||||
if (verbose > 2)
|
||||
rprintf(FINFO,"generate_files phase=%d\n",phase);
|
||||
|
||||
write_int(f,-1);
|
||||
write_int(f_out, -1);
|
||||
|
||||
/* files can cycle through the system more than once
|
||||
* to catch initial checksum errors */
|
||||
while ((i = get_redo_num()) != -1) {
|
||||
struct file_struct *file = flist->files[i];
|
||||
recv_generator(local_name ? local_name : f_name_to(file, fbuf),
|
||||
file, i, f);
|
||||
file, i, f_out);
|
||||
}
|
||||
|
||||
phase++;
|
||||
if (verbose > 2)
|
||||
rprintf(FINFO,"generate_files phase=%d\n",phase);
|
||||
|
||||
write_int(f,-1);
|
||||
write_int(f_out, -1);
|
||||
|
||||
if (preserve_hard_links)
|
||||
do_hard_links();
|
||||
@@ -596,7 +655,8 @@ void generate_files(int f, struct file_list *flist, char *local_name)
|
||||
* modified during the transfer */
|
||||
for (i = 0; i < flist->count; i++) {
|
||||
struct file_struct *file = flist->files[i];
|
||||
if (!file->basename || !S_ISDIR(file->mode)) continue;
|
||||
if (!file->basename || !S_ISDIR(file->mode))
|
||||
continue;
|
||||
recv_generator(local_name ? local_name : f_name(file),
|
||||
file, i, -1);
|
||||
}
|
||||
|
||||
17
getfsdev.c
Normal file
17
getfsdev.c
Normal file
@@ -0,0 +1,17 @@
|
||||
#include "rsync.h"
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
STRUCT_STAT st;
|
||||
|
||||
while (--argc > 0) {
|
||||
if (stat(*++argv, &st) < 0) {
|
||||
fprintf(stderr, "Unable to stat `%s'\n", *argv);
|
||||
exit(1);
|
||||
}
|
||||
printf("%ld/%ld\n", (long)major(st.st_dev),
|
||||
(long)minor(st.st_dev));
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
17
hlink.c
17
hlink.c
@@ -135,6 +135,7 @@ void init_hard_links(struct file_list *flist)
|
||||
|
||||
int hard_link_check(struct file_struct *file, int skip)
|
||||
{
|
||||
#if SUPPORT_HARD_LINKS
|
||||
if (!hlink_list || !file->link_u.links)
|
||||
return 0;
|
||||
if (skip && !(file->flags & FLAG_HLINK_EOL))
|
||||
@@ -146,6 +147,7 @@ int hard_link_check(struct file_struct *file, int skip)
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -154,8 +156,8 @@ static void hard_link_one(char *hlink1, char *hlink2)
|
||||
{
|
||||
if (do_link(hlink1, hlink2)) {
|
||||
if (verbose) {
|
||||
rprintf(FINFO, "link %s => %s failed: %s\n",
|
||||
hlink2, hlink1, strerror(errno));
|
||||
rsyserr(FINFO, errno, "link %s => %s failed",
|
||||
hlink2, hlink1);
|
||||
}
|
||||
}
|
||||
else if (verbose)
|
||||
@@ -183,11 +185,11 @@ void do_hard_links(void)
|
||||
|
||||
for (i = 0; i < hlink_count; i++) {
|
||||
first = file = hlink_list[i];
|
||||
if (link_stat(f_name_to(first, hlink1), &st1) != 0)
|
||||
if (link_stat(f_name_to(first, hlink1), &st1, 0) < 0)
|
||||
continue;
|
||||
while ((file = file->F_NEXT) != first) {
|
||||
hlink2 = f_name(file);
|
||||
if (link_stat(hlink2, &st2) == 0) {
|
||||
if (link_stat(hlink2, &st2, 0) == 0) {
|
||||
if (st2.st_dev == st1.st_dev
|
||||
&& st2.st_ino == st1.st_ino)
|
||||
continue;
|
||||
@@ -196,10 +198,9 @@ void do_hard_links(void)
|
||||
continue;
|
||||
} else if (robust_unlink(hlink2)) {
|
||||
if (verbose > 0) {
|
||||
rprintf(FINFO,
|
||||
"unlink %s failed: %s\n",
|
||||
full_fname(hlink2),
|
||||
strerror(errno));
|
||||
rsyserr(FINFO, errno,
|
||||
"unlink %s failed",
|
||||
full_fname(hlink2));
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
549
io.c
549
io.c
@@ -1,19 +1,19 @@
|
||||
/* -*- c-file-style: "linux" -*-
|
||||
*
|
||||
* Copyright (C) 1996-2001 by Andrew Tridgell
|
||||
*
|
||||
* Copyright (C) 1996-2001 by Andrew Tridgell
|
||||
* Copyright (C) Paul Mackerras 1996
|
||||
* Copyright (C) 2001, 2002 by Martin Pool <mbp@samba.org>
|
||||
*
|
||||
*
|
||||
* 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 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
@@ -22,7 +22,7 @@
|
||||
/**
|
||||
* @file io.c
|
||||
*
|
||||
* Socket and pipe IO utilities used in rsync.
|
||||
* Socket and pipe I/O utilities used in rsync.
|
||||
*
|
||||
* rsync provides its own multiplexing system, which is used to send
|
||||
* stderr and stdout over a single socket. We need this because
|
||||
@@ -39,23 +39,23 @@
|
||||
/** If no timeout is specified then use a 60 second select timeout */
|
||||
#define SELECT_TIMEOUT 60
|
||||
|
||||
static int io_multiplexing_out;
|
||||
static int io_multiplexing_in;
|
||||
static int multiplex_in_fd = -1;
|
||||
static int multiplex_out_fd = -1;
|
||||
static time_t last_io;
|
||||
static int no_flush;
|
||||
|
||||
extern int bwlimit;
|
||||
extern size_t bwlimit_writemax;
|
||||
extern int verbose;
|
||||
extern int io_timeout;
|
||||
extern int am_server;
|
||||
extern int am_daemon;
|
||||
extern int am_sender;
|
||||
extern int eol_nulls;
|
||||
extern int checksum_seed;
|
||||
extern int protocol_version;
|
||||
extern char *remote_filesfrom_file;
|
||||
extern struct stats stats;
|
||||
|
||||
|
||||
const char phase_unknown[] = "unknown";
|
||||
int select_timeout = SELECT_TIMEOUT;
|
||||
int batch_fd = -1;
|
||||
int batch_gen_fd = -1;
|
||||
|
||||
/**
|
||||
* The connection might be dropped at some point; perhaps because the
|
||||
@@ -63,9 +63,9 @@ const char phase_unknown[] = "unknown";
|
||||
* not very helpful. So instead we try to make io_phase_name point to
|
||||
* something useful.
|
||||
*
|
||||
* For buffered/multiplexed IO these names will be somewhat
|
||||
* For buffered/multiplexed I/O these names will be somewhat
|
||||
* approximate; perhaps for ease of support we would rather make the
|
||||
* buffer always flush when a single application-level IO finishes.
|
||||
* buffer always flush when a single application-level I/O finishes.
|
||||
*
|
||||
* @todo Perhaps we want some simple stack functionality, but there's
|
||||
* no need to overdo it.
|
||||
@@ -80,6 +80,16 @@ int kludge_around_eof = False;
|
||||
int msg_fd_in = -1;
|
||||
int msg_fd_out = -1;
|
||||
|
||||
static int io_multiplexing_out;
|
||||
static int io_multiplexing_in;
|
||||
static int sock_f_in = -1;
|
||||
static int sock_f_out = -1;
|
||||
static time_t last_io;
|
||||
static int no_flush;
|
||||
|
||||
static int write_batch_monitor_in = -1;
|
||||
static int write_batch_monitor_out = -1;
|
||||
|
||||
static int io_filesfrom_f_in = -1;
|
||||
static int io_filesfrom_f_out = -1;
|
||||
static char io_filesfrom_buf[2048];
|
||||
@@ -135,18 +145,26 @@ static void check_timeout(void)
|
||||
|
||||
t = time(NULL);
|
||||
|
||||
if (last_io && io_timeout && (t-last_io) >= io_timeout) {
|
||||
if (t - last_io >= io_timeout) {
|
||||
if (!am_server && !am_daemon) {
|
||||
rprintf(FERROR,"io timeout after %d seconds - exiting\n",
|
||||
rprintf(FERROR, "io timeout after %d seconds - exiting\n",
|
||||
(int)(t-last_io));
|
||||
}
|
||||
exit_cleanup(RERR_TIMEOUT);
|
||||
}
|
||||
}
|
||||
|
||||
/* Note the fds used for the main socket (which might really be a pipe
|
||||
* for a local transfer, but we can ignore that). */
|
||||
void io_set_sock_fds(int f_in, int f_out)
|
||||
{
|
||||
sock_f_in = f_in;
|
||||
sock_f_out = f_out;
|
||||
}
|
||||
|
||||
/** Setup the fd used to receive MSG_* messages. Only needed when
|
||||
* we're the generator because the sender and receiver both use the
|
||||
* multiplexed IO setup. */
|
||||
* multiplexed I/O setup. */
|
||||
void set_msg_fd_in(int fd)
|
||||
{
|
||||
msg_fd_in = fd;
|
||||
@@ -154,7 +172,7 @@ void set_msg_fd_in(int fd)
|
||||
|
||||
/** Setup the fd used to send our MSG_* messages. Only needed when
|
||||
* we're the receiver because the generator and the sender both use
|
||||
* the multiplexed IO setup. */
|
||||
* the multiplexed I/O setup. */
|
||||
void set_msg_fd_out(int fd)
|
||||
{
|
||||
msg_fd_out = fd;
|
||||
@@ -191,13 +209,13 @@ void send_msg(enum msgcode code, char *buf, int len)
|
||||
* called by the generator. */
|
||||
static void read_msg_fd(void)
|
||||
{
|
||||
char buf[200];
|
||||
char buf[2048];
|
||||
size_t n;
|
||||
int fd = msg_fd_in;
|
||||
int tag, len;
|
||||
|
||||
/* Temporarily disable msg_fd_in. This is needed because we
|
||||
* may call a write routine that could try to call us back. */
|
||||
/* Temporarily disable msg_fd_in. This is needed to avoid looping back
|
||||
* to this routine from read_timeout() and writefd_unbuffered(). */
|
||||
msg_fd_in = -1;
|
||||
|
||||
read_loop(fd, buf, 4);
|
||||
@@ -244,7 +262,7 @@ static void read_msg_fd(void)
|
||||
|
||||
/* Try to push messages off the list onto the wire. If we leave with more
|
||||
* to do, return 0. On error, return -1. If everything flushed, return 1.
|
||||
* This is only called by the receiver. */
|
||||
* This is only active in the receiver. */
|
||||
int msg_list_push(int flush_it_all)
|
||||
{
|
||||
static int written = 0;
|
||||
@@ -266,7 +284,7 @@ int msg_list_push(int flush_it_all)
|
||||
return 0;
|
||||
FD_ZERO(&fds);
|
||||
FD_SET(msg_fd_out, &fds);
|
||||
tv.tv_sec = io_timeout ? io_timeout : SELECT_TIMEOUT;
|
||||
tv.tv_sec = select_timeout;
|
||||
tv.tv_usec = 0;
|
||||
if (!select(msg_fd_out+1, NULL, &fds, NULL, &tv))
|
||||
check_timeout();
|
||||
@@ -329,34 +347,21 @@ void io_set_filesfrom_fds(int f_in, int f_out)
|
||||
* program where that is a problem (start_socket_client),
|
||||
* kludge_around_eof is True and we just exit.
|
||||
*/
|
||||
static void whine_about_eof(void)
|
||||
static void whine_about_eof(int fd)
|
||||
{
|
||||
if (kludge_around_eof)
|
||||
if (kludge_around_eof && fd == sock_f_in)
|
||||
exit_cleanup(0);
|
||||
else {
|
||||
rprintf(FERROR,
|
||||
"%s: connection unexpectedly closed "
|
||||
"(%.0f bytes read so far)\n",
|
||||
RSYNC_NAME, (double)stats.total_read);
|
||||
|
||||
exit_cleanup(RERR_STREAMIO);
|
||||
}
|
||||
}
|
||||
rprintf(FERROR, RSYNC_NAME ": connection unexpectedly closed "
|
||||
"(%.0f bytes received so far) [%s]\n",
|
||||
(double)stats.total_read, who_am_i());
|
||||
|
||||
|
||||
static void die_from_readerr(int err)
|
||||
{
|
||||
/* this prevents us trying to write errors on a dead socket */
|
||||
io_multiplexing_close();
|
||||
|
||||
rprintf(FERROR, "%s: read error: %s\n",
|
||||
RSYNC_NAME, strerror(err));
|
||||
exit_cleanup(RERR_STREAMIO);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Read from a socket with IO timeout. return the number of bytes
|
||||
* Read from a socket with I/O timeout. return the number of bytes
|
||||
* read. If no bytes can be read then exit, never return a number <= 0.
|
||||
*
|
||||
* TODO: If the remote shell connection fails, then current versions
|
||||
@@ -368,7 +373,7 @@ static void die_from_readerr(int err)
|
||||
*/
|
||||
static int read_timeout(int fd, char *buf, size_t len)
|
||||
{
|
||||
int n, ret=0;
|
||||
int n, ret = 0;
|
||||
|
||||
io_flush(NORMAL_FLUSH);
|
||||
|
||||
@@ -376,15 +381,20 @@ static int read_timeout(int fd, char *buf, size_t len)
|
||||
/* until we manage to read *something* */
|
||||
fd_set r_fds, w_fds;
|
||||
struct timeval tv;
|
||||
int fd_count = fd+1;
|
||||
int maxfd = fd;
|
||||
int count;
|
||||
|
||||
FD_ZERO(&r_fds);
|
||||
FD_ZERO(&w_fds);
|
||||
FD_SET(fd, &r_fds);
|
||||
if (msg_fd_in >= 0) {
|
||||
FD_SET(msg_fd_in, &r_fds);
|
||||
if (msg_fd_in >= fd_count)
|
||||
fd_count = msg_fd_in+1;
|
||||
if (msg_fd_in > maxfd)
|
||||
maxfd = msg_fd_in;
|
||||
} else if (msg_list_head) {
|
||||
FD_SET(msg_fd_out, &w_fds);
|
||||
if (msg_fd_out > maxfd)
|
||||
maxfd = msg_fd_out;
|
||||
}
|
||||
if (io_filesfrom_f_out >= 0) {
|
||||
int new_fd;
|
||||
@@ -397,37 +407,31 @@ static int read_timeout(int fd, char *buf, size_t len)
|
||||
new_fd = -1;
|
||||
}
|
||||
} else {
|
||||
FD_ZERO(&w_fds);
|
||||
FD_SET(io_filesfrom_f_out, &w_fds);
|
||||
new_fd = io_filesfrom_f_out;
|
||||
}
|
||||
if (new_fd >= fd_count)
|
||||
fd_count = new_fd+1;
|
||||
if (new_fd > maxfd)
|
||||
maxfd = new_fd;
|
||||
}
|
||||
|
||||
tv.tv_sec = io_timeout?io_timeout:SELECT_TIMEOUT;
|
||||
tv.tv_sec = select_timeout;
|
||||
tv.tv_usec = 0;
|
||||
|
||||
errno = 0;
|
||||
|
||||
count = select(fd_count, &r_fds,
|
||||
io_filesfrom_buflen? &w_fds : NULL,
|
||||
NULL, &tv);
|
||||
|
||||
if (count == 0) {
|
||||
msg_list_push(NORMAL_FLUSH);
|
||||
check_timeout();
|
||||
}
|
||||
count = select(maxfd + 1, &r_fds, &w_fds, NULL, &tv);
|
||||
|
||||
if (count <= 0) {
|
||||
if (errno == EBADF) {
|
||||
if (errno == EBADF)
|
||||
exit_cleanup(RERR_SOCKETIO);
|
||||
}
|
||||
check_timeout();
|
||||
continue;
|
||||
}
|
||||
|
||||
if (msg_fd_in >= 0 && FD_ISSET(msg_fd_in, &r_fds))
|
||||
read_msg_fd();
|
||||
else if (msg_list_head && FD_ISSET(msg_fd_out, &w_fds))
|
||||
msg_list_push(NORMAL_FLUSH);
|
||||
|
||||
if (io_filesfrom_f_out >= 0) {
|
||||
if (io_filesfrom_buflen) {
|
||||
@@ -457,7 +461,6 @@ static int read_timeout(int fd, char *buf, size_t len)
|
||||
io_filesfrom_buflen = io_filesfrom_lastchar? 2 : 1;
|
||||
io_filesfrom_f_in = -1;
|
||||
} else {
|
||||
extern int eol_nulls;
|
||||
if (!eol_nulls) {
|
||||
char *s = io_filesfrom_buf + l;
|
||||
/* Transform CR and/or LF into '\0' */
|
||||
@@ -493,26 +496,31 @@ static int read_timeout(int fd, char *buf, size_t len)
|
||||
}
|
||||
}
|
||||
|
||||
if (!FD_ISSET(fd, &r_fds)) continue;
|
||||
if (!FD_ISSET(fd, &r_fds))
|
||||
continue;
|
||||
|
||||
n = read(fd, buf, len);
|
||||
|
||||
if (n > 0) {
|
||||
buf += n;
|
||||
len -= n;
|
||||
ret += n;
|
||||
if (io_timeout)
|
||||
last_io = time(NULL);
|
||||
continue;
|
||||
} else if (n == 0) {
|
||||
whine_about_eof();
|
||||
return -1; /* doesn't return */
|
||||
} else if (n < 0) {
|
||||
if (errno == EINTR || errno == EWOULDBLOCK ||
|
||||
errno == EAGAIN)
|
||||
if (n <= 0) {
|
||||
if (n == 0)
|
||||
whine_about_eof(fd); /* Doesn't return. */
|
||||
if (errno == EINTR || errno == EWOULDBLOCK
|
||||
|| errno == EAGAIN)
|
||||
continue;
|
||||
die_from_readerr(errno);
|
||||
|
||||
/* Don't write errors on a dead socket. */
|
||||
if (fd == sock_f_in)
|
||||
close_multiplexing_out();
|
||||
rsyserr(FERROR, errno, "read error");
|
||||
exit_cleanup(RERR_STREAMIO);
|
||||
}
|
||||
|
||||
buf += n;
|
||||
len -= n;
|
||||
ret += n;
|
||||
|
||||
if (io_timeout && fd == sock_f_in)
|
||||
last_io = time(NULL);
|
||||
}
|
||||
|
||||
return ret;
|
||||
@@ -526,9 +534,6 @@ int read_filesfrom_line(int fd, char *fname)
|
||||
{
|
||||
char ch, *s, *eob = fname + MAXPATHLEN - 1;
|
||||
int cnt;
|
||||
extern int io_timeout;
|
||||
extern int eol_nulls;
|
||||
extern char *remote_filesfrom_file;
|
||||
int reading_remotely = remote_filesfrom_file != NULL;
|
||||
int nulls = eol_nulls || reading_remotely;
|
||||
|
||||
@@ -542,7 +547,7 @@ int read_filesfrom_line(int fd, char *fname)
|
||||
fd_set fds;
|
||||
FD_ZERO(&fds);
|
||||
FD_SET(fd, &fds);
|
||||
tv.tv_sec = io_timeout? io_timeout : SELECT_TIMEOUT;
|
||||
tv.tv_sec = select_timeout;
|
||||
tv.tv_usec = 0;
|
||||
if (!select(fd+1, &fds, NULL, NULL, &tv))
|
||||
check_timeout();
|
||||
@@ -569,6 +574,42 @@ int read_filesfrom_line(int fd, char *fname)
|
||||
}
|
||||
|
||||
|
||||
static char *iobuf_out;
|
||||
static int iobuf_out_cnt;
|
||||
|
||||
void io_start_buffering_out(void)
|
||||
{
|
||||
if (iobuf_out)
|
||||
return;
|
||||
if (!(iobuf_out = new_array(char, IO_BUFFER_SIZE)))
|
||||
out_of_memory("io_start_buffering_out");
|
||||
iobuf_out_cnt = 0;
|
||||
}
|
||||
|
||||
|
||||
static char *iobuf_in;
|
||||
static size_t iobuf_in_siz;
|
||||
|
||||
void io_start_buffering_in(void)
|
||||
{
|
||||
if (iobuf_in)
|
||||
return;
|
||||
iobuf_in_siz = 2 * IO_BUFFER_SIZE;
|
||||
if (!(iobuf_in = new_array(char, iobuf_in_siz)))
|
||||
out_of_memory("io_start_buffering_in");
|
||||
}
|
||||
|
||||
|
||||
void io_end_buffering(void)
|
||||
{
|
||||
io_flush(NORMAL_FLUSH);
|
||||
if (!io_multiplexing_out) {
|
||||
free(iobuf_out);
|
||||
iobuf_out = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Continue trying to read len bytes - don't return until len has been
|
||||
* read.
|
||||
@@ -587,36 +628,29 @@ static void read_loop(int fd, char *buf, size_t len)
|
||||
/**
|
||||
* Read from the file descriptor handling multiplexing - return number
|
||||
* of bytes read.
|
||||
*
|
||||
* Never returns <= 0.
|
||||
*
|
||||
* Never returns <= 0.
|
||||
*/
|
||||
static int read_unbuffered(int fd, char *buf, size_t len)
|
||||
static int readfd_unbuffered(int fd, char *buf, size_t len)
|
||||
{
|
||||
static size_t remaining;
|
||||
static size_t iobuf_in_ndx;
|
||||
int tag, ret = 0;
|
||||
char line[1024];
|
||||
static char *buffer;
|
||||
static size_t bufferIdx = 0;
|
||||
static size_t bufferSz;
|
||||
|
||||
if (fd != multiplex_in_fd)
|
||||
if (!iobuf_in || fd != sock_f_in)
|
||||
return read_timeout(fd, buf, len);
|
||||
|
||||
if (!io_multiplexing_in && remaining == 0) {
|
||||
if (!buffer) {
|
||||
bufferSz = 2 * IO_BUFFER_SIZE;
|
||||
buffer = new_array(char, bufferSz);
|
||||
if (!buffer) out_of_memory("read_unbuffered");
|
||||
}
|
||||
remaining = read_timeout(fd, buffer, bufferSz);
|
||||
bufferIdx = 0;
|
||||
remaining = read_timeout(fd, iobuf_in, iobuf_in_siz);
|
||||
iobuf_in_ndx = 0;
|
||||
}
|
||||
|
||||
while (ret == 0) {
|
||||
if (remaining) {
|
||||
len = MIN(len, remaining);
|
||||
memcpy(buf, buffer + bufferIdx, len);
|
||||
bufferIdx += len;
|
||||
memcpy(buf, iobuf_in + iobuf_in_ndx, len);
|
||||
iobuf_in_ndx += len;
|
||||
remaining -= len;
|
||||
ret = len;
|
||||
break;
|
||||
@@ -630,13 +664,14 @@ static int read_unbuffered(int fd, char *buf, size_t len)
|
||||
|
||||
switch (tag) {
|
||||
case MSG_DATA:
|
||||
if (!buffer || remaining > bufferSz) {
|
||||
buffer = realloc_array(buffer, char, remaining);
|
||||
if (!buffer) out_of_memory("read_unbuffered");
|
||||
bufferSz = remaining;
|
||||
if (remaining > iobuf_in_siz) {
|
||||
if (!(iobuf_in = realloc_array(iobuf_in, char,
|
||||
remaining)))
|
||||
out_of_memory("readfd_unbuffered");
|
||||
iobuf_in_siz = remaining;
|
||||
}
|
||||
read_loop(fd, buffer, remaining);
|
||||
bufferIdx = 0;
|
||||
read_loop(fd, iobuf_in, remaining);
|
||||
iobuf_in_ndx = 0;
|
||||
break;
|
||||
case MSG_INFO:
|
||||
case MSG_ERROR:
|
||||
@@ -671,14 +706,20 @@ static int read_unbuffered(int fd, char *buf, size_t len)
|
||||
static void readfd(int fd, char *buffer, size_t N)
|
||||
{
|
||||
int ret;
|
||||
size_t total=0;
|
||||
size_t total = 0;
|
||||
|
||||
while (total < N) {
|
||||
ret = read_unbuffered(fd, buffer + total, N-total);
|
||||
ret = readfd_unbuffered(fd, buffer + total, N-total);
|
||||
total += ret;
|
||||
}
|
||||
|
||||
stats.total_read += total;
|
||||
if (fd == write_batch_monitor_in) {
|
||||
if ((size_t)write(batch_fd, buffer, total) != total)
|
||||
exit_cleanup(RERR_FILEIO);
|
||||
}
|
||||
|
||||
if (fd == sock_f_in)
|
||||
stats.total_read += total;
|
||||
}
|
||||
|
||||
|
||||
@@ -689,7 +730,8 @@ int32 read_int(int f)
|
||||
|
||||
readfd(f,b,4);
|
||||
ret = IVAL(b,0);
|
||||
if (ret == (int32)0xffffffff) return -1;
|
||||
if (ret == (int32)0xffffffff)
|
||||
return -1;
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -699,17 +741,17 @@ int64 read_longint(int f)
|
||||
char b[8];
|
||||
ret = read_int(f);
|
||||
|
||||
if ((int32)ret != (int32)0xffffffff) {
|
||||
if ((int32)ret != (int32)0xffffffff)
|
||||
return ret;
|
||||
}
|
||||
|
||||
#ifdef NO_INT64
|
||||
rprintf(FERROR,"Integer overflow - attempted 64 bit offset\n");
|
||||
exit_cleanup(RERR_UNSUPPORTED);
|
||||
#else
|
||||
#ifdef INT64_IS_OFF_T
|
||||
if (sizeof (int64) < 8) {
|
||||
rprintf(FERROR, "Integer overflow: attempted 64-bit offset\n");
|
||||
exit_cleanup(RERR_UNSUPPORTED);
|
||||
}
|
||||
#endif
|
||||
readfd(f,b,8);
|
||||
ret = IVAL(b,0) | (((int64)IVAL(b,4))<<32);
|
||||
#endif
|
||||
|
||||
return ret;
|
||||
}
|
||||
@@ -721,14 +763,14 @@ void read_buf(int f,char *buf,size_t len)
|
||||
|
||||
void read_sbuf(int f,char *buf,size_t len)
|
||||
{
|
||||
read_buf(f,buf,len);
|
||||
readfd(f, buf, len);
|
||||
buf[len] = 0;
|
||||
}
|
||||
|
||||
unsigned char read_byte(int f)
|
||||
{
|
||||
unsigned char c;
|
||||
read_buf(f, (char *)&c, 1);
|
||||
readfd(f, (char *)&c, 1);
|
||||
return c;
|
||||
}
|
||||
|
||||
@@ -741,81 +783,107 @@ unsigned char read_byte(int f)
|
||||
* use a bit less bandwidth than specified, because it doesn't make up
|
||||
* for slow periods. But arguably this is a feature. In addition, we
|
||||
* ought to take the time used to write the data into account.
|
||||
*
|
||||
* During some phases of big transfers (file FOO is uptodate) this is
|
||||
* called with a small bytes_written every time. As the kernel has to
|
||||
* round small waits up to guarantee that we actually wait at least the
|
||||
* requested number of microseconds, this can become grossly inaccurate.
|
||||
* We therefore keep track of the bytes we've written over time and only
|
||||
* sleep when the accumulated delay is at least 1 tenth of a second.
|
||||
**/
|
||||
static void sleep_for_bwlimit(int bytes_written)
|
||||
{
|
||||
struct timeval tv;
|
||||
static struct timeval prior_tv;
|
||||
static long total_written = 0;
|
||||
struct timeval tv, start_tv;
|
||||
long elapsed_usec, sleep_usec;
|
||||
|
||||
#define ONE_SEC 1000000L /* # of microseconds in a second */
|
||||
|
||||
if (!bwlimit)
|
||||
return;
|
||||
|
||||
assert(bytes_written > 0);
|
||||
assert(bwlimit > 0);
|
||||
total_written += bytes_written;
|
||||
|
||||
tv.tv_usec = bytes_written * 1000 / bwlimit;
|
||||
tv.tv_sec = tv.tv_usec / 1000000;
|
||||
tv.tv_usec = tv.tv_usec % 1000000;
|
||||
gettimeofday(&start_tv, NULL);
|
||||
if (prior_tv.tv_sec) {
|
||||
elapsed_usec = (start_tv.tv_sec - prior_tv.tv_sec) * ONE_SEC
|
||||
+ (start_tv.tv_usec - prior_tv.tv_usec);
|
||||
total_written -= elapsed_usec * bwlimit / (ONE_SEC/1024);
|
||||
if (total_written < 0)
|
||||
total_written = 0;
|
||||
}
|
||||
|
||||
sleep_usec = total_written * (ONE_SEC/1024) / bwlimit;
|
||||
if (sleep_usec < ONE_SEC / 10) {
|
||||
prior_tv = start_tv;
|
||||
return;
|
||||
}
|
||||
|
||||
tv.tv_sec = sleep_usec / ONE_SEC;
|
||||
tv.tv_usec = sleep_usec % ONE_SEC;
|
||||
select(0, NULL, NULL, NULL, &tv);
|
||||
|
||||
gettimeofday(&prior_tv, NULL);
|
||||
elapsed_usec = (prior_tv.tv_sec - start_tv.tv_sec) * ONE_SEC
|
||||
+ (prior_tv.tv_usec - start_tv.tv_usec);
|
||||
total_written = (sleep_usec - elapsed_usec) * bwlimit / (ONE_SEC/1024);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Write len bytes to the file descriptor @p fd.
|
||||
/* Write len bytes to the file descriptor fd, looping as necessary to get
|
||||
* the job done and also (in the generator) reading any data on msg_fd_in
|
||||
* (to avoid deadlock).
|
||||
*
|
||||
* This function underlies the multiplexing system. The body of the
|
||||
* application never calls this function directly.
|
||||
**/
|
||||
* application never calls this function directly. */
|
||||
static void writefd_unbuffered(int fd,char *buf,size_t len)
|
||||
{
|
||||
size_t total = 0;
|
||||
size_t n, total = 0;
|
||||
fd_set w_fds, r_fds;
|
||||
int fd_count, count;
|
||||
int maxfd, count, ret;
|
||||
struct timeval tv;
|
||||
|
||||
msg_list_push(NORMAL_FLUSH);
|
||||
|
||||
no_flush++;
|
||||
|
||||
while (total < len) {
|
||||
FD_ZERO(&w_fds);
|
||||
FD_SET(fd,&w_fds);
|
||||
fd_count = fd;
|
||||
maxfd = fd;
|
||||
|
||||
if (msg_fd_in >= 0) {
|
||||
FD_ZERO(&r_fds);
|
||||
FD_SET(msg_fd_in,&r_fds);
|
||||
if (msg_fd_in > fd_count)
|
||||
fd_count = msg_fd_in;
|
||||
if (msg_fd_in > maxfd)
|
||||
maxfd = msg_fd_in;
|
||||
}
|
||||
|
||||
tv.tv_sec = io_timeout?io_timeout:SELECT_TIMEOUT;
|
||||
tv.tv_sec = select_timeout;
|
||||
tv.tv_usec = 0;
|
||||
|
||||
errno = 0;
|
||||
count = select(fd_count+1, msg_fd_in >= 0 ? &r_fds : NULL,
|
||||
count = select(maxfd + 1, msg_fd_in >= 0 ? &r_fds : NULL,
|
||||
&w_fds, NULL, &tv);
|
||||
|
||||
if (count == 0) {
|
||||
msg_list_push(NORMAL_FLUSH);
|
||||
check_timeout();
|
||||
}
|
||||
|
||||
if (count <= 0) {
|
||||
if (errno == EBADF) {
|
||||
if (count < 0 && errno == EBADF)
|
||||
exit_cleanup(RERR_SOCKETIO);
|
||||
}
|
||||
check_timeout();
|
||||
continue;
|
||||
}
|
||||
|
||||
if (msg_fd_in >= 0 && FD_ISSET(msg_fd_in, &r_fds))
|
||||
read_msg_fd();
|
||||
|
||||
if (FD_ISSET(fd, &w_fds)) {
|
||||
int ret;
|
||||
size_t n = len-total;
|
||||
ret = write(fd,buf+total,n);
|
||||
if (!FD_ISSET(fd, &w_fds))
|
||||
continue;
|
||||
|
||||
n = len - total;
|
||||
if (bwlimit && n > bwlimit_writemax)
|
||||
n = bwlimit_writemax;
|
||||
ret = write(fd, buf + total, n);
|
||||
|
||||
if (ret <= 0) {
|
||||
if (ret < 0) {
|
||||
if (errno == EINTR)
|
||||
continue;
|
||||
@@ -825,23 +893,28 @@ static void writefd_unbuffered(int fd,char *buf,size_t len)
|
||||
}
|
||||
}
|
||||
|
||||
if (ret <= 0) {
|
||||
/* Don't try to write errors back
|
||||
* across the stream */
|
||||
io_multiplexing_close();
|
||||
rprintf(FERROR, RSYNC_NAME
|
||||
": writefd_unbuffered failed to write %ld bytes: phase \"%s\": %s\n",
|
||||
(long) len, io_write_phase,
|
||||
strerror(errno));
|
||||
exit_cleanup(RERR_STREAMIO);
|
||||
/* Don't try to write errors back across the stream. */
|
||||
if (fd == sock_f_out)
|
||||
close_multiplexing_out();
|
||||
rsyserr(FERROR, errno,
|
||||
"writefd_unbuffered failed to write %ld bytes: phase \"%s\" [%s]",
|
||||
(long)len, io_write_phase, who_am_i());
|
||||
/* If the other side is sending us error messages, try
|
||||
* to grab any messages they sent before they died. */
|
||||
while (fd == sock_f_out && io_multiplexing_in) {
|
||||
io_timeout = 30;
|
||||
readfd_unbuffered(sock_f_in, io_filesfrom_buf,
|
||||
sizeof io_filesfrom_buf);
|
||||
}
|
||||
exit_cleanup(RERR_STREAMIO);
|
||||
}
|
||||
|
||||
sleep_for_bwlimit(ret);
|
||||
|
||||
total += ret;
|
||||
total += ret;
|
||||
|
||||
if (fd == sock_f_out) {
|
||||
if (io_timeout)
|
||||
last_io = time(NULL);
|
||||
sleep_for_bwlimit(ret);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -849,97 +922,76 @@ static void writefd_unbuffered(int fd,char *buf,size_t len)
|
||||
}
|
||||
|
||||
|
||||
static char *io_buffer;
|
||||
static int io_buffer_count;
|
||||
|
||||
void io_start_buffering_out(int fd)
|
||||
{
|
||||
if (io_buffer) return;
|
||||
multiplex_out_fd = fd;
|
||||
io_buffer = new_array(char, IO_BUFFER_SIZE);
|
||||
if (!io_buffer) out_of_memory("writefd");
|
||||
io_buffer_count = 0;
|
||||
}
|
||||
|
||||
void io_start_buffering_in(int fd)
|
||||
{
|
||||
multiplex_in_fd = fd;
|
||||
}
|
||||
|
||||
/**
|
||||
* Write an message to a multiplexed stream. If this fails then rsync
|
||||
* exits.
|
||||
**/
|
||||
static void mplex_write(int fd, enum msgcode code, char *buf, size_t len)
|
||||
static void mplex_write(enum msgcode code, char *buf, size_t len)
|
||||
{
|
||||
char buffer[4096];
|
||||
size_t n = len;
|
||||
|
||||
SIVAL(buffer, 0, ((MPLEX_BASE + (int)code)<<24) + len);
|
||||
|
||||
if (n > (sizeof buffer - 4)) {
|
||||
if (n > sizeof buffer - 4)
|
||||
n = sizeof buffer - 4;
|
||||
}
|
||||
|
||||
memcpy(&buffer[4], buf, n);
|
||||
writefd_unbuffered(fd, buffer, n+4);
|
||||
writefd_unbuffered(sock_f_out, buffer, n+4);
|
||||
|
||||
len -= n;
|
||||
buf += n;
|
||||
|
||||
if (len) {
|
||||
writefd_unbuffered(fd, buf, len);
|
||||
}
|
||||
if (len)
|
||||
writefd_unbuffered(sock_f_out, buf, len);
|
||||
}
|
||||
|
||||
|
||||
void io_flush(int flush_it_all)
|
||||
{
|
||||
int fd = multiplex_out_fd;
|
||||
|
||||
msg_list_push(flush_it_all);
|
||||
|
||||
if (!io_buffer_count || no_flush)
|
||||
if (!iobuf_out_cnt || no_flush)
|
||||
return;
|
||||
|
||||
if (io_multiplexing_out)
|
||||
mplex_write(fd, MSG_DATA, io_buffer, io_buffer_count);
|
||||
mplex_write(MSG_DATA, iobuf_out, iobuf_out_cnt);
|
||||
else
|
||||
writefd_unbuffered(fd, io_buffer, io_buffer_count);
|
||||
io_buffer_count = 0;
|
||||
writefd_unbuffered(sock_f_out, iobuf_out, iobuf_out_cnt);
|
||||
iobuf_out_cnt = 0;
|
||||
}
|
||||
|
||||
|
||||
void io_end_buffering(void)
|
||||
{
|
||||
io_flush(NORMAL_FLUSH);
|
||||
if (!io_multiplexing_out) {
|
||||
free(io_buffer);
|
||||
io_buffer = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
static void writefd(int fd,char *buf,size_t len)
|
||||
{
|
||||
stats.total_written += len;
|
||||
if (fd == msg_fd_out) {
|
||||
rprintf(FERROR, "Internal error: wrong write used in receiver.\n");
|
||||
exit_cleanup(RERR_PROTOCOL);
|
||||
}
|
||||
|
||||
msg_list_push(NORMAL_FLUSH);
|
||||
if (fd == sock_f_out)
|
||||
stats.total_written += len;
|
||||
|
||||
if (!io_buffer || fd != multiplex_out_fd) {
|
||||
if (fd == write_batch_monitor_out) {
|
||||
if ((size_t)write(batch_fd, buf, len) != len)
|
||||
exit_cleanup(RERR_FILEIO);
|
||||
}
|
||||
|
||||
if (!iobuf_out || fd != sock_f_out) {
|
||||
writefd_unbuffered(fd, buf, len);
|
||||
return;
|
||||
}
|
||||
|
||||
while (len) {
|
||||
int n = MIN((int) len, IO_BUFFER_SIZE-io_buffer_count);
|
||||
int n = MIN((int)len, IO_BUFFER_SIZE - iobuf_out_cnt);
|
||||
if (n > 0) {
|
||||
memcpy(io_buffer+io_buffer_count, buf, n);
|
||||
memcpy(iobuf_out+iobuf_out_cnt, buf, n);
|
||||
buf += n;
|
||||
len -= n;
|
||||
io_buffer_count += n;
|
||||
iobuf_out_cnt += n;
|
||||
}
|
||||
|
||||
if (io_buffer_count == IO_BUFFER_SIZE)
|
||||
if (iobuf_out_cnt == IO_BUFFER_SIZE)
|
||||
io_flush(NORMAL_FLUSH);
|
||||
}
|
||||
}
|
||||
@@ -974,16 +1026,18 @@ void write_longint(int f, int64 x)
|
||||
return;
|
||||
}
|
||||
|
||||
#ifdef NO_INT64
|
||||
rprintf(FERROR,"Integer overflow - attempted 64 bit offset\n");
|
||||
exit_cleanup(RERR_UNSUPPORTED);
|
||||
#else
|
||||
#ifdef INT64_IS_OFF_T
|
||||
if (sizeof (int64) < 8) {
|
||||
rprintf(FERROR, "Integer overflow: attempted 64-bit offset\n");
|
||||
exit_cleanup(RERR_UNSUPPORTED);
|
||||
}
|
||||
#endif
|
||||
|
||||
write_int(f, (int32)0xFFFFFFFF);
|
||||
SIVAL(b,0,(x&0xFFFFFFFF));
|
||||
SIVAL(b,4,((x>>32)&0xFFFFFFFF));
|
||||
|
||||
writefd(f,b,8);
|
||||
#endif
|
||||
}
|
||||
|
||||
void write_buf(int f,char *buf,size_t len)
|
||||
@@ -992,24 +1046,24 @@ void write_buf(int f,char *buf,size_t len)
|
||||
}
|
||||
|
||||
/** Write a string to the connection */
|
||||
static void write_sbuf(int f,char *buf)
|
||||
void write_sbuf(int f, char *buf)
|
||||
{
|
||||
write_buf(f, buf, strlen(buf));
|
||||
writefd(f, buf, strlen(buf));
|
||||
}
|
||||
|
||||
|
||||
void write_byte(int f,unsigned char c)
|
||||
{
|
||||
write_buf(f,(char *)&c,1);
|
||||
writefd(f, (char *)&c, 1);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Read a line of up to @p maxlen characters into @p buf. Does not
|
||||
* contain a trailing newline or carriage return.
|
||||
* Read a line of up to @p maxlen characters into @p buf (not counting
|
||||
* the trailing null). Strips the (required) trailing newline and all
|
||||
* carriage returns.
|
||||
*
|
||||
* @return 1 for success; 0 for io error or truncation.
|
||||
* @return 1 for success; 0 for I/O error or truncation.
|
||||
**/
|
||||
int read_line(int f, char *buf, size_t maxlen)
|
||||
{
|
||||
@@ -1018,27 +1072,21 @@ int read_line(int f, char *buf, size_t maxlen)
|
||||
read_buf(f, buf, 1);
|
||||
if (buf[0] == 0)
|
||||
return 0;
|
||||
if (buf[0] == '\n') {
|
||||
buf[0] = 0;
|
||||
if (buf[0] == '\n')
|
||||
break;
|
||||
}
|
||||
if (buf[0] != '\r') {
|
||||
buf++;
|
||||
maxlen--;
|
||||
}
|
||||
}
|
||||
if (maxlen == 0) {
|
||||
*buf = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
*buf = '\0';
|
||||
return maxlen > 0;
|
||||
}
|
||||
|
||||
|
||||
void io_printf(int fd, const char *format, ...)
|
||||
{
|
||||
va_list ap;
|
||||
va_list ap;
|
||||
char buf[1024];
|
||||
int len;
|
||||
|
||||
@@ -1046,43 +1094,72 @@ void io_printf(int fd, const char *format, ...)
|
||||
len = vsnprintf(buf, sizeof buf, format, ap);
|
||||
va_end(ap);
|
||||
|
||||
if (len < 0) exit_cleanup(RERR_STREAMIO);
|
||||
if (len < 0)
|
||||
exit_cleanup(RERR_STREAMIO);
|
||||
|
||||
write_sbuf(fd, buf);
|
||||
}
|
||||
|
||||
|
||||
/** Setup for multiplexing a MSG_* stream with the data stream. */
|
||||
void io_start_multiplex_out(int fd)
|
||||
void io_start_multiplex_out(void)
|
||||
{
|
||||
multiplex_out_fd = fd;
|
||||
io_flush(NORMAL_FLUSH);
|
||||
io_start_buffering_out(fd);
|
||||
io_start_buffering_out();
|
||||
io_multiplexing_out = 1;
|
||||
}
|
||||
|
||||
/** Setup for multiplexing a MSG_* stream with the data stream. */
|
||||
void io_start_multiplex_in(int fd)
|
||||
void io_start_multiplex_in(void)
|
||||
{
|
||||
multiplex_in_fd = fd;
|
||||
io_flush(NORMAL_FLUSH);
|
||||
io_start_buffering_in();
|
||||
io_multiplexing_in = 1;
|
||||
}
|
||||
|
||||
/** Write an message to the multiplexed data stream. */
|
||||
int io_multiplex_write(enum msgcode code, char *buf, size_t len)
|
||||
{
|
||||
if (!io_multiplexing_out) return 0;
|
||||
if (!io_multiplexing_out)
|
||||
return 0;
|
||||
|
||||
io_flush(NORMAL_FLUSH);
|
||||
stats.total_written += (len+4);
|
||||
mplex_write(multiplex_out_fd, code, buf, len);
|
||||
mplex_write(code, buf, len);
|
||||
return 1;
|
||||
}
|
||||
|
||||
void close_multiplexing_in(void)
|
||||
{
|
||||
io_multiplexing_in = 0;
|
||||
}
|
||||
|
||||
/** Stop output multiplexing. */
|
||||
void io_multiplexing_close(void)
|
||||
void close_multiplexing_out(void)
|
||||
{
|
||||
io_multiplexing_out = 0;
|
||||
}
|
||||
|
||||
void start_write_batch(int fd)
|
||||
{
|
||||
write_stream_flags(batch_fd);
|
||||
|
||||
/* Some communication has already taken place, but we don't
|
||||
* enable batch writing until here so that we can write a
|
||||
* canonical record of the communication even though the
|
||||
* actual communication so far depends on whether a daemon
|
||||
* is involved. */
|
||||
write_int(batch_fd, protocol_version);
|
||||
write_int(batch_fd, checksum_seed);
|
||||
|
||||
if (am_sender)
|
||||
write_batch_monitor_out = fd;
|
||||
else
|
||||
write_batch_monitor_in = fd;
|
||||
}
|
||||
|
||||
void stop_write_batch(void)
|
||||
{
|
||||
write_batch_monitor_out = -1;
|
||||
write_batch_monitor_in = -1;
|
||||
}
|
||||
|
||||
@@ -119,6 +119,7 @@ typedef struct
|
||||
char *comment;
|
||||
char *lock_file;
|
||||
BOOL read_only;
|
||||
BOOL write_only;
|
||||
BOOL list;
|
||||
BOOL use_chroot;
|
||||
BOOL transfer_logging;
|
||||
@@ -151,6 +152,7 @@ static service sDefault =
|
||||
NULL, /* comment */
|
||||
DEFAULT_LOCK_FILE, /* lock file */
|
||||
True, /* read only */
|
||||
False, /* write only */
|
||||
True, /* list */
|
||||
True, /* use chroot */
|
||||
False, /* transfer logging */
|
||||
@@ -277,6 +279,7 @@ static struct parm_struct parm_table[] =
|
||||
{"lock file", P_STRING, P_LOCAL, &sDefault.lock_file, NULL, 0},
|
||||
{"path", P_PATH, P_LOCAL, &sDefault.path, NULL, 0},
|
||||
{"read only", P_BOOL, P_LOCAL, &sDefault.read_only, NULL, 0},
|
||||
{"write only", P_BOOL, P_LOCAL, &sDefault.write_only, NULL, 0},
|
||||
{"list", P_BOOL, P_LOCAL, &sDefault.list, NULL, 0},
|
||||
{"use chroot", P_BOOL, P_LOCAL, &sDefault.use_chroot, NULL, 0},
|
||||
{"ignore nonreadable",P_BOOL, P_LOCAL, &sDefault.ignore_nonreadable, NULL, 0},
|
||||
@@ -356,6 +359,7 @@ FN_LOCAL_STRING(lp_comment, comment)
|
||||
FN_LOCAL_STRING(lp_path, path)
|
||||
FN_LOCAL_STRING(lp_lock_file, lock_file)
|
||||
FN_LOCAL_BOOL(lp_read_only, read_only)
|
||||
FN_LOCAL_BOOL(lp_write_only, write_only)
|
||||
FN_LOCAL_BOOL(lp_list, list)
|
||||
FN_LOCAL_BOOL(lp_use_chroot, use_chroot)
|
||||
FN_LOCAL_BOOL(lp_transfer_logging, transfer_logging)
|
||||
@@ -807,7 +811,7 @@ int lp_number(char *name)
|
||||
int iService;
|
||||
|
||||
for (iService = iNumServices - 1; iService >= 0; iService--)
|
||||
if (strequal(lp_name(iService), name))
|
||||
if (strcmp(lp_name(iService), name) == 0)
|
||||
break;
|
||||
|
||||
return (iService);
|
||||
|
||||
135
log.c
135
log.c
@@ -41,7 +41,7 @@ static char *logfname;
|
||||
static FILE *logfile;
|
||||
struct stats stats;
|
||||
|
||||
int log_got_error=0;
|
||||
int log_got_error = 0;
|
||||
|
||||
struct {
|
||||
int code;
|
||||
@@ -61,7 +61,7 @@ struct {
|
||||
{ RERR_WAITCHILD , "some error returned by waitpid()" },
|
||||
{ RERR_MALLOC , "error allocating core memory buffers" },
|
||||
{ RERR_PARTIAL , "some files could not be transferred" },
|
||||
{ RERR_VANISHED , "some files vanished before they could be transfered" },
|
||||
{ RERR_VANISHED , "some files vanished before they could be transferred" },
|
||||
{ RERR_TIMEOUT , "timeout in data send/receive" },
|
||||
{ RERR_CMD_FAILED , "remote shell failed" },
|
||||
{ RERR_CMD_KILLED , "remote shell killed" },
|
||||
@@ -104,7 +104,8 @@ void log_init(void)
|
||||
int options = LOG_PID;
|
||||
time_t t;
|
||||
|
||||
if (log_initialised) return;
|
||||
if (log_initialised)
|
||||
return;
|
||||
log_initialised = 1;
|
||||
|
||||
/* this looks pointless, but it is needed in order for the
|
||||
@@ -160,7 +161,7 @@ void log_close(void)
|
||||
* it with FINFO, FERROR or FLOG */
|
||||
void rwrite(enum logcode code, char *buf, int len)
|
||||
{
|
||||
FILE *f=NULL;
|
||||
FILE *f = NULL;
|
||||
/* recursion can happen with certain fatal conditions */
|
||||
|
||||
if (quiet && code == FINFO)
|
||||
@@ -171,44 +172,39 @@ void rwrite(enum logcode code, char *buf, int len)
|
||||
|
||||
buf[len] = 0;
|
||||
|
||||
if (code == FLOG) {
|
||||
if (am_daemon) logit(LOG_INFO, buf);
|
||||
if (am_server && msg_fd_out >= 0) {
|
||||
/* Pass the message to our sibling. */
|
||||
send_msg((enum msgcode)code, buf, len);
|
||||
return;
|
||||
}
|
||||
|
||||
if (am_daemon) {
|
||||
static int in_block;
|
||||
char msg[2048];
|
||||
int priority = code == FERROR ? LOG_WARNING : LOG_INFO;
|
||||
|
||||
if (in_block)
|
||||
return;
|
||||
in_block = 1;
|
||||
if (!log_initialised)
|
||||
log_init();
|
||||
strlcpy(msg, buf, MIN((int)sizeof msg, len + 1));
|
||||
logit(priority, msg);
|
||||
in_block = 0;
|
||||
|
||||
if (code == FLOG || !am_server)
|
||||
return;
|
||||
} else if (code == FLOG)
|
||||
return;
|
||||
|
||||
if (am_server) {
|
||||
/* Pass it to non-server side, perhaps through our sibling. */
|
||||
if (msg_fd_out >= 0) {
|
||||
send_msg((enum msgcode)code, buf, len);
|
||||
return;
|
||||
}
|
||||
/* Pass the message to the non-server side. */
|
||||
if (io_multiplex_write((enum msgcode)code, buf, len))
|
||||
return;
|
||||
}
|
||||
|
||||
/* otherwise, if in daemon mode and either we are not a server
|
||||
* (that is, we are not running --daemon over a remote shell) or
|
||||
* the log has already been initialised, log the message on this
|
||||
* side because we don't want the client to see most errors for
|
||||
* security reasons. We do want early messages when running daemon
|
||||
* mode over a remote shell to go to the remote side; those will
|
||||
* fall through to the next case.
|
||||
* Note that this is only for the time before multiplexing is enabled.
|
||||
*/
|
||||
if (am_daemon && (!am_server || log_initialised)) {
|
||||
static int depth;
|
||||
int priority = LOG_INFO;
|
||||
if (code == FERROR) priority = LOG_WARNING;
|
||||
|
||||
if (depth) return;
|
||||
|
||||
depth++;
|
||||
|
||||
log_init();
|
||||
logit(priority, buf);
|
||||
|
||||
depth--;
|
||||
return;
|
||||
if (am_daemon) {
|
||||
/* TODO: can we send the error to the user somehow? */
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (code == FERROR) {
|
||||
@@ -216,18 +212,17 @@ void rwrite(enum logcode code, char *buf, int len)
|
||||
f = stderr;
|
||||
}
|
||||
|
||||
if (code == FINFO) {
|
||||
if (am_server)
|
||||
f = stderr;
|
||||
else
|
||||
f = stdout;
|
||||
}
|
||||
if (code == FINFO)
|
||||
f = am_server ? stderr : stdout;
|
||||
|
||||
if (!f) exit_cleanup(RERR_MESSAGEIO);
|
||||
if (!f)
|
||||
exit_cleanup(RERR_MESSAGEIO);
|
||||
|
||||
if (fwrite(buf, len, 1, f) != 1) exit_cleanup(RERR_MESSAGEIO);
|
||||
if (fwrite(buf, len, 1, f) != 1)
|
||||
exit_cleanup(RERR_MESSAGEIO);
|
||||
|
||||
if (buf[len-1] == '\r' || buf[len-1] == '\n') fflush(f);
|
||||
if (buf[len-1] == '\r' || buf[len-1] == '\n')
|
||||
fflush(f);
|
||||
}
|
||||
|
||||
|
||||
@@ -236,18 +231,17 @@ void rwrite(enum logcode code, char *buf, int len)
|
||||
void rprintf(enum logcode code, const char *format, ...)
|
||||
{
|
||||
va_list ap;
|
||||
char buf[1024];
|
||||
int len;
|
||||
char buf[MAXPATHLEN+512];
|
||||
size_t len;
|
||||
|
||||
va_start(ap, format);
|
||||
/* Note: might return -1 */
|
||||
len = vsnprintf(buf, sizeof(buf), format, ap);
|
||||
va_end(ap);
|
||||
|
||||
/* Deal with buffer overruns. Instead of panicking, just
|
||||
* truncate the resulting string. Note that some vsnprintf()s
|
||||
* return -1 on truncation, e.g., glibc 2.0.6 and earlier. */
|
||||
if ((size_t) len > sizeof(buf)-1 || len < 0) {
|
||||
* truncate the resulting string. (Note that configure ensures
|
||||
* that we have a vsnprintf() that doesn't ever return -1.) */
|
||||
if (len > sizeof buf - 1) {
|
||||
const char ellipsis[] = "[...]";
|
||||
|
||||
/* Reset length, and zero-terminate the end of our buffer */
|
||||
@@ -285,33 +279,23 @@ void rprintf(enum logcode code, const char *format, ...)
|
||||
void rsyserr(enum logcode code, int errcode, const char *format, ...)
|
||||
{
|
||||
va_list ap;
|
||||
char buf[1024];
|
||||
int len;
|
||||
size_t sys_len;
|
||||
char *sysmsg;
|
||||
char buf[MAXPATHLEN+512];
|
||||
size_t len;
|
||||
|
||||
strcpy(buf, RSYNC_NAME ": ");
|
||||
len = (sizeof RSYNC_NAME ": ") - 1;
|
||||
|
||||
va_start(ap, format);
|
||||
/* Note: might return <0 */
|
||||
len = vsnprintf(buf, sizeof(buf), format, ap);
|
||||
len += vsnprintf(buf + len, sizeof buf - len, format, ap);
|
||||
va_end(ap);
|
||||
|
||||
/* TODO: Put in RSYNC_NAME at the start. */
|
||||
|
||||
if ((size_t) len > sizeof(buf)-1)
|
||||
if (len < sizeof buf) {
|
||||
len += snprintf(buf + len, sizeof buf - len,
|
||||
": %s (%d)\n", strerror(errcode), errcode);
|
||||
}
|
||||
if (len >= sizeof buf)
|
||||
exit_cleanup(RERR_MESSAGEIO);
|
||||
|
||||
sysmsg = strerror(errcode);
|
||||
sys_len = strlen(sysmsg);
|
||||
if ((size_t) len + 3 + sys_len > sizeof(buf) - 1)
|
||||
exit_cleanup(RERR_MESSAGEIO);
|
||||
|
||||
strcpy(buf + len, ": ");
|
||||
len += 2;
|
||||
strcpy(buf + len, sysmsg);
|
||||
len += sys_len;
|
||||
strcpy(buf + len, "\n");
|
||||
len++;
|
||||
|
||||
rwrite(code, buf, len);
|
||||
}
|
||||
|
||||
@@ -363,8 +347,9 @@ static void log_formatted(enum logcode code,
|
||||
* rather keep going until we reach the nul of the format.
|
||||
* Just to make sure we don't clobber that nul and therefore
|
||||
* accidentally keep going, we zero the buffer now. */
|
||||
memset(buf, 0, sizeof buf);
|
||||
strlcpy(buf, format, sizeof(buf));
|
||||
l = strlcpy(buf, format, sizeof buf);
|
||||
if (l < sizeof buf)
|
||||
memset(buf + l, 0, sizeof buf - l);
|
||||
|
||||
for (s = &buf[0]; s && (p = strchr(s,'%')); ) {
|
||||
n = NULL;
|
||||
@@ -388,7 +373,7 @@ static void log_formatted(enum logcode code,
|
||||
pathjoin(buf2, sizeof buf2,
|
||||
file->basedir ? file->basedir : "",
|
||||
f_name(file));
|
||||
clean_fname(buf2);
|
||||
clean_fname(buf2, 0);
|
||||
n = buf2;
|
||||
if (*n == '/') n++;
|
||||
break;
|
||||
|
||||
342
main.c
342
main.c
@@ -43,20 +43,25 @@ extern int local_server;
|
||||
extern int log_got_error;
|
||||
extern int module_id;
|
||||
extern int orig_umask;
|
||||
extern int copy_links;
|
||||
extern int keep_dirlinks;
|
||||
extern int preserve_hard_links;
|
||||
extern int protocol_version;
|
||||
extern int recurse;
|
||||
extern int relative_paths;
|
||||
extern int rsync_port;
|
||||
extern int whole_file;
|
||||
extern int read_batch;
|
||||
extern int write_batch;
|
||||
extern int batch_fd;
|
||||
extern int batch_gen_fd;
|
||||
extern int filesfrom_fd;
|
||||
extern pid_t cleanup_child_pid;
|
||||
extern char *files_from;
|
||||
extern char *remote_filesfrom_file;
|
||||
extern char *rsync_path;
|
||||
extern char *shell_cmd;
|
||||
extern struct file_list *batch_flist;
|
||||
extern char *batch_name;
|
||||
|
||||
|
||||
/* there's probably never more than at most 2 outstanding child processes,
|
||||
@@ -84,7 +89,7 @@ void wait_process(pid_t pid, int *status)
|
||||
io_flush(FULL_FLUSH);
|
||||
}
|
||||
|
||||
if ((waited_pid == -1) && (errno == ECHILD)) {
|
||||
if (waited_pid == -1 && errno == ECHILD) {
|
||||
/* status of requested child no longer available.
|
||||
* check to see if it was processed by the sigchld_handler.
|
||||
*/
|
||||
@@ -105,8 +110,19 @@ void wait_process(pid_t pid, int *status)
|
||||
*status = WEXITSTATUS(*status);
|
||||
}
|
||||
|
||||
/* 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.
|
||||
* If we're a server sender, we write the stats on the supplied fd. If
|
||||
* we're the client receiver we read the stats from the supplied fd and do
|
||||
* the report. All processes might also generate a set of debug stats, if
|
||||
* the verbose level is high enough (this is the only thing that the
|
||||
* generator process and the server receiver ever do here). */
|
||||
static void report(int f)
|
||||
{
|
||||
/* Cache two stats because the read/write code can change it. */
|
||||
int64 total_read = stats.total_read;
|
||||
int64 total_written = stats.total_written;
|
||||
time_t t = time(NULL);
|
||||
|
||||
if (do_stats && verbose > 1) {
|
||||
@@ -120,18 +136,15 @@ static void report(int f)
|
||||
|
||||
if (am_daemon) {
|
||||
log_exit(0, __FILE__, __LINE__);
|
||||
if (f == -1 || !am_sender) return;
|
||||
if (f == -1 || !am_sender)
|
||||
return;
|
||||
}
|
||||
|
||||
if (am_server) {
|
||||
if (am_sender) {
|
||||
int64 w;
|
||||
/* store total_written in a temporary
|
||||
* because write_longint changes it */
|
||||
w = stats.total_written;
|
||||
write_longint(f,stats.total_read);
|
||||
write_longint(f,w);
|
||||
write_longint(f,stats.total_size);
|
||||
write_longint(f, total_read);
|
||||
write_longint(f, total_written);
|
||||
write_longint(f, stats.total_size);
|
||||
}
|
||||
return;
|
||||
}
|
||||
@@ -139,12 +152,17 @@ static void report(int f)
|
||||
/* this is the client */
|
||||
|
||||
if (!am_sender) {
|
||||
int64 r;
|
||||
stats.total_written = read_longint(f);
|
||||
/* store total_read in a temporary, read_longint changes it */
|
||||
r = read_longint(f);
|
||||
/* Read the first two in opposite order because the meaning of
|
||||
* read/write swaps when switching from sender to receiver. */
|
||||
total_written = read_longint(f);
|
||||
total_read = read_longint(f);
|
||||
stats.total_size = read_longint(f);
|
||||
stats.total_read = r;
|
||||
} else if (write_batch) {
|
||||
/* The --read-batch process is going to be a client
|
||||
* receiver, so we need to give it the stats. */
|
||||
write_longint(batch_fd, total_read);
|
||||
write_longint(batch_fd, total_written);
|
||||
write_longint(batch_fd, stats.total_size);
|
||||
}
|
||||
|
||||
if (do_stats) {
|
||||
@@ -160,20 +178,20 @@ static void report(int f)
|
||||
rprintf(FINFO,"Matched data: %.0f bytes\n",
|
||||
(double)stats.matched_data);
|
||||
rprintf(FINFO,"File list size: %d\n", stats.flist_size);
|
||||
rprintf(FINFO,"Total bytes written: %.0f\n",
|
||||
(double)stats.total_written);
|
||||
rprintf(FINFO,"Total bytes read: %.0f\n",
|
||||
(double)stats.total_read);
|
||||
rprintf(FINFO,"Total bytes sent: %.0f\n",
|
||||
(double)total_written);
|
||||
rprintf(FINFO,"Total bytes received: %.0f\n",
|
||||
(double)total_read);
|
||||
}
|
||||
|
||||
if (verbose || do_stats) {
|
||||
rprintf(FINFO,"\nwrote %.0f bytes read %.0f bytes %.2f bytes/sec\n",
|
||||
(double)stats.total_written,
|
||||
(double)stats.total_read,
|
||||
(stats.total_written+stats.total_read)/(0.5 + (t-starttime)));
|
||||
rprintf(FINFO,"total size is %.0f speedup is %.2f\n",
|
||||
rprintf(FINFO,
|
||||
"\nsent %.0f bytes received %.0f bytes %.2f bytes/sec\n",
|
||||
(double)total_written, (double)total_read,
|
||||
(total_written + total_read)/(0.5 + (t - starttime)));
|
||||
rprintf(FINFO, "total size is %.0f speedup is %.2f\n",
|
||||
(double)stats.total_size,
|
||||
(1.0*stats.total_size)/(stats.total_written+stats.total_read));
|
||||
(double)stats.total_size / (total_written+total_read));
|
||||
}
|
||||
|
||||
fflush(stdout);
|
||||
@@ -217,7 +235,7 @@ static pid_t do_cmd(char *cmd, char *machine, char *user, char *path,
|
||||
int *f_in, int *f_out)
|
||||
{
|
||||
int i, argc = 0;
|
||||
char *args[100];
|
||||
char *args[MAX_ARGS];
|
||||
pid_t ret;
|
||||
char *tok, *dir = NULL;
|
||||
int dash_l_set = 0;
|
||||
@@ -232,8 +250,14 @@ static pid_t do_cmd(char *cmd, char *machine, char *user, char *path,
|
||||
if (!cmd)
|
||||
goto oom;
|
||||
|
||||
for (tok = strtok(cmd, " "); tok; tok = strtok(NULL, " "))
|
||||
for (tok = strtok(cmd, " "); tok; tok = strtok(NULL, " ")) {
|
||||
/* Comparison leaves rooms for server_options(). */
|
||||
if (argc >= MAX_ARGS - 100) {
|
||||
rprintf(FERROR, "internal: args[] overflowed in do_cmd()\n");
|
||||
exit_cleanup(RERR_SYNTAX);
|
||||
}
|
||||
args[argc++] = tok;
|
||||
}
|
||||
|
||||
/* check to see if we've already been given '-l user' in
|
||||
* the remote-shell command */
|
||||
@@ -270,6 +294,11 @@ static pid_t do_cmd(char *cmd, char *machine, char *user, char *path,
|
||||
}
|
||||
|
||||
server_options(args,&argc);
|
||||
|
||||
if (argc >= MAX_ARGS - 2) {
|
||||
rprintf(FERROR, "internal: args[] overflowed in do_cmd()\n");
|
||||
exit_cleanup(RERR_SYNTAX);
|
||||
}
|
||||
}
|
||||
|
||||
args[argc++] = ".";
|
||||
@@ -277,29 +306,36 @@ static pid_t do_cmd(char *cmd, char *machine, char *user, char *path,
|
||||
if (!daemon_over_rsh && path && *path)
|
||||
args[argc++] = path;
|
||||
|
||||
if (argc >= (int)(sizeof args / sizeof args[0])) {
|
||||
rprintf(FERROR, "internal: args[] overflowed in do_cmd()\n");
|
||||
exit_cleanup(RERR_MALLOC); /* XXX Need better RERR? */
|
||||
}
|
||||
|
||||
args[argc] = NULL;
|
||||
|
||||
if (verbose > 3) {
|
||||
rprintf(FINFO,"cmd=");
|
||||
for (i=0;i<argc;i++)
|
||||
for (i = 0; i < argc; i++)
|
||||
rprintf(FINFO,"%s ",args[i]);
|
||||
rprintf(FINFO,"\n");
|
||||
}
|
||||
|
||||
if (local_server) {
|
||||
if (read_batch)
|
||||
create_flist_from_batch(); /* sets batch_flist */
|
||||
if (read_batch) {
|
||||
int from_gen_pipe[2];
|
||||
if (fd_pair(from_gen_pipe) < 0) {
|
||||
rsyserr(FERROR, errno, "pipe");
|
||||
exit_cleanup(RERR_IPC);
|
||||
}
|
||||
batch_gen_fd = from_gen_pipe[0];
|
||||
*f_out = from_gen_pipe[1];
|
||||
*f_in = batch_fd;
|
||||
ret = -1; /* no child pid */
|
||||
} else if (local_server) {
|
||||
/* If the user didn't request --[no-]whole-file, force
|
||||
* it on, but only if we're not batch processing. */
|
||||
if (whole_file < 0 && !write_batch)
|
||||
whole_file = 1;
|
||||
ret = local_child(argc, args, f_in, f_out, child_main);
|
||||
} else {
|
||||
} else
|
||||
ret = piped_child(args,f_in,f_out);
|
||||
}
|
||||
|
||||
if (dir) free(dir);
|
||||
if (dir)
|
||||
free(dir);
|
||||
|
||||
return ret;
|
||||
|
||||
@@ -324,8 +360,8 @@ static char *get_local_name(struct file_list *flist,char *name)
|
||||
if (do_stat(name,&st) == 0) {
|
||||
if (S_ISDIR(st.st_mode)) {
|
||||
if (!push_dir(name)) {
|
||||
rprintf(FERROR, "push_dir %s failed: %s (1)\n",
|
||||
full_fname(name), strerror(errno));
|
||||
rsyserr(FERROR, errno, "push_dir#1 %s failed",
|
||||
full_fname(name));
|
||||
exit_cleanup(RERR_FILESELECT);
|
||||
}
|
||||
return NULL;
|
||||
@@ -341,17 +377,20 @@ static char *get_local_name(struct file_list *flist,char *name)
|
||||
return name;
|
||||
|
||||
if (do_mkdir(name,0777 & ~orig_umask) != 0) {
|
||||
rprintf(FERROR, "mkdir %s failed: %s\n",
|
||||
full_fname(name), strerror(errno));
|
||||
rsyserr(FERROR, errno, "mkdir %s failed", full_fname(name));
|
||||
exit_cleanup(RERR_FILEIO);
|
||||
} else {
|
||||
if (verbose > 0)
|
||||
rprintf(FINFO,"created directory %s\n",name);
|
||||
}
|
||||
if (verbose > 0)
|
||||
rprintf(FINFO, "created directory %s\n", name);
|
||||
|
||||
if (dry_run) {
|
||||
dry_run++;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (!push_dir(name)) {
|
||||
rprintf(FERROR, "push_dir %s failed: %s (2)\n",
|
||||
full_fname(name), strerror(errno));
|
||||
rsyserr(FERROR, errno, "push_dir#2 %s failed",
|
||||
full_fname(name));
|
||||
exit_cleanup(RERR_FILESELECT);
|
||||
}
|
||||
|
||||
@@ -370,9 +409,15 @@ static void do_server_sender(int f_in, int f_out, int argc,char *argv[])
|
||||
(long)getpid());
|
||||
}
|
||||
|
||||
if (am_daemon && lp_write_only(module_id)) {
|
||||
rprintf(FERROR, "ERROR: module is write only\n");
|
||||
exit_cleanup(RERR_SYNTAX);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!relative_paths && !push_dir(dir)) {
|
||||
rprintf(FERROR, "push_dir %s failed: %s (3)\n",
|
||||
full_fname(dir), strerror(errno));
|
||||
rsyserr(FERROR, errno, "push_dir#3 %s failed",
|
||||
full_fname(dir));
|
||||
exit_cleanup(RERR_FILESELECT);
|
||||
}
|
||||
argc--;
|
||||
@@ -382,12 +427,12 @@ static void do_server_sender(int f_in, int f_out, int argc,char *argv[])
|
||||
int l = strlen(dir);
|
||||
if (strcmp(dir,"/") == 0)
|
||||
l = 0;
|
||||
for (i=0;i<argc;i++)
|
||||
for (i = 0; i < argc; i++)
|
||||
argv[i] += l+1;
|
||||
}
|
||||
|
||||
if (argc == 0 && recurse) {
|
||||
argc=1;
|
||||
argc = 1;
|
||||
argv--;
|
||||
argv[0] = ".";
|
||||
}
|
||||
@@ -397,8 +442,9 @@ static void do_server_sender(int f_in, int f_out, int argc,char *argv[])
|
||||
exit_cleanup(0);
|
||||
}
|
||||
|
||||
io_start_buffering_in(f_in);
|
||||
io_start_buffering_out(f_out);
|
||||
io_start_buffering_in();
|
||||
io_start_buffering_out();
|
||||
|
||||
send_files(flist,f_out,f_in);
|
||||
io_flush(FULL_FLUSH);
|
||||
report(f_out);
|
||||
@@ -414,17 +460,20 @@ static void do_server_sender(int f_in, int f_out, int argc,char *argv[])
|
||||
static int do_recv(int f_in,int f_out,struct file_list *flist,char *local_name)
|
||||
{
|
||||
int pid;
|
||||
int status=0;
|
||||
int status = 0;
|
||||
int error_pipe[2];
|
||||
|
||||
/* The receiving side mustn't obey this, or an existing symlink that
|
||||
* points to an identical file won't be replaced by the referent. */
|
||||
copy_links = 0;
|
||||
|
||||
if (preserve_hard_links)
|
||||
init_hard_links(flist);
|
||||
|
||||
if (!delete_after) {
|
||||
/* I moved this here from recv_files() to prevent a race condition */
|
||||
if (recurse && delete_mode && !local_name && flist->count>0) {
|
||||
if (recurse && delete_mode && !local_name && flist->count > 0)
|
||||
delete_files(flist);
|
||||
}
|
||||
}
|
||||
|
||||
if (fd_pair(error_pipe) < 0) {
|
||||
@@ -434,12 +483,13 @@ static int do_recv(int f_in,int f_out,struct file_list *flist,char *local_name)
|
||||
|
||||
io_flush(NORMAL_FLUSH);
|
||||
|
||||
if ((pid=do_fork()) == 0) {
|
||||
if ((pid = do_fork()) == 0) {
|
||||
close(error_pipe[0]);
|
||||
if (f_in != f_out) close(f_out);
|
||||
if (f_in != f_out)
|
||||
close(f_out);
|
||||
|
||||
/* we can't let two processes write to the socket at one time */
|
||||
io_multiplexing_close();
|
||||
close_multiplexing_out();
|
||||
|
||||
/* set place to send errors */
|
||||
set_msg_fd_out(error_pipe[1]);
|
||||
@@ -458,11 +508,15 @@ static int do_recv(int f_in,int f_out,struct file_list *flist,char *local_name)
|
||||
}
|
||||
|
||||
am_generator = 1;
|
||||
close_multiplexing_in();
|
||||
if (write_batch)
|
||||
stop_write_batch();
|
||||
|
||||
close(error_pipe[1]);
|
||||
if (f_in != f_out) close(f_in);
|
||||
if (f_in != f_out)
|
||||
close(f_in);
|
||||
|
||||
io_start_buffering_out(f_out);
|
||||
io_start_buffering_out();
|
||||
|
||||
set_msg_fd_in(error_pipe[0]);
|
||||
|
||||
@@ -496,7 +550,7 @@ static void do_server_recv(int f_in, int f_out, int argc,char *argv[])
|
||||
argc, (long)getpid());
|
||||
}
|
||||
|
||||
if (am_daemon && lp_read_only(module_id) && !am_sender) {
|
||||
if (am_daemon && lp_read_only(module_id)) {
|
||||
rprintf(FERROR,"ERROR: module is read only\n");
|
||||
exit_cleanup(RERR_SYNTAX);
|
||||
return;
|
||||
@@ -508,13 +562,13 @@ static void do_server_recv(int f_in, int f_out, int argc,char *argv[])
|
||||
argc--;
|
||||
argv++;
|
||||
if (!am_daemon && !push_dir(dir)) {
|
||||
rprintf(FERROR, "push_dir %s failed: %s (4)\n",
|
||||
full_fname(dir), strerror(errno));
|
||||
rsyserr(FERROR, errno, "push_dir#4 %s failed",
|
||||
full_fname(dir));
|
||||
exit_cleanup(RERR_FILESELECT);
|
||||
}
|
||||
}
|
||||
|
||||
io_start_buffering_in(f_in);
|
||||
io_start_buffering_in();
|
||||
if (delete_mode && !delete_excluded)
|
||||
recv_exclude_list(f_in);
|
||||
|
||||
@@ -527,10 +581,7 @@ static void do_server_recv(int f_in, int f_out, int argc,char *argv[])
|
||||
filesfrom_fd = -1;
|
||||
}
|
||||
|
||||
if (read_batch)
|
||||
flist = batch_flist;
|
||||
else
|
||||
flist = recv_file_list(f_in);
|
||||
flist = recv_file_list(f_in);
|
||||
if (!flist) {
|
||||
rprintf(FERROR,"server_recv: recv_file_list error\n");
|
||||
exit_cleanup(RERR_FILESELECT);
|
||||
@@ -539,7 +590,8 @@ static void do_server_recv(int f_in, int f_out, int argc,char *argv[])
|
||||
if (argc > 0) {
|
||||
if (strcmp(dir,".")) {
|
||||
argv[0] += strlen(dir);
|
||||
if (argv[0][0] == '/') argv[0]++;
|
||||
if (argv[0][0] == '/')
|
||||
argv[0]++;
|
||||
}
|
||||
local_name = get_local_name(flist,argv[0]);
|
||||
}
|
||||
@@ -558,20 +610,21 @@ int child_main(int argc, char *argv[])
|
||||
|
||||
void start_server(int f_in, int f_out, int argc, char *argv[])
|
||||
{
|
||||
setup_protocol(f_out, f_in);
|
||||
|
||||
set_nonblocking(f_in);
|
||||
set_nonblocking(f_out);
|
||||
|
||||
io_set_sock_fds(f_in, f_out);
|
||||
setup_protocol(f_out, f_in);
|
||||
|
||||
if (protocol_version >= 23)
|
||||
io_start_multiplex_out(f_out);
|
||||
io_start_multiplex_out();
|
||||
|
||||
if (am_sender) {
|
||||
if (!read_batch) {
|
||||
recv_exclude_list(f_in);
|
||||
if (cvs_exclude)
|
||||
add_cvs_excludes();
|
||||
}
|
||||
keep_dirlinks = 0; /* Must be disabled on the sender. */
|
||||
|
||||
recv_exclude_list(f_in);
|
||||
if (cvs_exclude)
|
||||
add_cvs_excludes();
|
||||
do_server_sender(f_in, f_out, argc, argv);
|
||||
} else {
|
||||
do_server_recv(f_in, f_out, argc, argv);
|
||||
@@ -591,25 +644,41 @@ int client_run(int f_in, int f_out, pid_t pid, int argc, char *argv[])
|
||||
char *local_name = NULL;
|
||||
|
||||
cleanup_child_pid = pid;
|
||||
if (read_batch)
|
||||
flist = batch_flist;
|
||||
|
||||
set_nonblocking(f_in);
|
||||
set_nonblocking(f_out);
|
||||
if (read_batch) {
|
||||
assert(am_sender == 0);
|
||||
} else {
|
||||
set_nonblocking(f_in);
|
||||
set_nonblocking(f_out);
|
||||
}
|
||||
|
||||
io_set_sock_fds(f_in, f_out);
|
||||
setup_protocol(f_out,f_in);
|
||||
|
||||
if (protocol_version >= 23)
|
||||
io_start_multiplex_in(f_in);
|
||||
if (protocol_version >= 23 && !read_batch)
|
||||
io_start_multiplex_in();
|
||||
|
||||
/* We set our stderr file handle to blocking because ssh might have
|
||||
* set it to non-blocking. This can be particularly troublesome if
|
||||
* stderr is a clone of stdout, because ssh would have set our stdout
|
||||
* to non-blocking at the same time (which can easily cause us to lose
|
||||
* output from our print statements). This kluge shouldn't cause ssh
|
||||
* any problems for how we use it. Note also that we delayed setting
|
||||
* this until after the above protocol setup so that we know for sure
|
||||
* that ssh is done twiddling its file descriptors. */
|
||||
set_blocking(STDERR_FILENO);
|
||||
|
||||
if (am_sender) {
|
||||
io_start_buffering_out(f_out);
|
||||
keep_dirlinks = 0; /* Must be disabled on the sender. */
|
||||
io_start_buffering_out();
|
||||
if (cvs_exclude)
|
||||
add_cvs_excludes();
|
||||
if (delete_mode && !delete_excluded)
|
||||
send_exclude_list(f_out);
|
||||
if (remote_filesfrom_file)
|
||||
filesfrom_fd = f_in;
|
||||
|
||||
if (write_batch)
|
||||
start_write_batch(f_out);
|
||||
if (!read_batch) /* don't write to pipe */
|
||||
flist = send_file_list(f_out,argc,argv);
|
||||
if (verbose > 3)
|
||||
@@ -633,11 +702,10 @@ int client_run(int f_in, int f_out, pid_t pid, int argc, char *argv[])
|
||||
exit_cleanup(status);
|
||||
}
|
||||
|
||||
if (argc == 0) {
|
||||
if (argc == 0)
|
||||
list_only = 1;
|
||||
}
|
||||
|
||||
if (!write_batch)
|
||||
if (!read_batch)
|
||||
send_exclude_list(f_out);
|
||||
|
||||
if (filesfrom_fd >= 0) {
|
||||
@@ -645,6 +713,8 @@ int client_run(int f_in, int f_out, pid_t pid, int argc, char *argv[])
|
||||
filesfrom_fd = -1;
|
||||
}
|
||||
|
||||
if (write_batch)
|
||||
start_write_batch(f_in);
|
||||
flist = recv_file_list(f_in);
|
||||
if (!flist || flist->count == 0) {
|
||||
rprintf(FINFO, "client: nothing to do: "
|
||||
@@ -708,33 +778,39 @@ static int start_client(int argc, char *argv[])
|
||||
return rc;
|
||||
|
||||
/* rsync:// always uses rsync server over direct socket connection */
|
||||
if (strncasecmp(URL_PREFIX, argv[0], strlen(URL_PREFIX)) == 0) {
|
||||
if (strncasecmp(URL_PREFIX, argv[0], strlen(URL_PREFIX)) == 0
|
||||
&& !read_batch) {
|
||||
char *host, *path;
|
||||
|
||||
host = argv[0] + strlen(URL_PREFIX);
|
||||
p = strchr(host,'/');
|
||||
if (p) {
|
||||
*p = 0;
|
||||
*p = '\0';
|
||||
path = p+1;
|
||||
} else {
|
||||
} else
|
||||
path = "";
|
||||
}
|
||||
p = strchr(host,':');
|
||||
if (*host == '[' && (p = strchr(host, ']')) != NULL) {
|
||||
host++;
|
||||
*p++ = '\0';
|
||||
if (*p != ':')
|
||||
p = NULL;
|
||||
} else
|
||||
p = strchr(host, ':');
|
||||
if (p) {
|
||||
rsync_port = atoi(p+1);
|
||||
*p = 0;
|
||||
*p = '\0';
|
||||
}
|
||||
return start_socket_client(host, path, argc-1, argv+1);
|
||||
}
|
||||
|
||||
if (!read_batch) {
|
||||
if (!read_batch) { /* for read_batch, NO source is specified */
|
||||
p = find_colon(argv[0]);
|
||||
if (p) {
|
||||
if (p) { /* source is remote */
|
||||
if (remote_filesfrom_file
|
||||
&& remote_filesfrom_file != files_from + 1
|
||||
&& strncmp(files_from, argv[0], p-argv[0]+1) != 0) {
|
||||
rprintf(FERROR,
|
||||
"--files-from hostname is not transfer hostname\n");
|
||||
"--files-from hostname is not the same as the transfer hostname\n");
|
||||
exit_cleanup(RERR_SYNTAX);
|
||||
}
|
||||
if (p[1] == ':') { /* double colon */
|
||||
@@ -747,7 +823,7 @@ static int start_client(int argc, char *argv[])
|
||||
daemon_over_rsh = 1;
|
||||
}
|
||||
|
||||
if (argc < 1) {
|
||||
if (argc < 1) { /* destination required */
|
||||
usage(FERROR);
|
||||
exit_cleanup(RERR_SYNTAX);
|
||||
}
|
||||
@@ -756,9 +832,8 @@ static int start_client(int argc, char *argv[])
|
||||
*p = 0;
|
||||
shell_machine = argv[0];
|
||||
shell_path = p+1;
|
||||
argc--;
|
||||
argv++;
|
||||
} else {
|
||||
} else { /* source is local */
|
||||
am_sender = 1;
|
||||
|
||||
/* rsync:// destination uses rsync server over direct socket */
|
||||
@@ -768,32 +843,37 @@ static int start_client(int argc, char *argv[])
|
||||
host = argv[argc-1] + strlen(URL_PREFIX);
|
||||
p = strchr(host,'/');
|
||||
if (p) {
|
||||
*p = 0;
|
||||
*p = '\0';
|
||||
path = p+1;
|
||||
} else {
|
||||
} else
|
||||
path = "";
|
||||
}
|
||||
p = strchr(host,':');
|
||||
if (*host == '[' && (p = strchr(host, ']')) != NULL) {
|
||||
host++;
|
||||
*p++ = '\0';
|
||||
if (*p != ':')
|
||||
p = NULL;
|
||||
} else
|
||||
p = strchr(host, ':');
|
||||
if (p) {
|
||||
rsync_port = atoi(p+1);
|
||||
*p = 0;
|
||||
*p = '\0';
|
||||
}
|
||||
return start_socket_client(host, path, argc-1, argv);
|
||||
}
|
||||
|
||||
p = find_colon(argv[argc-1]);
|
||||
p = find_colon(argv[argc-1]); /* look in dest arg */
|
||||
if (p && remote_filesfrom_file
|
||||
&& remote_filesfrom_file != files_from + 1
|
||||
&& strncmp(files_from, argv[argc-1], p-argv[argc-1]+1) != 0) {
|
||||
rprintf(FERROR,
|
||||
"--files-from hostname is not transfer hostname\n");
|
||||
"--files-from hostname is not the same as the transfer hostname\n");
|
||||
exit_cleanup(RERR_SYNTAX);
|
||||
}
|
||||
if (!p) {
|
||||
if (!p) { /* no colon found, so src & dest are local */
|
||||
local_server = 1;
|
||||
if (remote_filesfrom_file) {
|
||||
rprintf(FERROR,
|
||||
"--files-from is remote but transfer is local\n");
|
||||
"--files-from cannot be remote when the transfer is local\n");
|
||||
exit_cleanup(RERR_SYNTAX);
|
||||
}
|
||||
} else if (p[1] == ':') { /* double colon */
|
||||
@@ -819,12 +899,15 @@ static int start_client(int argc, char *argv[])
|
||||
shell_machine = argv[argc-1];
|
||||
shell_path = p+1;
|
||||
}
|
||||
argc--;
|
||||
}
|
||||
} else {
|
||||
am_sender = 1;
|
||||
argc--;
|
||||
} else { /* read_batch */
|
||||
local_server = 1;
|
||||
shell_path = argv[argc-1];
|
||||
if (find_colon(shell_path)) {
|
||||
rprintf(FERROR, "remote destination is not allowed with --read-batch\n");
|
||||
exit_cleanup(RERR_SYNTAX);
|
||||
}
|
||||
}
|
||||
|
||||
if (shell_machine) {
|
||||
@@ -844,12 +927,14 @@ static int start_client(int argc, char *argv[])
|
||||
shell_path?shell_path:"");
|
||||
}
|
||||
|
||||
/* for remote source, only single dest arg can remain ... */
|
||||
if (!am_sender && argc > 1) {
|
||||
usage(FERROR);
|
||||
exit_cleanup(RERR_SYNTAX);
|
||||
}
|
||||
|
||||
if (argc == 0 && !am_sender) {
|
||||
/* ... or no dest at all */
|
||||
if (!am_sender && argc == 0) {
|
||||
list_only = 1;
|
||||
}
|
||||
|
||||
@@ -965,11 +1050,8 @@ static RETSIGTYPE rsync_panic_handler(UNUSED(int whatsig))
|
||||
int main(int argc,char *argv[])
|
||||
{
|
||||
int ret;
|
||||
int orig_argc;
|
||||
char **orig_argv;
|
||||
|
||||
orig_argc = argc;
|
||||
orig_argv = argv;
|
||||
int orig_argc = argc;
|
||||
char **orig_argv = argv;
|
||||
|
||||
signal(SIGUSR1, sigusr1_handler);
|
||||
signal(SIGUSR2, sigusr2_handler);
|
||||
@@ -1018,8 +1100,24 @@ int main(int argc,char *argv[])
|
||||
|
||||
init_flist();
|
||||
|
||||
if (write_batch && !am_server) {
|
||||
write_batch_argvs_file(orig_argc, orig_argv);
|
||||
if (write_batch || read_batch) {
|
||||
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",
|
||||
batch_name);
|
||||
exit_cleanup(RERR_FILEIO);
|
||||
}
|
||||
if (read_batch)
|
||||
read_stream_flags(batch_fd);
|
||||
}
|
||||
|
||||
if (am_daemon && !am_server)
|
||||
|
||||
99
match.c
99
match.c
@@ -22,6 +22,9 @@
|
||||
extern int verbose;
|
||||
extern int am_server;
|
||||
extern int do_progress;
|
||||
extern int checksum_seed;
|
||||
extern int inplace;
|
||||
extern int make_backups;
|
||||
|
||||
typedef unsigned short tag;
|
||||
|
||||
@@ -139,16 +142,17 @@ static void matched(int f,struct sum_struct *s,struct map_struct *buf,
|
||||
static void hash_search(int f,struct sum_struct *s,
|
||||
struct map_struct *buf, OFF_T len)
|
||||
{
|
||||
OFF_T offset, end;
|
||||
OFF_T offset, end, backup;
|
||||
unsigned int k;
|
||||
size_t last_i;
|
||||
size_t want_i;
|
||||
char sum2[SUM_LENGTH];
|
||||
uint32 s1, s2, sum;
|
||||
int more;
|
||||
schar *map;
|
||||
|
||||
/* last_i is used to encourage adjacent matches, allowing the RLL coding of the
|
||||
output to work more efficiently */
|
||||
last_i = (size_t)-1;
|
||||
/* want_i is used to encourage adjacent matches, allowing the RLL
|
||||
* coding of the output to work more efficiently. */
|
||||
want_i = 0;
|
||||
|
||||
if (verbose > 2) {
|
||||
rprintf(FINFO,"hash search b=%u len=%.0f\n",
|
||||
@@ -187,7 +191,7 @@ static void hash_search(int f,struct sum_struct *s,
|
||||
|
||||
sum = (s1 & 0xffff) | (s2 << 16);
|
||||
tag_hits++;
|
||||
for (; j < s->count && targets[j].t == t; j++) {
|
||||
do {
|
||||
unsigned int l;
|
||||
size_t i = targets[j].i;
|
||||
|
||||
@@ -199,6 +203,12 @@ static void hash_search(int f,struct sum_struct *s,
|
||||
if (l != s->sums[i].len)
|
||||
continue;
|
||||
|
||||
/* inplace: ensure chunk's offset is either >= our
|
||||
* offset or that the data didn't move. */
|
||||
if (inplace && !make_backups && s->sums[i].offset < offset
|
||||
&& !(s->sums[i].flags & SUMFLG_SAME_OFFSET))
|
||||
continue;
|
||||
|
||||
if (verbose > 3)
|
||||
rprintf(FINFO,"potential match at %.0f target=%.0f %.0f sum=%08x\n",
|
||||
(double)offset,(double)j,(double)i,sum);
|
||||
@@ -214,23 +224,42 @@ static void hash_search(int f,struct sum_struct *s,
|
||||
continue;
|
||||
}
|
||||
|
||||
/* we've found a match, but now check to see
|
||||
* if last_i can hint at a better match */
|
||||
for (j++; j < s->count && targets[j].t == t; j++) {
|
||||
size_t i2 = targets[j].i;
|
||||
if (i2 == last_i + 1) {
|
||||
if (sum != s->sums[i2].sum1)
|
||||
break;
|
||||
if (memcmp(sum2,s->sums[i2].sum2,s->s2length) != 0)
|
||||
break;
|
||||
/* we've found an adjacent match - the RLL coder
|
||||
* will be happy */
|
||||
i = i2;
|
||||
break;
|
||||
}
|
||||
/* If inplace is enabled, the best possible match is
|
||||
* one with an identical offset, so we prefer that over
|
||||
* the following want_i optimization. */
|
||||
if (inplace && !make_backups) {
|
||||
do {
|
||||
size_t i2 = targets[j].i;
|
||||
if (s->sums[i2].offset != offset)
|
||||
continue;
|
||||
if (i2 != i) {
|
||||
if (sum != s->sums[i2].sum1)
|
||||
break;
|
||||
if (memcmp(sum2, s->sums[i2].sum2,
|
||||
s->s2length) != 0)
|
||||
break;
|
||||
i = i2;
|
||||
}
|
||||
/* This chunk was at the same offset on
|
||||
* both the sender and the receiver. */
|
||||
s->sums[i].flags |= SUMFLG_SAME_OFFSET;
|
||||
goto set_want_i;
|
||||
} while (++j < s->count && targets[j].t == t);
|
||||
}
|
||||
|
||||
last_i = i;
|
||||
/* we've found a match, but now check to see
|
||||
* if want_i can hint at a better match. */
|
||||
if (i != want_i && want_i < s->count
|
||||
&& (!inplace || make_backups || s->sums[want_i].offset >= offset
|
||||
|| s->sums[want_i].flags & SUMFLG_SAME_OFFSET)
|
||||
&& sum == s->sums[want_i].sum1
|
||||
&& memcmp(sum2, s->sums[want_i].sum2, s->s2length) == 0) {
|
||||
/* we've found an adjacent match - the RLL coder
|
||||
* will be happy */
|
||||
i = want_i;
|
||||
}
|
||||
set_want_i:
|
||||
want_i = i + 1;
|
||||
|
||||
matched(f,s,buf,offset,i);
|
||||
offset += s->sums[i].len - 1;
|
||||
@@ -241,17 +270,24 @@ static void hash_search(int f,struct sum_struct *s,
|
||||
s2 = sum >> 16;
|
||||
matches++;
|
||||
break;
|
||||
}
|
||||
} while (++j < s->count && targets[j].t == t);
|
||||
|
||||
null_tag:
|
||||
backup = offset - last_match;
|
||||
/* We sometimes read 1 byte prior to last_match... */
|
||||
if (backup < 0)
|
||||
backup = 0;
|
||||
|
||||
/* Trim off the first byte from the checksum */
|
||||
map = (schar *)map_ptr(buf, offset, k+1);
|
||||
more = offset + k < len;
|
||||
map = (schar *)map_ptr(buf, offset - backup, k + more + backup)
|
||||
+ backup;
|
||||
s1 -= map[0] + CHAR_OFFSET;
|
||||
s2 -= k * (map[0]+CHAR_OFFSET);
|
||||
|
||||
/* Add on the next byte (if there is one) to the checksum */
|
||||
if (k < (len-offset)) {
|
||||
s1 += (map[k]+CHAR_OFFSET);
|
||||
if (more) {
|
||||
s1 += map[k] + CHAR_OFFSET;
|
||||
s2 += s1;
|
||||
} else
|
||||
--k;
|
||||
@@ -262,9 +298,8 @@ static void hash_search(int f,struct sum_struct *s,
|
||||
match. The 3 reads are caused by the
|
||||
running match, the checksum update and the
|
||||
literal send. */
|
||||
if (offset > last_match
|
||||
&& offset-last_match >= CHUNK_SIZE+s->blength
|
||||
&& end-offset > CHUNK_SIZE) {
|
||||
if (backup >= CHUNK_SIZE + s->blength
|
||||
&& end - offset > CHUNK_SIZE) {
|
||||
matched(f,s,buf,offset - s->blength, -2);
|
||||
}
|
||||
} while (++offset < end);
|
||||
@@ -291,7 +326,6 @@ static void hash_search(int f,struct sum_struct *s,
|
||||
void match_sums(int f, struct sum_struct *s, struct map_struct *buf, OFF_T len)
|
||||
{
|
||||
char file_sum[MD4_SUM_LENGTH];
|
||||
extern int write_batch;
|
||||
|
||||
last_match = 0;
|
||||
false_alarms = 0;
|
||||
@@ -299,7 +333,7 @@ void match_sums(int f, struct sum_struct *s, struct map_struct *buf, OFF_T len)
|
||||
matches = 0;
|
||||
data_transfer = 0;
|
||||
|
||||
sum_init();
|
||||
sum_init(checksum_seed);
|
||||
|
||||
if (len > 0 && s->count>0) {
|
||||
build_hash_table(s);
|
||||
@@ -322,12 +356,13 @@ void match_sums(int f, struct sum_struct *s, struct map_struct *buf, OFF_T len)
|
||||
}
|
||||
|
||||
sum_end(file_sum);
|
||||
/* If we had a read error, send a bad checksum. */
|
||||
if (buf && buf->status != 0)
|
||||
file_sum[0]++;
|
||||
|
||||
if (verbose > 2)
|
||||
rprintf(FINFO,"sending file_sum\n");
|
||||
write_buf(f,file_sum,MD4_SUM_LENGTH);
|
||||
if (write_batch)
|
||||
write_batch_delta_file(file_sum, MD4_SUM_LENGTH);
|
||||
|
||||
if (targets) {
|
||||
free(targets);
|
||||
|
||||
360
options.c
360
options.c
@@ -22,8 +22,9 @@
|
||||
#include "popt.h"
|
||||
|
||||
extern int sanitize_paths;
|
||||
extern char curr_dir[MAXPATHLEN];
|
||||
extern int select_timeout;
|
||||
extern struct exclude_list_struct exclude_list;
|
||||
extern struct exclude_list_struct server_exclude_list;
|
||||
|
||||
int make_backups = 0;
|
||||
|
||||
@@ -38,6 +39,7 @@ int make_backups = 0;
|
||||
int whole_file = -1;
|
||||
|
||||
int archive_mode = 0;
|
||||
int keep_dirlinks = 0;
|
||||
int copy_links = 0;
|
||||
int preserve_links = 0;
|
||||
int preserve_hard_links = 0;
|
||||
@@ -83,6 +85,7 @@ int safe_symlinks = 0;
|
||||
int copy_unsafe_links = 0;
|
||||
int size_only = 0;
|
||||
int bwlimit = 0;
|
||||
size_t bwlimit_writemax = 0;
|
||||
int delete_after = 0;
|
||||
int only_existing = 0;
|
||||
int opt_ignore_existing = 0;
|
||||
@@ -91,6 +94,7 @@ int ignore_errors = 0;
|
||||
int modify_window = 0;
|
||||
int blocking_io = -1;
|
||||
int checksum_seed = 0;
|
||||
int inplace = 0;
|
||||
unsigned int block_size = 0;
|
||||
|
||||
|
||||
@@ -114,6 +118,7 @@ unsigned int backup_dir_remainder;
|
||||
|
||||
char *backup_suffix = NULL;
|
||||
char *tmpdir = NULL;
|
||||
char *partial_dir = NULL;
|
||||
char *compare_dest = NULL;
|
||||
char *config_file = NULL;
|
||||
char *shell_cmd = NULL;
|
||||
@@ -130,15 +135,14 @@ int quiet = 0;
|
||||
int always_checksum = 0;
|
||||
int list_only = 0;
|
||||
|
||||
#define FIXED_CHECKSUM_SEED 32761
|
||||
#define MAX_BATCH_PREFIX_LEN 256 /* Must be less than MAXPATHLEN-13 */
|
||||
char *batch_prefix = NULL;
|
||||
#define MAX_BATCH_NAME_LEN 256 /* Must be less than MAXPATHLEN-13 */
|
||||
char *batch_name = NULL;
|
||||
|
||||
static int daemon_opt; /* sets am_daemon after option error-reporting */
|
||||
static int modify_window_set;
|
||||
|
||||
/** Local address to bind. As a character string because it's
|
||||
* interpreted by the IPv6 layer: should be a numeric IP4 or ip6
|
||||
* interpreted by the IPv6 layer: should be a numeric IP4 or IP6
|
||||
* address, or a hostname. **/
|
||||
char *bind_address;
|
||||
|
||||
@@ -146,6 +150,7 @@ char *bind_address;
|
||||
static void print_rsync_version(enum logcode f)
|
||||
{
|
||||
char const *got_socketpair = "no ";
|
||||
char const *have_inplace = "no ";
|
||||
char const *hardlinks = "no ";
|
||||
char const *links = "no ";
|
||||
char const *ipv6 = "no ";
|
||||
@@ -155,6 +160,10 @@ static void print_rsync_version(enum logcode f)
|
||||
got_socketpair = "";
|
||||
#endif
|
||||
|
||||
#if HAVE_FTRUNCATE
|
||||
have_inplace = "";
|
||||
#endif
|
||||
|
||||
#if SUPPORT_HARD_LINKS
|
||||
hardlinks = "";
|
||||
#endif
|
||||
@@ -180,8 +189,8 @@ static void print_rsync_version(enum logcode f)
|
||||
/* Note that this field may not have type ino_t. It depends
|
||||
* on the complicated interaction between largefile feature
|
||||
* macros. */
|
||||
rprintf(f, " %sIPv6, %d-bit system inums, %d-bit internal inums\n",
|
||||
ipv6,
|
||||
rprintf(f, " %sinplace, %sIPv6, %d-bit system inums, %d-bit internal inums\n",
|
||||
have_inplace, ipv6,
|
||||
(int) (sizeof dumstat->st_ino * 8),
|
||||
(int) (sizeof (uint64) * 8));
|
||||
#ifdef MAINTAINER_MODE
|
||||
@@ -189,8 +198,9 @@ static void print_rsync_version(enum logcode f)
|
||||
get_panic_action());
|
||||
#endif
|
||||
|
||||
#ifdef NO_INT64
|
||||
rprintf(f, "WARNING: no 64-bit integers on this platform!\n");
|
||||
#ifdef INT64_IS_OFF_T
|
||||
if (sizeof (int64) < 8)
|
||||
rprintf(f, "WARNING: no 64-bit integers on this platform!\n");
|
||||
#endif
|
||||
|
||||
rprintf(f,
|
||||
@@ -231,6 +241,8 @@ void usage(enum logcode F)
|
||||
rprintf(F," --backup-dir make backups into this directory\n");
|
||||
rprintf(F," --suffix=SUFFIX backup suffix (default %s w/o --backup-dir)\n",BACKUP_SUFFIX);
|
||||
rprintf(F," -u, --update update only (don't overwrite newer files)\n");
|
||||
rprintf(F," --inplace update destination files inplace (SEE MAN PAGE)\n");
|
||||
rprintf(F," -K, --keep-dirlinks treat symlinked dir on receiver as dir\n");
|
||||
rprintf(F," -l, --links copy symlinks as symlinks\n");
|
||||
rprintf(F," -L, --copy-links copy the referent of all symlinks\n");
|
||||
rprintf(F," --copy-unsafe-links copy the referent of \"unsafe\" symlinks\n");
|
||||
@@ -246,7 +258,7 @@ void usage(enum logcode F)
|
||||
rprintf(F," -W, --whole-file copy whole files, no incremental checks\n");
|
||||
rprintf(F," --no-whole-file turn off --whole-file\n");
|
||||
rprintf(F," -x, --one-file-system don't cross filesystem boundaries\n");
|
||||
rprintf(F," -B, --block-size=SIZE checksum blocking size (default %d)\n",BLOCK_SIZE);
|
||||
rprintf(F," -B, --block-size=SIZE force a fixed checksum block-size\n");
|
||||
rprintf(F," -e, --rsh=COMMAND specify the remote shell\n");
|
||||
rprintf(F," --rsync-path=PATH specify path to rsync on the remote machine\n");
|
||||
rprintf(F," --existing only update files that already exist\n");
|
||||
@@ -257,13 +269,14 @@ void usage(enum logcode F)
|
||||
rprintf(F," --ignore-errors delete even if there are I/O errors\n");
|
||||
rprintf(F," --max-delete=NUM don't delete more than NUM files\n");
|
||||
rprintf(F," --partial keep partially transferred files\n");
|
||||
rprintf(F," --partial-dir=DIR put a partially transferred file into DIR\n");
|
||||
rprintf(F," --force force deletion of directories even if not empty\n");
|
||||
rprintf(F," --numeric-ids don't map uid/gid values by user/group name\n");
|
||||
rprintf(F," --timeout=TIME set I/O timeout in seconds\n");
|
||||
rprintf(F," -I, --ignore-times turn off mod time & file size quick check\n");
|
||||
rprintf(F," --size-only ignore mod time for quick check (use size)\n");
|
||||
rprintf(F," --modify-window=NUM compare mod times with reduced accuracy\n");
|
||||
rprintf(F," -T --temp-dir=DIR create temporary files in directory DIR\n");
|
||||
rprintf(F," -T, --temp-dir=DIR create temporary files in directory DIR\n");
|
||||
rprintf(F," --compare-dest=DIR also compare destination files relative to DIR\n");
|
||||
rprintf(F," --link-dest=DIR create hardlinks to DIR for unchanged files\n");
|
||||
rprintf(F," -P equivalent to --partial --progress\n");
|
||||
@@ -274,7 +287,7 @@ void usage(enum logcode F)
|
||||
rprintf(F," --include=PATTERN don't exclude files matching PATTERN\n");
|
||||
rprintf(F," --include-from=FILE don't exclude patterns listed in FILE\n");
|
||||
rprintf(F," --files-from=FILE read FILE for list of source-file names\n");
|
||||
rprintf(F," -0 --from0 all *-from file lists are delimited by nulls\n");
|
||||
rprintf(F," -0, --from0 all *-from file lists are delimited by nulls\n");
|
||||
rprintf(F," --version print version number\n");
|
||||
rprintf(F," --daemon run as an rsync daemon\n");
|
||||
rprintf(F," --no-detach do not detach from the parent\n");
|
||||
@@ -288,13 +301,14 @@ void usage(enum logcode F)
|
||||
rprintf(F," --log-format=FORMAT log file transfers using specified format\n");
|
||||
rprintf(F," --password-file=FILE get password from FILE\n");
|
||||
rprintf(F," --bwlimit=KBPS limit I/O bandwidth, KBytes per second\n");
|
||||
rprintf(F," --write-batch=PREFIX write batch fileset starting with PREFIX\n");
|
||||
rprintf(F," --read-batch=PREFIX read batch fileset starting with PREFIX\n");
|
||||
rprintf(F," -h, --help show this help screen\n");
|
||||
rprintf(F," --write-batch=FILE write a batch to FILE\n");
|
||||
rprintf(F," --read-batch=FILE read a batch from FILE\n");
|
||||
rprintf(F," --checksum-seed=NUM set block/file checksum seed\n");
|
||||
#ifdef INET6
|
||||
rprintf(F," -4 prefer IPv4\n");
|
||||
rprintf(F," -6 prefer IPv6\n");
|
||||
rprintf(F," -4, --ipv4 prefer IPv4\n");
|
||||
rprintf(F," -6, --ipv6 prefer IPv6\n");
|
||||
#endif
|
||||
rprintf(F," -h, --help show this help screen\n");
|
||||
|
||||
rprintf(F,"\n");
|
||||
|
||||
@@ -305,15 +319,15 @@ void usage(enum logcode F)
|
||||
enum {OPT_VERSION = 1000, OPT_SENDER, OPT_EXCLUDE, OPT_EXCLUDE_FROM,
|
||||
OPT_DELETE_AFTER, OPT_DELETE_EXCLUDED, OPT_LINK_DEST,
|
||||
OPT_INCLUDE, OPT_INCLUDE_FROM, OPT_MODIFY_WINDOW,
|
||||
OPT_READ_BATCH, OPT_WRITE_BATCH,
|
||||
OPT_READ_BATCH, OPT_WRITE_BATCH, OPT_TIMEOUT,
|
||||
OPT_REFUSED_BASE = 9000};
|
||||
|
||||
static struct poptOption long_options[] = {
|
||||
/* longName, shortName, argInfo, argPtr, value, descrip, argDesc */
|
||||
{"version", 0, POPT_ARG_NONE, 0, OPT_VERSION, 0, 0},
|
||||
{"suffix", 0, POPT_ARG_STRING, &backup_suffix, 0, 0, 0 },
|
||||
{"rsync-path", 0, POPT_ARG_STRING, &rsync_path, 0, 0, 0 },
|
||||
{"password-file", 0, POPT_ARG_STRING, &password_file, 0, 0, 0 },
|
||||
{"rsync-path", 0, POPT_ARG_STRING, &rsync_path, 0, 0, 0 },
|
||||
{"password-file", 0, POPT_ARG_STRING, &password_file, 0, 0, 0 },
|
||||
{"ignore-times", 'I', POPT_ARG_NONE, &ignore_times, 0, 0, 0 },
|
||||
{"size-only", 0, POPT_ARG_NONE, &size_only, 0, 0, 0 },
|
||||
{"modify-window", 0, POPT_ARG_INT, &modify_window, OPT_MODIFY_WINDOW, 0, 0 },
|
||||
@@ -336,6 +350,8 @@ static struct poptOption long_options[] = {
|
||||
{"sparse", 'S', POPT_ARG_NONE, &sparse_files, 0, 0, 0 },
|
||||
{"cvs-exclude", 'C', POPT_ARG_NONE, &cvs_exclude, 0, 0, 0 },
|
||||
{"update", 'u', POPT_ARG_NONE, &update_only, 0, 0, 0 },
|
||||
{"inplace", 0, POPT_ARG_NONE, &inplace, 0, 0, 0 },
|
||||
{"keep-dirlinks", 'K', POPT_ARG_NONE, &keep_dirlinks, 0, 0, 0 },
|
||||
{"links", 'l', POPT_ARG_NONE, &preserve_links, 0, 0, 0 },
|
||||
{"copy-links", 'L', POPT_ARG_NONE, ©_links, 0, 0, 0 },
|
||||
{"whole-file", 'W', POPT_ARG_VAL, &whole_file, 1, 0, 0 },
|
||||
@@ -358,7 +374,7 @@ static struct poptOption long_options[] = {
|
||||
{"rsh", 'e', POPT_ARG_STRING, &shell_cmd, 0, 0, 0 },
|
||||
{"block-size", 'B', POPT_ARG_INT, &block_size, 0, 0, 0 },
|
||||
{"max-delete", 0, POPT_ARG_INT, &max_delete, 0, 0, 0 },
|
||||
{"timeout", 0, POPT_ARG_INT, &io_timeout, 0, 0, 0 },
|
||||
{"timeout", 0, POPT_ARG_INT, &io_timeout, OPT_TIMEOUT, 0, 0 },
|
||||
{"temp-dir", 'T', POPT_ARG_STRING, &tmpdir, 0, 0, 0 },
|
||||
{"compare-dest", 0, POPT_ARG_STRING, &compare_dest, 0, 0, 0 },
|
||||
{"link-dest", 0, POPT_ARG_STRING, &compare_dest, OPT_LINK_DEST, 0, 0 },
|
||||
@@ -369,6 +385,7 @@ static struct poptOption long_options[] = {
|
||||
{"stats", 0, POPT_ARG_NONE, &do_stats, 0, 0, 0 },
|
||||
{"progress", 0, POPT_ARG_NONE, &do_progress, 0, 0, 0 },
|
||||
{"partial", 0, POPT_ARG_NONE, &keep_partial, 0, 0, 0 },
|
||||
{"partial-dir", 0, POPT_ARG_STRING, &partial_dir, 0, 0, 0 },
|
||||
{"ignore-errors", 0, POPT_ARG_NONE, &ignore_errors, 0, 0, 0 },
|
||||
{"blocking-io", 0, POPT_ARG_VAL, &blocking_io, 1, 0, 0 },
|
||||
{"no-blocking-io", 0, POPT_ARG_VAL, &blocking_io, 0, 0, 0 },
|
||||
@@ -380,21 +397,22 @@ static struct poptOption long_options[] = {
|
||||
{"address", 0, POPT_ARG_STRING, &bind_address, 0, 0, 0 },
|
||||
{"backup-dir", 0, POPT_ARG_STRING, &backup_dir, 0, 0, 0 },
|
||||
{"hard-links", 'H', POPT_ARG_NONE, &preserve_hard_links, 0, 0, 0 },
|
||||
{"read-batch", 0, POPT_ARG_STRING, &batch_prefix, OPT_READ_BATCH, 0, 0 },
|
||||
{"write-batch", 0, POPT_ARG_STRING, &batch_prefix, OPT_WRITE_BATCH, 0, 0 },
|
||||
{"read-batch", 0, POPT_ARG_STRING, &batch_name, OPT_READ_BATCH, 0, 0 },
|
||||
{"write-batch", 0, POPT_ARG_STRING, &batch_name, OPT_WRITE_BATCH, 0, 0 },
|
||||
{"files-from", 0, POPT_ARG_STRING, &files_from, 0, 0, 0 },
|
||||
{"from0", '0', POPT_ARG_NONE, &eol_nulls, 0, 0, 0},
|
||||
{"no-implied-dirs", 0, POPT_ARG_VAL, &implied_dirs, 0, 0, 0 },
|
||||
{"protocol", 0, POPT_ARG_INT, &protocol_version, 0, 0, 0 },
|
||||
{"checksum-seed", 0, POPT_ARG_INT, &checksum_seed, 0, 0, 0 },
|
||||
#ifdef INET6
|
||||
{0, '4', POPT_ARG_VAL, &default_af_hint, AF_INET, 0, 0 },
|
||||
{0, '6', POPT_ARG_VAL, &default_af_hint, AF_INET6, 0, 0 },
|
||||
{"ipv4", '4', POPT_ARG_VAL, &default_af_hint, AF_INET, 0, 0 },
|
||||
{"ipv6", '6', POPT_ARG_VAL, &default_af_hint, AF_INET6, 0, 0 },
|
||||
#endif
|
||||
{0,0,0,0, 0, 0, 0}
|
||||
};
|
||||
|
||||
|
||||
static char err_buf[100];
|
||||
static char err_buf[200];
|
||||
|
||||
|
||||
/**
|
||||
@@ -404,15 +422,12 @@ static char err_buf[100];
|
||||
**/
|
||||
void option_error(void)
|
||||
{
|
||||
if (err_buf[0]) {
|
||||
rprintf(FLOG, "%s", err_buf);
|
||||
rprintf(FERROR, RSYNC_NAME ": %s", err_buf);
|
||||
} else {
|
||||
rprintf (FERROR, "Error parsing options: "
|
||||
"option may be supported on client but not on server?\n");
|
||||
rprintf (FERROR, RSYNC_NAME ": Error parsing options: "
|
||||
"option may be supported on client but not on server?\n");
|
||||
if (!err_buf[0]) {
|
||||
strcpy(err_buf, "Error parsing options: "
|
||||
"option may be supported on client but not on server?\n");
|
||||
}
|
||||
|
||||
rprintf(FERROR, RSYNC_NAME ": %s", err_buf);
|
||||
}
|
||||
|
||||
|
||||
@@ -423,23 +438,38 @@ void option_error(void)
|
||||
static void set_refuse_options(char *bp)
|
||||
{
|
||||
struct poptOption *op;
|
||||
char *cp;
|
||||
char *cp, shortname[2];
|
||||
int is_wild, found_match;
|
||||
|
||||
shortname[1] = '\0';
|
||||
|
||||
while (1) {
|
||||
while (*bp == ' ') bp++;
|
||||
if (!*bp)
|
||||
break;
|
||||
if ((cp = strchr(bp, ' ')) != NULL)
|
||||
*cp= '\0';
|
||||
/* If they specify "delete", reject all delete options. */
|
||||
if (strcmp(bp, "delete") == 0)
|
||||
bp = "delete*";
|
||||
is_wild = strpbrk(bp, "*?[") != NULL;
|
||||
found_match = 0;
|
||||
for (op = long_options; ; op++) {
|
||||
if (!op->longName) {
|
||||
rprintf(FLOG,
|
||||
"Unknown option %s in \"refuse options\" setting\n",
|
||||
bp);
|
||||
break;
|
||||
}
|
||||
if (strcmp(bp, op->longName) == 0) {
|
||||
op->val = (op - long_options)+OPT_REFUSED_BASE;
|
||||
*shortname = op->shortName;
|
||||
if (!op->longName && !*shortname)
|
||||
break;
|
||||
if ((op->longName && wildmatch(bp, op->longName))
|
||||
|| (*shortname && wildmatch(bp, shortname))) {
|
||||
op->val = (op - long_options) + OPT_REFUSED_BASE;
|
||||
found_match = 1;
|
||||
if (!is_wild)
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!found_match) {
|
||||
rprintf(FLOG, "No match for refuse-options string \"%s\"\n",
|
||||
bp);
|
||||
}
|
||||
if (!cp)
|
||||
break;
|
||||
*cp = ' ';
|
||||
@@ -519,19 +549,19 @@ int parse_arguments(int *argc, const char ***argv, int frommain)
|
||||
break;
|
||||
|
||||
case OPT_EXCLUDE_FROM:
|
||||
arg = poptGetOptArg(pc);
|
||||
if (sanitize_paths)
|
||||
arg = alloc_sanitize_path(arg, curr_dir);
|
||||
add_exclude_file(&exclude_list, arg,
|
||||
XFLG_FATAL_ERRORS);
|
||||
break;
|
||||
|
||||
case OPT_INCLUDE_FROM:
|
||||
arg = poptGetOptArg(pc);
|
||||
if (sanitize_paths)
|
||||
arg = alloc_sanitize_path(arg, curr_dir);
|
||||
add_exclude_file(&exclude_list, arg,
|
||||
XFLG_FATAL_ERRORS | XFLG_DEF_INCLUDE);
|
||||
arg = sanitize_path(NULL, arg, NULL, 0);
|
||||
if (server_exclude_list.head) {
|
||||
char *cp = (char *)arg;
|
||||
clean_fname(cp, 1);
|
||||
if (check_exclude(&server_exclude_list, cp, 0) < 0)
|
||||
goto options_rejected;
|
||||
}
|
||||
add_exclude_file(&exclude_list, arg, XFLG_FATAL_ERRORS
|
||||
| (opt == OPT_INCLUDE_FROM
|
||||
? XFLG_DEF_INCLUDE : 0));
|
||||
break;
|
||||
|
||||
case 'h':
|
||||
@@ -561,15 +591,18 @@ int parse_arguments(int *argc, const char ***argv, int frommain)
|
||||
break;
|
||||
|
||||
case OPT_WRITE_BATCH:
|
||||
/* popt stores the filename in batch_prefix for us */
|
||||
/* batch_name is already set */
|
||||
write_batch = 1;
|
||||
checksum_seed = FIXED_CHECKSUM_SEED;
|
||||
break;
|
||||
|
||||
case OPT_READ_BATCH:
|
||||
/* popt stores the filename in batch_prefix for us */
|
||||
/* batch_name is already set */
|
||||
read_batch = 1;
|
||||
checksum_seed = FIXED_CHECKSUM_SEED;
|
||||
break;
|
||||
|
||||
case OPT_TIMEOUT:
|
||||
if (io_timeout && io_timeout < select_timeout)
|
||||
select_timeout = io_timeout;
|
||||
break;
|
||||
|
||||
case OPT_LINK_DEST:
|
||||
@@ -580,7 +613,6 @@ int parse_arguments(int *argc, const char ***argv, int frommain)
|
||||
snprintf(err_buf, sizeof err_buf,
|
||||
"hard links are not supported on this %s\n",
|
||||
am_server ? "server" : "client");
|
||||
rprintf(FERROR, "ERROR: %s", err_buf);
|
||||
return 0;
|
||||
#endif
|
||||
|
||||
@@ -591,7 +623,7 @@ int parse_arguments(int *argc, const char ***argv, int frommain)
|
||||
struct poptOption *op =
|
||||
&long_options[opt-OPT_REFUSED_BASE];
|
||||
int n = snprintf(err_buf, sizeof err_buf,
|
||||
"This server does not support --%s\n",
|
||||
"The server is configured to refuse --%s\n",
|
||||
op->longName) - 1;
|
||||
if (op->shortName) {
|
||||
snprintf(err_buf+n, sizeof err_buf-n,
|
||||
@@ -613,7 +645,6 @@ int parse_arguments(int *argc, const char ***argv, int frommain)
|
||||
snprintf(err_buf, sizeof err_buf,
|
||||
"symlinks are not supported on this %s\n",
|
||||
am_server ? "server" : "client");
|
||||
rprintf(FERROR, "ERROR: %s", err_buf);
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
@@ -623,32 +654,49 @@ int parse_arguments(int *argc, const char ***argv, int frommain)
|
||||
snprintf(err_buf, sizeof err_buf,
|
||||
"hard links are not supported on this %s\n",
|
||||
am_server ? "server" : "client");
|
||||
rprintf(FERROR, "ERROR: %s", err_buf);
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (write_batch && read_batch) {
|
||||
rprintf(FERROR,
|
||||
"write-batch and read-batch can not be used together\n");
|
||||
exit_cleanup(RERR_SYNTAX);
|
||||
snprintf(err_buf, sizeof err_buf,
|
||||
"--write-batch and --read-batch can not be used together\n");
|
||||
return 0;
|
||||
}
|
||||
if (batch_prefix && strlen(batch_prefix) > MAX_BATCH_PREFIX_LEN) {
|
||||
rprintf(FERROR,
|
||||
"the batch-file prefix must be %d characters or less.\n",
|
||||
MAX_BATCH_PREFIX_LEN);
|
||||
exit_cleanup(RERR_SYNTAX);
|
||||
if (write_batch || read_batch) {
|
||||
if (dry_run) {
|
||||
snprintf(err_buf, sizeof err_buf,
|
||||
"--%s-batch cannot be used with --dry_run (-n)\n",
|
||||
write_batch ? "write" : "read");
|
||||
return 0;
|
||||
}
|
||||
if (am_server) {
|
||||
rprintf(FINFO,
|
||||
"ignoring --%s-batch option sent to server\n",
|
||||
write_batch ? "write" : "read");
|
||||
/* We don't actually exit_cleanup(), so that we can
|
||||
* still service older version clients that still send
|
||||
* batch args to server. */
|
||||
read_batch = write_batch = 0;
|
||||
batch_name = NULL;
|
||||
}
|
||||
}
|
||||
if (read_batch && files_from) {
|
||||
snprintf(err_buf, sizeof err_buf,
|
||||
"--read-batch cannot be used with --files-from\n");
|
||||
return 0;
|
||||
}
|
||||
if (batch_name && strlen(batch_name) > MAX_BATCH_NAME_LEN) {
|
||||
snprintf(err_buf, sizeof err_buf,
|
||||
"the batch-file name must be %d characters or less.\n",
|
||||
MAX_BATCH_NAME_LEN);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (tmpdir && strlen(tmpdir) >= MAXPATHLEN - 10) {
|
||||
rprintf(FERROR, "the --temp-dir path is WAY too long.\n");
|
||||
exit_cleanup(RERR_SYNTAX);
|
||||
}
|
||||
|
||||
if (do_compression && (write_batch || read_batch)) {
|
||||
rprintf(FERROR,
|
||||
"compress can not be used with write-batch or read-batch\n");
|
||||
exit_cleanup(RERR_SYNTAX);
|
||||
snprintf(err_buf, sizeof err_buf,
|
||||
"the --temp-dir path is WAY too long.\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (archive_mode) {
|
||||
@@ -676,15 +724,49 @@ int parse_arguments(int *argc, const char ***argv, int frommain)
|
||||
if (sanitize_paths) {
|
||||
int i;
|
||||
for (i = *argc; i-- > 0; )
|
||||
(*argv)[i] = alloc_sanitize_path((*argv)[i], NULL);
|
||||
(*argv)[i] = sanitize_path(NULL, (*argv)[i], "", 0);
|
||||
if (tmpdir)
|
||||
tmpdir = alloc_sanitize_path(tmpdir, curr_dir);
|
||||
tmpdir = sanitize_path(NULL, tmpdir, NULL, 0);
|
||||
if (partial_dir)
|
||||
partial_dir = sanitize_path(NULL, partial_dir, NULL, 0);
|
||||
if (compare_dest)
|
||||
compare_dest = alloc_sanitize_path(compare_dest, curr_dir);
|
||||
compare_dest = sanitize_path(NULL, compare_dest, NULL, 0);
|
||||
if (backup_dir)
|
||||
backup_dir = alloc_sanitize_path(backup_dir, curr_dir);
|
||||
backup_dir = sanitize_path(NULL, backup_dir, NULL, 0);
|
||||
if (files_from)
|
||||
files_from = alloc_sanitize_path(files_from, curr_dir);
|
||||
files_from = sanitize_path(NULL, files_from, NULL, 0);
|
||||
}
|
||||
if (server_exclude_list.head && !am_sender) {
|
||||
struct exclude_list_struct *elp = &server_exclude_list;
|
||||
if (tmpdir) {
|
||||
clean_fname(tmpdir, 1);
|
||||
if (check_exclude(elp, tmpdir, 1) < 0)
|
||||
goto options_rejected;
|
||||
}
|
||||
if (partial_dir) {
|
||||
clean_fname(partial_dir, 1);
|
||||
if (check_exclude(elp, partial_dir, 1) < 0)
|
||||
goto options_rejected;
|
||||
}
|
||||
if (compare_dest) {
|
||||
clean_fname(compare_dest, 1);
|
||||
if (check_exclude(elp, compare_dest, 1) < 0)
|
||||
goto options_rejected;
|
||||
}
|
||||
if (backup_dir) {
|
||||
clean_fname(backup_dir, 1);
|
||||
if (check_exclude(elp, backup_dir, 1) < 0)
|
||||
goto options_rejected;
|
||||
}
|
||||
}
|
||||
if (server_exclude_list.head && files_from) {
|
||||
clean_fname(files_from, 1);
|
||||
if (check_exclude(&server_exclude_list, files_from, 0) < 0) {
|
||||
options_rejected:
|
||||
snprintf(err_buf, sizeof err_buf,
|
||||
"Your options have been rejected by the server.\n");
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (daemon_opt) {
|
||||
@@ -697,16 +779,18 @@ int parse_arguments(int *argc, const char ***argv, int frommain)
|
||||
backup_suffix = backup_dir ? "" : BACKUP_SUFFIX;
|
||||
backup_suffix_len = strlen(backup_suffix);
|
||||
if (strchr(backup_suffix, '/') != NULL) {
|
||||
rprintf(FERROR, "--suffix cannot contain slashes: %s\n",
|
||||
snprintf(err_buf, sizeof err_buf,
|
||||
"--suffix cannot contain slashes: %s\n",
|
||||
backup_suffix);
|
||||
exit_cleanup(RERR_SYNTAX);
|
||||
return 0;
|
||||
}
|
||||
if (backup_dir) {
|
||||
backup_dir_len = strlcpy(backup_dir_buf, backup_dir, sizeof backup_dir_buf);
|
||||
backup_dir_remainder = sizeof backup_dir_buf - backup_dir_len;
|
||||
if (backup_dir_remainder < 32) {
|
||||
rprintf(FERROR, "the --backup-dir path is WAY too long.\n");
|
||||
exit_cleanup(RERR_SYNTAX);
|
||||
snprintf(err_buf, sizeof err_buf,
|
||||
"the --backup-dir path is WAY too long.\n");
|
||||
return 0;
|
||||
}
|
||||
if (backup_dir_buf[backup_dir_len - 1] != '/') {
|
||||
backup_dir_buf[backup_dir_len++] = '/';
|
||||
@@ -715,17 +799,57 @@ int parse_arguments(int *argc, const char ***argv, int frommain)
|
||||
if (verbose > 1 && !am_sender)
|
||||
rprintf(FINFO, "backup_dir is %s\n", backup_dir_buf);
|
||||
} else if (!backup_suffix_len && (!am_server || !am_sender)) {
|
||||
rprintf(FERROR,
|
||||
snprintf(err_buf, sizeof err_buf,
|
||||
"--suffix cannot be a null string without --backup-dir\n");
|
||||
exit_cleanup(RERR_SYNTAX);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (do_progress && !verbose)
|
||||
verbose = 1;
|
||||
|
||||
if (bwlimit) {
|
||||
bwlimit_writemax = (size_t)bwlimit * 128;
|
||||
if (bwlimit_writemax < 512)
|
||||
bwlimit_writemax = 512;
|
||||
}
|
||||
|
||||
if (inplace) {
|
||||
#if HAVE_FTRUNCATE
|
||||
if (partial_dir) {
|
||||
snprintf(err_buf, sizeof err_buf,
|
||||
"--inplace cannot be used with --partial-dir\n");
|
||||
return 0;
|
||||
}
|
||||
keep_partial = 0;
|
||||
#else
|
||||
snprintf(err_buf, sizeof err_buf,
|
||||
"--inplace is not supported on this %s\n",
|
||||
am_server ? "server" : "client");
|
||||
return 0;
|
||||
#endif
|
||||
if (compare_dest) {
|
||||
snprintf(err_buf, sizeof err_buf,
|
||||
"--inplace does not yet work with %s\n",
|
||||
link_dest ? "--link-dest" : "--compare-dest");
|
||||
return 0;
|
||||
}
|
||||
} else {
|
||||
if (keep_partial && !partial_dir)
|
||||
partial_dir = getenv("RSYNC_PARTIAL_DIR");
|
||||
if (partial_dir) {
|
||||
if (!*partial_dir || strcmp(partial_dir, ".") == 0)
|
||||
partial_dir = NULL;
|
||||
else if (*partial_dir != '/') {
|
||||
add_exclude(&exclude_list, partial_dir,
|
||||
XFLG_DIRECTORY);
|
||||
}
|
||||
keep_partial = 1;
|
||||
}
|
||||
}
|
||||
|
||||
if (files_from) {
|
||||
char *colon;
|
||||
if (*argc != 2 && !(am_server && am_sender && *argc == 1)) {
|
||||
if (*argc > 2 || (!am_daemon && *argc == 1)) {
|
||||
usage(FERROR);
|
||||
exit_cleanup(RERR_SYNTAX);
|
||||
}
|
||||
@@ -741,16 +865,17 @@ int parse_arguments(int *argc, const char ***argv, int frommain)
|
||||
}
|
||||
remote_filesfrom_file = colon+1 + (colon[1] == ':');
|
||||
if (strcmp(remote_filesfrom_file, "-") == 0) {
|
||||
rprintf(FERROR, "Invalid --files-from remote filename\n");
|
||||
exit_cleanup(RERR_SYNTAX);
|
||||
snprintf(err_buf, sizeof err_buf,
|
||||
"Invalid --files-from remote filename\n");
|
||||
return 0;
|
||||
}
|
||||
} else {
|
||||
filesfrom_fd = open(files_from, O_RDONLY|O_BINARY);
|
||||
if (filesfrom_fd < 0) {
|
||||
rsyserr(FERROR, errno,
|
||||
"failed to open files-from file %s",
|
||||
files_from);
|
||||
exit_cleanup(RERR_FILEIO);
|
||||
snprintf(err_buf, sizeof err_buf,
|
||||
"failed to open files-from file %s: %s\n",
|
||||
files_from, strerror(errno));
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -806,6 +931,8 @@ void server_options(char **args,int *argc)
|
||||
argstr[x++] = 'l';
|
||||
if (copy_links)
|
||||
argstr[x++] = 'L';
|
||||
if (keep_dirlinks && am_sender)
|
||||
argstr[x++] = 'K';
|
||||
|
||||
if (whole_file > 0)
|
||||
argstr[x++] = 'W';
|
||||
@@ -866,13 +993,6 @@ void server_options(char **args,int *argc)
|
||||
args[ac++] = arg;
|
||||
}
|
||||
|
||||
if (batch_prefix) {
|
||||
char *r_or_w = write_batch ? "write" : "read";
|
||||
if (asprintf(&arg, "--%s-batch=%s", r_or_w, batch_prefix) < 0)
|
||||
goto oom;
|
||||
args[ac++] = arg;
|
||||
}
|
||||
|
||||
if (io_timeout) {
|
||||
if (asprintf(&arg, "--timeout=%d", io_timeout) < 0)
|
||||
goto oom;
|
||||
@@ -898,10 +1018,18 @@ void server_options(char **args,int *argc)
|
||||
args[ac++] = arg;
|
||||
}
|
||||
|
||||
if (delete_excluded)
|
||||
args[ac++] = "--delete-excluded";
|
||||
else if (delete_mode)
|
||||
args[ac++] = "--delete";
|
||||
if (am_sender) {
|
||||
if (delete_excluded)
|
||||
args[ac++] = "--delete-excluded";
|
||||
else if (delete_mode)
|
||||
args[ac++] = "--delete";
|
||||
|
||||
if (delete_after)
|
||||
args[ac++] = "--delete-after";
|
||||
|
||||
if (force_delete)
|
||||
args[ac++] = "--force";
|
||||
}
|
||||
|
||||
if (size_only)
|
||||
args[ac++] = "--size-only";
|
||||
@@ -912,15 +1040,18 @@ void server_options(char **args,int *argc)
|
||||
args[ac++] = arg;
|
||||
}
|
||||
|
||||
if (keep_partial)
|
||||
if (checksum_seed) {
|
||||
if (asprintf(&arg, "--checksum-seed=%d", checksum_seed) < 0)
|
||||
goto oom;
|
||||
args[ac++] = arg;
|
||||
}
|
||||
|
||||
if (partial_dir && am_sender) {
|
||||
args[ac++] = "--partial-dir";
|
||||
args[ac++] = partial_dir;
|
||||
} else if (keep_partial)
|
||||
args[ac++] = "--partial";
|
||||
|
||||
if (force_delete)
|
||||
args[ac++] = "--force";
|
||||
|
||||
if (delete_after)
|
||||
args[ac++] = "--delete-after";
|
||||
|
||||
if (ignore_errors)
|
||||
args[ac++] = "--ignore-errors";
|
||||
|
||||
@@ -939,6 +1070,9 @@ void server_options(char **args,int *argc)
|
||||
if (opt_ignore_existing && am_sender)
|
||||
args[ac++] = "--ignore-existing";
|
||||
|
||||
if (inplace)
|
||||
args[ac++] = "--inplace";
|
||||
|
||||
if (tmpdir) {
|
||||
args[ac++] = "--temp-dir";
|
||||
args[ac++] = tmpdir;
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
Summary: Program for efficient remote updates of files.
|
||||
Name: rsync
|
||||
Version: 2.6.1
|
||||
Version: 2.6.3
|
||||
Release: 1
|
||||
Copyright: GPL
|
||||
Group: Applications/Networking
|
||||
|
||||
4
params.c
4
params.c
@@ -491,8 +491,8 @@ static FILE *OpenConfFile( char *FileName )
|
||||
OpenedFile = fopen( FileName, "r" );
|
||||
if( NULL == OpenedFile )
|
||||
{
|
||||
rprintf(FERROR,"rsync: unable to open configuration file \"%s\": %s\n",
|
||||
FileName, strerror(errno));
|
||||
rsyserr(FERROR, errno, "rsync: unable to open configuration file \"%s\"",
|
||||
FileName);
|
||||
}
|
||||
|
||||
return( OpenedFile );
|
||||
|
||||
68
pipe.c
68
pipe.c
@@ -1,19 +1,19 @@
|
||||
/* -*- c-file-style: "linux" -*-
|
||||
*
|
||||
* Copyright (C) 1996-2000 by Andrew Tridgell
|
||||
*
|
||||
* Copyright (C) 1996-2000 by Andrew Tridgell
|
||||
* Copyright (C) Paul Mackerras 1996
|
||||
* Copyright (C) 2001, 2002 by Martin Pool <mbp@samba.org>
|
||||
*
|
||||
*
|
||||
* 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 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
@@ -25,14 +25,14 @@ extern int am_sender;
|
||||
extern int am_server;
|
||||
extern int blocking_io;
|
||||
extern int orig_umask;
|
||||
extern int read_batch;
|
||||
extern int write_batch;
|
||||
extern int filesfrom_fd;
|
||||
|
||||
/**
|
||||
* Create a child connected to use on stdin/stdout.
|
||||
*
|
||||
* This is derived from CVS code
|
||||
*
|
||||
* This is derived from CVS code
|
||||
*
|
||||
* Note that in the child STDIN is set to blocking and STDOUT
|
||||
* is set to non-blocking. This is necessary as rsh relies on stdin being blocking
|
||||
* and ssh relies on stdout being non-blocking
|
||||
@@ -46,20 +46,19 @@ pid_t piped_child(char **command, int *f_in, int *f_out)
|
||||
pid_t pid;
|
||||
int to_child_pipe[2];
|
||||
int from_child_pipe[2];
|
||||
|
||||
|
||||
if (verbose >= 2) {
|
||||
print_child_argv(command);
|
||||
}
|
||||
|
||||
if (fd_pair(to_child_pipe) < 0 || fd_pair(from_child_pipe) < 0) {
|
||||
rprintf(FERROR, "pipe: %s\n", strerror(errno));
|
||||
rsyserr(FERROR, errno, "pipe");
|
||||
exit_cleanup(RERR_IPC);
|
||||
}
|
||||
|
||||
|
||||
pid = do_fork();
|
||||
if (pid == -1) {
|
||||
rprintf(FERROR, "fork: %s\n", strerror(errno));
|
||||
rsyserr(FERROR, errno, "fork");
|
||||
exit_cleanup(RERR_IPC);
|
||||
}
|
||||
|
||||
@@ -68,8 +67,7 @@ pid_t piped_child(char **command, int *f_in, int *f_out)
|
||||
close(to_child_pipe[1]) < 0 ||
|
||||
close(from_child_pipe[0]) < 0 ||
|
||||
dup2(from_child_pipe[1], STDOUT_FILENO) < 0) {
|
||||
rprintf(FERROR, "Failed to dup/close : %s\n",
|
||||
strerror(errno));
|
||||
rsyserr(FERROR, errno, "Failed to dup/close");
|
||||
exit_cleanup(RERR_IPC);
|
||||
}
|
||||
if (to_child_pipe[0] != STDIN_FILENO)
|
||||
@@ -81,13 +79,12 @@ pid_t piped_child(char **command, int *f_in, int *f_out)
|
||||
if (blocking_io > 0)
|
||||
set_blocking(STDOUT_FILENO);
|
||||
execvp(command[0], command);
|
||||
rprintf(FERROR, "Failed to exec %s : %s\n",
|
||||
command[0], strerror(errno));
|
||||
rsyserr(FERROR, errno, "Failed to exec %s", command[0]);
|
||||
exit_cleanup(RERR_IPC);
|
||||
}
|
||||
|
||||
if (close(from_child_pipe[1]) < 0 || close(to_child_pipe[0]) < 0) {
|
||||
rprintf(FERROR, "Failed to close : %s\n", strerror(errno));
|
||||
rsyserr(FERROR, errno, "Failed to close");
|
||||
exit_cleanup(RERR_IPC);
|
||||
}
|
||||
|
||||
@@ -97,7 +94,17 @@ pid_t piped_child(char **command, int *f_in, int *f_out)
|
||||
return pid;
|
||||
}
|
||||
|
||||
pid_t local_child(int argc, char **argv,int *f_in,int *f_out,
|
||||
/* This function forks a child which calls child_main(). First,
|
||||
* however, it has to establish communication paths to and from the
|
||||
* newborn child. It creates two socket pairs -- one for writing to
|
||||
* the child (from the parent) and one for reading from the child
|
||||
* (writing to the parent). Since that's four socket ends, each
|
||||
* process has to close the two ends it doesn't need. The remaining
|
||||
* two socket ends are retained for reading and writing. In the
|
||||
* child, the STDIN and STDOUT file descriptors refer to these
|
||||
* sockets. In the parent, the function arguments f_in and f_out are
|
||||
* set to refer to these sockets. */
|
||||
pid_t local_child(int argc, char **argv, int *f_in, int *f_out,
|
||||
int (*child_main)(int, char*[]))
|
||||
{
|
||||
pid_t pid;
|
||||
@@ -106,20 +113,23 @@ pid_t local_child(int argc, char **argv,int *f_in,int *f_out,
|
||||
|
||||
if (fd_pair(to_child_pipe) < 0 ||
|
||||
fd_pair(from_child_pipe) < 0) {
|
||||
rprintf(FERROR,"pipe: %s\n",strerror(errno));
|
||||
rsyserr(FERROR, errno, "pipe");
|
||||
exit_cleanup(RERR_IPC);
|
||||
}
|
||||
|
||||
|
||||
pid = do_fork();
|
||||
if (pid == -1) {
|
||||
rprintf(FERROR,"fork: %s\n",strerror(errno));
|
||||
rsyserr(FERROR, errno, "fork");
|
||||
exit_cleanup(RERR_IPC);
|
||||
}
|
||||
|
||||
if (pid == 0) {
|
||||
am_sender = read_batch ? 0 : !am_sender;
|
||||
am_server = 1;
|
||||
am_sender = !am_sender;
|
||||
am_server = 1;
|
||||
|
||||
/* The server side never writes the batch, even if it
|
||||
* is local (it makes the logic easier elsewhere). */
|
||||
write_batch = 0;
|
||||
|
||||
if (!am_sender)
|
||||
filesfrom_fd = -1;
|
||||
@@ -128,11 +138,13 @@ pid_t local_child(int argc, char **argv,int *f_in,int *f_out,
|
||||
close(to_child_pipe[1]) < 0 ||
|
||||
close(from_child_pipe[0]) < 0 ||
|
||||
dup2(from_child_pipe[1], STDOUT_FILENO) < 0) {
|
||||
rprintf(FERROR,"Failed to dup/close : %s\n",strerror(errno));
|
||||
rsyserr(FERROR, errno, "Failed to dup/close");
|
||||
exit_cleanup(RERR_IPC);
|
||||
}
|
||||
if (to_child_pipe[0] != STDIN_FILENO) close(to_child_pipe[0]);
|
||||
if (from_child_pipe[1] != STDOUT_FILENO) close(from_child_pipe[1]);
|
||||
if (to_child_pipe[0] != STDIN_FILENO)
|
||||
close(to_child_pipe[0]);
|
||||
if (from_child_pipe[1] != STDOUT_FILENO)
|
||||
close(from_child_pipe[1]);
|
||||
child_main(argc, argv);
|
||||
}
|
||||
|
||||
@@ -141,12 +153,12 @@ pid_t local_child(int argc, char **argv,int *f_in,int *f_out,
|
||||
|
||||
if (close(from_child_pipe[1]) < 0 ||
|
||||
close(to_child_pipe[0]) < 0) {
|
||||
rprintf(FERROR,"Failed to close : %s\n",strerror(errno));
|
||||
rsyserr(FERROR, errno, "Failed to close");
|
||||
exit_cleanup(RERR_IPC);
|
||||
}
|
||||
|
||||
*f_in = from_child_pipe[0];
|
||||
*f_out = to_child_pipe[1];
|
||||
|
||||
|
||||
return pid;
|
||||
}
|
||||
|
||||
@@ -63,7 +63,7 @@ struct poptOption poptHelpOptions[] = {
|
||||
/**
|
||||
* @param table option(s)
|
||||
*/
|
||||
/*@observer@*/ /*@null@*/ static const char *const
|
||||
/*@observer@*/ /*@null@*/ static const char *
|
||||
getTableTranslationDomain(/*@null@*/ const struct poptOption *table)
|
||||
/*@*/
|
||||
{
|
||||
@@ -81,10 +81,10 @@ getTableTranslationDomain(/*@null@*/ const struct poptOption *table)
|
||||
* @param opt option(s)
|
||||
* @param translation_domain translation domain
|
||||
*/
|
||||
/*@observer@*/ /*@null@*/ static const char *const
|
||||
/*@observer@*/ /*@null@*/ static const char *
|
||||
getArgDescrip(const struct poptOption * opt,
|
||||
/*@-paramuse@*/ /* FIX: wazzup? */
|
||||
/*@null@*/ UNUSED(const char * translation_domain))
|
||||
/*@null@*/ const char * translation_domain)
|
||||
/*@=paramuse@*/
|
||||
/*@*/
|
||||
{
|
||||
@@ -115,7 +115,7 @@ static /*@only@*/ /*@null@*/ char *
|
||||
singleOptionDefaultValue(int lineLength,
|
||||
const struct poptOption * opt,
|
||||
/*@-paramuse@*/ /* FIX: i18n macros disable with lclint */
|
||||
/*@null@*/ UNUSED(const char * translation_domain))
|
||||
/*@null@*/ const char * translation_domain)
|
||||
/*@=paramuse@*/
|
||||
/*@*/
|
||||
{
|
||||
|
||||
@@ -19,6 +19,14 @@
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
|
||||
#if !defined(__GNUC__) || defined(APPLE)
|
||||
/* Apparently the OS X port of gcc gags on __attribute__.
|
||||
*
|
||||
* <http://www.opensource.apple.com/bugs/X/gcc/2512150.html> */
|
||||
#define __attribute__(x)
|
||||
|
||||
#endif
|
||||
|
||||
#ifdef __NeXT
|
||||
/* access macros are not declared in non posix mode in unistd.h -
|
||||
don't try to use posix on NeXTstep 3.3 ! */
|
||||
|
||||
356
receiver.c
356
receiver.c
@@ -22,19 +22,22 @@
|
||||
|
||||
extern int verbose;
|
||||
extern int recurse;
|
||||
extern int delete_mode;
|
||||
extern int delete_after;
|
||||
extern int max_delete;
|
||||
extern int csum_length;
|
||||
extern struct stats stats;
|
||||
extern int dry_run;
|
||||
extern int read_batch;
|
||||
extern int batch_gen_fd;
|
||||
extern int am_server;
|
||||
extern int relative_paths;
|
||||
extern int keep_dirlinks;
|
||||
extern int preserve_hard_links;
|
||||
extern int preserve_perms;
|
||||
extern int cvs_exclude;
|
||||
extern int io_error;
|
||||
extern char *tmpdir;
|
||||
extern char *partial_dir;
|
||||
extern char *compare_dest;
|
||||
extern int make_backups;
|
||||
extern int do_progress;
|
||||
@@ -45,24 +48,31 @@ extern int cleanup_got_literal;
|
||||
extern int module_id;
|
||||
extern int ignore_errors;
|
||||
extern int orig_umask;
|
||||
extern int keep_partial;
|
||||
extern int checksum_seed;
|
||||
extern int inplace;
|
||||
|
||||
extern struct exclude_list_struct server_exclude_list;
|
||||
|
||||
|
||||
static void delete_one(char *fn, int is_dir)
|
||||
{
|
||||
if (!is_dir) {
|
||||
if (robust_unlink(fn) != 0) {
|
||||
rprintf(FERROR, "delete_one: unlink %s failed: %s\n",
|
||||
full_fname(fn), strerror(errno));
|
||||
} else if (verbose) {
|
||||
rprintf(FINFO, "deleting %s\n", fn);
|
||||
}
|
||||
rsyserr(FERROR, errno, "delete_one: unlink %s failed",
|
||||
full_fname(fn));
|
||||
} else if (verbose)
|
||||
rprintf(FINFO, "deleting %s\n", safe_fname(fn));
|
||||
} else {
|
||||
if (do_rmdir(fn) != 0) {
|
||||
if (errno != ENOTEMPTY && errno != EEXIST) {
|
||||
rprintf(FERROR, "delete_one: rmdir %s failed: %s\n",
|
||||
full_fname(fn), strerror(errno));
|
||||
rsyserr(FERROR, errno,
|
||||
"delete_one: rmdir %s failed",
|
||||
full_fname(fn));
|
||||
}
|
||||
} else if (verbose) {
|
||||
rprintf(FINFO, "deleting directory %s\n", fn);
|
||||
rprintf(FINFO, "deleting directory %s\n",
|
||||
safe_fname(fn));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -103,7 +113,7 @@ void delete_files(struct file_list *flist)
|
||||
continue;
|
||||
|
||||
if (verbose > 1)
|
||||
rprintf(FINFO, "deleting in %s\n", fbuf);
|
||||
rprintf(FINFO, "deleting in %s\n", safe_fname(fbuf));
|
||||
|
||||
for (i = local_file_list->count-1; i >= 0; i--) {
|
||||
if (max_delete && deletion_count > max_delete)
|
||||
@@ -113,9 +123,11 @@ void delete_files(struct file_list *flist)
|
||||
if (flist_find(flist,local_file_list->files[i]) < 0) {
|
||||
char *f = f_name(local_file_list->files[i]);
|
||||
if (make_backups && (backup_dir || !is_backup_file(f))) {
|
||||
(void) make_backup(f);
|
||||
if (verbose)
|
||||
rprintf(FINFO, "deleting %s\n", f);
|
||||
make_backup(f);
|
||||
if (verbose) {
|
||||
rprintf(FINFO, "deleting %s\n",
|
||||
safe_fname(f));
|
||||
}
|
||||
} else {
|
||||
int mode = local_file_list->files[i]->mode;
|
||||
delete_one(f, S_ISDIR(mode) != 0);
|
||||
@@ -189,22 +201,33 @@ static int get_tmpname(char *fnametmp, char *fname)
|
||||
}
|
||||
|
||||
|
||||
static int receive_data(int f_in,struct map_struct *mapbuf,int fd,char *fname,
|
||||
OFF_T total_size)
|
||||
static int receive_data(int f_in, char *fname_r, int fd_r, OFF_T size_r,
|
||||
char *fname, int fd, OFF_T total_size)
|
||||
{
|
||||
int i;
|
||||
static char file_sum1[MD4_SUM_LENGTH];
|
||||
static char file_sum2[MD4_SUM_LENGTH];
|
||||
struct map_struct *mapbuf;
|
||||
struct sum_struct sum;
|
||||
unsigned int len;
|
||||
OFF_T offset = 0;
|
||||
OFF_T offset2;
|
||||
char *data;
|
||||
static char file_sum1[MD4_SUM_LENGTH];
|
||||
static char file_sum2[MD4_SUM_LENGTH];
|
||||
char *map=NULL;
|
||||
int i;
|
||||
char *map = NULL;
|
||||
|
||||
read_sum_head(f_in, &sum);
|
||||
|
||||
sum_init();
|
||||
if (fd_r >= 0 && size_r > 0) {
|
||||
OFF_T map_size = MAX(sum.blength * 2, 16*1024);
|
||||
mapbuf = map_file(fd_r, size_r, map_size, sum.blength);
|
||||
if (verbose > 2) {
|
||||
rprintf(FINFO, "recv mapped %s of size %.0f\n",
|
||||
safe_fname(fname_r), (double)size_r);
|
||||
}
|
||||
} else
|
||||
mapbuf = NULL;
|
||||
|
||||
sum_init(checksum_seed);
|
||||
|
||||
while ((i = recv_token(f_in, &data)) != 0) {
|
||||
if (do_progress)
|
||||
@@ -221,11 +244,8 @@ static int receive_data(int f_in,struct map_struct *mapbuf,int fd,char *fname,
|
||||
|
||||
sum_update(data,i);
|
||||
|
||||
if (fd != -1 && write_file(fd,data,i) != i) {
|
||||
rprintf(FERROR, "write failed on %s: %s\n",
|
||||
full_fname(fname), strerror(errno));
|
||||
exit_cleanup(RERR_FILEIO);
|
||||
}
|
||||
if (fd != -1 && write_file(fd,data,i) != i)
|
||||
goto report_write_error;
|
||||
offset += i;
|
||||
continue;
|
||||
}
|
||||
@@ -233,7 +253,7 @@ static int receive_data(int f_in,struct map_struct *mapbuf,int fd,char *fname,
|
||||
i = -(i+1);
|
||||
offset2 = i*(OFF_T)sum.blength;
|
||||
len = sum.blength;
|
||||
if (i == (int) sum.count-1 && sum.remainder != 0)
|
||||
if (i == (int)sum.count-1 && sum.remainder != 0)
|
||||
len = sum.remainder;
|
||||
|
||||
stats.matched_data += len;
|
||||
@@ -249,61 +269,83 @@ static int receive_data(int f_in,struct map_struct *mapbuf,int fd,char *fname,
|
||||
sum_update(map,len);
|
||||
}
|
||||
|
||||
if (fd != -1 && write_file(fd,map,len) != (int) len) {
|
||||
rprintf(FERROR, "write failed on %s: %s\n",
|
||||
full_fname(fname), strerror(errno));
|
||||
exit_cleanup(RERR_FILEIO);
|
||||
if (inplace) {
|
||||
if (offset == offset2 && fd != -1) {
|
||||
if (flush_write_file(fd) < 0)
|
||||
goto report_write_error;
|
||||
offset += len;
|
||||
if (do_lseek(fd, len, SEEK_CUR) != offset) {
|
||||
rsyserr(FERROR, errno,
|
||||
"lseek failed on %s",
|
||||
full_fname(fname));
|
||||
exit_cleanup(RERR_FILEIO);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
}
|
||||
if (fd != -1 && write_file(fd, map, len) != (int)len)
|
||||
goto report_write_error;
|
||||
offset += len;
|
||||
}
|
||||
|
||||
flush_write_file(fd);
|
||||
|
||||
#ifdef HAVE_FTRUNCATE
|
||||
if (inplace && fd != -1)
|
||||
ftruncate(fd, offset);
|
||||
#endif
|
||||
|
||||
if (do_progress)
|
||||
end_progress(total_size);
|
||||
|
||||
if (fd != -1 && offset > 0 && sparse_end(fd) != 0) {
|
||||
rprintf(FERROR, "write failed on %s: %s\n",
|
||||
full_fname(fname), strerror(errno));
|
||||
report_write_error:
|
||||
rsyserr(FERROR, errno, "write failed on %s",
|
||||
full_fname(fname));
|
||||
exit_cleanup(RERR_FILEIO);
|
||||
}
|
||||
|
||||
sum_end(file_sum1);
|
||||
|
||||
if (mapbuf)
|
||||
unmap_file(mapbuf);
|
||||
|
||||
read_buf(f_in,file_sum2,MD4_SUM_LENGTH);
|
||||
if (verbose > 2) {
|
||||
if (verbose > 2)
|
||||
rprintf(FINFO,"got file_sum\n");
|
||||
}
|
||||
if (fd != -1 && memcmp(file_sum1,file_sum2,MD4_SUM_LENGTH) != 0) {
|
||||
if (fd != -1 && memcmp(file_sum1, file_sum2, MD4_SUM_LENGTH) != 0)
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
static void discard_receive_data(int f_in, OFF_T length)
|
||||
{
|
||||
receive_data(f_in, NULL, -1, 0, NULL, -1, length);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* main routine for receiver process.
|
||||
*
|
||||
* Receiver process runs on the same host as the generator process. */
|
||||
int recv_files(int f_in,struct file_list *flist,char *local_name)
|
||||
int recv_files(int f_in, struct file_list *flist, char *local_name)
|
||||
{
|
||||
int next_gen_i = -1;
|
||||
int fd1,fd2;
|
||||
STRUCT_STAT st;
|
||||
char *fname, fbuf[MAXPATHLEN];
|
||||
char template[MAXPATHLEN];
|
||||
char fnametmp[MAXPATHLEN];
|
||||
char *fnamecmp;
|
||||
char *fnamecmp, *partialptr;
|
||||
char fnamecmpbuf[MAXPATHLEN];
|
||||
struct map_struct *mapbuf;
|
||||
int i;
|
||||
struct file_struct *file;
|
||||
int phase=0;
|
||||
int recv_ok;
|
||||
struct stats initial_stats;
|
||||
int save_make_backups = make_backups;
|
||||
int i, recv_ok, phase = 0;
|
||||
|
||||
if (verbose > 2) {
|
||||
if (verbose > 2)
|
||||
rprintf(FINFO,"recv_files(%d) starting\n",flist->count);
|
||||
}
|
||||
|
||||
if (flist->hlink_pool) {
|
||||
pool_destroy(flist->hlink_pool);
|
||||
@@ -315,15 +357,23 @@ int recv_files(int f_in,struct file_list *flist,char *local_name)
|
||||
|
||||
i = read_int(f_in);
|
||||
if (i == -1) {
|
||||
if (phase == 0) {
|
||||
phase++;
|
||||
csum_length = SUM_LENGTH;
|
||||
if (verbose > 2)
|
||||
rprintf(FINFO,"recv_files phase=%d\n",phase);
|
||||
send_msg(MSG_DONE, "", 0);
|
||||
continue;
|
||||
if (read_batch) {
|
||||
if (next_gen_i != flist->count)
|
||||
while (read_int(batch_gen_fd) != -1) {}
|
||||
next_gen_i = -1;
|
||||
}
|
||||
break;
|
||||
|
||||
if (phase)
|
||||
break;
|
||||
|
||||
phase = 1;
|
||||
csum_length = SUM_LENGTH;
|
||||
if (verbose > 2)
|
||||
rprintf(FINFO, "recv_files phase=%d\n", phase);
|
||||
send_msg(MSG_DONE, "", 0);
|
||||
if (keep_partial)
|
||||
make_backups = 0; /* prevents double backup */
|
||||
continue;
|
||||
}
|
||||
|
||||
if (i < 0 || i >= flist->count) {
|
||||
@@ -345,22 +395,58 @@ int recv_files(int f_in,struct file_list *flist,char *local_name)
|
||||
fname = f_name_to(file, fbuf);
|
||||
|
||||
if (dry_run) {
|
||||
if (!am_server && verbose) { /* log transfer */
|
||||
rprintf(FINFO, "%s\n", fname);
|
||||
}
|
||||
if (!am_server && verbose) /* log the transfer */
|
||||
rprintf(FINFO, "%s\n", safe_fname(fname));
|
||||
continue;
|
||||
}
|
||||
|
||||
initial_stats = stats;
|
||||
|
||||
if (verbose > 2)
|
||||
rprintf(FINFO,"recv_files(%s)\n",fname);
|
||||
rprintf(FINFO, "recv_files(%s)\n", safe_fname(fname));
|
||||
|
||||
fnamecmp = fname;
|
||||
if (read_batch) {
|
||||
while (i > next_gen_i) {
|
||||
next_gen_i = read_int(batch_gen_fd);
|
||||
if (next_gen_i == -1)
|
||||
next_gen_i = flist->count;
|
||||
}
|
||||
if (i < next_gen_i) {
|
||||
rprintf(FINFO, "skipping update for \"%s\"\n",
|
||||
safe_fname(fname));
|
||||
discard_receive_data(f_in, file->length);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
if (server_exclude_list.head
|
||||
&& check_exclude(&server_exclude_list, fname,
|
||||
S_ISDIR(file->mode)) < 0) {
|
||||
rprintf(FERROR, "attempt to hack rsync failed.\n");
|
||||
exit_cleanup(RERR_PROTOCOL);
|
||||
}
|
||||
|
||||
if (partial_dir) {
|
||||
if ((partialptr = partial_dir_fname(fname)) != NULL)
|
||||
fnamecmp = partialptr;
|
||||
else
|
||||
fnamecmp = fname;
|
||||
} else
|
||||
fnamecmp = partialptr = fname;
|
||||
|
||||
if (inplace && make_backups) {
|
||||
if (!(fnamecmp = get_backup_name(fname)))
|
||||
fnamecmp = partialptr;
|
||||
}
|
||||
|
||||
/* open the file */
|
||||
fd1 = do_open(fnamecmp, O_RDONLY, 0);
|
||||
|
||||
if (fd1 == -1 && fnamecmp != fname) {
|
||||
fnamecmp = fname;
|
||||
fd1 = do_open(fnamecmp, O_RDONLY, 0);
|
||||
}
|
||||
|
||||
if (fd1 == -1 && compare_dest != NULL) {
|
||||
/* try the file at compare_dest instead */
|
||||
pathjoin(fnamecmpbuf, sizeof fnamecmpbuf,
|
||||
@@ -370,9 +456,9 @@ int recv_files(int f_in,struct file_list *flist,char *local_name)
|
||||
}
|
||||
|
||||
if (fd1 != -1 && do_fstat(fd1,&st) != 0) {
|
||||
rprintf(FERROR, "fstat %s failed: %s\n",
|
||||
full_fname(fnamecmp), strerror(errno));
|
||||
receive_data(f_in,NULL,-1,NULL,file->length);
|
||||
rsyserr(FERROR, errno, "fstat %s failed",
|
||||
full_fname(fnamecmp));
|
||||
discard_receive_data(f_in, file->length);
|
||||
close(fd1);
|
||||
continue;
|
||||
}
|
||||
@@ -385,7 +471,7 @@ int recv_files(int f_in,struct file_list *flist,char *local_name)
|
||||
*/
|
||||
rprintf(FERROR,"recv_files: %s is a directory\n",
|
||||
full_fname(fnamecmp));
|
||||
receive_data(f_in, NULL, -1, NULL, file->length);
|
||||
discard_receive_data(f_in, file->length);
|
||||
close(fd1);
|
||||
continue;
|
||||
}
|
||||
@@ -393,7 +479,6 @@ int recv_files(int f_in,struct file_list *flist,char *local_name)
|
||||
if (fd1 != -1 && !S_ISREG(st.st_mode)) {
|
||||
close(fd1);
|
||||
fd1 = -1;
|
||||
mapbuf = NULL;
|
||||
}
|
||||
|
||||
if (fd1 != -1 && !preserve_perms) {
|
||||
@@ -403,86 +488,123 @@ int recv_files(int f_in,struct file_list *flist,char *local_name)
|
||||
file->mode = st.st_mode;
|
||||
}
|
||||
|
||||
if (fd1 != -1 && st.st_size > 0) {
|
||||
mapbuf = map_file(fd1,st.st_size);
|
||||
if (verbose > 2)
|
||||
rprintf(FINFO,"recv mapped %s of size %.0f\n",fnamecmp,(double)st.st_size);
|
||||
} else
|
||||
mapbuf = NULL;
|
||||
/* We now check to see if we are writing file "inplace" */
|
||||
if (inplace) {
|
||||
fd2 = do_open(fname, O_WRONLY|O_CREAT, 0);
|
||||
if (fd2 == -1) {
|
||||
rsyserr(FERROR, errno, "open %s failed",
|
||||
full_fname(fname));
|
||||
discard_receive_data(f_in, file->length);
|
||||
if (fd1 != -1)
|
||||
close(fd1);
|
||||
continue;
|
||||
}
|
||||
} else {
|
||||
if (!get_tmpname(fnametmp,fname)) {
|
||||
discard_receive_data(f_in, file->length);
|
||||
if (fd1 != -1)
|
||||
close(fd1);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!get_tmpname(fnametmp,fname)) {
|
||||
if (mapbuf) unmap_file(mapbuf);
|
||||
if (fd1 != -1) close(fd1);
|
||||
continue;
|
||||
}
|
||||
strlcpy(template, fnametmp, sizeof template);
|
||||
|
||||
strlcpy(template, fnametmp, sizeof template);
|
||||
|
||||
/* we initially set the perms without the
|
||||
* setuid/setgid bits to ensure that there is no race
|
||||
* condition. They are then correctly updated after
|
||||
* the lchown. Thanks to snabb@epipe.fi for pointing
|
||||
* this out. We also set it initially without group
|
||||
* access because of a similar race condition. */
|
||||
fd2 = do_mkstemp(fnametmp, file->mode & INITACCESSPERMS);
|
||||
|
||||
/* in most cases parent directories will already exist
|
||||
* because their information should have been previously
|
||||
* transferred, but that may not be the case with -R */
|
||||
if (fd2 == -1 && relative_paths && errno == ENOENT &&
|
||||
create_directory_path(fnametmp, orig_umask) == 0) {
|
||||
strlcpy(fnametmp, template, sizeof fnametmp);
|
||||
/* we initially set the perms without the
|
||||
* setuid/setgid bits to ensure that there is no race
|
||||
* condition. They are then correctly updated after
|
||||
* the lchown. Thanks to snabb@epipe.fi for pointing
|
||||
* this out. We also set it initially without group
|
||||
* access because of a similar race condition. */
|
||||
fd2 = do_mkstemp(fnametmp, file->mode & INITACCESSPERMS);
|
||||
}
|
||||
if (fd2 == -1) {
|
||||
rprintf(FERROR, "mkstemp %s failed: %s\n",
|
||||
full_fname(fnametmp), strerror(errno));
|
||||
receive_data(f_in,mapbuf,-1,NULL,file->length);
|
||||
if (mapbuf) unmap_file(mapbuf);
|
||||
if (fd1 != -1) close(fd1);
|
||||
continue;
|
||||
|
||||
/* in most cases parent directories will already exist
|
||||
* because their information should have been previously
|
||||
* transferred, but that may not be the case with -R */
|
||||
if (fd2 == -1 && relative_paths && errno == ENOENT
|
||||
&& create_directory_path(fnametmp, orig_umask) == 0) {
|
||||
strlcpy(fnametmp, template, sizeof fnametmp);
|
||||
fd2 = do_mkstemp(fnametmp, file->mode & INITACCESSPERMS);
|
||||
}
|
||||
if (fd2 == -1) {
|
||||
rsyserr(FERROR, errno, "mkstemp %s failed",
|
||||
full_fname(fnametmp));
|
||||
discard_receive_data(f_in, file->length);
|
||||
if (fd1 != -1)
|
||||
close(fd1);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (partialptr)
|
||||
cleanup_set(fnametmp, partialptr, file, fd1, fd2);
|
||||
}
|
||||
|
||||
cleanup_set(fnametmp, fname, file, mapbuf, fd1, fd2);
|
||||
|
||||
if (!am_server && verbose) { /* log transfer */
|
||||
rprintf(FINFO, "%s\n", fname);
|
||||
}
|
||||
if (!am_server && verbose) /* log the transfer */
|
||||
rprintf(FINFO, "%s\n", safe_fname(fname));
|
||||
|
||||
/* recv file data */
|
||||
recv_ok = receive_data(f_in,mapbuf,fd2,fname,file->length);
|
||||
recv_ok = receive_data(f_in, fnamecmp, fd1, st.st_size,
|
||||
fname, fd2, file->length);
|
||||
|
||||
log_recv(file, &initial_stats);
|
||||
|
||||
if (mapbuf) unmap_file(mapbuf);
|
||||
if (fd1 != -1) {
|
||||
if (fd1 != -1)
|
||||
close(fd1);
|
||||
if (close(fd2) < 0) {
|
||||
rsyserr(FERROR, errno, "close failed on %s",
|
||||
full_fname(fnametmp));
|
||||
exit_cleanup(RERR_FILEIO);
|
||||
}
|
||||
close(fd2);
|
||||
|
||||
if (verbose > 2)
|
||||
rprintf(FINFO,"renaming %s to %s\n",fnametmp,fname);
|
||||
if (recv_ok || inplace)
|
||||
finish_transfer(fname, fnametmp, file, recv_ok);
|
||||
else if (keep_partial && partialptr
|
||||
&& handle_partial_dir(partialptr, PDIR_CREATE))
|
||||
finish_transfer(partialptr, fnametmp, file, 0);
|
||||
else {
|
||||
partialptr = NULL;
|
||||
do_unlink(fnametmp);
|
||||
}
|
||||
|
||||
finish_transfer(fname, fnametmp, file);
|
||||
if (partialptr != fname && fnamecmp == partialptr && recv_ok) {
|
||||
do_unlink(partialptr);
|
||||
handle_partial_dir(partialptr, PDIR_DELETE);
|
||||
}
|
||||
|
||||
cleanup_disable();
|
||||
|
||||
if (!recv_ok) {
|
||||
if (csum_length == SUM_LENGTH) {
|
||||
rprintf(FERROR,"ERROR: file corruption in %s. File changed during transfer?\n",
|
||||
full_fname(fname));
|
||||
} else {
|
||||
int msgtype = csum_length == SUM_LENGTH || read_batch ?
|
||||
FERROR : FINFO;
|
||||
if (msgtype == FERROR || verbose) {
|
||||
char *errstr, *redostr, *keptstr;
|
||||
if (!(keep_partial && partialptr) && !inplace)
|
||||
keptstr = "discarded";
|
||||
else if (partial_dir)
|
||||
keptstr = "put into partial-dir";
|
||||
else
|
||||
keptstr = "retained";
|
||||
if (msgtype == FERROR) {
|
||||
errstr = "ERROR";
|
||||
redostr = "";
|
||||
} else {
|
||||
errstr = "WARNING";
|
||||
redostr = " (will try again)";
|
||||
}
|
||||
rprintf(msgtype,
|
||||
"%s: %s failed verification -- update %s%s.\n",
|
||||
errstr, safe_fname(fname),
|
||||
keptstr, redostr);
|
||||
}
|
||||
if (csum_length != SUM_LENGTH) {
|
||||
char buf[4];
|
||||
if (verbose > 1)
|
||||
rprintf(FINFO,"redoing %s(%d)\n",fname,i);
|
||||
SIVAL(buf, 0, i);
|
||||
send_msg(MSG_REDO, buf, 4);
|
||||
}
|
||||
}
|
||||
}
|
||||
make_backups = save_make_backups;
|
||||
|
||||
if (delete_after && recurse && delete_mode && !local_name
|
||||
&& flist->count > 0)
|
||||
if (delete_after && recurse && !local_name && flist->count > 0)
|
||||
delete_files(flist);
|
||||
|
||||
if (verbose > 2)
|
||||
|
||||
95
rsync.c
95
rsync.c
@@ -26,13 +26,16 @@ extern int verbose;
|
||||
extern int dry_run;
|
||||
extern int preserve_times;
|
||||
extern int am_root;
|
||||
extern int am_server;
|
||||
extern int am_sender;
|
||||
extern int am_generator;
|
||||
extern int preserve_uid;
|
||||
extern int preserve_gid;
|
||||
extern int preserve_perms;
|
||||
extern int force_delete;
|
||||
extern int recurse;
|
||||
extern int keep_dirlinks;
|
||||
extern int make_backups;
|
||||
extern char *backup_dir;
|
||||
extern int inplace;
|
||||
|
||||
|
||||
/*
|
||||
@@ -54,10 +57,8 @@ int delete_file(char *fname)
|
||||
DIR *d;
|
||||
struct dirent *di;
|
||||
char buf[MAXPATHLEN];
|
||||
extern int force_delete;
|
||||
STRUCT_STAT st;
|
||||
int ret;
|
||||
extern int recurse;
|
||||
|
||||
#if SUPPORT_LINKS
|
||||
ret = do_lstat(fname, &st);
|
||||
@@ -70,8 +71,8 @@ int delete_file(char *fname)
|
||||
if (!S_ISDIR(st.st_mode)) {
|
||||
if (robust_unlink(fname) == 0 || errno == ENOENT)
|
||||
return 0;
|
||||
rprintf(FERROR, "delete_file: unlink %s failed: %s\n",
|
||||
full_fname(fname), strerror(errno));
|
||||
rsyserr(FERROR, errno, "delete_file: unlink %s failed",
|
||||
full_fname(fname));
|
||||
return -1;
|
||||
}
|
||||
|
||||
@@ -79,15 +80,15 @@ int delete_file(char *fname)
|
||||
return 0;
|
||||
if (!force_delete || !recurse
|
||||
|| (errno != ENOTEMPTY && errno != EEXIST)) {
|
||||
rprintf(FERROR, "delete_file: rmdir %s failed: %s\n",
|
||||
full_fname(fname), strerror(errno));
|
||||
rsyserr(FERROR, errno, "delete_file: rmdir %s failed",
|
||||
full_fname(fname));
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* now we do a recsursive delete on the directory ... */
|
||||
if (!(d = opendir(fname))) {
|
||||
rprintf(FERROR, "delete_file: opendir %s failed: %s\n",
|
||||
full_fname(fname), strerror(errno));
|
||||
rsyserr(FERROR, errno, "delete_file: opendir %s failed",
|
||||
full_fname(fname));
|
||||
return -1;
|
||||
}
|
||||
|
||||
@@ -98,15 +99,15 @@ int delete_file(char *fname)
|
||||
continue;
|
||||
pathjoin(buf, sizeof buf, fname, dname);
|
||||
if (verbose > 0)
|
||||
rprintf(FINFO, "deleting %s\n", buf);
|
||||
rprintf(FINFO, "deleting %s\n", safe_fname(buf));
|
||||
if (delete_file(buf) != 0) {
|
||||
closedir(d);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
if (errno) {
|
||||
rprintf(FERROR, "delete_file: readdir %s failed: %s\n",
|
||||
full_fname(fname), strerror(errno));
|
||||
rsyserr(FERROR, errno, "delete_file: readdir %s failed",
|
||||
full_fname(fname));
|
||||
closedir(d);
|
||||
return -1;
|
||||
}
|
||||
@@ -114,8 +115,8 @@ int delete_file(char *fname)
|
||||
closedir(d);
|
||||
|
||||
if (do_rmdir(fname) != 0) {
|
||||
rprintf(FERROR, "delete_file: rmdir %s failed: %s\n",
|
||||
full_fname(fname), strerror(errno));
|
||||
rsyserr(FERROR, errno, "delete_file: rmdir %s failed",
|
||||
full_fname(fname));
|
||||
return -1;
|
||||
}
|
||||
|
||||
@@ -123,31 +124,35 @@ int delete_file(char *fname)
|
||||
}
|
||||
|
||||
int set_perms(char *fname,struct file_struct *file,STRUCT_STAT *st,
|
||||
int report)
|
||||
int flags)
|
||||
{
|
||||
int updated = 0;
|
||||
STRUCT_STAT st2;
|
||||
int change_uid, change_gid;
|
||||
|
||||
if (dry_run) return 0;
|
||||
if (dry_run)
|
||||
return 0;
|
||||
|
||||
if (!st) {
|
||||
if (link_stat(fname,&st2) != 0) {
|
||||
rprintf(FERROR, "stat %s failed: %s\n",
|
||||
full_fname(fname), strerror(errno));
|
||||
if (link_stat(fname, &st2, 0) < 0) {
|
||||
rsyserr(FERROR, errno, "stat %s failed",
|
||||
full_fname(fname));
|
||||
return 0;
|
||||
}
|
||||
st = &st2;
|
||||
}
|
||||
|
||||
if (preserve_times && !S_ISLNK(st->st_mode) &&
|
||||
cmp_modtime(st->st_mtime, file->modtime) != 0) {
|
||||
if (!preserve_times || S_ISLNK(st->st_mode)
|
||||
|| (make_backups && !backup_dir && S_ISDIR(st->st_mode)))
|
||||
flags |= PERMS_SKIP_MTIME;
|
||||
if (!(flags & PERMS_SKIP_MTIME)
|
||||
&& cmp_modtime(st->st_mtime, file->modtime) != 0) {
|
||||
/* don't complain about not setting times on directories
|
||||
* because some filesystems can't do it */
|
||||
if (set_modtime(fname,file->modtime) != 0 &&
|
||||
!S_ISDIR(st->st_mode)) {
|
||||
rprintf(FERROR, "failed to set times on %s: %s\n",
|
||||
full_fname(fname), strerror(errno));
|
||||
rsyserr(FERROR, errno, "failed to set times on %s",
|
||||
full_fname(fname));
|
||||
return 0;
|
||||
}
|
||||
updated = 1;
|
||||
@@ -174,16 +179,17 @@ int set_perms(char *fname,struct file_struct *file,STRUCT_STAT *st,
|
||||
change_gid ? file->gid : st->st_gid) != 0) {
|
||||
/* shouldn't have attempted to change uid or gid
|
||||
* unless have the privilege */
|
||||
rprintf(FERROR, "%s %s failed: %s\n",
|
||||
rsyserr(FERROR, errno, "%s %s failed",
|
||||
change_uid ? "chown" : "chgrp",
|
||||
full_fname(fname), strerror(errno));
|
||||
full_fname(fname));
|
||||
return 0;
|
||||
}
|
||||
/* a lchown had been done - we have to re-stat if the
|
||||
* destination had the setuid or setgid bits set due
|
||||
* to the side effect of the chown call */
|
||||
if (st->st_mode & (S_ISUID | S_ISGID)) {
|
||||
link_stat(fname, st);
|
||||
link_stat(fname, st,
|
||||
keep_dirlinks && S_ISDIR(st->st_mode));
|
||||
}
|
||||
updated = 1;
|
||||
}
|
||||
@@ -193,15 +199,15 @@ int set_perms(char *fname,struct file_struct *file,STRUCT_STAT *st,
|
||||
if ((st->st_mode & CHMOD_BITS) != (file->mode & CHMOD_BITS)) {
|
||||
updated = 1;
|
||||
if (do_chmod(fname,(file->mode & CHMOD_BITS)) != 0) {
|
||||
rprintf(FERROR, "failed to set permissions on %s: %s\n",
|
||||
full_fname(fname), strerror(errno));
|
||||
rsyserr(FERROR, errno, "failed to set permissions on %s",
|
||||
full_fname(fname));
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
if (verbose > 1 && report) {
|
||||
if (verbose > 1 && flags & PERMS_REPORT) {
|
||||
if (updated)
|
||||
rprintf(FINFO,"%s\n",fname);
|
||||
else
|
||||
@@ -228,26 +234,43 @@ void sig_int(void)
|
||||
|
||||
/* finish off a file transfer, renaming the file and setting the permissions
|
||||
and ownership */
|
||||
void finish_transfer(char *fname, char *fnametmp, struct file_struct *file)
|
||||
void finish_transfer(char *fname, char *fnametmp, struct file_struct *file,
|
||||
int ok_to_set_time)
|
||||
{
|
||||
int ret;
|
||||
|
||||
if (inplace) {
|
||||
if (verbose > 2)
|
||||
rprintf(FINFO, "finishing %s\n", fname);
|
||||
goto do_set_perms;
|
||||
}
|
||||
|
||||
if (make_backups && !make_backup(fname))
|
||||
return;
|
||||
|
||||
/* Change permissions before putting the file into place. */
|
||||
set_perms(fnametmp, file, NULL, ok_to_set_time ? 0 : PERMS_SKIP_MTIME);
|
||||
|
||||
/* move tmp file over real file */
|
||||
if (verbose > 2)
|
||||
rprintf(FINFO, "renaming %s to %s\n", fnametmp, fname);
|
||||
ret = robust_rename(fnametmp, fname, file->mode & INITACCESSPERMS);
|
||||
if (ret < 0) {
|
||||
rprintf(FERROR, "%s %s -> \"%s\": %s\n",
|
||||
rsyserr(FERROR, errno, "%s %s -> \"%s\"",
|
||||
ret == -2 ? "copy" : "rename",
|
||||
full_fname(fnametmp), fname, strerror(errno));
|
||||
full_fname(fnametmp), fname);
|
||||
do_unlink(fnametmp);
|
||||
} else {
|
||||
set_perms(fname,file,NULL,0);
|
||||
return;
|
||||
}
|
||||
if (ret == 0) {
|
||||
/* The file was moved into place (not copied), so it's done. */
|
||||
return;
|
||||
}
|
||||
do_set_perms:
|
||||
set_perms(fname, file, NULL, ok_to_set_time ? 0 : PERMS_SKIP_MTIME);
|
||||
}
|
||||
|
||||
const char *who_am_i(void)
|
||||
{
|
||||
return am_sender ? "sender" : am_generator ? "generator" : "receiver";
|
||||
return am_sender ? "sender" : am_generator ? "generator" : "receiver";
|
||||
}
|
||||
|
||||
36
rsync.h
36
rsync.h
@@ -108,10 +108,17 @@
|
||||
#define XFLG_DEF_INCLUDE (1<<1)
|
||||
#define XFLG_WORDS_ONLY (1<<2)
|
||||
#define XFLG_WORD_SPLIT (1<<3)
|
||||
#define XFLG_DIRECTORY (1<<4)
|
||||
|
||||
#define PERMS_REPORT (1<<0)
|
||||
#define PERMS_SKIP_MTIME (1<<1)
|
||||
|
||||
#define FULL_FLUSH 1
|
||||
#define NORMAL_FLUSH 0
|
||||
|
||||
#define PDIR_CREATE 1
|
||||
#define PDIR_DELETE 0
|
||||
|
||||
|
||||
/* Log-message categories. FLOG is only used on the daemon side to
|
||||
* output messages to the log file. */
|
||||
@@ -120,10 +127,10 @@ enum logcode { FERROR=1, FINFO=2, FLOG=3 };
|
||||
/* Messages types that are sent over the message channel. The logcode
|
||||
* values must all be present here with identical numbers. */
|
||||
enum msgcode {
|
||||
MSG_DATA=0, /* raw data on the multiplexed stream */
|
||||
MSG_ERROR=FERROR, MSG_INFO=FINFO, MSG_LOG=FLOG, /* remote logging */
|
||||
MSG_REDO=4, /* reprocess indicated flist index */
|
||||
MSG_DONE=5, /* current phase is done */
|
||||
MSG_REDO=4, /* reprocess indicated flist index */
|
||||
MSG_ERROR=FERROR, MSG_INFO=FINFO, MSG_LOG=FLOG, /* remote logging */
|
||||
MSG_DATA=0 /* raw data on the multiplexed stream */
|
||||
};
|
||||
|
||||
#include "errcode.h"
|
||||
@@ -309,7 +316,7 @@ enum msgcode {
|
||||
#else
|
||||
/* As long as it gets... */
|
||||
#define int64 off_t
|
||||
#define NO_INT64
|
||||
#define INT64_IS_OFF_T
|
||||
#endif
|
||||
|
||||
#if (SIZEOF_LONG == 8)
|
||||
@@ -388,7 +395,7 @@ struct idev {
|
||||
#define IN_LOOPBACKNET 127
|
||||
#endif
|
||||
|
||||
#define GID_NONE (gid_t) -1
|
||||
#define GID_NONE ((gid_t)-1)
|
||||
|
||||
#define HL_CHECK_MASTER 0
|
||||
#define HL_SKIP 1
|
||||
@@ -455,11 +462,13 @@ struct file_list {
|
||||
struct file_struct **files;
|
||||
};
|
||||
|
||||
#define SUMFLG_SAME_OFFSET (1<<0)
|
||||
|
||||
struct sum_buf {
|
||||
OFF_T offset; /**< offset in file of this chunk */
|
||||
unsigned int len; /**< length of chunk of file */
|
||||
int i; /**< index of this chunk */
|
||||
uint32 sum1; /**< simple checksum */
|
||||
short flags; /**< flag bits */
|
||||
char sum2[SUM_LENGTH]; /**< checksum */
|
||||
};
|
||||
|
||||
@@ -475,11 +484,9 @@ struct sum_struct {
|
||||
struct map_struct {
|
||||
char *p; /* Window pointer */
|
||||
int fd; /* File Descriptor */
|
||||
int p_size; /* Window size at allocation */
|
||||
int p_len; /* Window size after fill */
|
||||
/* p_size and p_len could be
|
||||
* consolodated by using a local
|
||||
* variable in map_ptr() */
|
||||
int p_size; /* Largest window size we allocated */
|
||||
int p_len; /* Latest (rounded) window size */
|
||||
int def_window_size; /* Default window size */
|
||||
int status; /* first errno from read errors */
|
||||
OFF_T file_size; /* File size (from stat) */
|
||||
OFF_T p_offset; /* Window start */
|
||||
@@ -490,12 +497,13 @@ struct map_struct {
|
||||
#define MATCHFLG_WILD2 (1<<1) /* pattern has '**' */
|
||||
#define MATCHFLG_WILD2_PREFIX (1<<2) /* pattern starts with '**' */
|
||||
#define MATCHFLG_ABS_PATH (1<<3) /* path-match on absolute path */
|
||||
#define MATCHFLG_INCLUDE (1<<4) /* this is an include, not an exclude */
|
||||
#define MATCHFLG_DIRECTORY (1<<5) /* this matches only directories */
|
||||
#define MATCHFLG_CLEAR_LIST (1<<6) /* this item is the "!" token */
|
||||
struct exclude_struct {
|
||||
struct exclude_struct *next;
|
||||
char *pattern;
|
||||
int match_flags;
|
||||
int include;
|
||||
int directory;
|
||||
unsigned int match_flags;
|
||||
int slash_cnt;
|
||||
};
|
||||
|
||||
|
||||
341
rsync.yo
341
rsync.yo
@@ -1,5 +1,5 @@
|
||||
mailto(rsync-bugs@samba.org)
|
||||
manpage(rsync)(1)(26 Apr 2004)()()
|
||||
manpage(rsync)(1)(30 Sep 2004)()()
|
||||
manpagename(rsync)(faster, flexible replacement for rcp)
|
||||
manpagesynopsis()
|
||||
|
||||
@@ -21,8 +21,8 @@ manpagedescription()
|
||||
|
||||
rsync is a program that behaves in much the same way that rcp does,
|
||||
but has many more options and uses the rsync remote-update protocol to
|
||||
greatly speed up file transfers when the destination file already
|
||||
exists.
|
||||
greatly speed up file transfers when the destination file is being
|
||||
updated.
|
||||
|
||||
The rsync remote-update protocol allows rsync to transfer just the
|
||||
differences between two sets of files across the network connection, using
|
||||
@@ -32,7 +32,7 @@ report that accompanies this package.
|
||||
Some of the additional features of rsync are:
|
||||
|
||||
itemize(
|
||||
it() support for copying links, devices, owners, groups and permissions
|
||||
it() support for copying links, devices, owners, groups, and permissions
|
||||
it() exclude and exclude-from options similar to GNU tar
|
||||
it() a CVS exclude mode for ignoring the same files that CVS would ignore
|
||||
it() can use any transparent remote shell, including ssh or rsh
|
||||
@@ -113,7 +113,7 @@ and a destination, one of which may be remote.
|
||||
|
||||
Perhaps the best way to explain the syntax is with some examples:
|
||||
|
||||
quote(rsync *.c foo:src/)
|
||||
quote(rsync -t *.c foo:src/)
|
||||
|
||||
This would transfer all files matching the pattern *.c from the
|
||||
current directory to the directory src on the machine foo. If any of
|
||||
@@ -141,8 +141,8 @@ destination. In other words, each of the following commands copies the
|
||||
files in the same way, including their setting of the attributes of
|
||||
/dest/foo:
|
||||
|
||||
quote(rsync -avz /src/foo /dest)
|
||||
quote(rsync -avz /src/foo/ /dest/foo)
|
||||
quote(rsync -av /src/foo /dest)
|
||||
quote(rsync -av /src/foo/ /dest/foo)
|
||||
|
||||
You can also use rsync in local-only mode, where both the source and
|
||||
destination don't have a ':' in the name. In this case it behaves like
|
||||
@@ -154,6 +154,35 @@ This would list all the anonymous rsync modules available on the host
|
||||
somehost.mydomain.com. (See the following section for more details.)
|
||||
|
||||
|
||||
manpagesection(ADVANCED USAGE)
|
||||
|
||||
The syntax for requesting multiple files from a remote host involves using
|
||||
quoted spaces in the SRC. Some examples:
|
||||
|
||||
quote(rsync host::'modname/dir1/file1 modname/dir2/file2' /dest)
|
||||
|
||||
This would copy file1 and file2 into /dest from an rsync daemon. Each
|
||||
additional arg must include the same "modname/" prefix as the first one,
|
||||
and must be preceded by a single space. All other spaces are assumed
|
||||
to be a part of the filenames.
|
||||
|
||||
quote(rsync -av host:'dir1/file1 dir2/file2' /dest)
|
||||
|
||||
This would copy file1 and file2 into /dest using a remote shell. This
|
||||
word-splitting is done by the remote shell, so if it doesn't work it means
|
||||
that the remote shell isn't configured to split its args based on
|
||||
whitespace (a very rare setting, but not unknown). If you need to transfer
|
||||
a filename that contains whitespace, you'll need to either escape the
|
||||
whitespace in a way that the remote shell will understand, or use wildcards
|
||||
in place of the spaces. Two examples of this are:
|
||||
|
||||
quote(rsync -av host:'file\ name\ with\ spaces' /dest)
|
||||
quote(rsync -av host:file?name?with?spaces /dest)
|
||||
|
||||
This latter example assumes that your shell passes through unmatched
|
||||
wildcards. If it complains about "no match", put the name in quotes.
|
||||
|
||||
|
||||
manpagesection(CONNECTING TO AN RSYNC SERVER)
|
||||
|
||||
It is also possible to use rsync without a remote shell as the
|
||||
@@ -289,6 +318,8 @@ verb(
|
||||
--backup-dir make backups into this directory
|
||||
--suffix=SUFFIX backup suffix (default ~ w/o --backup-dir)
|
||||
-u, --update update only (don't overwrite newer files)
|
||||
--inplace update the destination files inplace
|
||||
-K, --keep-dirlinks treat symlinked dir on receiver as dir
|
||||
-l, --links copy symlinks as symlinks
|
||||
-L, --copy-links copy the referent of all symlinks
|
||||
--copy-unsafe-links copy the referent of "unsafe" symlinks
|
||||
@@ -304,7 +335,7 @@ verb(
|
||||
-W, --whole-file copy whole files, no incremental checks
|
||||
--no-whole-file turn off --whole-file
|
||||
-x, --one-file-system don't cross filesystem boundaries
|
||||
-B, --block-size=SIZE checksum blocking size (default 700)
|
||||
-B, --block-size=SIZE force a fixed checksum block-size
|
||||
-e, --rsh=COMMAND specify the remote shell
|
||||
--rsync-path=PATH specify path to rsync on the remote machine
|
||||
--existing only update files that already exist
|
||||
@@ -315,6 +346,7 @@ verb(
|
||||
--ignore-errors delete even if there are I/O errors
|
||||
--max-delete=NUM don't delete more than NUM files
|
||||
--partial keep partially transferred files
|
||||
--partial-dir=DIR put a partially transferred file into DIR
|
||||
--force force deletion of dirs even if not empty
|
||||
--numeric-ids don't map uid/gid values by user/group name
|
||||
--timeout=TIME set I/O timeout in seconds
|
||||
@@ -346,8 +378,11 @@ verb(
|
||||
--log-format=FORMAT log file transfers using specified format
|
||||
--password-file=FILE get password from FILE
|
||||
--bwlimit=KBPS limit I/O bandwidth, KBytes per second
|
||||
--write-batch=PREFIX write batch fileset starting with PREFIX
|
||||
--read-batch=PREFIX read batch fileset starting with PREFIX
|
||||
--write-batch=FILE write a batch to FILE
|
||||
--read-batch=FILE read a batch from FILE
|
||||
--checksum-seed=NUM set block/file checksum seed
|
||||
-4 --ipv4 prefer IPv4
|
||||
-6 --ipv6 prefer IPv6
|
||||
-h, --help show this help screen
|
||||
|
||||
|
||||
@@ -476,11 +511,42 @@ symlink where the destination has a file, the transfer would occur
|
||||
regardless of the timestamps. This might change in the future (feel
|
||||
free to comment on this on the mailing list if you have an opinion).
|
||||
|
||||
dit(bf(-K, --keep-dirlinks)) On the receiving side, if a symlink is
|
||||
pointing to a directory, it will be treated as matching a directory
|
||||
from the sender.
|
||||
|
||||
dit(bf(--inplace)) This causes rsync not to create a new copy of the file
|
||||
and then move it into place. Instead rsync will overwrite the existing
|
||||
file, meaning that the rsync algorithm can't extract the full amount of
|
||||
network reduction it might otherwise (since it does not yet try to sort
|
||||
data matches -- a future version may improve this).
|
||||
|
||||
This option is useful for transfer of large files with block-based changes
|
||||
or appended data, and also on systems that are disk bound, not network
|
||||
bound.
|
||||
|
||||
The option implies --partial (since an interrupted transfer does not delete
|
||||
the file), but conflicts with --partial-dir, --compare-dest, and
|
||||
--link-dest (a future rsync version will hopefully update the protocol to
|
||||
remove these restrictions).
|
||||
|
||||
WARNING: The file's data will be in an inconsistent state during the
|
||||
transfer (and possibly afterward if the transfer gets interrupted), so you
|
||||
should not use this option to update files that are in use. Also note that
|
||||
rsync will be unable to update a file inplace that is not writable by the
|
||||
receiving user.
|
||||
|
||||
dit(bf(-l, --links)) When symlinks are encountered, recreate the
|
||||
symlink on the destination.
|
||||
|
||||
dit(bf(-L, --copy-links)) When symlinks are encountered, the file that
|
||||
they point to (the referent) is copied, rather than the symlink.
|
||||
they point to (the referent) is copied, rather than the symlink. In older
|
||||
versions of rsync, this option also had the side-effect of telling the
|
||||
receiving side to follow symlinks, such as symlinks to directories. In a
|
||||
modern rsync such as this one, you'll need to specify --keep-dirlinks (-K)
|
||||
to get this extra behavior. The only exception is when sending files to
|
||||
an rsync that is too old to understand -K -- in that case, the -L option
|
||||
will still have the side-effect of -K on that older receiving rsync.
|
||||
|
||||
dit(bf(--copy-unsafe-links)) This tells rsync to copy the referent of
|
||||
symbolic links that point outside the copied tree. Absolute symlinks
|
||||
@@ -504,9 +570,9 @@ This option can be quite slow, so only use it if you need it.
|
||||
dit(bf(-W, --whole-file)) With this option the incremental rsync algorithm
|
||||
is not used and the whole file is sent as-is instead. The transfer may be
|
||||
faster if this option is used when the bandwidth between the source and
|
||||
target machines is higher than the bandwidth to disk (especially when the
|
||||
destination machines is higher than the bandwidth to disk (especially when the
|
||||
"disk" is actually a networked filesystem). This is the default when both
|
||||
the source and target are on the local machine.
|
||||
the source and destination are specified as local paths.
|
||||
|
||||
dit(bf(--no-whole-file)) Turn off --whole-file, for use when it is the
|
||||
default.
|
||||
@@ -540,9 +606,9 @@ dit(bf(-t, --times)) This tells rsync to transfer modification times along
|
||||
with the files and update them on the remote system. Note that if this
|
||||
option is not used, the optimization that excludes files that have not been
|
||||
modified cannot be effective; in other words, a missing -t or -a will
|
||||
cause the next transfer to behave as if it used -I, and all files will have
|
||||
their checksums compared and show up in log messages even if they haven't
|
||||
changed.
|
||||
cause the next transfer to behave as if it used -I, causing all files to be
|
||||
updated (though the rsync algorithm will make the update fairly efficient
|
||||
if the files haven't actually changed, you're much better off using -t).
|
||||
|
||||
dit(bf(-n, --dry-run)) This tells rsync to not do any file transfers,
|
||||
instead it will just report the actions it would have taken.
|
||||
@@ -603,8 +669,9 @@ they are not empty when they are to be replaced by non-directories. This
|
||||
is only relevant without --delete because deletions are now done depth-first.
|
||||
Requires the --recursive option (which is implied by -a) to have any effect.
|
||||
|
||||
dit(bf(-B , --block-size=BLOCKSIZE)) This controls the block size used in
|
||||
the rsync algorithm. See the technical report for details.
|
||||
dit(bf(-B, --block-size=BLOCKSIZE)) This forces the block size used in
|
||||
the rsync algorithm to a fixed value. It is normally selected based on
|
||||
the size of each file being updated. See the technical report for details.
|
||||
|
||||
dit(bf(-e, --rsh=COMMAND)) This option allows you to choose an alternative
|
||||
remote shell program to use for communication between the local and
|
||||
@@ -678,11 +745,11 @@ See the EXCLUDE PATTERNS section for detailed information on this option.
|
||||
|
||||
dit(bf(--include-from=FILE)) This specifies a list of include patterns
|
||||
from a file.
|
||||
If em(FILE) is bf(-) the list will be read from standard input.
|
||||
If em(FILE) is "-" the list will be read from standard input.
|
||||
|
||||
dit(bf(--files-from=FILE)) Using this option allows you to specify the
|
||||
exact list of files to transfer (as read from the specified FILE or "-"
|
||||
for stdin). It also tweaks the default behavior of rsync to make
|
||||
for standard input). It also tweaks the default behavior of rsync to make
|
||||
transferring just the specified files and directories easier. For
|
||||
instance, the --relative option is enabled by default when this option
|
||||
is used (use --no-relative if you want to turn that off), all
|
||||
@@ -739,20 +806,25 @@ although this skips files that haven't changed; see also --link-dest).
|
||||
This option increases the usefulness of --partial because partially
|
||||
transferred files will remain in the new temporary destination until they
|
||||
have a chance to be completed. If DIR is a relative path, it is relative
|
||||
to the destination directory (which changes in a recursive transfer).
|
||||
to the destination directory.
|
||||
|
||||
dit(bf(--link-dest=DIR)) This option behaves like bf(--compare-dest) but
|
||||
also will create hard links from em(DIR) to the destination directory for
|
||||
unchanged files. Files with changed ownership or permissions will not be
|
||||
linked.
|
||||
Like bf(--compare-dest) if DIR is a relative path, it is relative
|
||||
to the destination directory (which changes in a recursive transfer).
|
||||
An example:
|
||||
|
||||
verb(
|
||||
rsync -av --link-dest=$PWD/prior_dir host:src_dir/ new_dir/
|
||||
)
|
||||
|
||||
Like bf(--compare-dest) if DIR is a relative path, it is relative to the
|
||||
destination directory.
|
||||
Note that rsync versions prior to 2.6.1 had a bug that could prevent
|
||||
--link-dest from working properly for a non-root user when -o was specified
|
||||
(or implied by -a). If the receiving rsync is not new enough, you can work
|
||||
around this bug by avoiding the -o option.
|
||||
|
||||
dit(bf(-z, --compress)) With this option, rsync compresses any data from
|
||||
the files that it sends to the destination machine. This
|
||||
option is useful on slow connections. The compression method used is the
|
||||
@@ -842,6 +914,46 @@ it is more desirable to keep partially transferred files. Using the
|
||||
--partial option tells rsync to keep the partial file which should
|
||||
make a subsequent transfer of the rest of the file much faster.
|
||||
|
||||
dit(bf(--partial-dir=DIR)) Turns on --partial mode, but tells rsync to
|
||||
put a partially transferred file into DIR instead of writing out the
|
||||
file to the destination dir. Rsync will also use a file found in this
|
||||
dir as data to speed up the transfer (i.e. when you redo the send after
|
||||
rsync creates a partial file) and delete such a file after it has served
|
||||
its purpose. Note that if --whole-file is specified (or implied) that an
|
||||
existing partial-dir file will not be used to speedup the transfer (since
|
||||
rsync is sending files without using the incremental rsync algorithm).
|
||||
|
||||
Rsync will create the dir if it is missing (just the last dir -- not the
|
||||
whole path). This makes it easy to use a relative path (such as
|
||||
"--partial-dir=.rsync-partial") to have rsync create the partial-directory
|
||||
in the destination file's directory (rsync will also try to remove the DIR
|
||||
if a partial file was found to exist at the start of the transfer and the
|
||||
DIR was specified as a relative path).
|
||||
|
||||
If the partial-dir value is not an absolute path, rsync will also add an
|
||||
--exclude of this value at the end of all your existing excludes. This
|
||||
will prevent partial-dir files from being transferred and also prevent the
|
||||
untimely deletion of partial-dir items on the receiving side. An example:
|
||||
the above --partial-dir option would add an "--exclude=.rsync-partial/"
|
||||
rule at the end of any other include/exclude rules. Note that if you are
|
||||
supplying your own include/exclude rules, you may need to manually insert a
|
||||
rule for this directory exclusion somewhere higher up in the list so that
|
||||
it has a high enough priority to be effective (e.g., if your rules specify
|
||||
a trailing --exclude=* rule, the auto-added rule will be ineffective).
|
||||
|
||||
IMPORTANT: the --partial-dir should not be writable by other users or it
|
||||
is a security risk. E.g. AVOID "/tmp".
|
||||
|
||||
You can also set the partial-dir value the RSYNC_PARTIAL_DIR environment
|
||||
variable. Setting this in the environment does not force --partial to be
|
||||
enabled, but rather it effects where partial files go when --partial (or
|
||||
-P) is used. For instance, instead of specifying --partial-dir=.rsync-tmp
|
||||
along with --progress, you could set RSYNC_PARTIAL_DIR=.rsync-tmp in your
|
||||
environment and then just use the -P option to turn on the use of the
|
||||
.rsync-tmp dir for partial transfers. The only time the --partial option
|
||||
does not look for this environment value is when --inplace was also
|
||||
specified (since --inplace conflicts with --partial-dir).
|
||||
|
||||
dit(bf(--progress)) This option tells rsync to print information
|
||||
showing the progress of the transfer. This gives a bored user
|
||||
something to watch.
|
||||
@@ -870,9 +982,9 @@ the file, and the addition of a total-transfer summary in parentheses.
|
||||
These additional numbers tell you how many files have been updated, and
|
||||
what percent of the total number of files has been scanned.
|
||||
|
||||
dit(bf(-P)) The -P option is equivalent to --partial --progress. I
|
||||
found myself typing that combination quite often so I created an
|
||||
option to make it easier.
|
||||
dit(bf(-P)) The -P option is equivalent to --partial --progress. Its
|
||||
purpose is to make it much easier to specify these two options for a long
|
||||
transfer that may be interrupted.
|
||||
|
||||
dit(bf(--password-file)) This option allows you to provide a password
|
||||
in a file for accessing a remote rsync server. Note that this option
|
||||
@@ -889,13 +1001,33 @@ transfer was too fast, it will wait before sending the next data block. The
|
||||
result is an average transfer rate equaling the specified limit. A value
|
||||
of zero specifies no limit.
|
||||
|
||||
dit(bf(--write-batch=PREFIX)) Generate a set of files that can be
|
||||
transferred as a batch update. Each filename in the set starts with
|
||||
PREFIX. See the "BATCH MODE" section for details.
|
||||
dit(bf(--write-batch=FILE)) Record a file that can later be applied to
|
||||
another identical destination with --read-batch. See the "BATCH MODE"
|
||||
section for details.
|
||||
|
||||
dit(bf(--read-batch=PREFIX)) Apply a previously generated change batch,
|
||||
using the fileset whose filenames start with PREFIX. See the "BATCH
|
||||
MODE" section for details.
|
||||
dit(bf(--read-batch=FILE)) Apply all of the changes stored in FILE, a
|
||||
file previously generated by --write-batch.
|
||||
If em(FILE) is "-" the batch data will be read from standard input.
|
||||
See the "BATCH MODE" section for details.
|
||||
|
||||
dit(bf(-4, --ipv4) or bf(-6, --ipv6)) Tells rsync to prefer IPv4/IPv6
|
||||
when creating sockets. This only affects sockets that rsync has direct
|
||||
control over, such as the outgoing socket when directly contacting an
|
||||
rsync daemon, or the incoming sockets that an rsync daemon uses to
|
||||
listen for connections. One of these options may be required in older
|
||||
versions of Linux to work around an IPv6 bug in the kernel (if you see
|
||||
an "address already in use" error when nothing else is using the port,
|
||||
try specifying --ipv6 or --ipv4 when starting the daemon).
|
||||
|
||||
dit(bf(--checksum-seed=NUM)) Set the MD4 checksum seed to the integer
|
||||
NUM. This 4 byte checksum seed is included in each block and file
|
||||
MD4 checksum calculation. By default the checksum seed is generated
|
||||
by the server and defaults to the current time(). This option
|
||||
is used to set a specific checksum seed, which is useful for
|
||||
applications that want repeatable block and file checksums, or
|
||||
in the case where the user wants a more random checksum seed.
|
||||
Note that setting NUM to 0 causes rsync to use the default of time()
|
||||
for checksum seed.
|
||||
|
||||
enddit()
|
||||
|
||||
@@ -1035,7 +1167,7 @@ This fails because the parent directory "some" is excluded by the '*' rule,
|
||||
so rsync never visits any of the files in the "some" or "some/path"
|
||||
directories. One solution is to ask for all directories in the hierarchy
|
||||
to be included by using a single rule: --include='*/' (put it somewhere
|
||||
before the --excludde='*' rule). Another solution is to add specific
|
||||
before the --exclude='*' rule). Another solution is to add specific
|
||||
include rules for all the parent dirs that need to be visited. For
|
||||
instance, this set of rules works fine:
|
||||
|
||||
@@ -1067,7 +1199,8 @@ itemize(
|
||||
manpagesection(BATCH MODE)
|
||||
|
||||
bf(Note:) Batch mode should be considered experimental in this version
|
||||
of rsync. The interface or behaviour may change before it stabilizes.
|
||||
of rsync. The interface and behavior have now stabilized, though, so
|
||||
feel free to try this out.
|
||||
|
||||
Batch mode can be used to apply the same set of updates to many
|
||||
identical systems. Suppose one has a tree which is replicated on a
|
||||
@@ -1076,80 +1209,112 @@ source tree and those changes need to be propagated to the other
|
||||
hosts. In order to do this using batch mode, rsync is run with the
|
||||
write-batch option to apply the changes made to the source tree to one
|
||||
of the destination trees. The write-batch option causes the rsync
|
||||
client to store the information needed to repeat this operation against
|
||||
other destination trees in a batch update fileset (see below). The
|
||||
filename of each file in the fileset starts with a prefix specified by
|
||||
the user as an argument to the write-batch option. This fileset is
|
||||
then copied to each remote host, where rsync is run with the read-batch
|
||||
option, again specifying the same prefix, and the destination tree.
|
||||
Rsync updates the destination tree using the information stored in the
|
||||
batch update fileset.
|
||||
client to store in a "batch file" all the information needed to repeat
|
||||
this operation against other, identical destination trees.
|
||||
|
||||
The fileset consists of 4 files:
|
||||
To apply the recorded changes to another destination tree, run rsync
|
||||
with the read-batch option, specifying the name of the same batch
|
||||
file, and the destination tree. Rsync updates the destination tree
|
||||
using the information stored in the batch file.
|
||||
|
||||
itemize(
|
||||
it() bf(<prefix>.rsync_argvs) command-line arguments
|
||||
it() bf(<prefix>.rsync_flist) rsync internal file metadata
|
||||
it() bf(<prefix>.rsync_csums) rsync checksums
|
||||
it() bf(<prefix>.rsync_delta) data blocks for file update & change
|
||||
)
|
||||
For convenience, one additional file is creating when the write-batch
|
||||
option is used. This file's name is created by appending
|
||||
".sh" to the batch filename. The .sh file contains
|
||||
a command-line suitable for updating a destination tree using that
|
||||
batch file. It can be executed using a Bourne(-like) shell, optionally
|
||||
passing in an alternate destination tree pathname which is then used
|
||||
instead of the original path. This is useful when the destination tree
|
||||
path differs from the original destination tree path.
|
||||
|
||||
The .rsync_argvs file contains a command-line suitable for updating a
|
||||
destination tree using that batch update fileset. It can be executed
|
||||
using a Bourne(-like) shell, optionally passing in an alternate
|
||||
destination tree pathname which is then used instead of the original
|
||||
path. This is useful when the destination tree path differs from the
|
||||
original destination tree path.
|
||||
|
||||
Generating the batch update fileset once saves having to perform the
|
||||
file status, checksum and data block generation more than once when
|
||||
Generating the batch file once saves having to perform the file
|
||||
status, checksum, and data block generation more than once when
|
||||
updating multiple destination trees. Multicast transport protocols can
|
||||
be used to transfer the batch update files in parallel to many hosts at
|
||||
once, instead of sending the same data to every host individually.
|
||||
be used to transfer the batch update files in parallel to many hosts
|
||||
at once, instead of sending the same data to every host individually.
|
||||
|
||||
Example:
|
||||
Examples:
|
||||
|
||||
verb(
|
||||
$ rsync --write-batch=pfx -a /source/dir/ /adest/dir/
|
||||
$ rcp pfx.rsync_* remote:
|
||||
$ ssh remote rsync --read-batch=pfx -a /bdest/dir/
|
||||
# or alternatively
|
||||
$ ssh remote ./pfx.rsync_argvs /bdest/dir/
|
||||
$ rsync --write-batch=foo -a host:/source/dir/ /adest/dir/
|
||||
$ scp foo* remote:
|
||||
$ ssh remote ./foo.sh /bdest/dir/
|
||||
)
|
||||
|
||||
In this example, rsync is used to update /adest/dir/ with /source/dir/
|
||||
and the information to repeat this operation is stored in the files
|
||||
pfx.rsync_*. These files are then copied to the machine named "remote".
|
||||
Rsync is then invoked on "remote" to update /bdest/dir/ the same way as
|
||||
/adest/dir/. The last line shows the rsync_argvs file being used to
|
||||
invoke rsync.
|
||||
verb(
|
||||
$ rsync --write-batch=foo -a /source/dir/ /adest/dir/
|
||||
$ ssh remote rsync --read-batch=- -a /bdest/dir/ <foo
|
||||
)
|
||||
|
||||
In these examples, rsync is used to update /adest/dir/ from /source/dir/
|
||||
and the information to repeat this operation is stored in "foo" and
|
||||
"foo.sh". The host "remote" is then updated with the batched data going
|
||||
into the directory /bdest/dir. The differences between the two examples
|
||||
reveals some of the flexibility you have in how you deal with batches:
|
||||
|
||||
itemize(
|
||||
|
||||
it() The first example shows that the initial copy doesn't have to be
|
||||
local -- you can push or pull data to/from a remote host using either the
|
||||
remote-shell syntax or rsync daemon syntax, as desired.
|
||||
|
||||
it() The first example uses the created "foo.sh" file to get the right
|
||||
rsync options when running the read-batch command on the remote host.
|
||||
|
||||
it() The second example reads the batch data via standard input so that
|
||||
the batch file doesn't need to be copied to the remote machine first.
|
||||
This example avoids the foo.sh script because it needed to use a modified
|
||||
--read-batch option, but you could edit the script file if you wished to
|
||||
make use of it (just be sure that no other option is trying to use
|
||||
standard input, such as the "--exclude-from=-" option).
|
||||
|
||||
)
|
||||
|
||||
Caveats:
|
||||
|
||||
The read-batch option expects the destination tree it is meant to update
|
||||
The read-batch option expects the destination tree that it is updating
|
||||
to be identical to the destination tree that was used to create the
|
||||
batch update fileset. When a difference between the destination trees
|
||||
is encountered the update will fail at that point, leaving the
|
||||
destination tree in a partially updated state. In that case, rsync can
|
||||
is encountered the update might be discarded with no error (if the file
|
||||
appears to be up-to-date already) or the file-update may be attempted
|
||||
and then, if the file fails to verify, the update discarded with an
|
||||
error. This means that it should be safe to re-run a read-batch operation
|
||||
if the command got interrupted. If you wish to force the batched-update to
|
||||
always be attempted regardless of the file's size and date, use the -I
|
||||
option (when reading the batch).
|
||||
If an error occurs, the destination tree will probably be in a
|
||||
partially updated state. In that case, rsync can
|
||||
be used in its regular (non-batch) mode of operation to fix up the
|
||||
destination tree.
|
||||
|
||||
The rsync version used on all destinations should be identical to the
|
||||
one used on the original destination.
|
||||
The rsync version used on all destinations must be at least as new as the
|
||||
one used to generate the batch file. Rsync will die with an error if the
|
||||
protocol version in the batch file is too new for the batch-reading rsync
|
||||
to handle.
|
||||
|
||||
The -z/--compress option does not work in batch mode and yields a usage
|
||||
error. A separate compression tool can be used instead to reduce the
|
||||
size of the batch update files for transport to the destination.
|
||||
|
||||
The -n/--dryrun option does not work in batch mode and yields a runtime
|
||||
The --dry-run (-n) option does not work in batch mode and yields a runtime
|
||||
error.
|
||||
|
||||
See bf(http://www.ils.unc.edu/i2dsi/unc_rsync+.html) for papers and technical
|
||||
reports.
|
||||
When reading a batch file, rsync will force the value of certain options
|
||||
to match the data in the batch file if you didn't set them to the same
|
||||
as the batch-writing command. Other options can (and should) be changed.
|
||||
For instance
|
||||
--write-batch changes to --read-batch, --files-from is dropped, and the
|
||||
--include/--exclude options are not needed unless --delete is specified
|
||||
without --delete-excluded.
|
||||
|
||||
The code that creates the BATCH.sh file transforms any include/exclude
|
||||
options into a single list that is appended as a "here" document to the
|
||||
shell script file. An advanced user can use this to modify the exclude
|
||||
list if a change in what gets deleted by --delete is desired. A normal
|
||||
user can ignore this detail and just use the shell script as an easy way
|
||||
to run the appropriate --read-batch command for the batched data.
|
||||
|
||||
The original batch mode in rsync was based on "rsync+", but the latest
|
||||
version uses a new implementation.
|
||||
|
||||
manpagesection(SYMBOLIC LINKS)
|
||||
|
||||
Three basic behaviours are possible when rsync encounters a symbolic
|
||||
Three basic behaviors are possible when rsync encounters a symbolic
|
||||
link in the source directory.
|
||||
|
||||
By default, symbolic links are not transferred at all. A message
|
||||
@@ -1210,7 +1375,7 @@ dit(bf(2)) Protocol incompatibility
|
||||
dit(bf(3)) Errors selecting input/output files, dirs
|
||||
dit(bf(4)) Requested action not supported: an attempt
|
||||
was made to manipulate 64-bit files on a platform that cannot support
|
||||
them; or an option was specifed that is supported by the client and
|
||||
them; or an option was specified that is supported by the client and
|
||||
not by the server.
|
||||
dit(bf(5)) Error starting client-server protocol
|
||||
dit(bf(10)) Error in socket I/O
|
||||
@@ -1270,7 +1435,7 @@ manpagebugs()
|
||||
|
||||
times are transferred as unix time_t values
|
||||
|
||||
When transferring to FAT filesystems rsync may resync
|
||||
When transferring to FAT filesystems rsync may re-sync
|
||||
unmodified files.
|
||||
See the comments on the --modify-window option.
|
||||
|
||||
@@ -1307,7 +1472,7 @@ and David Bell for helpful suggestions, patches and testing of rsync.
|
||||
I've probably missed some people, my apologies if I have.
|
||||
|
||||
Especial thanks also to: David Dykstra, Jos Backus, Sebastian Krahmer,
|
||||
Martin Pool, Wayne Davison.
|
||||
Martin Pool, Wayne Davison, J.W. Schultz.
|
||||
|
||||
manpageauthor()
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
mailto(rsync-bugs@samba.org)
|
||||
manpage(rsyncd.conf)(5)(26 Apr 2004)()()
|
||||
manpage(rsyncd.conf)(5)(30 Sep 2004)()()
|
||||
manpagename(rsyncd.conf)(configuration file for rsync server)
|
||||
manpagesynopsis()
|
||||
|
||||
@@ -134,8 +134,8 @@ dit(bf(use chroot)) If "use chroot" is true, the rsync server 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 outside of the new root path
|
||||
when reading, and of complicating the preservation of usernames and groups
|
||||
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 usernames and groups
|
||||
(see below). When "use chroot" is false, for security reasons,
|
||||
symlinks may only be relative paths pointing to other files within the root
|
||||
path, and leading slashes are removed from most absolute paths (options
|
||||
@@ -154,12 +154,11 @@ specified.
|
||||
|
||||
Note that you are free to setup user/group information in the chroot area
|
||||
differently from your normal system. For example, you could abbreviate
|
||||
the list of users and groups. Also, you can protect this information
|
||||
from being downloaded by adding an exclude rule to the rsync.conf file
|
||||
(e.g. "exclude = /etc/"). To protect it from being changed by an upload
|
||||
(if the module is not read only), be sure to set the permissions (or
|
||||
owner) on the files and/or parent directories so that they cannot be
|
||||
written by the daemon.
|
||||
the list of users and groups. Also, you can protect this information from
|
||||
being downloaded/uploaded by adding an exclude rule to the rsync.conf file
|
||||
(e.g. "exclude = /etc/"). Note that having the exclusion affect uploads
|
||||
is a relatively new feature in rsync, so make sure your server is running
|
||||
at least 2.6.3 to effect this.
|
||||
|
||||
dit(bf(max connections)) The "max connections" option allows you to
|
||||
specify the maximum number of simultaneous connections you will allow.
|
||||
@@ -179,6 +178,12 @@ attempted uploads will fail. If "read only" is false then uploads will
|
||||
be possible if file permissions on the server allow them. The default
|
||||
is for all modules to be read only.
|
||||
|
||||
dit(bf(write only)) The "write only" option 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 server allow them. The
|
||||
default is for this option to be disabled.
|
||||
|
||||
dit(bf(list)) The "list" option determines if this module should be
|
||||
listed when the client asks for a listing of available modules. By
|
||||
setting this to false you can create hidden modules. The default is
|
||||
@@ -195,24 +200,18 @@ file transfers to and from that module should take place as when the daemon
|
||||
was run as root. This complements the "uid" option. The default is gid -2,
|
||||
which is normally the group "nobody".
|
||||
|
||||
dit(bf(exclude)) The "exclude" option allows you to specify a space
|
||||
separated list of patterns to add to the exclude list.
|
||||
This is only superficially equivalent
|
||||
to the client specifying these patterns with the --exclude option.
|
||||
Only one "exclude" option may be specified, but
|
||||
you can use "-" and "+" before patterns to specify exclude/include.
|
||||
dit(bf(exclude)) The "exclude" option allows you to specify a
|
||||
space-separated list of patterns that the server will not allow to be read
|
||||
or written. This is only superficially equivalent to the client
|
||||
specifying these patterns with the --exclude option. Only one "exclude"
|
||||
option may be specified, but you can use "-" and "+" before patterns to
|
||||
specify exclude/include.
|
||||
|
||||
Because this exclude list is not passed to the client it only applies on
|
||||
the server: that is, it excludes files received by a client when receiving
|
||||
from a server and files deleted on a server when sending to a server, but
|
||||
it doesn't exclude files sent from a client when sending to a server or
|
||||
files deleted on a client when receiving from a server.
|
||||
|
||||
Note that this option is not designed with strong security in
|
||||
mind, it is quite possible that a client may find a way to bypass this
|
||||
exclude list. If you want to absolutely ensure that certain files
|
||||
cannot be accessed then use the uid/gid options in combination with
|
||||
file permissions.
|
||||
it doesn't exclude files from being deleted on a client when receiving
|
||||
from a server.
|
||||
|
||||
dit(bf(exclude from)) The "exclude from" option specifies a filename
|
||||
on the server that contains exclude patterns, one per line.
|
||||
@@ -220,14 +219,14 @@ This is only superficially equivalent
|
||||
to the client specifying the --exclude-from option with an equivalent file.
|
||||
See the "exclude" option above.
|
||||
|
||||
dit(bf(include)) The "include" option allows you to specify a space
|
||||
separated list of patterns which rsync should not exclude. This is
|
||||
only superficially equivalent to the client specifying these patterns
|
||||
with the --include option because it applies only on the server.
|
||||
This is useful as it
|
||||
allows you to build up quite complex exclude/include rules. Only one
|
||||
"include" option may be specified, but you can use "+" and "-" before
|
||||
patterns to switch include/exclude. See the "exclude" option above.
|
||||
dit(bf(include)) The "include" option allows you to specify a
|
||||
space-separated list of patterns which rsync should not exclude. This is
|
||||
only superficially equivalent to the client specifying these patterns with
|
||||
the --include option because it applies only on the server. This is
|
||||
useful as it allows you to build up quite complex exclude/include rules.
|
||||
Only one "include" option may be specified, but you can use "+" and "-"
|
||||
before patterns to switch include/exclude. See the "exclude" option
|
||||
above.
|
||||
|
||||
dit(bf(include from)) The "include from" option specifies a filename
|
||||
on the server that contains include patterns, one per line. This is
|
||||
@@ -236,7 +235,7 @@ only superficially equivalent to the client specifying the
|
||||
See the "exclude" option above.
|
||||
|
||||
dit(bf(auth users)) The "auth users" option specifies a comma and
|
||||
space separated list of usernames that will be allowed to connect to
|
||||
space-separated list of usernames that will be allowed to connect to
|
||||
this module. The usernames do not need to exist on the local
|
||||
system. The usernames may also contain shell wildcard characters. If
|
||||
"auth users" is set then the client will be challenged to supply a
|
||||
@@ -380,9 +379,15 @@ default. A good choice for anonymous rsync servers may be 600 (giving
|
||||
a 10 minute timeout).
|
||||
|
||||
dit(bf(refuse options)) The "refuse options" option allows you to
|
||||
specify a space separated list of rsync command line options that will
|
||||
be refused by your rsync server. The full names of the options must be
|
||||
used (i.e., you must use "checksum" not "c" to disable checksumming).
|
||||
specify a space-separated list of rsync command line options that will
|
||||
be refused by your rsync server.
|
||||
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 --checksum (-c) and all the options that
|
||||
start with "delete":
|
||||
|
||||
quote(refuse options = c delete*)
|
||||
|
||||
When an option is refused, the server prints an error message and exits.
|
||||
To prevent all compression, you can use "dont compress = *" (see below)
|
||||
instead of "refuse options = compress" to avoid returning an error to a
|
||||
@@ -394,7 +399,7 @@ during transfer. 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" option takes a space separated list of
|
||||
The "dont compress" option takes a space-separated list of
|
||||
case-insensitive wildcard patterns. Any source filename matching one
|
||||
of the patterns will not be compressed during transfer.
|
||||
|
||||
|
||||
224
sender.c
224
sender.c
@@ -27,6 +27,8 @@ extern int dry_run;
|
||||
extern int am_server;
|
||||
extern int am_daemon;
|
||||
extern int protocol_version;
|
||||
extern int make_backups;
|
||||
extern struct stats stats;
|
||||
|
||||
|
||||
/**
|
||||
@@ -62,8 +64,8 @@ static struct sum_struct *receive_sums(int f)
|
||||
int i;
|
||||
OFF_T offset = 0;
|
||||
|
||||
s = new(struct sum_struct);
|
||||
if (!s) out_of_memory("receive_sums");
|
||||
if (!(s = new(struct sum_struct)))
|
||||
out_of_memory("receive_sums");
|
||||
|
||||
read_sum_head(f, s);
|
||||
|
||||
@@ -77,26 +79,28 @@ static struct sum_struct *receive_sums(int f)
|
||||
if (s->count == 0)
|
||||
return(s);
|
||||
|
||||
s->sums = new_array(struct sum_buf, s->count);
|
||||
if (!s->sums) out_of_memory("receive_sums");
|
||||
if (!(s->sums = new_array(struct sum_buf, s->count)))
|
||||
out_of_memory("receive_sums");
|
||||
|
||||
for (i = 0; i < (int) s->count; i++) {
|
||||
for (i = 0; i < (int)s->count; i++) {
|
||||
s->sums[i].sum1 = read_int(f);
|
||||
read_buf(f, s->sums[i].sum2, s->s2length);
|
||||
|
||||
s->sums[i].offset = offset;
|
||||
s->sums[i].i = i;
|
||||
s->sums[i].flags = 0;
|
||||
|
||||
if (i == (int) s->count-1 && s->remainder != 0) {
|
||||
if (i == (int)s->count-1 && s->remainder != 0)
|
||||
s->sums[i].len = s->remainder;
|
||||
} else {
|
||||
else
|
||||
s->sums[i].len = s->blength;
|
||||
}
|
||||
offset += s->sums[i].len;
|
||||
|
||||
if (verbose > 3)
|
||||
rprintf(FINFO, "chunk[%d] len=%d offset=%.0f sum1=%08x\n",
|
||||
i, s->sums[i].len, (double)s->sums[i].offset, s->sums[i].sum1);
|
||||
if (verbose > 3) {
|
||||
rprintf(FINFO,
|
||||
"chunk[%d] len=%d offset=%.0f sum1=%08x\n",
|
||||
i, s->sums[i].len, (double)s->sums[i].offset,
|
||||
s->sums[i].sum1);
|
||||
}
|
||||
}
|
||||
|
||||
s->flength = offset;
|
||||
@@ -110,21 +114,15 @@ void send_files(struct file_list *flist, int f_out, int f_in)
|
||||
{
|
||||
int fd = -1;
|
||||
struct sum_struct *s;
|
||||
struct map_struct *buf = NULL;
|
||||
struct map_struct *mbuf = NULL;
|
||||
STRUCT_STAT st;
|
||||
char fname[MAXPATHLEN];
|
||||
char *fname2, fname[MAXPATHLEN];
|
||||
int i;
|
||||
struct file_struct *file;
|
||||
int phase = 0;
|
||||
extern struct stats stats;
|
||||
struct stats initial_stats;
|
||||
extern int write_batch;
|
||||
extern int read_batch;
|
||||
int checksums_match;
|
||||
int buff_len;
|
||||
char buff[CHUNK_SIZE];
|
||||
int save_make_backups = make_backups;
|
||||
int j;
|
||||
int done;
|
||||
|
||||
if (verbose > 2)
|
||||
rprintf(FINFO, "send_files starting\n");
|
||||
@@ -140,6 +138,9 @@ void send_files(struct file_list *flist, int f_out, int f_in)
|
||||
write_int(f_out, -1);
|
||||
if (verbose > 2)
|
||||
rprintf(FINFO, "send_files phase=%d\n", phase);
|
||||
/* For inplace: redo phase turns off the backup
|
||||
* flag so that we do a regular inplace send. */
|
||||
make_backups = 0;
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
@@ -164,145 +165,100 @@ void send_files(struct file_list *flist, int f_out, int f_in)
|
||||
fname[offset++] = '/';
|
||||
} else
|
||||
offset = 0;
|
||||
f_name_to(file, fname + offset);
|
||||
fname2 = f_name_to(file, fname + offset);
|
||||
|
||||
if (verbose > 2)
|
||||
rprintf(FINFO, "send_files(%d, %s)\n", i, fname);
|
||||
|
||||
if (dry_run) {
|
||||
if (!am_server && verbose) { /* log transfer */
|
||||
rprintf(FINFO, "%s\n", fname+offset);
|
||||
}
|
||||
if (!am_server && verbose) /* log the transfer */
|
||||
rprintf(FINFO, "%s\n", safe_fname(fname2));
|
||||
write_int(f_out, i);
|
||||
continue;
|
||||
}
|
||||
|
||||
initial_stats = stats;
|
||||
|
||||
s = receive_sums(f_in);
|
||||
if (!s) {
|
||||
if (!(s = receive_sums(f_in))) {
|
||||
io_error |= IOERR_GENERAL;
|
||||
rprintf(FERROR, "receive_sums failed\n");
|
||||
return;
|
||||
}
|
||||
|
||||
if (write_batch)
|
||||
write_batch_csum_info(&i, s);
|
||||
|
||||
if (!read_batch) {
|
||||
fd = do_open(fname, O_RDONLY, 0);
|
||||
if (fd == -1) {
|
||||
if (errno == ENOENT) {
|
||||
enum logcode c = am_daemon
|
||||
&& protocol_version < 28 ? FERROR
|
||||
: FINFO;
|
||||
io_error |= IOERR_VANISHED;
|
||||
rprintf(c, "file has vanished: %s\n",
|
||||
full_fname(fname));
|
||||
} else {
|
||||
io_error |= IOERR_GENERAL;
|
||||
rprintf(FERROR, "send_files failed to open %s: %s\n",
|
||||
full_fname(fname), strerror(errno));
|
||||
}
|
||||
free_sums(s);
|
||||
continue;
|
||||
}
|
||||
|
||||
/* map the local file */
|
||||
if (do_fstat(fd, &st) != 0) {
|
||||
io_error |= IOERR_GENERAL;
|
||||
rprintf(FERROR, "fstat failed: %s\n", strerror(errno));
|
||||
free_sums(s);
|
||||
close(fd);
|
||||
return;
|
||||
}
|
||||
|
||||
if (st.st_size > 0) {
|
||||
buf = map_file(fd, st.st_size);
|
||||
fd = do_open(fname, O_RDONLY, 0);
|
||||
if (fd == -1) {
|
||||
if (errno == ENOENT) {
|
||||
enum logcode c = am_daemon
|
||||
&& protocol_version < 28 ? FERROR
|
||||
: FINFO;
|
||||
io_error |= IOERR_VANISHED;
|
||||
rprintf(c, "file has vanished: %s\n",
|
||||
full_fname(fname));
|
||||
} else {
|
||||
buf = NULL;
|
||||
io_error |= IOERR_GENERAL;
|
||||
rsyserr(FERROR, errno,
|
||||
"send_files failed to open %s",
|
||||
full_fname(fname));
|
||||
}
|
||||
|
||||
if (verbose > 2)
|
||||
rprintf(FINFO, "send_files mapped %s of size %.0f\n",
|
||||
fname, (double)st.st_size);
|
||||
|
||||
write_int(f_out, i);
|
||||
|
||||
if (write_batch)
|
||||
write_batch_delta_file((char *)&i, sizeof i);
|
||||
|
||||
write_sum_head(f_out, s);
|
||||
free_sums(s);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (verbose > 2 && !read_batch)
|
||||
rprintf(FINFO, "calling match_sums %s\n", fname);
|
||||
|
||||
if (!am_server && verbose) { /* log transfer */
|
||||
rprintf(FINFO, "%s\n", fname+offset);
|
||||
/* map the local file */
|
||||
if (do_fstat(fd, &st) != 0) {
|
||||
io_error |= IOERR_GENERAL;
|
||||
rsyserr(FERROR, errno, "fstat failed");
|
||||
free_sums(s);
|
||||
close(fd);
|
||||
return;
|
||||
}
|
||||
|
||||
if (st.st_size) {
|
||||
OFF_T map_size = MAX(s->blength * 3, MAX_MAP_SIZE);
|
||||
mbuf = map_file(fd, st.st_size, map_size, s->blength);
|
||||
} else
|
||||
mbuf = NULL;
|
||||
|
||||
if (verbose > 2) {
|
||||
rprintf(FINFO, "send_files mapped %s of size %.0f\n",
|
||||
safe_fname(fname), (double)st.st_size);
|
||||
}
|
||||
|
||||
write_int(f_out, i);
|
||||
write_sum_head(f_out, s);
|
||||
|
||||
if (verbose > 2) {
|
||||
rprintf(FINFO, "calling match_sums %s\n",
|
||||
safe_fname(fname));
|
||||
}
|
||||
|
||||
if (!am_server && verbose) /* log the transfer */
|
||||
rprintf(FINFO, "%s\n", safe_fname(fname2));
|
||||
|
||||
set_compression(fname);
|
||||
|
||||
if (read_batch) {
|
||||
/* read checksums originally computed on sender side */
|
||||
read_batch_csum_info(i, s, &checksums_match);
|
||||
if (checksums_match) {
|
||||
read_batch_delta_file((char*)&j, sizeof (int));
|
||||
if (j != i) { /* if flist index entries don't match*/
|
||||
rprintf(FINFO, "index mismatch in send_files\n");
|
||||
rprintf(FINFO, "read index = %d flist ndx = %d\n", j, i);
|
||||
close_batch_delta_file();
|
||||
close_batch_csums_file();
|
||||
exit_cleanup(1);
|
||||
} else {
|
||||
write_int(f_out, j);
|
||||
write_sum_head(f_out, s);
|
||||
done = 0;
|
||||
while (!done) {
|
||||
read_batch_delta_file((char*)&buff_len, sizeof (int));
|
||||
write_int(f_out, buff_len);
|
||||
if (buff_len == 0) {
|
||||
done = 1;
|
||||
} else {
|
||||
if (buff_len > 0) {
|
||||
read_batch_delta_file(buff, buff_len);
|
||||
write_buf(f_out, buff, buff_len);
|
||||
}
|
||||
}
|
||||
} /* end while */
|
||||
read_batch_delta_file( buff, MD4_SUM_LENGTH);
|
||||
write_buf(f_out, buff, MD4_SUM_LENGTH);
|
||||
match_sums(f_out, s, mbuf, st.st_size);
|
||||
log_send(file, &initial_stats);
|
||||
|
||||
} /* j=i */
|
||||
} else { /* not checksum match */
|
||||
rprintf (FINFO, "readbatch & checksums don't match\n");
|
||||
rprintf (FINFO, "filename=%s is being skipped\n", fname);
|
||||
continue;
|
||||
if (mbuf) {
|
||||
j = unmap_file(mbuf);
|
||||
if (j) {
|
||||
io_error |= IOERR_GENERAL;
|
||||
rsyserr(FERROR, j,
|
||||
"read errors mapping %s",
|
||||
full_fname(fname));
|
||||
}
|
||||
} else {
|
||||
match_sums(f_out, s, buf, st.st_size);
|
||||
log_send(file, &initial_stats);
|
||||
}
|
||||
|
||||
if (!read_batch) {
|
||||
if (buf) {
|
||||
j = unmap_file(buf);
|
||||
if (j) {
|
||||
io_error |= IOERR_GENERAL;
|
||||
rprintf(FERROR,
|
||||
"read errors mapping %s: (%d) %s\n",
|
||||
full_fname(fname), j, strerror(j));
|
||||
}
|
||||
}
|
||||
close(fd);
|
||||
}
|
||||
close(fd);
|
||||
|
||||
free_sums(s);
|
||||
|
||||
if (verbose > 2)
|
||||
rprintf(FINFO, "sender finished %s\n", fname);
|
||||
if (verbose > 2) {
|
||||
rprintf(FINFO, "sender finished %s\n",
|
||||
safe_fname(fname));
|
||||
}
|
||||
}
|
||||
make_backups = save_make_backups;
|
||||
|
||||
if (verbose > 2)
|
||||
rprintf(FINFO, "send files finished\n");
|
||||
@@ -310,14 +266,4 @@ void send_files(struct file_list *flist, int f_out, int f_in)
|
||||
match_report();
|
||||
|
||||
write_int(f_out, -1);
|
||||
if (write_batch || read_batch) {
|
||||
close_batch_csums_file();
|
||||
close_batch_delta_file();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
113
socket.c
113
socket.c
@@ -33,6 +33,8 @@
|
||||
|
||||
#include "rsync.h"
|
||||
|
||||
extern char *bind_address;
|
||||
extern int default_af_hint;
|
||||
|
||||
/**
|
||||
* Establish a proxy connection on an open socket to a web proxy by
|
||||
@@ -69,15 +71,13 @@ static int establish_proxy_connection(int fd, char *host, int port,
|
||||
host, port, authhdr, authbuf);
|
||||
len = strlen(buffer);
|
||||
if (write(fd, buffer, len) != len) {
|
||||
rprintf(FERROR, "failed to write to proxy: %s\n",
|
||||
strerror(errno));
|
||||
rsyserr(FERROR, errno, "failed to write to proxy");
|
||||
return -1;
|
||||
}
|
||||
|
||||
for (cp = buffer; cp < &buffer[sizeof buffer - 1]; cp++) {
|
||||
if (read(fd, cp, 1) != 1) {
|
||||
rprintf(FERROR, "failed to read from proxy: %s\n",
|
||||
strerror(errno));
|
||||
rsyserr(FERROR, errno, "failed to read from proxy");
|
||||
return -1;
|
||||
}
|
||||
if (*cp == '\n')
|
||||
@@ -106,8 +106,8 @@ static int establish_proxy_connection(int fd, char *host, int port,
|
||||
while (1) {
|
||||
for (cp = buffer; cp < &buffer[sizeof buffer - 1]; cp++) {
|
||||
if (read(fd, cp, 1) != 1) {
|
||||
rprintf(FERROR, "failed to read from proxy: %s\n",
|
||||
strerror(errno));
|
||||
rsyserr(FERROR, errno,
|
||||
"failed to read from proxy");
|
||||
return -1;
|
||||
}
|
||||
if (*cp == '\n')
|
||||
@@ -276,8 +276,7 @@ int open_socket_out(char *host, int port, const char *bind_address,
|
||||
}
|
||||
freeaddrinfo(res0);
|
||||
if (s < 0) {
|
||||
rprintf(FERROR, RSYNC_NAME ": failed to connect to %s: %s\n",
|
||||
h, strerror(errno));
|
||||
rsyserr(FERROR, errno, "failed to connect to %s", h);
|
||||
return -1;
|
||||
}
|
||||
return s;
|
||||
@@ -314,19 +313,14 @@ int open_socket_out_wrapped(char *host, int port, const char *bind_address,
|
||||
|
||||
|
||||
/**
|
||||
* Open a socket of the specified type, port and address for incoming data
|
||||
* Open one or more sockets for incoming data using the specified type,
|
||||
* port, and address.
|
||||
*
|
||||
* Try to be better about handling the results of getaddrinfo(): when
|
||||
* opening an inbound socket, we might get several address results,
|
||||
* e.g. for the machine's ipv4 and ipv6 name.
|
||||
* The getaddrinfo() call may return several address results, e.g. for
|
||||
* the machine's IPv4 and IPv6 name.
|
||||
*
|
||||
* If binding a wildcard, then any one of them should do. If an address
|
||||
* was specified but it's insufficiently specific then that's not our
|
||||
* fault.
|
||||
*
|
||||
* However, some of the advertized addresses may not work because e.g. we
|
||||
* don't have IPv6 support in the kernel. In that case go on and try all
|
||||
* addresses until one succeeds.
|
||||
* We return an array of file-descriptors to the sockets, with a trailing
|
||||
* -1 value to indicate the end of the list.
|
||||
*
|
||||
* @param bind_address Local address to bind, or NULL to allow it to
|
||||
* default.
|
||||
@@ -334,8 +328,8 @@ int open_socket_out_wrapped(char *host, int port, const char *bind_address,
|
||||
static int *open_socket_in(int type, int port, const char *bind_address,
|
||||
int af_hint)
|
||||
{
|
||||
int one=1;
|
||||
int s, *sp, *socks, maxs;
|
||||
int one = 1;
|
||||
int s, *socks, maxs, i;
|
||||
struct addrinfo hints, *all_ai, *resp;
|
||||
char portbuf[10];
|
||||
int error;
|
||||
@@ -354,18 +348,14 @@ static int *open_socket_in(int type, int port, const char *bind_address,
|
||||
|
||||
/* Count max number of sockets we might open. */
|
||||
for (maxs = 0, resp = all_ai; resp; resp = resp->ai_next, maxs++) {}
|
||||
socks = new_array(int, maxs + 1);
|
||||
if (!socks) {
|
||||
rprintf(FERROR,
|
||||
RSYNC_NAME "couldn't allocate memory for sockets");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (!(socks = new_array(int, maxs + 1)))
|
||||
out_of_memory("open_socket_in");
|
||||
|
||||
/* We may not be able to create the socket, if for example the
|
||||
* machine knows about IPv6 in the C library, but not in the
|
||||
* kernel. */
|
||||
sp = socks + 1; /* Leave room for count at start of array. */
|
||||
for (resp = all_ai; resp; resp = resp->ai_next) {
|
||||
for (resp = all_ai, i = 0; resp; resp = resp->ai_next) {
|
||||
s = socket(resp->ai_family, resp->ai_socktype,
|
||||
resp->ai_protocol);
|
||||
|
||||
@@ -379,8 +369,12 @@ static int *open_socket_in(int type, int port, const char *bind_address,
|
||||
|
||||
#ifdef IPV6_V6ONLY
|
||||
if (resp->ai_family == AF_INET6) {
|
||||
setsockopt(s, IPPROTO_IPV6, IPV6_V6ONLY,
|
||||
(char *)&one, sizeof one);
|
||||
if (setsockopt(s, IPPROTO_IPV6, IPV6_V6ONLY,
|
||||
(char *)&one, sizeof one) < 0
|
||||
&& default_af_hint != AF_INET6) {
|
||||
close(s);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -391,17 +385,17 @@ static int *open_socket_in(int type, int port, const char *bind_address,
|
||||
continue;
|
||||
}
|
||||
|
||||
*sp++ = s;
|
||||
socks[i++] = s;
|
||||
}
|
||||
*socks = sp - socks - 1; /* Save count. */
|
||||
socks[i] = -1;
|
||||
|
||||
if (all_ai)
|
||||
freeaddrinfo(all_ai);
|
||||
|
||||
if (*socks == 0) {
|
||||
if (!i) {
|
||||
rprintf(FERROR,
|
||||
RSYNC_NAME ": open inbound socket on port %d failed: "
|
||||
"%s\n", port, strerror(errno));
|
||||
"unable to bind any inbound sockets on port %d\n",
|
||||
port);
|
||||
free(socks);
|
||||
return NULL;
|
||||
}
|
||||
@@ -446,9 +440,7 @@ static RETSIGTYPE sigchld_handler(UNUSED(int val))
|
||||
void start_accept_loop(int port, int (*fn)(int, int))
|
||||
{
|
||||
fd_set deffds;
|
||||
int *sp, maxfd, i, j;
|
||||
extern char *bind_address;
|
||||
extern int default_af_hint;
|
||||
int *sp, maxfd, i;
|
||||
|
||||
/* open an incoming socket */
|
||||
sp = open_socket_in(SOCK_STREAM, port, bind_address, default_af_hint);
|
||||
@@ -457,12 +449,15 @@ void start_accept_loop(int port, int (*fn)(int, int))
|
||||
|
||||
/* ready to listen */
|
||||
FD_ZERO(&deffds);
|
||||
maxfd = -1;
|
||||
for (i = 1; i <= *sp; i++) {
|
||||
if (listen(sp[i], 5) == -1) {
|
||||
for (j = 1; j <= i; j++)
|
||||
close(sp[j]);
|
||||
free(sp);
|
||||
for (i = 0, maxfd = -1; sp[i] >= 0; i++) {
|
||||
if (listen(sp[i], 5) < 0) {
|
||||
rsyserr(FERROR, errno, "listen() on socket failed");
|
||||
#ifdef INET6
|
||||
if (errno == EADDRINUSE && i > 0) {
|
||||
rprintf(FINFO,
|
||||
"Try using --ipv4 or --ipv6 to avoid this listen() error.");
|
||||
}
|
||||
#endif
|
||||
exit_cleanup(RERR_SOCKETIO);
|
||||
}
|
||||
FD_SET(sp[i], &deffds);
|
||||
@@ -494,8 +489,7 @@ void start_accept_loop(int port, int (*fn)(int, int))
|
||||
if (select(maxfd + 1, &fds, NULL, NULL, NULL) != 1)
|
||||
continue;
|
||||
|
||||
fd = -1;
|
||||
for (i = 1; i <= *sp; i++) {
|
||||
for (i = 0, fd = -1; sp[i] >= 0; i++) {
|
||||
if (FD_ISSET(sp[i], &fds)) {
|
||||
fd = accept(sp[i], (struct sockaddr *)&addr,
|
||||
&addrlen);
|
||||
@@ -510,7 +504,8 @@ void start_accept_loop(int port, int (*fn)(int, int))
|
||||
|
||||
if ((pid = fork()) == 0) {
|
||||
int ret;
|
||||
close(sp[i]);
|
||||
for (i = 0; sp[i] >= 0; i++)
|
||||
close(sp[i]);
|
||||
/* open log file in child before possibly giving
|
||||
* up privileges */
|
||||
log_open();
|
||||
@@ -518,10 +513,8 @@ void start_accept_loop(int port, int (*fn)(int, int))
|
||||
close_all();
|
||||
_exit(ret);
|
||||
} else if (pid < 0) {
|
||||
rprintf(FERROR,
|
||||
RSYNC_NAME
|
||||
": could not create child server process: %s\n",
|
||||
strerror(errno));
|
||||
rsyserr(FERROR, errno,
|
||||
"could not create child server process");
|
||||
close(fd);
|
||||
/* This might have happened because we're
|
||||
* overloaded. Sleep briefly before trying to
|
||||
@@ -638,9 +631,10 @@ void set_socket_options(int fd, char *options)
|
||||
break;
|
||||
}
|
||||
|
||||
if (ret != 0)
|
||||
rprintf(FERROR, "failed to set socket option %s: %s\n", tok,
|
||||
strerror(errno));
|
||||
if (ret != 0) {
|
||||
rsyserr(FERROR, errno,
|
||||
"failed to set socket option %s", tok);
|
||||
}
|
||||
}
|
||||
|
||||
free(options);
|
||||
@@ -733,14 +727,16 @@ static int socketpair_tcp(int fd[2])
|
||||
goto failed;
|
||||
|
||||
close(listener);
|
||||
listener = -1;
|
||||
|
||||
set_blocking(fd[1]);
|
||||
|
||||
if (connect_done == 0) {
|
||||
if (connect(fd[1], (struct sockaddr *)&sock, sizeof sock) != 0
|
||||
&& errno != EISCONN)
|
||||
goto failed;
|
||||
}
|
||||
|
||||
set_blocking(fd[1]);
|
||||
|
||||
/* all OK! */
|
||||
return 0;
|
||||
|
||||
@@ -770,8 +766,7 @@ int sock_exec(const char *prog)
|
||||
int fd[2];
|
||||
|
||||
if (socketpair_tcp(fd) != 0) {
|
||||
rprintf(FERROR, RSYNC_NAME ": socketpair_tcp failed (%s)\n",
|
||||
strerror(errno));
|
||||
rsyserr(FERROR, errno, "socketpair_tcp failed");
|
||||
return -1;
|
||||
}
|
||||
if (verbose >= 2)
|
||||
|
||||
@@ -152,7 +152,7 @@ int do_mkstemp(char *template, mode_t perms)
|
||||
RETURN_ERROR_IF(dry_run, 0);
|
||||
RETURN_ERROR_IF(read_only, EROFS);
|
||||
|
||||
#if defined(HAVE_SECURE_MKSTEMP) && defined(HAVE_FCHMOD)
|
||||
#if HAVE_SECURE_MKSTEMP && HAVE_FCHMOD && (!HAVE_OPEN64 || HAVE_MKSTEMP64)
|
||||
{
|
||||
int fd = mkstemp(template);
|
||||
if (fd == -1)
|
||||
|
||||
11
t_stub.c
11
t_stub.c
@@ -28,6 +28,7 @@
|
||||
|
||||
int modify_window = 0;
|
||||
int module_id = -1;
|
||||
char *partial_dir;
|
||||
struct exclude_list_struct server_exclude_list;
|
||||
|
||||
void rprintf(UNUSED(enum logcode code), const char *format, ...)
|
||||
@@ -38,6 +39,16 @@ struct exclude_list_struct server_exclude_list;
|
||||
va_end(ap);
|
||||
}
|
||||
|
||||
void rsyserr(UNUSED(enum logcode code), int errcode, const char *format, ...)
|
||||
{
|
||||
va_list ap;
|
||||
fputs(RSYNC_NAME ": ", stderr);
|
||||
va_start(ap, format);
|
||||
vfprintf(stderr, format, ap);
|
||||
va_end(ap);
|
||||
fprintf(stderr, ": %s (%d)\n", strerror(errcode), errcode);
|
||||
}
|
||||
|
||||
void _exit_cleanup(int code, const char *file, int line)
|
||||
{
|
||||
fprintf(stderr, "exit(%d): %s(%d)\n",
|
||||
|
||||
173
test.sh
173
test.sh
@@ -1,173 +0,0 @@
|
||||
#!/bin/sh
|
||||
|
||||
# Copyright (C) 1998,1999 Philip Hands <phil@hands.com>
|
||||
#
|
||||
# This program is distributable under the terms of the GNU GPL (see COPYING)
|
||||
#
|
||||
# This is a simple test script that tests a few rsync
|
||||
# features to make sure I haven't broken them before a release.
|
||||
#
|
||||
#
|
||||
|
||||
# check if we are running under debian-test, and change behaviour to suit
|
||||
if test -n "${DEBIANTEST_LIB}" ; then
|
||||
# make sure rsync is installed
|
||||
test -e /usr/bin/rsync || exit 0
|
||||
|
||||
. ${DEBIANTEST_LIB}/functions.sh
|
||||
Debian=1
|
||||
else
|
||||
cat <<EOF
|
||||
|
||||
This set of tests is not completely portable. It is intended for developers
|
||||
not for end users. You may experience failures on some platforms that
|
||||
do not indicate a problem with rsync.
|
||||
|
||||
EOF
|
||||
|
||||
RSYNC=`pwd`/rsync
|
||||
|
||||
runtest() {
|
||||
echo -n "Test $1: "
|
||||
eval "$2"
|
||||
}
|
||||
printmsg() {
|
||||
echo ""
|
||||
echo "**** ${1}^G ****"
|
||||
echo ""
|
||||
}
|
||||
fi
|
||||
|
||||
TMP=/tmp/rsync-test.$$
|
||||
FROM=${TMP}/from
|
||||
TO=${TMP}/to
|
||||
F1=text1
|
||||
LOG=${TMP}/log
|
||||
|
||||
mkdir $TMP
|
||||
mkdir $FROM
|
||||
mkdir $TO
|
||||
|
||||
# set up test data
|
||||
touch ${FROM}/empty
|
||||
mkdir ${FROM}/emptydir
|
||||
ps ax > ${FROM}/pslist
|
||||
echo -n "This file has no trailing lf" > ${FROM}/nolf
|
||||
ln -s nolf ${FROM}/nolf-symlink
|
||||
|
||||
# Gather some random text. We need files that will exist and be
|
||||
# publicly readable on all platforms: hopefully this will work.
|
||||
cat /etc/*tab /etc/services /etc/*.conf /etc/*rc > ${FROM}/${F1}
|
||||
|
||||
mkdir ${FROM}/dir
|
||||
cp ${FROM}/${F1} ${FROM}/dir/
|
||||
mkdir ${FROM}/dir/subdir
|
||||
mkdir ${FROM}/dir/subdir/subsubdir
|
||||
ls -ltr /etc > ${FROM}/dir/subdir/subsubdir/etc-ltr-list
|
||||
mkdir ${FROM}/dir/subdir/subsubdir2
|
||||
ls -lt /bin > ${FROM}/dir/subdir/subsubdir2/bin-lt-list
|
||||
|
||||
checkit() {
|
||||
testnum=`expr 0${testnum} + 1`
|
||||
log=${LOG}.${testnum}
|
||||
failed=
|
||||
echo "Running: \"$1\"" >${log}
|
||||
echo "">>${log}
|
||||
eval "$1" >>${log} 2>&1
|
||||
status=$?
|
||||
if [ $status != 0 ]; then
|
||||
failed="YES";
|
||||
fi
|
||||
echo "-------------">>${log}
|
||||
echo "check how the files compare with diff:">>${log}
|
||||
echo "">>${log}
|
||||
diff -ur $2 $3 >>${log} 2>&1 || failed=YES
|
||||
echo "-------------">>${log}
|
||||
echo "check how the directory listings compare with diff:">>${log}
|
||||
echo "">>${log}
|
||||
( cd $2 ; ls -laR ) > ${TMP}/ls-from 2>>${log}
|
||||
( cd $3 ; ls -laR ) > ${TMP}/ls-to 2>>${log}
|
||||
diff -u ${TMP}/ls-from ${TMP}/ls-to >>${log} 2>&1 || failed=YES
|
||||
if [ -z "${failed}" ] ; then
|
||||
test -z "${Debian}" && echo " done."
|
||||
rm $log
|
||||
return 0
|
||||
else
|
||||
if test -n "${Debian}" ; then
|
||||
cat ${log}
|
||||
rm ${log}
|
||||
else
|
||||
echo " FAILED (test # ${testnum} status=$status)."
|
||||
fi
|
||||
return 1
|
||||
fi
|
||||
}
|
||||
|
||||
|
||||
checkforlogs() {
|
||||
# skip it if we're under debian-test
|
||||
if test -n "${Debian}" ; then return 0 ; fi
|
||||
|
||||
if [ -f $1 ] ; then
|
||||
cat <<EOF
|
||||
|
||||
Failures have occured.
|
||||
|
||||
You can find the output of the tests in these files:
|
||||
$@
|
||||
|
||||
Please hit <RETURN>
|
||||
EOF
|
||||
read input
|
||||
else
|
||||
|
||||
rm -rf ${TMP}
|
||||
echo ""
|
||||
echo "Tests Completed Successfully :-)"
|
||||
fi
|
||||
}
|
||||
|
||||
# Main script starts here
|
||||
|
||||
runtest "basic operation" 'checkit "$RSYNC -av ${FROM}/ ${TO}" ${FROM}/ ${TO}'
|
||||
|
||||
ln ${FROM}/pslist ${FROM}/dir
|
||||
runtest "hard links" 'checkit "$RSYNC -avH ${FROM}/ ${TO}" ${FROM}/ ${TO}'
|
||||
|
||||
rm ${TO}/${F1}
|
||||
runtest "one file" 'checkit "$RSYNC -avH ${FROM}/ ${TO}" ${FROM}/ ${TO}'
|
||||
|
||||
echo "extra line" >> ${TO}/${F1}
|
||||
runtest "extra data" 'checkit "$RSYNC -avH ${FROM}/ ${TO}" ${FROM}/ ${TO}'
|
||||
|
||||
cp ${FROM}/${F1} ${TO}/ThisShouldGo
|
||||
runtest " --delete" 'checkit "$RSYNC --delete -avH ${FROM}/ ${TO}" ${FROM}/ ${TO}'
|
||||
|
||||
LONGDIR=${FROM}/This-is-a-directory-with-a-stupidly-long-name-created-in-an-attempt-to-provoke-an-error-found-in-2.0.11-that-should-hopefully-never-appear-again-if-this-test-does-its-job/This-is-a-directory-with-a-stupidly-long-name-created-in-an-attempt-to-provoke-an-error-found-in-2.0.11-that-should-hopefully-never-appear-again-if-this-test-does-its-job/This-is-a-directory-with-a-stupidly-long-name-created-in-an-attempt-to-provoke-an-error-found-in-2.0.11-that-should-hopefully-never-appear-again-if-this-test-does-its-job
|
||||
mkdir -p ${LONGDIR}
|
||||
date > ${LONGDIR}/1
|
||||
ls -la / > ${LONGDIR}/2
|
||||
runtest "long paths" 'checkit "$RSYNC --delete -avH ${FROM}/ ${TO}" ${FROM}/ ${TO}'
|
||||
|
||||
if type ssh >/dev/null 2>&1; then
|
||||
if [ "`ssh -o'BatchMode yes' localhost echo yes 2>/dev/null`" = "yes" ]; then
|
||||
rm -rf ${TO}
|
||||
runtest "ssh: basic test" 'checkit "$RSYNC -avH -e ssh --rsync-path=$RSYNC ${FROM}/ localhost:${TO}" ${FROM}/ ${TO}'
|
||||
|
||||
mv ${TO}/${F1} ${TO}/ThisShouldGo
|
||||
runtest "ssh: renamed file" 'checkit "$RSYNC --delete -avH -e ssh --rsync-path=$RSYNC ${FROM}/ localhost:${TO}" ${FROM}/ ${TO}'
|
||||
else
|
||||
printmsg "Skipping SSH tests because ssh conection to localhost not authorised"
|
||||
fi
|
||||
else
|
||||
printmsg "Skipping SSH tests because ssh is not in the path"
|
||||
fi
|
||||
|
||||
rm -rf ${TO}
|
||||
mkdir -p ${FROM}2/dir/subdir
|
||||
cp -a ${FROM}/dir/subdir/subsubdir ${FROM}2/dir/subdir
|
||||
cp ${FROM}/dir/* ${FROM}2/dir 2>/dev/null
|
||||
runtest "excludes" 'checkit "$RSYNC -vv -Hlrt --delete --include /dir/ --include /dir/\* --include /dir/\*/subsubdir --include /dir/\*/subsubdir/\*\* --exclude \*\* ${FROM}/dir ${TO}" ${FROM}2/ ${TO}'
|
||||
rm -r ${FROM}2
|
||||
|
||||
checkforlogs ${LOG}.?
|
||||
@@ -17,8 +17,8 @@ with the GNU Standards, installcheck does not look for rsync on the
|
||||
path.
|
||||
|
||||
If the tests pass, you should see a report to that effect. Some tests
|
||||
require being root or some other precondition, and so will normally be
|
||||
checked -- look at the test scripts for more information.
|
||||
require being root or some other precondition, and so will normally not
|
||||
be checked -- look at the test scripts for more information.
|
||||
|
||||
If the tests fail, you will see rather more output. The scratch
|
||||
directory will remain in the build directory. It would be useful if
|
||||
|
||||
61
testsuite/backup.test
Normal file
61
testsuite/backup.test
Normal file
@@ -0,0 +1,61 @@
|
||||
#! /bin/sh
|
||||
|
||||
# Copyright (C) 2004 by Wayne Davison <wayned@samba.org>
|
||||
|
||||
# This program is distributable under the terms of the GNU GPL (see
|
||||
# COPYING).
|
||||
|
||||
# Test that the --backup option works right.
|
||||
|
||||
. "$suitedir/rsync.fns"
|
||||
|
||||
bakdir="$tmpdir/bak"
|
||||
|
||||
mkdir "$fromdir" "$bakdir"
|
||||
name1="$fromdir/name1"
|
||||
name2="$fromdir/name2"
|
||||
|
||||
outfile="$scratchdir/rsync.out"
|
||||
|
||||
cat $srcdir/[gr]*.[ch] > "$name1"
|
||||
cat $srcdir/[et]*.[ch] > "$name2"
|
||||
|
||||
checkit "$RSYNC -avv \"$fromdir/\" \"$todir/\"" "$fromdir" "$todir"
|
||||
|
||||
checkit "$RSYNC -avv \"$fromdir/\" \"$chkdir/\"" "$fromdir" "$chkdir"
|
||||
cat $srcdir/[fgpr]*.[ch] > "$name1"
|
||||
cat $srcdir/[etw]*.[ch] > "$name2"
|
||||
|
||||
$RSYNC -avv --no-whole-file --backup "$fromdir/" "$todir/" \
|
||||
| tee "$outfile"
|
||||
for fn in name1 name2; do
|
||||
grep "backed up $fn to $fn~" "$outfile" >/dev/null || test_fail "no backup message output for $fn"
|
||||
diff $diffopt "$fromdir/$fn" "$todir" || test_fail "copy of $fn failed"
|
||||
diff $diffopt "$chkdir/$fn" "$todir/$fn~" || test_fail "backup of $fn to $fn~ failed"
|
||||
mv "$todir/$fn~" "$todir/$fn"
|
||||
done
|
||||
|
||||
checkit "$RSYNC -avv --no-whole-file --backup --backup-dir=\"$bakdir\" \"$fromdir/\" \"$todir/\"" "$fromdir" "$todir" \
|
||||
| tee "$outfile"
|
||||
|
||||
for fn in name1 name2; do
|
||||
grep "backed up $fn to .*/$fn$" "$outfile" >/dev/null || test_fail "no backup message output for $fn"
|
||||
done
|
||||
diff -r $diffopt "$chkdir" "$bakdir" || test_fail "backup dir contents are bogus"
|
||||
|
||||
checkit "$RSYNC -avv \"$fromdir/\" \"$chkdir/\"" "$fromdir" "$chkdir"
|
||||
cat $srcdir/[efgr]*.[ch] > "$name1"
|
||||
cat $srcdir/[ew]*.[ch] > "$name2"
|
||||
|
||||
checkit "$RSYNC -avv --inplace --no-whole-file --backup --backup-dir=\"$bakdir\" \"$fromdir/\" \"$todir/\"" "$fromdir" "$todir" \
|
||||
| tee "$outfile"
|
||||
|
||||
for fn in name1 name2; do
|
||||
grep "backed up $fn to .*/$fn$" "$outfile" >/dev/null || test_fail "no backup message output for $fn"
|
||||
done
|
||||
diff -r $diffopt "$chkdir" "$bakdir" || test_fail "backup dir contents are bogus"
|
||||
|
||||
checkit "$RSYNC -avv --inplace --no-whole-file \"$fromdir/\" \"$bakdir/\"" "$fromdir" "$bakdir"
|
||||
|
||||
# The script would have aborted on error, so getting here means we've won.
|
||||
exit 0
|
||||
45
testsuite/batch-mode.test
Normal file
45
testsuite/batch-mode.test
Normal file
@@ -0,0 +1,45 @@
|
||||
#! /bin/sh
|
||||
|
||||
# Copyright (C) 2004 by Chris Shoemaker <c.shoemaker@cox.net>
|
||||
|
||||
# This program is distributable under the terms of the GNU GPL (see
|
||||
# COPYING).
|
||||
|
||||
# Test rsync's --write-batch and --read-batch options
|
||||
|
||||
. "$suitedir/rsync.fns"
|
||||
|
||||
set -x
|
||||
|
||||
hands_setup
|
||||
|
||||
cd "$tmpdir"
|
||||
|
||||
# Build chkdir for the daemon tests using a normal rsync and an --exclude.
|
||||
$RSYNC -av --exclude=foobar.baz "$fromdir/" "$chkdir/"
|
||||
|
||||
runtest "local --write-batch" 'checkit "$RSYNC -av --write-batch=BATCH \"$fromdir/\" \"$todir\"" "$fromdir" "$todir"'
|
||||
|
||||
rm -rf "$todir"
|
||||
runtest "--read-batch" 'checkit "$RSYNC -av --read-batch=BATCH \"$todir\"" "$fromdir" "$todir"'
|
||||
|
||||
build_rsyncd_conf
|
||||
|
||||
RSYNC_CONNECT_PROG="$RSYNC --config=$conf --daemon"
|
||||
export RSYNC_CONNECT_PROG
|
||||
|
||||
rm -rf "$todir"
|
||||
runtest "daemon sender --write-batch" 'checkit "$RSYNC -av --write-batch=BATCH rsync://localhost/test-from/ \"$todir\"" "$chkdir" "$todir"'
|
||||
|
||||
rm -rf "$todir"
|
||||
runtest "--read-batch from daemon" 'checkit "$RSYNC -av --read-batch=BATCH \"$todir\"" "$chkdir" "$todir"'
|
||||
|
||||
rm -rf "$todir"
|
||||
runtest "BATCH.sh use of --read-batch" 'checkit "./BATCH.sh" "$chkdir" "$todir"'
|
||||
|
||||
rm -rf "$todir"
|
||||
mkdir "$todir" || test_fail "failed to restore empty destination directory"
|
||||
runtest "daemon recv --write-batch" 'checkit "$RSYNC -av --write-batch=BATCH \"$fromdir/\" rsync://localhost/test-to" "$chkdir" "$todir"'
|
||||
|
||||
# The script would have aborted on error, so getting here means we pass.
|
||||
exit 0
|
||||
@@ -9,15 +9,12 @@
|
||||
# the test is a member of them. Hopefully they're in at least one
|
||||
# test.
|
||||
|
||||
. $srcdir/testsuite/rsync.fns
|
||||
. "$suitedir/rsync.fns"
|
||||
|
||||
set -x
|
||||
|
||||
# Build some hardlinks
|
||||
|
||||
fromdir="$scratchdir/from"
|
||||
todir="$scratchdir/to"
|
||||
|
||||
mygrps="`rsync_getgroups`" || fail "Can't get groups"
|
||||
mkdir "$fromdir"
|
||||
|
||||
@@ -29,7 +26,7 @@ do
|
||||
done
|
||||
sleep 2
|
||||
|
||||
checkit "$RSYNC -rtgvvv \"$fromdir/\" \"$todir/\"" "$fromdir" "$todir"
|
||||
checkit "$RSYNC -rtgpvvv \"$fromdir/\" \"$todir/\"" "$fromdir" "$todir"
|
||||
|
||||
# The script would have aborted on error, so getting here means we've won.
|
||||
exit 0
|
||||
|
||||
41
testsuite/chmod-temp-dir.test
Normal file
41
testsuite/chmod-temp-dir.test
Normal file
@@ -0,0 +1,41 @@
|
||||
#! /bin/sh
|
||||
|
||||
# Copyright (C) 2004 by Wayne Davison <wayned@samba.org>
|
||||
|
||||
# This program is distributable under the terms of the GNU GPL see
|
||||
# COPYING).
|
||||
|
||||
# Test that various read-only and set[ug]id permissions work properly,
|
||||
# even when using a --temp-dir option (which we try to point at a
|
||||
# different filesystem than the destination dir).
|
||||
|
||||
. "$suitedir/rsync.fns"
|
||||
|
||||
set -x
|
||||
|
||||
hands_setup
|
||||
|
||||
tmpdir2=/tmp
|
||||
sdev=`$TOOLDIR/getfsdev $scratchdir`
|
||||
tdev=`$TOOLDIR/getfsdev $tmpdir2`
|
||||
if [ x$sdev = x$tdev ]; then
|
||||
tmpdir2=/var/tmp
|
||||
tdev=`$TOOLDIR/getfsdev $tmpdir2`
|
||||
[ x$sdev = x$tdev ] && test_skipped "Can't find a tmp dir on a different file system"
|
||||
fi
|
||||
|
||||
chmod 440 "$fromdir/text"
|
||||
chmod 500 "$fromdir/dir/text"
|
||||
e="$fromdir/dir/subdir/foobar.baz"
|
||||
chmod 6450 "$e" || chmod 2450 "$e" || chmod 1450 "$e" || chmod 450 "$e"
|
||||
e="$fromdir/dir/subdir/subsubdir/etc-ltr-list"
|
||||
chmod 2670 "$e" || chmod 1670 "$e" || chmod 670 "$e"
|
||||
|
||||
# First a normal copy.
|
||||
runtest "normal copy" 'checkit "$RSYNC -avv --temp-dir=\"$tmpdir2\" \"$fromdir/\" \"$todir\"" "$fromdir" "$todir"'
|
||||
|
||||
# Then we update all the files.
|
||||
runtest "update copy" 'checkit "$RSYNC -avvI --no-whole-file --temp-dir=\"$tmpdir2\" \"$fromdir/\" \"$todir\"" "$fromdir" "$todir"'
|
||||
|
||||
# The script would have aborted on error, so getting here means we've won.
|
||||
exit 0
|
||||
32
testsuite/chmod.test
Normal file
32
testsuite/chmod.test
Normal file
@@ -0,0 +1,32 @@
|
||||
#! /bin/sh
|
||||
|
||||
# Copyright (C) 2004 by Wayne Davison <wayned@samba.org>
|
||||
|
||||
# This program is distributable under the terms of the GNU GPL see
|
||||
# COPYING).
|
||||
|
||||
# Test that various read-only and set[ug]id permissions work properly,
|
||||
# even when using a --temp-dir option (which we try to point at a
|
||||
# different filesystem than the destination dir).
|
||||
|
||||
. "$suitedir/rsync.fns"
|
||||
|
||||
set -x
|
||||
|
||||
hands_setup
|
||||
|
||||
chmod 440 "$fromdir/text"
|
||||
chmod 500 "$fromdir/dir/text"
|
||||
e="$fromdir/dir/subdir/foobar.baz"
|
||||
chmod 6450 "$e" || chmod 2450 "$e" || chmod 1450 "$e" || chmod 450 "$e"
|
||||
e="$fromdir/dir/subdir/subsubdir/etc-ltr-list"
|
||||
chmod 2670 "$e" || chmod 1670 "$e" || chmod 670 "$e"
|
||||
|
||||
# First a normal copy.
|
||||
runtest "normal copy" 'checkit "$RSYNC -avv \"$fromdir/\" \"$todir\"" "$fromdir" "$todir"'
|
||||
|
||||
# Then we update all the files.
|
||||
runtest "update copy" 'checkit "$RSYNC -avvI --no-whole-file \"$fromdir/\" \"$todir\"" "$fromdir" "$todir"'
|
||||
|
||||
# The script would have aborted on error, so getting here means we've won.
|
||||
exit 0
|
||||
@@ -11,15 +11,12 @@
|
||||
# We don't know what users will be present on this system, so we just
|
||||
# use random numeric uids and gids.
|
||||
|
||||
. $srcdir/testsuite/rsync.fns
|
||||
. "$suitedir/rsync.fns"
|
||||
|
||||
set -x
|
||||
|
||||
# Build some hardlinks
|
||||
|
||||
fromdir="$scratchdir/from"
|
||||
todir="$scratchdir/to"
|
||||
|
||||
mkdir "$fromdir"
|
||||
name1="$fromdir/name1"
|
||||
name2="$fromdir/name2"
|
||||
|
||||
33
testsuite/compare-dest.test
Normal file
33
testsuite/compare-dest.test
Normal file
@@ -0,0 +1,33 @@
|
||||
#! /bin/sh
|
||||
|
||||
# Copyright (C) 2004 by Wayne Davison <wayned@samba.org>
|
||||
|
||||
# This program is distributable under the terms of the GNU GPL see
|
||||
# COPYING).
|
||||
|
||||
# Test rsync handling of the --compare-dest option.
|
||||
|
||||
. "$suitedir/rsync.fns"
|
||||
|
||||
set -x
|
||||
|
||||
altdir="$tmpdir/alt"
|
||||
|
||||
# Build some files/dirs/links to copy
|
||||
|
||||
hands_setup
|
||||
|
||||
# Setup the alt and chk dirs
|
||||
$RSYNC -av --include=text --include='*/' --exclude='*' "$fromdir/" "$altdir/"
|
||||
|
||||
sleep 1
|
||||
touch "$fromdir/dir/text"
|
||||
|
||||
$RSYNC -av --exclude=/text "$fromdir/" "$chkdir/"
|
||||
|
||||
# Let's do it!
|
||||
checkit "$RSYNC -avv --no-whole-file --compare-dest=\"$altdir\" \
|
||||
\"$fromdir/\" \"$todir/\"" "$chkdir" "$todir"
|
||||
|
||||
# The script would have aborted on error, so getting here means we've won.
|
||||
exit 0
|
||||
@@ -27,7 +27,11 @@ RSYNC_CONNECT_PROG="$RSYNC --config=$conf --daemon"
|
||||
export RSYNC_CONNECT_PROG
|
||||
|
||||
hands_setup
|
||||
checkit "$RSYNC -avvvvz localhost::test-from/ \"$TO/\"" "$FROM" "$TO"
|
||||
|
||||
# Build chkdir with a normal rsync and an --exclude.
|
||||
$RSYNC -av --exclude=foobar.baz "$fromdir/" "$chkdir/"
|
||||
|
||||
checkit "$RSYNC -avvvvz localhost::test-from/ \"$todir/\"" "$chkdir" "$todir"
|
||||
|
||||
# The script would have aborted on error, so getting here means we've won.
|
||||
exit 0
|
||||
|
||||
@@ -21,7 +21,11 @@ RSYNC_CONNECT_PROG="$RSYNC --config=$conf --daemon"
|
||||
export RSYNC_CONNECT_PROG
|
||||
|
||||
hands_setup
|
||||
checkit "$RSYNC -avvvvz \"$FROM/\" localhost::test-to/" "$FROM" "$TO"
|
||||
|
||||
# Build chkdir with a normal rsync and an --exclude.
|
||||
$RSYNC -av --exclude=foobar.baz "$fromdir/" "$chkdir/"
|
||||
|
||||
checkit "$RSYNC -avvvvz \"$fromdir/\" localhost::test-to/" "$chkdir" "$todir"
|
||||
|
||||
# The script would have aborted on error, so getting here means we've won.
|
||||
exit 0
|
||||
|
||||
@@ -7,15 +7,12 @@
|
||||
|
||||
# Test rsync handling of devices. This can only run if you're root.
|
||||
|
||||
. $srcdir/testsuite/rsync.fns
|
||||
. "$suitedir/rsync.fns"
|
||||
|
||||
set -x
|
||||
|
||||
# Build some hardlinks
|
||||
|
||||
fromdir="$scratchdir/from"
|
||||
todir="$scratchdir/to"
|
||||
|
||||
case `id -u` in
|
||||
'') ;; # If "id" failed, try to continue...
|
||||
0) ;;
|
||||
@@ -31,6 +28,7 @@ mknod "$fromdir/char3" c 42 69 || test_skipped "Can't create char device node u
|
||||
mknod "$fromdir/block" b 42 69 || test_skipped "Can't create block device node unless root"
|
||||
mknod "$fromdir/block2" b 42 73 || test_skipped "Can't create block device node unless root"
|
||||
mknod "$fromdir/block3" b 105 73 || test_skipped "Can't create block device node unless root"
|
||||
mkfifo "$fromdir/fifo" || test_skipped "Can't run mkfifo"
|
||||
|
||||
checkit "$RSYNC -aHvv \"$fromdir/\" \"$todir/\"" "$fromdir" "$todir"
|
||||
|
||||
|
||||
@@ -19,15 +19,12 @@
|
||||
|
||||
# This test is not great, because it is a timing-dependent bug.
|
||||
|
||||
. $srcdir/testsuite/rsync.fns
|
||||
. "$suitedir/rsync.fns"
|
||||
|
||||
set -x
|
||||
|
||||
# Build some hardlinks
|
||||
|
||||
fromdir="$scratchdir/from"
|
||||
todir="$scratchdir/to"
|
||||
|
||||
mkdir "$fromdir"
|
||||
name1="$fromdir/name1"
|
||||
name2="$fromdir/name2"
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
# Test some of the more obscure wildcard handling of exclude/include
|
||||
# processing.
|
||||
|
||||
. $srcdir/testsuite/rsync.fns
|
||||
. "$suitedir/rsync.fns"
|
||||
|
||||
set -x
|
||||
|
||||
@@ -20,33 +20,28 @@ export HOME CVSIGNORE
|
||||
|
||||
# Build some files/dirs/links to copy
|
||||
|
||||
fromdir="$scratchdir/from"
|
||||
todir="$scratchdir/to"
|
||||
chkdir="$scratchdir/chk"
|
||||
|
||||
echo home-cvs-exclude >"$scratchdir"/.cvsignore
|
||||
makepath "$fromdir/foo/down/to/you"
|
||||
makepath "$fromdir/bar/down/to/foo/too"
|
||||
makepath "$fromdir/mid/for/foo/and/that/is/who"
|
||||
echo kept >"$fromdir/foo/file1"
|
||||
echo removed >"$fromdir/foo/file2"
|
||||
echo cvsout >"$fromdir/foo/file2.old"
|
||||
echo cvsout >"$fromdir/bar/down/to/home-cvs-exclude"
|
||||
echo keeper >"$fromdir/bar/down/to/foo/file1"
|
||||
echo cvsout >"$fromdir/bar/down/to/foo/file1.bak"
|
||||
echo gone >"$fromdir/bar/down/to/foo/file3"
|
||||
echo lost >"$fromdir/bar/down/to/foo/file4"
|
||||
echo cvsout >"$fromdir/bar/down/to/foo/file4.junk"
|
||||
echo smashed >"$fromdir/bar/down/to/foo/to"
|
||||
echo cvsout >"$fromdir/bar/down/to/home-cvs-exclude"
|
||||
echo cvsout >"$fromdir/mid/one-in-one-out"
|
||||
echo one-in-one-out >"$fromdir/mid/.cvsignore"
|
||||
echo cvsin >"$fromdir/mid/one-for-all"
|
||||
echo cvsin >"$fromdir/mid/for/one-in-one-out"
|
||||
echo expunged >"$fromdir/mid/for/foo/extra"
|
||||
echo retained >"$fromdir/mid/for/foo/keep"
|
||||
echo cvsin >"$fromdir/mid/for/one-in-one-out"
|
||||
ln -s too "$fromdir/bar/down/to/foo/sym"
|
||||
|
||||
# Setup our test exclude/include file.
|
||||
# Setup our test exclude/include files.
|
||||
|
||||
excl="$scratchdir/exclude-from"
|
||||
cat >"$excl" <<EOF
|
||||
@@ -65,6 +60,10 @@ cat >"$excl" <<EOF
|
||||
- /mid/for/foo/extra
|
||||
EOF
|
||||
|
||||
cat >"$scratchdir/.cvsignore" <<EOF
|
||||
home-cvs-exclude
|
||||
EOF
|
||||
|
||||
# Create the chk dir with what we expect to be excluded
|
||||
|
||||
checkit "$RSYNC -avv \"$fromdir/\" \"$chkdir/\"" "$fromdir" "$chkdir"
|
||||
@@ -83,7 +82,7 @@ $RSYNC -av --existing --include='*/' --exclude='*' "$fromdir/" "$chkdir/"
|
||||
|
||||
# Now, test if rsync excludes the same files.
|
||||
|
||||
checkit "$RSYNC -avv --exclude-from=$excl \"$fromdir/\" \"$todir/\"" "$chkdir" "$todir"
|
||||
checkit "$RSYNC -avv --exclude-from=\"$excl\" \"$fromdir/\" \"$todir/\"" "$chkdir" "$todir"
|
||||
|
||||
# Modify the chk dir by removing cvs-ignored files and then tweaking the dir times.
|
||||
|
||||
@@ -98,8 +97,8 @@ $RSYNC -av --existing --include='*/' --exclude='*' "$fromdir/" "$chkdir/"
|
||||
# Now, test if rsync excludes the same files, this time with --cvs-exclude
|
||||
# and --delete-excluded.
|
||||
|
||||
checkit "$RSYNC -avvC --delete-excluded --exclude-from=$excl \
|
||||
\"$fromdir/\" \"$todir/\"" "$chkdir" "$todir"
|
||||
checkit "$RSYNC -avvC --exclude-from=\"$excl\" \
|
||||
--delete-excluded \"$fromdir/\" \"$todir/\"" "$chkdir" "$todir"
|
||||
|
||||
# The script would have aborted on error, so getting here means we've won.
|
||||
exit 0
|
||||
|
||||
@@ -11,19 +11,19 @@ hands_setup
|
||||
|
||||
# Main script starts here
|
||||
|
||||
runtest "basic operation" 'checkit "$RSYNC -av ${FROM}/ ${TO}" ${FROM}/ ${TO}'
|
||||
runtest "basic operation" 'checkit "$RSYNC -av \"$fromdir/\" \"$todir\"" "$fromdir/" "$todir"'
|
||||
|
||||
ln ${FROM}/filelist ${FROM}/dir
|
||||
runtest "hard links" 'checkit "$RSYNC -avH ${FROM}/ ${TO}" ${FROM}/ ${TO}'
|
||||
ln "$fromdir/filelist" "$fromdir/dir"
|
||||
runtest "hard links" 'checkit "$RSYNC -avH \"$fromdir/\" \"$todir\"" "$fromdir/" "$todir"'
|
||||
|
||||
rm ${TO}/text
|
||||
runtest "one file" 'checkit "$RSYNC -avH ${FROM}/ ${TO}" ${FROM}/ ${TO}'
|
||||
rm "$todir/text"
|
||||
runtest "one file" 'checkit "$RSYNC -avH \"$fromdir/\" \"$todir\"" "$fromdir/" "$todir"'
|
||||
|
||||
echo "extra line" >> ${TO}/text
|
||||
runtest "extra data" 'checkit "$RSYNC -avH ${FROM}/ ${TO}" ${FROM}/ ${TO}'
|
||||
echo "extra line" >> "$todir/text"
|
||||
runtest "extra data" 'checkit "$RSYNC -avH \"$fromdir/\" \"$todir\"" "$fromdir/" "$todir"'
|
||||
|
||||
cp ${FROM}/text ${TO}/ThisShouldGo
|
||||
runtest " --delete" 'checkit "$RSYNC --delete -avH ${FROM}/ ${TO}" ${FROM}/ ${TO}'
|
||||
cp "$fromdir/text" "$todir/ThisShouldGo"
|
||||
runtest " --delete" 'checkit "$RSYNC --delete -avH \"$fromdir/\" \"$todir\"" "$fromdir/" "$todir"'
|
||||
|
||||
# The script would have aborted on error, so getting here means we've won.
|
||||
exit 0
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
# specify -H, then hard links are detected and recreated as hardlinks
|
||||
# on the other end.
|
||||
|
||||
. $srcdir/testsuite/rsync.fns
|
||||
. "$suitedir/rsync.fns"
|
||||
|
||||
set -x
|
||||
|
||||
|
||||
@@ -11,14 +11,14 @@
|
||||
|
||||
hands_setup
|
||||
|
||||
LONGNAME=This-is-a-directory-with-a-stupidly-long-name-created-in-an-attempt-to-provoke-an-error-found-in-2.0.11-that-should-hopefully-never-appear-again-if-this-test-does-its-job
|
||||
LONGDIR=$FROM/$LONGNAME/$LONGNAME/$LONGNAME
|
||||
longname=This-is-a-directory-with-a-stupidly-long-name-created-in-an-attempt-to-provoke-an-error-found-in-2.0.11-that-should-hopefully-never-appear-again-if-this-test-does-its-job
|
||||
longdir="$fromdir/$longname/$longname/$longname"
|
||||
|
||||
makepath $LONGDIR || test_skipped "unable to create long directory"
|
||||
touch $LONGDIR/1 || test_skipped "unable to create files in long directory"
|
||||
date > ${LONGDIR}/1
|
||||
ls -la / > ${LONGDIR}/2
|
||||
checkit "$RSYNC --delete -avH ${FROM}/ ${TO}" ${FROM}/ ${TO}
|
||||
makepath "$longdir" || test_skipped "unable to create long directory"
|
||||
touch "$longdir/1" || test_skipped "unable to create files in long directory"
|
||||
date > "$longdir/1"
|
||||
ls -la / > "$longdir/2"
|
||||
checkit "$RSYNC --delete -avH \"$fromdir/\" \"$todir\"" "$fromdir/" "$todir"
|
||||
|
||||
# The script would have aborted on error, so getting here means we've won.
|
||||
exit 0
|
||||
|
||||
@@ -7,18 +7,15 @@
|
||||
|
||||
# Make sure we can merge files from multiple directories into one.
|
||||
|
||||
. $srcdir/testsuite/rsync.fns
|
||||
. "$suitedir/rsync.fns"
|
||||
|
||||
set -x
|
||||
|
||||
# Build some files/dirs/links to copy
|
||||
|
||||
fromdir="$scratchdir/from"
|
||||
from1dir="${fromdir}1"
|
||||
from2dir="${fromdir}2"
|
||||
from3dir="${fromdir}3"
|
||||
todir="$scratchdir/to"
|
||||
chkdir="$scratchdir/chk"
|
||||
|
||||
mkdir "$from1dir" "$from2dir" "$from3dir"
|
||||
mkdir "$from2dir"/sub1 "$from3dir"/sub1
|
||||
@@ -43,9 +40,9 @@ cp -p "$from2dir"/sub1/uno "$from3dir"/sub1/dos "$from2dir"/sub1/tres "$chkdir"/
|
||||
cp -p "$from3dir"/sub2/subby "$chkdir"/sub2
|
||||
|
||||
# Get rid of any directory-time differences
|
||||
touch "$fromdir"? "$chkdir" "$fromdir"?/sub? "$chkdir"/sub?
|
||||
$RSYNC -av --existing --include='*/' --exclude='*' "$from1dir/" "$from2dir/" "$from3dir/" "$chkdir/"
|
||||
|
||||
checkit "$RSYNC -aHvv \"$fromdir\"?/ \"$todir/\"" "$chkdir" "$todir"
|
||||
checkit "$RSYNC -aHvv \"$from1dir/\" \"$from2dir/\" \"$from3dir/\" \"$todir/\"" "$chkdir" "$todir"
|
||||
|
||||
# The script would have aborted on error, so getting here means we've won.
|
||||
exit 0
|
||||
|
||||
@@ -18,16 +18,15 @@
|
||||
# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
|
||||
|
||||
TMP="$scratchdir"
|
||||
FROM=${TMP}/from
|
||||
TO=${TMP}/to
|
||||
LOG=${TMP}/log
|
||||
RSYNC="$rsync_bin"
|
||||
tmpdir="$scratchdir"
|
||||
fromdir="$tmpdir/from"
|
||||
todir="$tmpdir/to"
|
||||
chkdir="$tmpdir/chk"
|
||||
|
||||
# Berkley's nice.
|
||||
PATH="$PATH:/usr/ucb"
|
||||
|
||||
if diff -u $srcdir/testsuite/rsync.fns $srcdir/testsuite/rsync.fns >/dev/null 2>&1; then
|
||||
if diff -u "$srcdir/testsuite/rsync.fns" "$srcdir/testsuite/rsync.fns" >/dev/null 2>&1; then
|
||||
diffopt="-u"
|
||||
else
|
||||
diffopt="-c"
|
||||
@@ -37,10 +36,10 @@ runtest() {
|
||||
echo $ECHO_N "Test $1: $ECHO_C"
|
||||
if eval "$2"
|
||||
then
|
||||
echo "${ECHO_T} done."
|
||||
echo "$ECHO_T done."
|
||||
return 0
|
||||
else
|
||||
echo "${ECHO_T} failed!"
|
||||
echo "$ECHO_T failed!"
|
||||
return 1
|
||||
fi
|
||||
}
|
||||
@@ -60,16 +59,16 @@ rsync_getgroups() {
|
||||
|
||||
|
||||
####################
|
||||
# Build test directories TO and FROM, with FROM full of files.
|
||||
# Build test directories $todir and $fromdir, with $fromdir full of files.
|
||||
|
||||
hands_setup() {
|
||||
# Clean before creation
|
||||
rm -rf $FROM
|
||||
rm -rf $TO
|
||||
rm -rf "$fromdir"
|
||||
rm -rf "$todir"
|
||||
|
||||
[ -d $TMP ] || mkdir $TMP
|
||||
[ -d $FROM ] || mkdir $FROM
|
||||
[ -d $TO ] || mkdir $TO
|
||||
[ -d "$tmpdir" ] || mkdir "$tmpdir"
|
||||
[ -d "$fromdir" ] || mkdir "$fromdir"
|
||||
[ -d "$todir" ] || mkdir "$todir"
|
||||
|
||||
# On some BSD systems, the umask affects the mode of created
|
||||
# symlinks, even though the mode apparently has no effect on how
|
||||
@@ -82,29 +81,37 @@ hands_setup() {
|
||||
# the same. So, we need to set our umask before doing any creations.
|
||||
|
||||
# set up test data
|
||||
touch ${FROM}/empty
|
||||
mkdir ${FROM}/emptydir
|
||||
touch "$fromdir/empty"
|
||||
mkdir "$fromdir/emptydir"
|
||||
|
||||
# a hundred lines of text or so
|
||||
rsync_ls_lR "${srcdir}" > ${FROM}/filelist
|
||||
rsync_ls_lR "$srcdir" > "$fromdir/filelist"
|
||||
|
||||
# This might fail on systems that don't have -n
|
||||
echo $ECHO_N "This file has no trailing lf$ECHO_C" > ${FROM}/nolf
|
||||
echo $ECHO_N "This file has no trailing lf$ECHO_C" > "$fromdir/nolf"
|
||||
umask 0
|
||||
ln -s nolf ${FROM}/nolf-symlink
|
||||
ln -s nolf "$fromdir/nolf-symlink"
|
||||
umask 022
|
||||
|
||||
cat $srcdir/*.c > ${FROM}/text
|
||||
mkdir ${FROM}/dir
|
||||
cp ${FROM}/text ${FROM}/dir
|
||||
mkdir ${FROM}/dir/subdir
|
||||
mkdir ${FROM}/dir/subdir/subsubdir
|
||||
ls -ltr /etc > ${FROM}/dir/subdir/subsubdir/etc-ltr-list
|
||||
mkdir ${FROM}/dir/subdir/subsubdir2
|
||||
ls -lt /bin > ${FROM}/dir/subdir/subsubdir2/bin-lt-list
|
||||
cat $srcdir/*.c > "$fromdir/text"
|
||||
mkdir "$fromdir/dir"
|
||||
cp "$fromdir/text" "$fromdir/dir"
|
||||
mkdir "$fromdir/dir/subdir"
|
||||
echo some data > "$fromdir/dir/subdir/foobar.baz"
|
||||
mkdir "$fromdir/dir/subdir/subsubdir"
|
||||
if [ -r /etc ]; then
|
||||
ls -ltr /etc > "$fromdir/dir/subdir/subsubdir/etc-ltr-list"
|
||||
else
|
||||
ls -ltr / > "$fromdir/dir/subdir/subsubdir/etc-ltr-list"
|
||||
fi
|
||||
mkdir "$fromdir/dir/subdir/subsubdir2"
|
||||
if [ -r /bin ]; then
|
||||
ls -lt /bin > "$fromdir/dir/subdir/subsubdir2/bin-lt-list"
|
||||
else
|
||||
ls -lt / > "$fromdir/dir/subdir/subsubdir2/bin-lt-list"
|
||||
fi
|
||||
|
||||
# echo testing head:
|
||||
# ls -lR ${srcdir} | head -10 || echo failed
|
||||
# ls -lR "$srcdir" | head -10 || echo failed
|
||||
}
|
||||
|
||||
|
||||
@@ -169,10 +176,10 @@ checkit() {
|
||||
echo "-------------"
|
||||
echo "check how the directory listings compare with diff:"
|
||||
echo ""
|
||||
( cd "$2" && rsync_ls_lR . ) > ${TMP}/ls-from
|
||||
( cd "$3" && rsync_ls_lR . ) > ${TMP}/ls-to
|
||||
diff $diffopt ${TMP}/ls-from ${TMP}/ls-to || failed=YES
|
||||
if [ -z "${failed}" ] ; then
|
||||
( cd "$2" && rsync_ls_lR . ) > "$tmpdir/ls-from"
|
||||
( cd "$3" && rsync_ls_lR . ) > "$tmpdir/ls-to"
|
||||
diff $diffopt "$tmpdir/ls-from" "$tmpdir/ls-to" || failed=YES
|
||||
if [ -z "$failed" ] ; then
|
||||
return 0
|
||||
else
|
||||
return 1
|
||||
@@ -189,32 +196,31 @@ build_rsyncd_conf() {
|
||||
pidfile="$scratchdir/rsyncd.pid"
|
||||
logfile="$scratchdir/rsyncd.log"
|
||||
|
||||
cat >$conf <<EOF
|
||||
cat >"$conf" <<EOF
|
||||
# rsyncd configuration file autogenerated by $0
|
||||
|
||||
pid file = $pidfile
|
||||
use chroot = no
|
||||
hosts allow = localhost, 127.0.0.1
|
||||
log file = $logfile
|
||||
exclude = foobar.baz
|
||||
max verbosity = 9
|
||||
|
||||
uid = 0
|
||||
gid = 0
|
||||
|
||||
[test-from]
|
||||
path = $FROM
|
||||
path = $fromdir
|
||||
read only = yes
|
||||
|
||||
[test-to]
|
||||
path = $TO
|
||||
path = $todir
|
||||
read only = no
|
||||
EOF
|
||||
}
|
||||
|
||||
|
||||
build_symlinks() {
|
||||
fromdir="$scratchdir/from"
|
||||
todir="$scratchdir/to"
|
||||
mkdir "$fromdir"
|
||||
date >"$fromdir/referent"
|
||||
ln -s referent "$fromdir/relative"
|
||||
@@ -230,7 +236,7 @@ test_fail() {
|
||||
|
||||
test_skipped() {
|
||||
echo "$@" >&2
|
||||
echo "$@" > "$TMP/whyskipped"
|
||||
echo "$@" > "$tmpdir/whyskipped"
|
||||
exit 77
|
||||
}
|
||||
|
||||
|
||||
@@ -24,11 +24,11 @@ if ! [ "`ssh -o'BatchMode yes' localhost echo yes`" = "yes" ]; then
|
||||
fi
|
||||
|
||||
# Added by Steve Bonds Feb 2 2003
|
||||
# Without this, there are no files in the ${FROM} directory, so rsync has
|
||||
# Without this, there are no files in the $fromdir directory, so rsync has
|
||||
# nothing to do.
|
||||
hands_setup
|
||||
|
||||
runtest "ssh: basic test" 'checkit "$RSYNC -avH -e ssh --rsync-path=$RSYNC ${FROM}/ localhost:${TO}" ${FROM}/ ${TO}'
|
||||
runtest "ssh: basic test" 'checkit "$RSYNC -avH -e ssh --rsync-path=$RSYNC \"$fromdir/\" \"localhost:$todir\"" "$fromdir/" "$todir"'
|
||||
|
||||
# Added by Steve Bonds Feb 2 2003
|
||||
# I assumed that "F1" was intended to hold a single file for testing if
|
||||
@@ -36,8 +36,8 @@ runtest "ssh: basic test" 'checkit "$RSYNC -avH -e ssh --rsync-path=$RSYNC ${FRO
|
||||
# it was unset so the "mv" tried to move a parent directory into a
|
||||
# subdirectory of itself. There is probably a better way of pulling out
|
||||
# a sample file to rename.
|
||||
F1=`ls ${TO} | head -5 | tail -1`
|
||||
F1=`ls "$todir" | head -5 | tail -1`
|
||||
|
||||
mv ${TO}/${F1} ${TO}/ThisShouldGo
|
||||
mv "$todir/$F1" "$todir/ThisShouldGo"
|
||||
|
||||
runtest "ssh: renamed file" 'checkit "$RSYNC --delete -avH -e ssh --rsync-path=$RSYNC ${FROM}/ localhost:${TO}" ${FROM}/ ${TO}'
|
||||
runtest "ssh: renamed file" 'checkit "$RSYNC --delete -avH -e ssh --rsync-path=$RSYNC \"$fromdir/\" \"localhost:$todir\"" "$fromdir/" "$todir"'
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
# Test rsync's somewhat over-featured symlink control: the default
|
||||
# behaviour is that symlinks should not be copied at all.
|
||||
|
||||
. $srcdir/testsuite/rsync.fns
|
||||
. "$suitedir/rsync.fns"
|
||||
|
||||
set -x
|
||||
|
||||
@@ -18,19 +18,19 @@ build_symlinks || test_fail "failed to build symlinks"
|
||||
# should be missing.
|
||||
$RSYNC -r "$fromdir/" "$todir" || test_fail "$RSYNC returned $?"
|
||||
|
||||
[ -f "${todir}/referent" ] || test_fail "referent was not copied"
|
||||
[ -d "${todir}/from" ] && test_fail "extra level of directories"
|
||||
if is_a_link "${todir}/dangling"
|
||||
[ -f "$todir/referent" ] || test_fail "referent was not copied"
|
||||
[ -d "$todir/from" ] && test_fail "extra level of directories"
|
||||
if is_a_link "$todir/dangling"
|
||||
then
|
||||
test_fail "dangling symlink was copied"
|
||||
fi
|
||||
|
||||
if is_a_link "${todir}/relative"
|
||||
if is_a_link "$todir/relative"
|
||||
then
|
||||
test_fail "relative symlink was copied"
|
||||
fi
|
||||
|
||||
if is_a_link "${todir}/absolute"
|
||||
if is_a_link "$todir/absolute"
|
||||
then
|
||||
test_fail "absolute symlink was copied"
|
||||
fi
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
|
||||
# Test tiny function to trim trailing slashes.
|
||||
|
||||
. $srcdir/testsuite/rsync.fns
|
||||
. "$suitedir/rsync.fns"
|
||||
|
||||
set -x
|
||||
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
|
||||
# Call directly into unsafe_symlink and test its handling of various filenames
|
||||
|
||||
. $srcdir/testsuite/rsync.fns
|
||||
. "$suitedir/rsync.fns"
|
||||
|
||||
test_unsafe() {
|
||||
# $1 is the target of a symlink
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
# Originally by Vladim<69>r Michl <Vladimir.Michl@hlubocky.del.cz>
|
||||
|
||||
. $srcdir/testsuite/rsync.fns
|
||||
. "$suitedir/rsync.fns"
|
||||
|
||||
test_symlink() {
|
||||
is_a_link "$1" || test_fail "File $1 is not a symlink"
|
||||
@@ -14,7 +14,7 @@ test_regular() {
|
||||
fi;
|
||||
};
|
||||
|
||||
cd "$TMP"
|
||||
cd "$tmpdir"
|
||||
|
||||
mkdir from
|
||||
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
|
||||
# Test the wildmatch functionality
|
||||
|
||||
. $srcdir/testsuite/rsync.fns
|
||||
. "$suitedir/rsync.fns"
|
||||
|
||||
set -x
|
||||
|
||||
|
||||
21
tls.c
21
tls.c
@@ -49,17 +49,16 @@ int list_only = 0;
|
||||
int preserve_perms = 0;
|
||||
|
||||
|
||||
static void failed (char const *what,
|
||||
char const *where)
|
||||
static void failed(char const *what, char const *where)
|
||||
{
|
||||
fprintf (stderr, PROGRAM ": %s %s: %s\n",
|
||||
what, where, strerror (errno));
|
||||
exit (1);
|
||||
fprintf(stderr, PROGRAM ": %s %s: %s\n",
|
||||
what, where, strerror(errno));
|
||||
exit(1);
|
||||
}
|
||||
|
||||
|
||||
|
||||
static void list_file (const char *fname)
|
||||
static void list_file(const char *fname)
|
||||
{
|
||||
STRUCT_STAT buf;
|
||||
char permbuf[PERMSTRING_SIZE];
|
||||
@@ -68,7 +67,7 @@ static void list_file (const char *fname)
|
||||
char linkbuf[4096];
|
||||
|
||||
if (do_lstat(fname, &buf) == -1)
|
||||
failed ("stat", fname);
|
||||
failed("stat", fname);
|
||||
|
||||
/* The size of anything but a regular file is probably not
|
||||
* worth thinking about. */
|
||||
@@ -114,7 +113,7 @@ static void list_file (const char *fname)
|
||||
/* TODO: Perhaps escape special characters in fname? */
|
||||
|
||||
printf("%s ", permbuf);
|
||||
if (IS_DEVICE(buf.st_mode)) {
|
||||
if (S_ISCHR(buf.st_mode) || S_ISBLK(buf.st_mode)) {
|
||||
printf("%5ld,%6ld",
|
||||
(long)major(buf.st_rdev),
|
||||
(long)minor(buf.st_rdev));
|
||||
@@ -130,13 +129,13 @@ int
|
||||
main(int argc, char *argv[])
|
||||
{
|
||||
if (argc < 2) {
|
||||
fprintf (stderr, "usage: " PROGRAM " DIR ...\n"
|
||||
"Trivial file listing program for portably checking rsync\n");
|
||||
fprintf(stderr, "usage: " PROGRAM " DIR ...\n"
|
||||
"Trivial file listing program for portably checking rsync\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
for (argv++; *argv; argv++) {
|
||||
list_file (*argv);
|
||||
list_file(*argv);
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
67
token.c
67
token.c
@@ -1,17 +1,17 @@
|
||||
/*
|
||||
/*
|
||||
Copyright (C) Andrew Tridgell 1996
|
||||
Copyright (C) Paul Mackerras 1996
|
||||
|
||||
|
||||
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 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
@@ -21,23 +21,26 @@
|
||||
#include "zlib/zlib.h"
|
||||
|
||||
extern int do_compression;
|
||||
extern int module_id;
|
||||
|
||||
static int compression_level = Z_DEFAULT_COMPRESSION;
|
||||
|
||||
/* determine the compression level based on a wildcard filename list */
|
||||
void set_compression(char *fname)
|
||||
{
|
||||
extern int module_id;
|
||||
char *dont;
|
||||
char *tok;
|
||||
|
||||
if (!do_compression) return;
|
||||
if (!do_compression)
|
||||
return;
|
||||
|
||||
compression_level = Z_DEFAULT_COMPRESSION;
|
||||
dont = lp_dont_compress(module_id);
|
||||
|
||||
if (!dont || !*dont) return;
|
||||
if (!dont || !*dont)
|
||||
return;
|
||||
|
||||
if ((dont[0] == '*') && (!dont[1])) {
|
||||
if (dont[0] == '*' && !dont[1]) {
|
||||
/* an optimization to skip the rest of this routine */
|
||||
compression_level = 0;
|
||||
return;
|
||||
@@ -45,12 +48,13 @@ void set_compression(char *fname)
|
||||
|
||||
dont = strdup(dont);
|
||||
fname = strdup(fname);
|
||||
if (!dont || !fname) return;
|
||||
if (!dont || !fname)
|
||||
return;
|
||||
|
||||
strlower(dont);
|
||||
strlower(fname);
|
||||
|
||||
for (tok=strtok(dont," ");tok;tok=strtok(NULL," ")) {
|
||||
for (tok = strtok(dont, " "); tok; tok = strtok(NULL, " ")) {
|
||||
if (wildmatch(tok, fname)) {
|
||||
compression_level = 0;
|
||||
break;
|
||||
@@ -69,12 +73,14 @@ static int simple_recv_token(int f,char **data)
|
||||
|
||||
if (!buf) {
|
||||
buf = new_array(char, CHUNK_SIZE);
|
||||
if (!buf) out_of_memory("simple_recv_token");
|
||||
if (!buf)
|
||||
out_of_memory("simple_recv_token");
|
||||
}
|
||||
|
||||
if (residue == 0) {
|
||||
int i = read_int(f);
|
||||
if (i <= 0) return i;
|
||||
if (i <= 0)
|
||||
return i;
|
||||
residue = i;
|
||||
}
|
||||
|
||||
@@ -90,29 +96,18 @@ static int simple_recv_token(int f,char **data)
|
||||
static void simple_send_token(int f,int token,
|
||||
struct map_struct *buf,OFF_T offset,int n)
|
||||
{
|
||||
extern int write_batch;
|
||||
int hold_int;
|
||||
|
||||
if (n > 0) {
|
||||
int l = 0;
|
||||
while (l < n) {
|
||||
int n1 = MIN(CHUNK_SIZE,n-l);
|
||||
write_int(f,n1);
|
||||
write_buf(f,map_ptr(buf,offset+l,n1),n1);
|
||||
if (write_batch) {
|
||||
write_batch_delta_file( (char *) &n1, sizeof(int) );
|
||||
write_batch_delta_file(map_ptr(buf,offset+l,n1),n1);
|
||||
}
|
||||
l += n1;
|
||||
}
|
||||
}
|
||||
/* a -2 token means to send data only and no token */
|
||||
if (token != -2) {
|
||||
write_int(f,-(token+1));
|
||||
if (write_batch) {
|
||||
hold_int = -(token+1);
|
||||
write_batch_delta_file( (char *) &hold_int, sizeof(int) );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -159,8 +154,6 @@ send_deflated_token(int f, int token,
|
||||
{
|
||||
int n, r;
|
||||
static int init_done, flush_pending;
|
||||
extern int write_batch;
|
||||
char temp_byte;
|
||||
|
||||
if (last_token == -1) {
|
||||
/* initialization */
|
||||
@@ -193,28 +186,13 @@ send_deflated_token(int f, int token,
|
||||
n = last_token - run_start;
|
||||
if (r >= 0 && r <= 63) {
|
||||
write_byte(f, (n==0? TOKEN_REL: TOKENRUN_REL) + r);
|
||||
if (write_batch) {
|
||||
temp_byte = (char)( (n==0? TOKEN_REL: TOKENRUN_REL) + r);
|
||||
write_batch_delta_file(&temp_byte,sizeof(char));
|
||||
}
|
||||
} else {
|
||||
write_byte(f, (n==0? TOKEN_LONG: TOKENRUN_LONG));
|
||||
write_int(f, run_start);
|
||||
if (write_batch) {
|
||||
temp_byte = (char)(n==0? TOKEN_LONG: TOKENRUN_LONG);
|
||||
write_batch_delta_file(&temp_byte,sizeof(char));
|
||||
write_batch_delta_file((char *)&run_start,sizeof(run_start));
|
||||
}
|
||||
}
|
||||
if (n != 0) {
|
||||
write_byte(f, n);
|
||||
write_byte(f, n >> 8);
|
||||
if (write_batch) {
|
||||
temp_byte = (char)n;
|
||||
write_batch_delta_file(&temp_byte,sizeof(char));
|
||||
temp_byte = (char)(n >> 8);
|
||||
write_batch_delta_file(&temp_byte,sizeof(char));
|
||||
}
|
||||
}
|
||||
last_run_end = last_token;
|
||||
run_start = token;
|
||||
@@ -273,8 +251,6 @@ send_deflated_token(int f, int token,
|
||||
obuf[0] = DEFLATED_DATA + (n >> 8);
|
||||
obuf[1] = n;
|
||||
write_buf(f, obuf, n+2);
|
||||
if (write_batch)
|
||||
write_batch_delta_file(obuf,n+2);
|
||||
}
|
||||
}
|
||||
} while (nb != 0 || tx_strm.avail_out == 0);
|
||||
@@ -284,11 +260,6 @@ send_deflated_token(int f, int token,
|
||||
if (token == -1) {
|
||||
/* end of file - clean up */
|
||||
write_byte(f, END_FLAG);
|
||||
if (write_batch) {
|
||||
temp_byte = END_FLAG;
|
||||
write_batch_delta_file(&temp_byte,sizeof(char));
|
||||
}
|
||||
|
||||
} else if (token != -2) {
|
||||
/* add the data in the current block to the compressor's
|
||||
history and hash table */
|
||||
@@ -491,7 +462,7 @@ static void see_deflate_token(char *buf, int len)
|
||||
|
||||
/**
|
||||
* Transmit a verbatim buffer of length @p n followed by a token.
|
||||
* If token == -1 then we have reached EOF
|
||||
* If token == -1 then we have reached EOF
|
||||
* If n == 0 then don't send a buffer
|
||||
*/
|
||||
void send_token(int f,int token,struct map_struct *buf,OFF_T offset,
|
||||
|
||||
@@ -81,7 +81,7 @@ static char *gid_to_name(gid_t gid)
|
||||
static int map_uid(int id, char *name)
|
||||
{
|
||||
uid_t uid;
|
||||
if (uid != 0 && name_to_uid(name, &uid))
|
||||
if (id != 0 && name_to_uid(name, &uid))
|
||||
return uid;
|
||||
return id;
|
||||
}
|
||||
@@ -89,7 +89,7 @@ static int map_uid(int id, char *name)
|
||||
static int map_gid(int id, char *name)
|
||||
{
|
||||
gid_t gid;
|
||||
if (gid != 0 && name_to_gid(name, &gid))
|
||||
if (id != 0 && name_to_gid(name, &gid))
|
||||
return gid;
|
||||
return id;
|
||||
}
|
||||
@@ -161,7 +161,7 @@ static struct idlist *recv_add_uid(int id, char *name)
|
||||
int id2 = name ? map_uid(id, name) : id;
|
||||
struct idlist *node;
|
||||
|
||||
node = add_to_list(&uidlist, id, name, map_uid(id, name));
|
||||
node = add_to_list(&uidlist, id, name, id2);
|
||||
|
||||
if (verbose > 3) {
|
||||
rprintf(FINFO, "uid %d(%s) maps to %d\n",
|
||||
|
||||
516
util.c
516
util.c
@@ -28,6 +28,10 @@
|
||||
#include "rsync.h"
|
||||
|
||||
extern int verbose;
|
||||
extern int dry_run;
|
||||
extern int module_id;
|
||||
extern int modify_window;
|
||||
extern char *partial_dir;
|
||||
extern struct exclude_list_struct server_exclude_list;
|
||||
|
||||
int sanitize_paths = 0;
|
||||
@@ -126,13 +130,12 @@ void overflow(char *str)
|
||||
|
||||
int set_modtime(char *fname, time_t modtime)
|
||||
{
|
||||
extern int dry_run;
|
||||
if (dry_run)
|
||||
return 0;
|
||||
|
||||
if (verbose > 2) {
|
||||
rprintf(FINFO, "set modtime of %s to (%ld) %s",
|
||||
fname, (long) modtime,
|
||||
fname, (long)modtime,
|
||||
asctime(localtime(&modtime)));
|
||||
}
|
||||
|
||||
@@ -194,7 +197,7 @@ int create_directory_path(char *fname, int base_umask)
|
||||
*
|
||||
* Derived from GNU C's cccp.c.
|
||||
*/
|
||||
static int full_write(int desc, char *ptr, size_t len)
|
||||
int full_write(int desc, char *ptr, size_t len)
|
||||
{
|
||||
int total_written;
|
||||
|
||||
@@ -242,7 +245,7 @@ static int safe_read(int desc, char *ptr, size_t len)
|
||||
|
||||
/** Copy a file.
|
||||
*
|
||||
* This is used in conjunction with the --temp-dir option */
|
||||
* This is used in conjunction with the --temp-dir and --backup options */
|
||||
int copy_file(char *source, char *dest, mode_t mode)
|
||||
{
|
||||
int ifd;
|
||||
@@ -252,41 +255,46 @@ int copy_file(char *source, char *dest, mode_t mode)
|
||||
|
||||
ifd = do_open(source, O_RDONLY, 0);
|
||||
if (ifd == -1) {
|
||||
rprintf(FERROR,"open %s: %s\n",
|
||||
source,strerror(errno));
|
||||
rsyserr(FERROR, errno, "open %s", full_fname(source));
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (robust_unlink(dest) && errno != ENOENT) {
|
||||
rprintf(FERROR,"unlink %s: %s\n",
|
||||
dest,strerror(errno));
|
||||
rsyserr(FERROR, errno, "unlink %s", full_fname(dest));
|
||||
return -1;
|
||||
}
|
||||
|
||||
ofd = do_open(dest, O_WRONLY | O_CREAT | O_TRUNC | O_EXCL, mode);
|
||||
if (ofd == -1) {
|
||||
rprintf(FERROR,"open %s: %s\n",
|
||||
dest,strerror(errno));
|
||||
rsyserr(FERROR, errno, "open %s", full_fname(dest));
|
||||
close(ifd);
|
||||
return -1;
|
||||
}
|
||||
|
||||
while ((len = safe_read(ifd, buf, sizeof buf)) > 0) {
|
||||
if (full_write(ofd, buf, len) < 0) {
|
||||
rprintf(FERROR,"write %s: %s\n",
|
||||
dest,strerror(errno));
|
||||
rsyserr(FERROR, errno, "write %s", full_fname(dest));
|
||||
close(ifd);
|
||||
close(ofd);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
close(ifd);
|
||||
close(ofd);
|
||||
|
||||
if (len < 0) {
|
||||
rprintf(FERROR,"read %s: %s\n",
|
||||
source,strerror(errno));
|
||||
rsyserr(FERROR, errno, "read %s", full_fname(source));
|
||||
close(ifd);
|
||||
close(ofd);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (close(ifd) < 0) {
|
||||
rsyserr(FINFO, errno, "close failed on %s",
|
||||
full_fname(source));
|
||||
}
|
||||
|
||||
if (close(ofd) < 0) {
|
||||
rsyserr(FERROR, errno, "close failed on %s",
|
||||
full_fname(dest));
|
||||
return -1;
|
||||
}
|
||||
|
||||
@@ -354,8 +362,8 @@ int robust_unlink(char *fname)
|
||||
#endif
|
||||
}
|
||||
|
||||
/* Returns 0 on success, -1 on most errors, and -2 if we got an error
|
||||
* trying to copy the file across file systems. */
|
||||
/* Returns 0 on successful rename, 1 if we successfully copied the file
|
||||
* across filesystems, -2 if copy_file() failed, and -1 on other errors. */
|
||||
int robust_rename(char *from, char *to, int mode)
|
||||
{
|
||||
int tries = 4;
|
||||
@@ -375,7 +383,7 @@ int robust_rename(char *from, char *to, int mode)
|
||||
if (copy_file(from, to, mode) != 0)
|
||||
return -2;
|
||||
do_unlink(from);
|
||||
return 0;
|
||||
return 1;
|
||||
default:
|
||||
return -1;
|
||||
}
|
||||
@@ -432,7 +440,8 @@ void kill_all(int sig)
|
||||
int name_to_uid(char *name, uid_t *uid)
|
||||
{
|
||||
struct passwd *pass;
|
||||
if (!name || !*name) return 0;
|
||||
if (!name || !*name)
|
||||
return 0;
|
||||
pass = getpwnam(name);
|
||||
if (pass) {
|
||||
*uid = pass->pw_uid;
|
||||
@@ -445,7 +454,8 @@ int name_to_uid(char *name, uid_t *uid)
|
||||
int name_to_gid(char *name, gid_t *gid)
|
||||
{
|
||||
struct group *grp;
|
||||
if (!name || !*name) return 0;
|
||||
if (!name || !*name)
|
||||
return 0;
|
||||
grp = getgrnam(name);
|
||||
if (grp) {
|
||||
*gid = grp->gr_gid;
|
||||
@@ -486,75 +496,92 @@ static int exclude_server_path(char *arg)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void glob_expand_one(char *s, char **argv, int *argc, int maxargs)
|
||||
static void glob_expand_one(char *s, char ***argv_ptr, int *argc_ptr,
|
||||
int *maxargs_ptr)
|
||||
{
|
||||
char **argv = *argv_ptr;
|
||||
int argc = *argc_ptr;
|
||||
int maxargs = *maxargs_ptr;
|
||||
#if !(defined(HAVE_GLOB) && defined(HAVE_GLOB_H))
|
||||
if (!*s) s = ".";
|
||||
s = argv[*argc] = strdup(s);
|
||||
if (argc == maxargs) {
|
||||
maxargs += MAX_ARGS;
|
||||
if (!(argv = realloc_array(argv, char *, maxargs)))
|
||||
out_of_memory("glob_expand_one");
|
||||
*argv_ptr = argv;
|
||||
*maxargs_ptr = maxargs;
|
||||
}
|
||||
if (!*s)
|
||||
s = ".";
|
||||
s = argv[argc++] = strdup(s);
|
||||
exclude_server_path(s);
|
||||
(*argc)++;
|
||||
#else
|
||||
extern int sanitize_paths;
|
||||
glob_t globbuf;
|
||||
int i;
|
||||
|
||||
if (!*s) s = ".";
|
||||
if (maxargs <= argc)
|
||||
return;
|
||||
if (!*s)
|
||||
s = ".";
|
||||
|
||||
s = argv[*argc] = strdup(s);
|
||||
if (sanitize_paths) {
|
||||
sanitize_path(s, NULL);
|
||||
}
|
||||
if (sanitize_paths)
|
||||
s = sanitize_path(NULL, s, "", 0);
|
||||
else
|
||||
s = strdup(s);
|
||||
|
||||
memset(&globbuf, 0, sizeof globbuf);
|
||||
if (!exclude_server_path(s))
|
||||
glob(s, 0, NULL, &globbuf);
|
||||
if (globbuf.gl_pathc == 0) {
|
||||
(*argc)++;
|
||||
globfree(&globbuf);
|
||||
return;
|
||||
if (MAX((int)globbuf.gl_pathc, 1) > maxargs - argc) {
|
||||
maxargs += globbuf.gl_pathc + MAX_ARGS;
|
||||
if (!(argv = realloc_array(argv, char *, maxargs)))
|
||||
out_of_memory("glob_expand_one");
|
||||
*argv_ptr = argv;
|
||||
*maxargs_ptr = maxargs;
|
||||
}
|
||||
for (i = 0; i < maxargs - *argc && i < (int)globbuf.gl_pathc; i++) {
|
||||
if (i == 0)
|
||||
free(s);
|
||||
argv[*argc + i] = strdup(globbuf.gl_pathv[i]);
|
||||
if (!argv[*argc + i])
|
||||
out_of_memory("glob_expand");
|
||||
if (globbuf.gl_pathc == 0)
|
||||
argv[argc++] = s;
|
||||
else {
|
||||
int j = globbuf.gl_pathc;
|
||||
free(s);
|
||||
for (i = 0; i < j; i++) {
|
||||
if (!(argv[argc++] = strdup(globbuf.gl_pathv[i])))
|
||||
out_of_memory("glob_expand_one");
|
||||
}
|
||||
}
|
||||
globfree(&globbuf);
|
||||
*argc += i;
|
||||
#endif
|
||||
*argc_ptr = argc;
|
||||
}
|
||||
|
||||
/* This routine is only used in daemon mode. */
|
||||
void glob_expand(char *base1, char **argv, int *argc, int maxargs)
|
||||
void glob_expand(char *base1, char ***argv_ptr, int *argc_ptr, int *maxargs_ptr)
|
||||
{
|
||||
char *s = argv[*argc];
|
||||
char *s = (*argv_ptr)[*argc_ptr];
|
||||
char *p, *q;
|
||||
char *base = base1;
|
||||
int base_len = strlen(base);
|
||||
|
||||
if (!s || !*s) return;
|
||||
if (!s || !*s)
|
||||
return;
|
||||
|
||||
if (strncmp(s, base, base_len) == 0)
|
||||
s += base_len;
|
||||
|
||||
s = strdup(s);
|
||||
if (!s) out_of_memory("glob_expand");
|
||||
if (!(s = strdup(s)))
|
||||
out_of_memory("glob_expand");
|
||||
|
||||
if (asprintf(&base," %s/", base1) <= 0) out_of_memory("glob_expand");
|
||||
if (asprintf(&base," %s/", base1) <= 0)
|
||||
out_of_memory("glob_expand");
|
||||
base_len++;
|
||||
|
||||
q = s;
|
||||
while ((p = strstr(q,base)) != NULL && *argc < maxargs) {
|
||||
/* split it at this point */
|
||||
*p = 0;
|
||||
glob_expand_one(q, argv, argc, maxargs);
|
||||
q = p + base_len;
|
||||
for (q = s; *q; q = p + base_len) {
|
||||
if ((p = strstr(q, base)) != NULL)
|
||||
*p = '\0'; /* split it at this point */
|
||||
glob_expand_one(q, argv_ptr, argc_ptr, maxargs_ptr);
|
||||
if (!p)
|
||||
break;
|
||||
}
|
||||
|
||||
if (*q && *argc < maxargs)
|
||||
glob_expand_one(q, argv, argc, maxargs);
|
||||
|
||||
free(s);
|
||||
free(base);
|
||||
}
|
||||
@@ -565,8 +592,8 @@ void glob_expand(char *base1, char **argv, int *argc, int maxargs)
|
||||
void strlower(char *s)
|
||||
{
|
||||
while (*s) {
|
||||
if (isupper(* (unsigned char *) s))
|
||||
*s = tolower(* (unsigned char *) s);
|
||||
if (isupper(*(unsigned char *)s))
|
||||
*s = tolower(*(unsigned char *)s);
|
||||
s++;
|
||||
}
|
||||
}
|
||||
@@ -623,118 +650,143 @@ size_t stringjoin(char *dest, size_t destsize, ...)
|
||||
return ret;
|
||||
}
|
||||
|
||||
void clean_fname(char *name)
|
||||
int count_dir_elements(const char *p)
|
||||
{
|
||||
char *p;
|
||||
int l;
|
||||
int modified = 1;
|
||||
|
||||
if (!name) return;
|
||||
|
||||
while (modified) {
|
||||
modified = 0;
|
||||
|
||||
if ((p = strstr(name,"/./")) != NULL) {
|
||||
modified = 1;
|
||||
while (*p) {
|
||||
p[0] = p[2];
|
||||
p++;
|
||||
}
|
||||
}
|
||||
|
||||
if ((p = strstr(name,"//")) != NULL) {
|
||||
modified = 1;
|
||||
while (*p) {
|
||||
p[0] = p[1];
|
||||
p++;
|
||||
}
|
||||
}
|
||||
|
||||
if (strncmp(p = name, "./", 2) == 0) {
|
||||
modified = 1;
|
||||
do {
|
||||
p[0] = p[2];
|
||||
} while (*p++);
|
||||
}
|
||||
|
||||
l = strlen(p = name);
|
||||
if (l > 1 && p[l-1] == '/') {
|
||||
modified = 1;
|
||||
p[l-1] = 0;
|
||||
int cnt = 0, new_component = 1;
|
||||
while (*p) {
|
||||
if (*p++ == '/')
|
||||
new_component = 1;
|
||||
else if (new_component) {
|
||||
new_component = 0;
|
||||
cnt++;
|
||||
}
|
||||
}
|
||||
return cnt;
|
||||
}
|
||||
|
||||
/**
|
||||
* Make path appear as if a chroot had occurred:
|
||||
*
|
||||
* @li 1. remove leading "/" (or replace with "." if at end)
|
||||
*
|
||||
* @li 2. remove leading ".." components (except those allowed by @p reldir)
|
||||
*
|
||||
* @li 3. delete any other "<dir>/.." (recursively)
|
||||
*
|
||||
* Can only shrink paths, so sanitizes in place.
|
||||
*
|
||||
* While we're at it, remove double slashes and "." components like
|
||||
* clean_fname() does, but DON'T remove a trailing slash because that
|
||||
* is sometimes significant on command line arguments.
|
||||
*
|
||||
* If @p reldir is non-null, it is a sanitized directory that the path will be
|
||||
* relative to, so allow as many ".." at the beginning of the path as
|
||||
* there are components in reldir. This is used for symbolic link targets.
|
||||
* If reldir is non-null and the path began with "/", to be completely like
|
||||
* a chroot we should add in depth levels of ".." at the beginning of the
|
||||
* path, but that would blow the assumption that the path doesn't grow and
|
||||
* it is not likely to end up being a valid symlink anyway, so just do
|
||||
* the normal removal of the leading "/" instead.
|
||||
*
|
||||
* Contributed by Dave Dykstra <dwd@bell-labs.com>
|
||||
*/
|
||||
void sanitize_path(char *p, char *reldir)
|
||||
/* Turns multiple adjacent slashes into a single slash, gets rid of "./"
|
||||
* elements (but not a trailing dot dir), removes a trailing slash, and
|
||||
* optionally collapses ".." elements (except for those at the start of the
|
||||
* string). If the resulting name would be empty, change it into a ".". */
|
||||
unsigned int clean_fname(char *name, BOOL collapse_dot_dot)
|
||||
{
|
||||
char *start, *sanp;
|
||||
int depth = 0;
|
||||
int allowdotdot = 0;
|
||||
char *limit = name - 1, *t = name, *f = name;
|
||||
int anchored;
|
||||
|
||||
if (reldir) {
|
||||
depth++;
|
||||
while (*reldir) {
|
||||
if (*reldir++ == '/') {
|
||||
depth++;
|
||||
if (!name)
|
||||
return 0;
|
||||
|
||||
if ((anchored = *f == '/') != 0)
|
||||
*t++ = *f++;
|
||||
while (*f) {
|
||||
/* discard extra slashes */
|
||||
if (*f == '/') {
|
||||
f++;
|
||||
continue;
|
||||
}
|
||||
if (*f == '.') {
|
||||
/* discard "." dirs (but NOT a trailing '.'!) */
|
||||
if (f[1] == '/') {
|
||||
f += 2;
|
||||
continue;
|
||||
}
|
||||
/* collapse ".." dirs */
|
||||
if (collapse_dot_dot
|
||||
&& f[1] == '.' && (f[2] == '/' || !f[2])) {
|
||||
char *s = t - 1;
|
||||
if (s == name && anchored) {
|
||||
f += 2;
|
||||
continue;
|
||||
}
|
||||
while (s > limit && *--s != '/') {}
|
||||
if (s != t - 1 && (s < name || *s == '/')) {
|
||||
t = s + 1;
|
||||
f += 2;
|
||||
continue;
|
||||
}
|
||||
limit = t + 2;
|
||||
}
|
||||
}
|
||||
while (*f && (*t++ = *f++) != '/') {}
|
||||
}
|
||||
start = p;
|
||||
sanp = p;
|
||||
while (*p == '/') {
|
||||
/* remove leading slashes */
|
||||
p++;
|
||||
|
||||
if (t > name+anchored && t[-1] == '/')
|
||||
t--;
|
||||
if (t == name)
|
||||
*t++ = '.';
|
||||
*t = '\0';
|
||||
|
||||
return t - name;
|
||||
}
|
||||
|
||||
/* Make path appear as if a chroot had occurred. This handles a leading
|
||||
* "/" (either removing it or expanding it) and any leading or embedded
|
||||
* ".." components that attempt to escape past the module's top dir.
|
||||
*
|
||||
* If dest is NULL, a buffer is allocated to hold the result. It is legal
|
||||
* to call with the dest and the path (p) pointing to the same buffer, but
|
||||
* rootdir will be ignored to avoid expansion of the string.
|
||||
*
|
||||
* The rootdir string contains a value to use in place of a leading slash.
|
||||
* Specify NULL to get the default of lp_path(module_id).
|
||||
*
|
||||
* If depth is >= 0, it is a count of how many '..'s to allow at the start
|
||||
* of the path. Use -1 to allow unlimited depth.
|
||||
*
|
||||
* We also clean the path in a manner similar to clean_fname() but with a
|
||||
* few differences:
|
||||
*
|
||||
* Turns multiple adjacent slashes into a single slash, gets rid of "." dir
|
||||
* elements (INCLUDING a trailing dot dir), PRESERVES a trailing slash, and
|
||||
* ALWAYS collapses ".." elements (except for those at the start of the
|
||||
* string up to "depth" deep). If the resulting name would be empty,
|
||||
* change it into a ".". */
|
||||
char *sanitize_path(char *dest, const char *p, const char *rootdir, int depth)
|
||||
{
|
||||
char *start, *sanp;
|
||||
int rlen = 0;
|
||||
|
||||
if (dest != p) {
|
||||
int plen = strlen(p);
|
||||
if (*p == '/') {
|
||||
if (!rootdir)
|
||||
rootdir = lp_path(module_id);
|
||||
rlen = strlen(rootdir);
|
||||
depth = 0;
|
||||
p++;
|
||||
}
|
||||
if (dest) {
|
||||
if (rlen + plen + 1 >= MAXPATHLEN)
|
||||
return NULL;
|
||||
} else if (!(dest = new_array(char, rlen + plen + 1)))
|
||||
out_of_memory("sanitize_path");
|
||||
if (rlen) {
|
||||
memcpy(dest, rootdir, rlen);
|
||||
if (rlen > 1)
|
||||
dest[rlen++] = '/';
|
||||
}
|
||||
}
|
||||
|
||||
start = sanp = dest + rlen;
|
||||
while (*p != '\0') {
|
||||
/* discard leading or extra slashes */
|
||||
if (*p == '/') {
|
||||
p++;
|
||||
continue;
|
||||
}
|
||||
/* this loop iterates once per filename component in p.
|
||||
* both p (and sanp if the original had a slash) should
|
||||
* always be left pointing after a slash
|
||||
*/
|
||||
if (*p == '.' && (p[1] == '/' || p[1] == '\0')) {
|
||||
/* skip "." component */
|
||||
while (*++p == '/') {
|
||||
/* skip following slashes */
|
||||
;
|
||||
}
|
||||
p++;
|
||||
continue;
|
||||
}
|
||||
allowdotdot = 0;
|
||||
if (*p == '.' && p[1] == '.' && (p[2] == '/' || p[2] == '\0')) {
|
||||
/* ".." component followed by slash or end */
|
||||
if (depth > 0 && sanp == start) {
|
||||
/* allow depth levels of .. at the beginning */
|
||||
--depth;
|
||||
allowdotdot = 1;
|
||||
} else {
|
||||
if (depth <= 0 || sanp != start) {
|
||||
p += 2;
|
||||
if (*p == '/')
|
||||
p++;
|
||||
if (sanp != start) {
|
||||
/* back up sanp one level */
|
||||
--sanp; /* now pointing at slash */
|
||||
@@ -745,68 +797,21 @@ void sanitize_path(char *p, char *reldir)
|
||||
}
|
||||
continue;
|
||||
}
|
||||
}
|
||||
while (1) {
|
||||
/* copy one component through next slash */
|
||||
*sanp++ = *p++;
|
||||
if (*p == '\0' || p[-1] == '/') {
|
||||
while (*p == '/') {
|
||||
/* skip multiple slashes */
|
||||
p++;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (allowdotdot) {
|
||||
/* allow depth levels of .. at the beginning */
|
||||
depth--;
|
||||
/* move the virtual beginning to leave the .. alone */
|
||||
start = sanp;
|
||||
start = sanp + 3;
|
||||
}
|
||||
/* copy one component through next slash */
|
||||
while (*p && (*sanp++ = *p++) != '/') {}
|
||||
}
|
||||
if (sanp == start && !allowdotdot) {
|
||||
if (sanp == dest) {
|
||||
/* ended up with nothing, so put in "." component */
|
||||
/*
|
||||
* note that the !allowdotdot doesn't prevent this from
|
||||
* happening in all allowed ".." situations, but I didn't
|
||||
* think it was worth putting in an extra variable to ensure
|
||||
* it since an extra "." won't hurt in those situations.
|
||||
*/
|
||||
*sanp++ = '.';
|
||||
}
|
||||
*sanp = '\0';
|
||||
}
|
||||
|
||||
/* Works much like sanitize_path(), with these differences: (1) a new buffer
|
||||
* is allocated for the sanitized path rather than modifying it in-place; (2)
|
||||
* a leading slash gets transformed into the rootdir value (which can be empty
|
||||
* or NULL if you just want the slash to get dropped); (3) no "reldir" can be
|
||||
* specified. */
|
||||
char *alloc_sanitize_path(const char *path, const char *rootdir)
|
||||
{
|
||||
char *buf;
|
||||
int rlen, plen = strlen(path);
|
||||
|
||||
if (*path == '/' && rootdir) {
|
||||
rlen = strlen(rootdir);
|
||||
if (rlen == 1)
|
||||
path++;
|
||||
} else
|
||||
rlen = 0;
|
||||
if (!(buf = new_array(char, rlen + plen + 1)))
|
||||
out_of_memory("alloc_sanitize_path");
|
||||
if (rlen)
|
||||
memcpy(buf, rootdir, rlen);
|
||||
memcpy(buf + rlen, path, plen + 1);
|
||||
|
||||
if (rlen > 1)
|
||||
rlen++;
|
||||
sanitize_path(buf + rlen, NULL);
|
||||
if (rlen && buf[rlen] == '.' && buf[rlen+1] == '\0') {
|
||||
if (rlen > 1)
|
||||
rlen--;
|
||||
buf[rlen] = '\0';
|
||||
}
|
||||
|
||||
return buf;
|
||||
return dest;
|
||||
}
|
||||
|
||||
char curr_dir[MAXPATHLEN];
|
||||
@@ -850,7 +855,7 @@ int push_dir(char *dir)
|
||||
curr_dir_len += len;
|
||||
}
|
||||
|
||||
clean_fname(curr_dir);
|
||||
curr_dir_len = clean_fname(curr_dir, 1);
|
||||
|
||||
return 1;
|
||||
}
|
||||
@@ -871,14 +876,37 @@ int pop_dir(char *dir)
|
||||
return 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the filename, turning any newlines into '?'s. This ensures that
|
||||
* outputting it on a line of its own cannot generate an empty line. This
|
||||
* function can handle only 2 names at a time!
|
||||
**/
|
||||
const char *safe_fname(const char *fname)
|
||||
{
|
||||
static char fbuf1[MAXPATHLEN], fbuf2[MAXPATHLEN];
|
||||
static char *fbuf = fbuf2;
|
||||
char *nl = strchr(fname, '\n');
|
||||
|
||||
if (!nl)
|
||||
return fname;
|
||||
|
||||
fbuf = fbuf == fbuf1 ? fbuf2 : fbuf1;
|
||||
strlcpy(fbuf, fname, MAXPATHLEN);
|
||||
nl = fbuf + (nl - (char *)fname);
|
||||
do {
|
||||
*nl = '?';
|
||||
} while ((nl = strchr(nl+1, '\n')) != NULL);
|
||||
|
||||
return fbuf;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a quoted string with the full pathname of the indicated filename.
|
||||
* The string " (in MODNAME)" may also be appended. The returned pointer
|
||||
* remains valid until the next time full_fname() is called.
|
||||
**/
|
||||
char *full_fname(char *fn)
|
||||
char *full_fname(const char *fn)
|
||||
{
|
||||
extern int module_id;
|
||||
static char *result = NULL;
|
||||
char *m1, *m2, *m3;
|
||||
char *p1, *p2;
|
||||
@@ -886,6 +914,7 @@ char *full_fname(char *fn)
|
||||
if (result)
|
||||
free(result);
|
||||
|
||||
fn = safe_fname(fn);
|
||||
if (*fn == '/')
|
||||
p1 = p2 = "";
|
||||
else {
|
||||
@@ -917,6 +946,69 @@ char *full_fname(char *fn)
|
||||
return result;
|
||||
}
|
||||
|
||||
static char partial_fname[MAXPATHLEN];
|
||||
|
||||
char *partial_dir_fname(const char *fname)
|
||||
{
|
||||
char *t = partial_fname;
|
||||
int sz = sizeof partial_fname;
|
||||
const char *fn;
|
||||
|
||||
if ((fn = strrchr(fname, '/')) != NULL) {
|
||||
fn++;
|
||||
if (*partial_dir != '/') {
|
||||
int len = fn - fname;
|
||||
strncpy(t, fname, len); /* safe */
|
||||
t += len;
|
||||
sz -= len;
|
||||
}
|
||||
} else
|
||||
fn = fname;
|
||||
if ((int)pathjoin(t, sz, partial_dir, fn) >= sz)
|
||||
return NULL;
|
||||
if (server_exclude_list.head
|
||||
&& check_exclude(&server_exclude_list, partial_fname, 0) < 0)
|
||||
return NULL;
|
||||
|
||||
return partial_fname;
|
||||
}
|
||||
|
||||
/* If no --partial-dir option was specified, we don't need to do anything
|
||||
* (the partial-dir is essentially '.'), so just return success. */
|
||||
int handle_partial_dir(const char *fname, int create)
|
||||
{
|
||||
char *fn, *dir;
|
||||
|
||||
if (fname != partial_fname)
|
||||
return 1;
|
||||
if (!create && *partial_dir == '/')
|
||||
return 1;
|
||||
if (!(fn = strrchr(partial_fname, '/')))
|
||||
return 1;
|
||||
|
||||
*fn = '\0';
|
||||
dir = partial_fname;
|
||||
if (create) {
|
||||
STRUCT_STAT st;
|
||||
#if SUPPORT_LINKS
|
||||
int statret = do_lstat(dir, &st);
|
||||
#else
|
||||
int statret = do_stat(dir, &st);
|
||||
#endif
|
||||
if (statret == 0 && !S_ISDIR(st.st_mode)) {
|
||||
if (do_unlink(dir) < 0)
|
||||
return 0;
|
||||
statret = -1;
|
||||
}
|
||||
if (statret < 0 && do_mkdir(dir, 0700) < 0)
|
||||
return 0;
|
||||
} else
|
||||
do_rmdir(dir);
|
||||
*fn = '/';
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/** We need to supply our own strcmp function for file list comparisons
|
||||
to ensure that signed/unsigned usage is consistent between machines. */
|
||||
int u_strcmp(const char *cs1, const char *cs2)
|
||||
@@ -963,7 +1055,8 @@ int unsafe_symlink(const char *dest, const char *src)
|
||||
int depth = 0;
|
||||
|
||||
/* all absolute and null symlinks are unsafe */
|
||||
if (!dest || !*dest || *dest == '/') return 1;
|
||||
if (!dest || !*dest || *dest == '/')
|
||||
return 1;
|
||||
|
||||
/* find out what our safety margin is */
|
||||
for (name = src; (slash = strchr(name, '/')) != 0; name = slash+1) {
|
||||
@@ -1031,7 +1124,6 @@ int msleep(int t)
|
||||
struct timeval tval, t1, t2;
|
||||
|
||||
gettimeofday(&t1, NULL);
|
||||
gettimeofday(&t2, NULL);
|
||||
|
||||
while (tdiff < t) {
|
||||
tval.tv_sec = (t-tdiff)/1000;
|
||||
@@ -1062,13 +1154,13 @@ int msleep(int t)
|
||||
**/
|
||||
int cmp_modtime(time_t file1, time_t file2)
|
||||
{
|
||||
extern int modify_window;
|
||||
|
||||
if (file2 > file1) {
|
||||
if (file2 - file1 <= modify_window) return 0;
|
||||
if (file2 - file1 <= modify_window)
|
||||
return 0;
|
||||
return -1;
|
||||
}
|
||||
if (file1 - file2 <= modify_window) return 0;
|
||||
if (file1 - file2 <= modify_window)
|
||||
return 0;
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user