mirror of
https://github.com/RsyncProject/rsync.git
synced 2026-05-25 07:15:35 -04:00
Compare commits
262 Commits
v3.0.0pre1
...
v3.0.5
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
7221063019 | ||
|
|
b64ae8b3b4 | ||
|
|
9938bad34a | ||
|
|
1ff3e90507 | ||
|
|
b292021e45 | ||
|
|
13e40ca0c6 | ||
|
|
8e85627fb3 | ||
|
|
d552250fbb | ||
|
|
5436b64557 | ||
|
|
b325dd0326 | ||
|
|
49818a8378 | ||
|
|
af03a7049c | ||
|
|
e401b30403 | ||
|
|
e512826786 | ||
|
|
ccdc2efd67 | ||
|
|
b8a1fd6404 | ||
|
|
3082dffbe2 | ||
|
|
42130f9cb0 | ||
|
|
c6c339cd18 | ||
|
|
6767ca617b | ||
|
|
7d9e30d383 | ||
|
|
3f81ad6060 | ||
|
|
723e9f856d | ||
|
|
9189e41f6e | ||
|
|
6f6f9d1020 | ||
|
|
a76ba8b425 | ||
|
|
b8fd528794 | ||
|
|
0ea5d30479 | ||
|
|
cf1b292201 | ||
|
|
f3721ed133 | ||
|
|
b1220d62f4 | ||
|
|
5df89a1a44 | ||
|
|
d47ac91209 | ||
|
|
7c573428a9 | ||
|
|
f7e65c7b61 | ||
|
|
fe62d30de8 | ||
|
|
494895fb4b | ||
|
|
ac68345a34 | ||
|
|
6a9ade2ded | ||
|
|
d596d389fe | ||
|
|
bc2337717e | ||
|
|
3df40f044a | ||
|
|
d11a5b80c1 | ||
|
|
deea1f70bd | ||
|
|
a91e678324 | ||
|
|
25a22d8501 | ||
|
|
fac9e234ae | ||
|
|
f3d87ee972 | ||
|
|
9bed85542c | ||
|
|
5b979530a7 | ||
|
|
7ec8baaa7e | ||
|
|
8c2c008984 | ||
|
|
719a29e1cf | ||
|
|
4a95d61251 | ||
|
|
fc088e30c8 | ||
|
|
aef51b4c68 | ||
|
|
7790ee3684 | ||
|
|
ed12c8eb21 | ||
|
|
91dd3d0d48 | ||
|
|
95d1d2a9a4 | ||
|
|
a808346dbe | ||
|
|
fa181223d8 | ||
|
|
9ed569486f | ||
|
|
2fa069d85f | ||
|
|
a25aed50e6 | ||
|
|
302e4346c2 | ||
|
|
8e5eafccdf | ||
|
|
e88b92bade | ||
|
|
f8722dba56 | ||
|
|
ee03cb99d9 | ||
|
|
92d706a274 | ||
|
|
581c830c56 | ||
|
|
9e58ef45f3 | ||
|
|
05bd05a7a1 | ||
|
|
89b6b4ce4b | ||
|
|
68cdc3b791 | ||
|
|
209371b891 | ||
|
|
6fd2662982 | ||
|
|
1fdf0302c0 | ||
|
|
db8f3f7350 | ||
|
|
85fd80ce10 | ||
|
|
a24d64bfaa | ||
|
|
33cc92a63a | ||
|
|
5e7f63f0bf | ||
|
|
8bd77e7098 | ||
|
|
13074c982b | ||
|
|
2171b9395b | ||
|
|
20bb1eb7ae | ||
|
|
7ee7bcd4e9 | ||
|
|
844810d609 | ||
|
|
67347196b1 | ||
|
|
e424e26128 | ||
|
|
ca7d17e41d | ||
|
|
6283e9ef43 | ||
|
|
7462c6ac39 | ||
|
|
f31850966f | ||
|
|
4ecf3e0671 | ||
|
|
60a986f504 | ||
|
|
0e9c3564c6 | ||
|
|
164cb66add | ||
|
|
0d9eba0312 | ||
|
|
d1f66d8d79 | ||
|
|
cc911409d6 | ||
|
|
a64f19e24b | ||
|
|
4337eeb754 | ||
|
|
928da42359 | ||
|
|
e717fa4d37 | ||
|
|
cc56eb2acc | ||
|
|
88e05f8489 | ||
|
|
9ec8583ef5 | ||
|
|
e9489cd6cb | ||
|
|
f1ca7c4429 | ||
|
|
adc4ebdd76 | ||
|
|
9a30c0cc3c | ||
|
|
47f43c023b | ||
|
|
5b385336b9 | ||
|
|
c3a2d95cfa | ||
|
|
6b19df680a | ||
|
|
fdf74bede0 | ||
|
|
876ad10ccc | ||
|
|
34a2b39165 | ||
|
|
276cc45571 | ||
|
|
311676ed21 | ||
|
|
4616867b0d | ||
|
|
8a5ae84efd | ||
|
|
59d2cd5a7f | ||
|
|
1c3e6e8b26 | ||
|
|
f2681d42ff | ||
|
|
774d1c367b | ||
|
|
1b8e0e876b | ||
|
|
1502f4f58f | ||
|
|
6db1db5488 | ||
|
|
09ad90537d | ||
|
|
da9aefa6b4 | ||
|
|
8ba802f3b4 | ||
|
|
e53f49d1af | ||
|
|
0917f581bc | ||
|
|
1fe2a3533f | ||
|
|
237e9a178f | ||
|
|
0668bfe077 | ||
|
|
214af6ad83 | ||
|
|
2551c47eb7 | ||
|
|
83d22fd7f9 | ||
|
|
325c243210 | ||
|
|
4e90cfbfed | ||
|
|
6fd2c27f38 | ||
|
|
19173d224a | ||
|
|
5b83829669 | ||
|
|
8cd3c6dccf | ||
|
|
29a89172f7 | ||
|
|
2089375179 | ||
|
|
f8949e7647 | ||
|
|
84ecaa0eca | ||
|
|
3f2d8d683a | ||
|
|
fd2598022c | ||
|
|
b05c58cce6 | ||
|
|
05805cd6b7 | ||
|
|
a165be754b | ||
|
|
af3172c148 | ||
|
|
487cb52615 | ||
|
|
9793bbb364 | ||
|
|
f6f74b93ef | ||
|
|
7568ff448a | ||
|
|
56158b7e04 | ||
|
|
798a9e4e74 | ||
|
|
c202b4fa96 | ||
|
|
1df02d13d3 | ||
|
|
73cb6738b3 | ||
|
|
ba8672dfab | ||
|
|
a5e0bf3579 | ||
|
|
99ba99c74c | ||
|
|
469ff84e29 | ||
|
|
b5daf5300f | ||
|
|
f5aeb6ff9b | ||
|
|
4c74d44dab | ||
|
|
4a86fbcda0 | ||
|
|
bc267e0f57 | ||
|
|
fc05137846 | ||
|
|
c085ece623 | ||
|
|
91f625cee0 | ||
|
|
27b067f87b | ||
|
|
987a546756 | ||
|
|
4d30f17671 | ||
|
|
d48810ba5b | ||
|
|
819bfe4599 | ||
|
|
d2f6e19262 | ||
|
|
e889e0c43b | ||
|
|
6e0bf4d840 | ||
|
|
83a8ca7b14 | ||
|
|
100200d0d2 | ||
|
|
f28bf7f401 | ||
|
|
e0fd68f5ce | ||
|
|
cc12c488aa | ||
|
|
99c3e591b2 | ||
|
|
1aefb7ef73 | ||
|
|
d7b6774d82 | ||
|
|
d4c5cb2b01 | ||
|
|
df476bfcff | ||
|
|
aa0e6b9977 | ||
|
|
1ba6468f1b | ||
|
|
f490102454 | ||
|
|
18f3cb6957 | ||
|
|
7abcfd85b7 | ||
|
|
6de417d9d4 | ||
|
|
ffe8feb265 | ||
|
|
c9b62cf375 | ||
|
|
7bc595785e | ||
|
|
022dec7aba | ||
|
|
ddaef70ced | ||
|
|
2357a51e09 | ||
|
|
24ded29ff6 | ||
|
|
ddff23a7f9 | ||
|
|
53936ef935 | ||
|
|
7f9bf6b710 | ||
|
|
cfdb27b0c1 | ||
|
|
fc3ca11040 | ||
|
|
d6c9c3319b | ||
|
|
8afaef4219 | ||
|
|
11faa893ca | ||
|
|
600b56b316 | ||
|
|
ee39281d14 | ||
|
|
0607c30700 | ||
|
|
492ad04277 | ||
|
|
1ed9018e69 | ||
|
|
ff0e15804f | ||
|
|
894e6299c1 | ||
|
|
c080190365 | ||
|
|
26f0e56587 | ||
|
|
b4e6aac985 | ||
|
|
7c21776e54 | ||
|
|
d724dd186e | ||
|
|
cbbd8e2e8b | ||
|
|
af6241f7ad | ||
|
|
852e763b89 | ||
|
|
0f71592015 | ||
|
|
e63d3a29e2 | ||
|
|
38cef641a5 | ||
|
|
6226396c4a | ||
|
|
89b47d43de | ||
|
|
d1c06c2180 | ||
|
|
800a4485f3 | ||
|
|
fede378577 | ||
|
|
3bc207b9dd | ||
|
|
ebac031925 | ||
|
|
3cbe640d3c | ||
|
|
4cb6197b21 | ||
|
|
d3d07a5e86 | ||
|
|
62ca38262f | ||
|
|
d62fb8894f | ||
|
|
fc29efc38d | ||
|
|
c4c9bb944b | ||
|
|
236adddc18 | ||
|
|
5b3aa8028b | ||
|
|
16e24c2043 | ||
|
|
7869953bbf | ||
|
|
d07edfc895 | ||
|
|
85b057cccf | ||
|
|
a2c473bb59 | ||
|
|
f587061a5b | ||
|
|
d9e92804a5 | ||
|
|
46e858a631 | ||
|
|
e0fe5231c2 |
4
.gitignore
vendored
4
.gitignore
vendored
@@ -3,10 +3,13 @@
|
||||
dummy
|
||||
ID
|
||||
Makefile
|
||||
Makefile.old
|
||||
configure.sh
|
||||
configure.sh.old
|
||||
config.cache
|
||||
config.h
|
||||
config.h.in
|
||||
config.h.in.old
|
||||
config.log
|
||||
config.status
|
||||
/proto.h
|
||||
@@ -32,6 +35,7 @@ config.status
|
||||
/rounding.h
|
||||
/doc/rsync.pdf
|
||||
/doc/rsync.ps
|
||||
/support/savetransfer
|
||||
/testsuite/chown-fake.test
|
||||
/testsuite/devices-fake.test
|
||||
/patches
|
||||
|
||||
54
Makefile.in
54
Makefile.in
@@ -66,8 +66,8 @@ install: all
|
||||
${INSTALLCMD} ${INSTALL_STRIP} -m 755 rsync$(EXEEXT) ${DESTDIR}${bindir}
|
||||
-mkdir -p ${DESTDIR}${mandir}/man1
|
||||
-mkdir -p ${DESTDIR}${mandir}/man5
|
||||
if test -f $(srcdir)/rsync.1; then ${INSTALLMAN} -m 644 $(srcdir)/rsync.1 ${DESTDIR}${mandir}/man1; fi
|
||||
if test -f $(srcdir)/rsyncd.conf.5; then ${INSTALLMAN} -m 644 $(srcdir)/rsyncd.conf.5 ${DESTDIR}${mandir}/man5; fi
|
||||
if test -f rsync.1; then ${INSTALLMAN} -m 644 rsync.1 ${DESTDIR}${mandir}/man1; fi
|
||||
if test -f rsyncd.conf.5; then ${INSTALLMAN} -m 644 rsyncd.conf.5 ${DESTDIR}${mandir}/man5; fi
|
||||
|
||||
install-strip:
|
||||
$(MAKE) INSTALL_STRIP='-s' install
|
||||
@@ -82,7 +82,7 @@ flist.o: rounding.h
|
||||
|
||||
rounding.h: rounding.c rsync.h
|
||||
@for r in 0 1 3; do \
|
||||
if $(CC) $(CFLAGS) $(LDFLAGS) -o rounding -DEXTRA_ROUNDING=$$r -I. $(srcdir)/rounding.c >/dev/null 2>&1; then \
|
||||
if $(CC) $(CFLAGS) $(CPPFLAGS) $(LDFLAGS) -o rounding -DEXTRA_ROUNDING=$$r -I. $(srcdir)/rounding.c >rounding.out 2>&1; then \
|
||||
echo "#define EXTRA_ROUNDING $$r" >rounding.h; \
|
||||
if test -f "$$HOME/build_farm/build_test.fns"; then \
|
||||
echo "EXTRA_ROUNDING is $$r" >&2; \
|
||||
@@ -92,9 +92,11 @@ rounding.h: rounding.c rsync.h
|
||||
done
|
||||
@rm -f rounding
|
||||
@if test -f rounding.h; then : ; else \
|
||||
echo "Failed to create rounding.h!"; \
|
||||
cat rounding.out 1>&2; \
|
||||
echo "Failed to create rounding.h!" 1>&2; \
|
||||
exit 1; \
|
||||
fi
|
||||
@rm -f rounding.out
|
||||
|
||||
tls$(EXEEXT): $(TLS_OBJ)
|
||||
$(CC) $(CFLAGS) $(LDFLAGS) -o $@ $(TLS_OBJ) $(LIBS)
|
||||
@@ -109,7 +111,7 @@ TRIMSLASH_OBJ = trimslash.o syscall.o lib/compat.o lib/snprintf.o
|
||||
trimslash$(EXEEXT): $(TRIMSLASH_OBJ)
|
||||
$(CC) $(CFLAGS) $(LDFLAGS) -o $@ $(TRIMSLASH_OBJ) $(LIBS)
|
||||
|
||||
T_UNSAFE_OBJ = t_unsafe.o syscall.o util.o t_stub.o lib/compat.o lib/snprintf.o
|
||||
T_UNSAFE_OBJ = t_unsafe.o syscall.o util.o t_stub.o lib/compat.o lib/snprintf.o lib/wildmatch.o
|
||||
t_unsafe$(EXEEXT): $(T_UNSAFE_OBJ)
|
||||
$(CC) $(CFLAGS) $(LDFLAGS) -o $@ $(T_UNSAFE_OBJ) $(LIBS)
|
||||
|
||||
@@ -124,11 +126,31 @@ conf:
|
||||
conf_stop: configure.sh config.h.in
|
||||
|
||||
configure.sh config.h.in: configure.in aclocal.m4
|
||||
@if test -f configure.sh; then cp -p configure.sh configure.sh.old; else touch configure.sh.old; fi
|
||||
@if test -f config.h.in; then cp -p config.h.in config.h.in.old; else touch config.h.in.old; fi
|
||||
autoconf -o configure.sh
|
||||
autoheader && touch config.h.in
|
||||
@echo 'Configure files changed -- perhaps run:'
|
||||
@echo ' make reconfigure'
|
||||
@exit 1
|
||||
@if diff configure.sh configure.sh.old >/dev/null 2>&1; then \
|
||||
echo "configure.sh is unchanged."; \
|
||||
rm configure.sh.old; \
|
||||
else \
|
||||
echo "configure.sh has CHANGED."; \
|
||||
fi
|
||||
@if diff config.h.in config.h.in.old >/dev/null 2>&1; then \
|
||||
echo "config.h.in is unchanged."; \
|
||||
rm config.h.in.old; \
|
||||
else \
|
||||
echo "config.h.in has CHANGED."; \
|
||||
fi
|
||||
@if test -f configure.sh.old -o -f config.h.in.old; then \
|
||||
if test "$(MAKECMDGOALS)" = reconfigure; then \
|
||||
echo 'Continuing with "make reconfigure".'; \
|
||||
else \
|
||||
echo 'You may need to run:'; \
|
||||
echo ' make reconfigure'; \
|
||||
exit 1; \
|
||||
fi \
|
||||
fi
|
||||
|
||||
reconfigure: configure.sh
|
||||
./config.status --recheck
|
||||
@@ -137,19 +159,27 @@ reconfigure: configure.sh
|
||||
make_stop: Makefile
|
||||
|
||||
Makefile: Makefile.in config.status
|
||||
@if test -f Makefile; then cp -p Makefile Makefile.old; else touch Makefile.old; fi
|
||||
@./config.status
|
||||
@echo "Makefile updated -- rerun your make command."
|
||||
@exit 1
|
||||
@if diff Makefile Makefile.old >/dev/null 2>&1; then \
|
||||
echo "Makefile is unchanged."; \
|
||||
rm Makefile.old; \
|
||||
else \
|
||||
echo "Makefile updated -- rerun your make command."; \
|
||||
exit 1; \
|
||||
fi
|
||||
|
||||
proto: proto.h-tstamp
|
||||
|
||||
proto.h: proto.h-tstamp
|
||||
@echo ' ' >/dev/null
|
||||
@if test -f proto.h; then :; else cp -p $(srcdir)/proto.h .; fi
|
||||
|
||||
proto.h-tstamp: $(srcdir)/*.c $(srcdir)/lib/compat.c
|
||||
perl $(srcdir)/mkproto.pl $(srcdir)/*.c $(srcdir)/lib/compat.c
|
||||
|
||||
man: rsync.1 rsyncd.conf.5
|
||||
@if test -f rsync.1; then :; else cp -p $(srcdir)/rsync.1 .; fi
|
||||
@if test -f rsyncd.conf.5; then :; else cp -p $(srcdir)/rsyncd.conf.5 .; fi
|
||||
|
||||
rsync.1: rsync.yo
|
||||
yodl2man -o rsync.1 $(srcdir)/rsync.yo
|
||||
@@ -161,7 +191,7 @@ rsyncd.conf.5: rsyncd.conf.yo
|
||||
|
||||
clean: cleantests
|
||||
rm -f *~ $(OBJS) $(CHECK_PROGS) $(CHECK_OBJS) $(CHECK_SYMLINKS) \
|
||||
rounding rounding.h
|
||||
rounding rounding.h *.old
|
||||
|
||||
cleantests:
|
||||
rm -rf ./testtmp*
|
||||
|
||||
346
NEWS
346
NEWS
@@ -1,330 +1,62 @@
|
||||
NEWS for rsync 3.0.0 (UNRELEASED)
|
||||
Protocol: 30 (changed)
|
||||
Changes since 2.6.9:
|
||||
|
||||
NOTABLE CHANGES IN BEHAVIOR:
|
||||
|
||||
- The handling of implied directories when using --relative has changed to
|
||||
send them as directories (e.g. no implied dir is ever sent as a symlink).
|
||||
This avoids unexpected behavior and should not adversely affect most
|
||||
people. If you're one of those rare individuals who relied upon having
|
||||
an implied dir be duplicated as a symlink, you should specify the
|
||||
transfer of the symlink and the transfer of the referent directory as
|
||||
separate args. (See also --keep-dirlinks and --no-implied-dirs.)
|
||||
Also, exclude rules no longer have a partial effect on implied dirs.
|
||||
|
||||
- Requesting a remote file list without specifying -r (--recursive) now
|
||||
sends the -d (--dirs) option to the remote rsync rather than sending -r
|
||||
along with an extra exclude of /*/*. If the remote rsync does not
|
||||
understand the -d option (i.e. it is 2.6.3 or older), you will need to
|
||||
either turn off -d (--no-d), or specify -r --exclude='/*/*' manually.
|
||||
|
||||
- In --dry-run mode, the last line of the verbose summary text is output
|
||||
with a "(DRY RUN)" suffix to help remind you that no updates were made.
|
||||
Similarly, --only-write-batch outputs "(BATCH ONLY)".
|
||||
|
||||
- A writable rsync daemon with "use chroot" disabled now defaults to a
|
||||
symlink-munging behavior designed to make symlinks safer while also
|
||||
allowing absolute symlinks to be stored and retrieved. This also has
|
||||
the effect of making symlinks unusable while they're in the daemon's
|
||||
hierarchy. See the daemon's "munge symlinks" parameter for details.
|
||||
NEWS for rsync 3.0.5 (28 Dec 2008)
|
||||
Protocol: 30 (unchanged)
|
||||
Changes since 3.0.4:
|
||||
|
||||
BUG FIXES:
|
||||
|
||||
- A daemon with "use chroot = no" and excluded items listed in the daemon
|
||||
config file now properly checks an absolute-path arg specified for these
|
||||
options: --compare-dest, --link-dest, --copy-dest, --partial-dir,
|
||||
--backup-dir, --temp-dir, and --files-from.
|
||||
- Initialize xattr data in a couple spots in the hlink code, which avoids a
|
||||
crash when the xattr pointer's memory happens to start out non-zero.
|
||||
Also fixed the itemizing of an alt-dest file's xattrs when hard-linking.
|
||||
|
||||
- A daemon can now be told to disable all user- and group-name translation
|
||||
on a per-module basis. This avoids a potential problem with a writable
|
||||
daemon module that has "use chroot" enabled -- if precautions weren't
|
||||
taken, a user could try to add a missing library and get rsync to use
|
||||
it. This makes rsync safer by default, and more configurable when id-
|
||||
translation is not desired. See the daemon's "numeric ids" parameter
|
||||
for full details.
|
||||
- Don't send a bogus "-" option to an older server if there were no short
|
||||
options specified.
|
||||
|
||||
- A chroot daemon can now indicate which part of its path should affect the
|
||||
chroot call, and which part should become an inside-chroot path for the
|
||||
module. This allows you to have outside-the-transfer paths (such as for
|
||||
libraries) even when you enable chroot protection.
|
||||
- Fixed skipping of unneeded updates in a batch file when incremental
|
||||
recursion is active. Added a test for this. Made batch-mode handle
|
||||
"redo" files properly (and without hanging).
|
||||
|
||||
- If a file's data arrived successfully on the receiving side but the
|
||||
rename of the temporary file to the destination file failed AND the
|
||||
--remove-source-files (or the deprecated --remove-sent-files) option
|
||||
was specified, rsync no longer erroneously removes the associated
|
||||
source file.
|
||||
- Fix the %P logfile escape when the daemon logs from inside a chroot.
|
||||
|
||||
- Fixed the output of -ii when combined with one of the --*-dest options:
|
||||
it now itemizes all the items, not just the changed ones.
|
||||
- Fixed the use of -s (--protect-args) when used with a remote source or
|
||||
destination that had an empty path (e.g. "host:"). Also fixed a problem
|
||||
when -s was used when accessing a daemon via a remote-shell.
|
||||
|
||||
- Made the output of all file types consistent when using a --*-dest
|
||||
option. Prior versions would output too many creation events for
|
||||
matching items.
|
||||
- Fixed the use of a dot-dir path (e.g. foo/./bar) inside a --files-from
|
||||
file when the root of the transfer isn't the current directory.
|
||||
|
||||
- The code that waits for a child pid now handles being interrupted by a
|
||||
signal. This fixes a problem with the pre-xfer exec function not being
|
||||
able to get the exit status from the script.
|
||||
- Fixed a bug with "-K --delete" removing symlinks to directories when
|
||||
incremental recursion is active.
|
||||
|
||||
- A negated filter rule (i.e. with a '!' modifier) no longer loses the
|
||||
negation when sending the filter rules to the remote rsync.
|
||||
- Fixed a hard to trigger hang when using --remove-source-files.
|
||||
|
||||
- Fixed a problem with the --out-format (aka --log-format) option %f: it
|
||||
no longer outputs superfluous directory info for a non-daemon rsync.
|
||||
- Got rid of an annoying delay when accessing a daemon via a remote-shell.
|
||||
|
||||
- Fixed a problem with -vv (double --verbose) and --stats when "pushing"
|
||||
files (which includes local copies). Version 2.6.9 would complete the
|
||||
copy, but exit with an error when the receiver output its memory stats.
|
||||
- Properly ignore (superfluous) source args on a --read-batch command.
|
||||
|
||||
- If --password-file is used on a non-daemon transfer, rsync now complains
|
||||
and exits. This should help users figure out that they can't use this
|
||||
option to control a remote shell's password prompt.
|
||||
- Improved the manpage's description of the '*' wildcard to remove the
|
||||
confusing "non-empty" qualifier.
|
||||
|
||||
- Make sure that directory permissions of a newly-created destination
|
||||
directory are handled right when --perms is left off.
|
||||
- Fixed reverse lookups in the compatibility-library version of
|
||||
getnameinfo().
|
||||
|
||||
- The itemized output of a newly-created destination directory is now
|
||||
output as a creation event, not a change event.
|
||||
- Fixed a bug when using --sparse on a sparse file that has over 2GB of
|
||||
consecutive sparse data.
|
||||
|
||||
- Improved --hard-link so that more corner cases are handled correctly
|
||||
when combined with options such as --link-dest and/or --ignore-existing.
|
||||
- Avoid a hang when using at least 3 --verbose options on a transfer with a
|
||||
client sender (which includes local copying).
|
||||
|
||||
- The --append option no longer updates a file that has the same size.
|
||||
- Fixed a problem with --delete-delay reporting an error when it was ready
|
||||
to remove a directory that was now gone.
|
||||
|
||||
- Fixed a bug when combining --backup and --backup-dir with --inplace:
|
||||
any missing backup directories are now created.
|
||||
- Got rid of a bunch of "warn_unused_result" compiler warnings.
|
||||
|
||||
- Fixed a bug when using --backup and --inplace with --whole-file or
|
||||
--read-batch: backup files are actually created now.
|
||||
- If an ftruncate() on a received file fails, it now causes a partial-
|
||||
transfer warning.
|
||||
|
||||
- Starting up an extra copy of an rsync daemon will not clobber the pidfile
|
||||
for the running daemon -- if the pidfile exists, the new daemon will exit
|
||||
with an error.
|
||||
|
||||
- The daemon pidfile is checked and created sooner in the startup sequence.
|
||||
|
||||
- If a daemon module's "path" value is not an absolute pathname, the code
|
||||
now makes it absolute internally (making it work properly).
|
||||
|
||||
- Ensure that a temporary file always has owner-write permission while we
|
||||
are writing to it. This avoids problems with some network filesystems.
|
||||
|
||||
- Any errors output about password-file reading no longer cause an error at
|
||||
the end of the run about a partial transfer.
|
||||
|
||||
- The --read-batch option for protocol 30 now ensures that several more
|
||||
options are set correctly for the current batch file: --iconv, --acls,
|
||||
--xattrs, --inplace, --append, and --append-verify.
|
||||
|
||||
- Using --only-write-batch to a daemon receiver now work properly (older
|
||||
versions would update some files while writing the batch).
|
||||
|
||||
- Avoid outputting a "file has vanished" message when the file is a broken
|
||||
symlink and --copy-unsafe-links or --copy-dirlinks are used (the code
|
||||
already handled this for --copy-links).
|
||||
|
||||
- Fixed the combination of --only-write-batch and --dry-run.
|
||||
- Allow a path with a leading "//" to be preserved (CYGWIN only).
|
||||
|
||||
ENHANCEMENTS:
|
||||
|
||||
- A new incremental-recursion algorithm is now used when rsync is talking
|
||||
to another 3.x version. This starts the transfer going more quickly
|
||||
(before all the files have been found), and requires much less memory.
|
||||
See the --recursive option in the manpage for some restrictions.
|
||||
|
||||
- Lowered memory use in the non-incremental-recursion algorithm for typical
|
||||
option values (usually saving from 21-29 bytes per file).
|
||||
|
||||
- The default --delete algorithm is now --delete-during when talking to a
|
||||
3.x rsync. This is a faster scan than using --delete-before (which is
|
||||
the default when talking to older rsync versions), and is compatible with
|
||||
the new incremental recursion mode.
|
||||
|
||||
- Rsync now allows multiple remote-source args to be specified rather than
|
||||
having to rely on a special space-splitting side-effect of the remote-
|
||||
shell. Additional remote args must specify the same host or an empty one
|
||||
(e.g. empty: :file1 or ::module/file2). This means that local use of
|
||||
brace expansion now works: rsync -av host:dir/{f1,f2} .
|
||||
|
||||
- Added the --protect-args (-s) option, that tells rsync to send most of
|
||||
the command-line args at the start of the transfer rather than as args
|
||||
to the remote-shell command. This protects them from space-splitting,
|
||||
and only interprets basic wildcard special shell characters (*?[).
|
||||
|
||||
- Added the --delete-delay option, which is a more efficient way to delete
|
||||
files at the end of the transfer without needing a separate delete pass.
|
||||
|
||||
- Added the --acls (-A) option to preserve Access Control Lists. This is
|
||||
an improved version of the prior patch that was available, and it even
|
||||
supports OS X ACLs. If you need to have backward compatibility with old,
|
||||
ACL-patched versions of rsync, apply the acls.diff file from the patches
|
||||
dir.
|
||||
|
||||
- Added the --xattrs (-X) option to preserver extended attributes. This is
|
||||
an improved version of the prior patch that was available, and it even
|
||||
supports OS X xattrs (which includes their resource fork data). If you
|
||||
need to have backward compatibility with old, xattr-patched versions of
|
||||
rsync, apply the xattrs.diff file from the patches dir.
|
||||
|
||||
- Added the --fake-super option that allows a non-super user to preserve
|
||||
all attributes of a file by using a special extended-attribute idiom.
|
||||
It even supports the storing of foreign ACL data on your backup server.
|
||||
There is also an analogous "fake super" parameter for an rsync daemon.
|
||||
|
||||
- Added the --iconv option, which allows rsync to convert filenames from
|
||||
one character-set to another during the transfer. The default is to make
|
||||
this feature available as long as your system has iconv_open(). If
|
||||
compilation fails, specify --disable-iconv to configure, and then
|
||||
rebuild. If you want rsync to perform character-set conversions by
|
||||
default, you can specify --enable-iconv=CONVERT_STRING with the default
|
||||
value for the --iconv option that you wish to use. For example,
|
||||
"--enable-iconv=." is a good choice. See the rsync manpage for an
|
||||
explanation of the --iconv option's settings.
|
||||
|
||||
- A new daemon config parameter, "charset", lets you control the character-
|
||||
set that is used during an --iconv transfer to/from a daemon module.
|
||||
|
||||
- Added the --skip-compress=LIST option to override the default list of
|
||||
file suffixes that will not be compressed when using --compress.
|
||||
|
||||
- The daemon's default for "dont compress" was extended to include:
|
||||
*.7z *.mp[34] *.mov *.avi *.ogg *.jpg *.jpeg
|
||||
The matching routine was also optimized to run more quickly.
|
||||
|
||||
- The --max-delete option now outputs a warning if it skipped any file
|
||||
deletions, including a count of how many deletions were skipped. (Older
|
||||
versions just silently stopped deleting things.)
|
||||
|
||||
- You may specify --max-delete=0 to a 3.0.0 client to request that it warn
|
||||
about extraneous files without deleting anything. If you're not sure
|
||||
what version the client is, you can use the less-obvious --max-delete=-1,
|
||||
as both old and new versions will treat that as the same request (though
|
||||
older versions don't warn).
|
||||
|
||||
- The --hard-link option now uses less memory on both the sending and
|
||||
receiving side for all protocol versions. For protocol 30, the use of a
|
||||
hashtable on the sending side allows us to more efficiently convey to the
|
||||
receiver what files are linked together. This reduces the amount of data
|
||||
sent over the socket by a considerable margin (rather than adding more
|
||||
data), and limits the in-memory storage of the device+inode information
|
||||
to just the sending side for the new protocol 30, or to the receiving
|
||||
side when speaking an older protocol (note that older rsync versions kept
|
||||
the device+inode information on both sides).
|
||||
|
||||
- The filter rules now support a perishable ("p") modifier that marks rules
|
||||
that should not have an effect in a directory that is being deleted. e.g.
|
||||
-f '-p .svn/' would only affect "live" .svn directories.
|
||||
|
||||
- Rsync checks all the alternate-destination args for validity (e.g.
|
||||
--link-dest). This lets the user know when they specified a directory
|
||||
that does not exist.
|
||||
|
||||
- If we get an error setting the time on a symlink, we don't complain about
|
||||
it anymore (since some operating systems don't support that, and it's not
|
||||
that important).
|
||||
|
||||
- Protocol 30 now uses MD5 checksums instead of MD4.
|
||||
|
||||
- Changed the --append option to not checksum the existing data in the
|
||||
destination file, which speeds up file appending.
|
||||
|
||||
- Added the --append-verify option, which works like the older --append
|
||||
option (verifying the existing data in the destination file). For
|
||||
compatibility with older rsync versions, any use of --append that is
|
||||
talking protocol 29 or older will revert to the --append-verify method.
|
||||
|
||||
- Added the --contimeout=SECONDS option that lets the user specify a
|
||||
connection timeout for rsync daemon access.
|
||||
|
||||
- Documented and extended the support for the RSYNC_CONNECT_PROG variable
|
||||
that can be used to enhance the client side of a daemon connection.
|
||||
|
||||
- Improved the dashes and double-quotes in the nroff manpage output.
|
||||
|
||||
- We now support a lot more --no-OPTION override options.
|
||||
|
||||
INTERNAL:
|
||||
|
||||
- The file-list sorting algorithm now uses a sort that keeps any same-
|
||||
named items in the same order as they were specified. This allows
|
||||
rsync to always ensure that the first of the duplicates is the one
|
||||
that will be included in the copy. The new sort was also faster
|
||||
than the glibc version of qsort() and mergesort() in my testing.
|
||||
|
||||
- Rsync now supports the transfer of 64-bit timestamps (time_t values).
|
||||
|
||||
- Made the file-deletion code use a little less stack when recursing
|
||||
through a directory hierarchy of extraneous files.
|
||||
|
||||
- Fixed a build problem with older (2.x) versions of gcc.
|
||||
|
||||
- Added some isType() functions that make dealing with signed characters
|
||||
easier without forcing variables via casts.
|
||||
|
||||
- Changed strcat/strcpy/sprintf function calls to use safer versions.
|
||||
|
||||
- Upgraded the included popt version to 1.10.2 and improved its use of
|
||||
string-handling functions.
|
||||
|
||||
- Added missing prototypes for compatibility functions from the lib dir.
|
||||
|
||||
- Configure determines if iconv() has a const arg, allowing us to avoid a
|
||||
compiler warning.
|
||||
|
||||
- Made the sending of some numbers more efficient for protocol 30.
|
||||
|
||||
- Make sure that a daemon process doesn't mind if the client was weird and
|
||||
omitted the --server option.
|
||||
|
||||
- There are more internal logging categories available in protocol 30 than
|
||||
the age-old FINFO and FERROR, including FERROR_XFER and FWARN. These new
|
||||
categories allow some errors and warnings to go to stderr without causing
|
||||
an erroneous end-of-run warning about some files not being able to be
|
||||
transferred.
|
||||
|
||||
- Improved the use of "const" on pointers.
|
||||
|
||||
- Improved J.W.'s pool_alloc routines to add a way of freeing older
|
||||
sections of a pool's memory.
|
||||
|
||||
- The getaddrinfo.c compatibility code in the "lib" dir was replaced with
|
||||
some new code (derived from samba, derived from PostgreSQL) that has a
|
||||
better license than the old code.
|
||||
|
||||
DEVELOPER RELATED:
|
||||
|
||||
- Rsync is now licensed under the GPLv3 or later.
|
||||
|
||||
- Rsync is now being maintained in a "git" repository instead of CVS
|
||||
(though the old CVS repository still exists). Several maintenance
|
||||
scripts were updated to work with git.
|
||||
|
||||
- Generated files are no longer committed into the source repository. The
|
||||
autoconf and autoheader commands are now automatically run during the
|
||||
normal use of "configure" and "make". The latest dev versions of all
|
||||
generated files can also be copied from the samba.org web site (see the
|
||||
"magic" configure script that now comes with rsync for its location).
|
||||
|
||||
- The "patches" directory of diff files is now built from branches in the
|
||||
rsync git repository (branch patch/FOO creates file patches/FOO.diff).
|
||||
|
||||
- The proto.h file is now built using a simple perl script rather than a
|
||||
complex awk script, which proved to be more widely compatible.
|
||||
|
||||
- When running the tests, we now put our per-test temp dirs into a sub-
|
||||
directory named testtmp (which is created, if missing). This allows
|
||||
someone to symlink the testtmp directory to another filesystem (which is
|
||||
useful if the build dir's filesystem does not support ACLs and xattrs,
|
||||
but another file system does).
|
||||
|
||||
- Rsync now has a way of handling protocol-version changes during the
|
||||
development of a new protocol version. This causes any out-of-sync
|
||||
versions to speak an older protocol rather than fail in a cryptic manner.
|
||||
This addition makes it safe to deploy a pre-release version that may
|
||||
interact with the public. This new exchange of sub-version info does not
|
||||
interfere with the {MIN,MAX}_PROTOCOL_VERSION checking algorithm (which
|
||||
does not have enough range to allow the main protocol number to be
|
||||
incremented for every minor tweak in that happens during development).
|
||||
|
||||
- The csprotocol.txt file was updated to mention the daemon protocol change
|
||||
in the 3.0.0 release.
|
||||
- Made the support/atomic-rsync script able to perform a fully atomic
|
||||
update of the copied hierarchy when the destination is setup using a
|
||||
particular symlink idiom.
|
||||
|
||||
670
OLDNEWS
670
OLDNEWS
@@ -1,3 +1,666 @@
|
||||
NEWS for rsync 3.0.4 (6 Sep 2008)
|
||||
Protocol: 30 (unchanged)
|
||||
Changes since 3.0.3:
|
||||
|
||||
BUG FIXES:
|
||||
|
||||
- Fixed a bug in the hard-linking code where it would sometimes try to
|
||||
allocate 0 bytes of memory (which fails on some OSes, such as AIX).
|
||||
|
||||
- Fixed the hard-linking of files from a device that has a device number
|
||||
of 0 (which seems to be a common device number on NetBSD).
|
||||
|
||||
- Fixed the handling of a --partial-dir that cannot be created. This
|
||||
particularly impacts the --delay-updates option (since the files cannot
|
||||
be delayed without a partial-dir), and was potentially destructive if
|
||||
the --remove-source-files was also specified.
|
||||
|
||||
- Fixed a couple issues in the --fake-super handling of xattrs when the
|
||||
destination files have root-level attributes (e.g. selinux values) that
|
||||
a non-root copy can't affect.
|
||||
|
||||
- Improved the keep-alive check in the generator to fire consistently in
|
||||
incremental-recursion mode when --timeout is enabled.
|
||||
|
||||
- The --iconv option now converts the content of a symlink too, instead
|
||||
of leaving it in the wrong character-set (requires 3.0.4 on both sides
|
||||
of the transfer).
|
||||
|
||||
- When using --iconv, if a filename fails to convert on the receiving side,
|
||||
this no longer makes deletions in the root-dir of the transfer fail
|
||||
silently (the user now gets a warning about deletions being disabled
|
||||
due to IO error as long as --ignore-errors was not specified).
|
||||
|
||||
- When using --iconv, if a server-side receiver can't convert a filename,
|
||||
the error message sent back to the client no longer mangles the name
|
||||
with the wrong charset conversion.
|
||||
|
||||
- Fixed a potential alignment issue in the IRIX ACL code when allocating
|
||||
the initial "struct acl" object. Also, cast mallocs to avoid warnings.
|
||||
|
||||
- Changed some errors that were going to stdout to go to stderr.
|
||||
|
||||
- Made human_num() and human_dnum() able to output a negative number
|
||||
(rather than outputting a cryptic string of punctuation).
|
||||
|
||||
ENHANCEMENTS:
|
||||
|
||||
- Rsync will avoid sending an -e option to the server if an older protocol
|
||||
is requested (and thus the option would not be useful). This lets the
|
||||
user specify the --protocol=29 option to access an overly-restrictive
|
||||
server that is rejecting the protocol-30 use of -e to the server.
|
||||
|
||||
- Improved the message output for an RERR_PARTIAL exit.
|
||||
|
||||
DEVELOPER RELATED:
|
||||
|
||||
- The Makefile will not halt for just a timestamp change on the Makefile
|
||||
or the configure files, only for actual changes in content.
|
||||
|
||||
- Changed some commands in the testsuite's xattrs.test that called "rsync"
|
||||
instead of "$RSYNC".
|
||||
|
||||
- Enhanced the release scripts to be able to handle a branch release and
|
||||
to do even more consistency checks on the files.
|
||||
|
||||
|
||||
NEWS for rsync 3.0.3 (29 Jun 2008)
|
||||
Protocol: 30 (unchanged)
|
||||
Changes since 3.0.2:
|
||||
|
||||
BUG FIXES:
|
||||
|
||||
- Fixed a wildcard matching problem in the daemon when a module has
|
||||
"use chroot" enabled.
|
||||
|
||||
- Fixed a crash bug in the hard-link code.
|
||||
|
||||
- Fixed the sending of xattr directory information when the code finds a
|
||||
--link-dest or --copy-dest directory with unchanged xattrs -- the
|
||||
destination directory now gets these unchanged xattrs properly applied.
|
||||
|
||||
- Fixed an xattr-sending glitch that could cause an "Internal abbrev"
|
||||
error.
|
||||
|
||||
- Fixed the combination of --xattrs and --backup.
|
||||
|
||||
- The generator no longer allows a '.' dir to be excluded by a daemon-
|
||||
exclude rule.
|
||||
|
||||
- Fixed deletion handling when copying a single, empty directory (with no
|
||||
files) to a differently named, non-existent directory.
|
||||
|
||||
- Fixed the conversion of spaces into dashes in the %M log escape.
|
||||
|
||||
- Fixed several places in the code that were not returning the right
|
||||
errno when a function failed.
|
||||
|
||||
- Fixed the backing up of a device or special file into a backup dir.
|
||||
|
||||
- Moved the setting of the socket options prior to the connect().
|
||||
|
||||
- If rsync exits in the middle of a --progress output, it now outputs a
|
||||
newline to help prevent the progress line from being overwritten.
|
||||
|
||||
- Fixed a problem with how a destination path with a trailing slash or
|
||||
a trailing dot-dir was compared against the daemon excludes.
|
||||
|
||||
- Fixed the sending of large (size > 16GB) files when talking to an older
|
||||
rsync (protocols < 30): we now use a compatible block size limit.
|
||||
|
||||
- If a file's length is so huge that we overflow a checksum buffer count
|
||||
(i.e. several hundred TB), warn the user and avoid sending an invalid
|
||||
checksum struct over the wire.
|
||||
|
||||
- If a source arg is excluded, --relative no longer adds the excluded
|
||||
arg's implied dirs to the transfer. This fix also made the exclude
|
||||
check happen in the better place in the sending code.
|
||||
|
||||
- Use the overflow_exit() function for overflows, not out_of_memory().
|
||||
|
||||
- Improved the code to better handle a system that has only 32-bit file
|
||||
offsets.
|
||||
|
||||
ENHANCEMENTS:
|
||||
|
||||
- The rsyncd.conf manpage now consistently refers to the parameters in
|
||||
the daemon config file as "parameters".
|
||||
|
||||
- The description of the --inplace option was improved.
|
||||
|
||||
EXTRAS:
|
||||
|
||||
- Added a new script in the support directory, deny-rsync, which allows
|
||||
an admin to (temporarily) replace the rsync command with a script that
|
||||
sends an error message to the remote client via the rsync protocol.
|
||||
|
||||
DEVELOPER RELATED:
|
||||
|
||||
- Fixed a testcase failure if the tests are run as root and made some
|
||||
compatibility improvements.
|
||||
|
||||
- Improved the daemon tests, including checking module comments, the
|
||||
listing of files, and the ensuring that daemon excludes can't affect
|
||||
a dot-dir arg.
|
||||
|
||||
- Improved some build rules for those that build in a separate directory
|
||||
from the source, including better install rules for the man pages, and
|
||||
the fixing of a proto.h-tstamp rule that could make the binaries get
|
||||
rebuild without cause.
|
||||
|
||||
- Improved the testsuite to work around a problem with some utilities
|
||||
(e.g. cp -p & touch -r) rounding sub-second timestamps.
|
||||
|
||||
- Ensure that the early patches don't cause any generated-file hunks to
|
||||
bleed-over into patches that follow.
|
||||
|
||||
|
||||
NEWS for rsync 3.0.2 (8 Apr 2008)
|
||||
Protocol: 30 (unchanged)
|
||||
Changes since 3.0.1:
|
||||
|
||||
BUG FIXES:
|
||||
|
||||
- Fixed a potential buffer overflow in the xattr code.
|
||||
|
||||
ENHANCEMENTS:
|
||||
|
||||
- None.
|
||||
|
||||
DEVELOPER RELATED:
|
||||
|
||||
- The RPM spec file was improved to install more useful files.
|
||||
|
||||
- A few developer-oriented scripts were moved from the support dir
|
||||
to the packaging dir.
|
||||
|
||||
|
||||
NEWS for rsync 3.0.1 (3 Apr 2008)
|
||||
Protocol: 30 (unchanged)
|
||||
Changes since 3.0.0:
|
||||
|
||||
NOTABLE CHANGES IN BEHAVIOR:
|
||||
|
||||
- Added the 'c'-flag to the itemizing of non-regular files so that the
|
||||
itemized output doesn't get hidden if there were no attribute changes,
|
||||
and also so that the itemizing of a --copy-links run will distinguish
|
||||
between copying an identical non-regular file and the creation of a
|
||||
revised version with a new value (e.g. a changed symlink referent, a
|
||||
new device number, etc.).
|
||||
|
||||
BUG FIXES:
|
||||
|
||||
- Fixed a crash bug when a single-use rsync daemon (via remote shell) was
|
||||
run without specifying a --config=FILE option.
|
||||
|
||||
- Fixed a crash when backing up a directory that has a default ACL.
|
||||
|
||||
- Fixed a bug in the handling of xattr values that could cause rsync to
|
||||
not think that a file's extended attributes are up-to-date.
|
||||
|
||||
- Fixed the working of --fake-super with --link-dest and --xattrs.
|
||||
|
||||
- Fixed a hang when combining --dry-run with --remove-source-files.
|
||||
|
||||
- Fixed a bug with --iconv's handling of files that cannot be converted:
|
||||
a failed name can no longer cause a transfer failure.
|
||||
|
||||
- Fixed the building of the rounding.h file on systems that need custom
|
||||
CPPFLAGS to be used. Also improved the error reporting if the building
|
||||
of rounding.h fails.
|
||||
|
||||
- Fixed the use of the --protect-args (-s) option when talking to a daemon.
|
||||
|
||||
- Fixed the --ignore-existing option's protection of files on the receiver
|
||||
that are non-regular files on the sender (e.g. if a symlink or a dir on
|
||||
the sender is trying to replace a file on the receiver). The reverse
|
||||
protection (protecting a dir/symlink/device from being replaced by a
|
||||
file) was already working.
|
||||
|
||||
- Fixed an assert failure if --hard-links is combined with an option that
|
||||
can skip a file in a set of hard-linked files (i.e. --ignore-existing,
|
||||
--append, etc.), without skipping all the files in the set.
|
||||
|
||||
- Avoid setting the modify time on a directory that already has the right
|
||||
modify time set. This avoids tweaking the dir's ctime.
|
||||
|
||||
- Improved the daemon-exclude handling to do a better job of applying the
|
||||
exclude rules to path entries. It also sends the user an error just as
|
||||
if the files were actually missing (instead of silently ignoring the
|
||||
user's args), and avoids sending the user the filter-action messages
|
||||
for these non-user-initiated rules.
|
||||
|
||||
- Fixed some glitches with the dry-run code's missing-directory
|
||||
handling, including a problem when combined with --fuzzy.
|
||||
|
||||
- Fixed some glitches with the skipped-directory handling.
|
||||
|
||||
- Fixed the 'T'-flag itemizing of symlinks when --time isn't preserved.
|
||||
|
||||
- Fixed a glitch in the itemizing of permissions with the -E option.
|
||||
|
||||
- The --append option's restricting of transfers to those that add data no
|
||||
longer prevents the updating of non-content changes to otherwise up-to-
|
||||
date files (i.e. those with the same content but differing permissions,
|
||||
ownership, xattrs, etc.).
|
||||
|
||||
- Don't allow --fake-super to be specified with -XX (double --xattrs)
|
||||
because the options conflict. If a daemon has "fake super" enabled,
|
||||
it automatically downgrades a -XX request to -X.
|
||||
|
||||
- Fixed a couple bugs in the parsing of daemon-config excludes that could
|
||||
make a floating exclude rule get treated as matching an absolute path.
|
||||
|
||||
- A daemon doesn't try to auto-refuse the "iconv" option if iconv-support
|
||||
wasn't compiled in to the daemon (avoiding a warning in the logs).
|
||||
|
||||
- Fixed the inclusion of per-dir merge files from implied dirs.
|
||||
|
||||
- Fixed the support/rrsync script to work with the latest options that
|
||||
rsync sends (including its flag-specifying use of -e to the server).
|
||||
|
||||
ENHANCEMENTS:
|
||||
|
||||
- Added the --old-dirs (--old-d) option to make it easier for a user to
|
||||
ask for file-listings with older rsync versions (this is easier than
|
||||
having to type "-r --exclude='/*/*'" manually).
|
||||
|
||||
- When getting an error while asking an older rsync daemon for a file
|
||||
listing, rsync will try to notice if the error is a rejection of the
|
||||
--dirs (-d) option and let the user know how to work around the issue.
|
||||
|
||||
- Added a few more --no-OPTION overrides.
|
||||
|
||||
- Improved the documentation of the --append option.
|
||||
|
||||
- Improved the documentation of the filter/exclude/include daemon
|
||||
parameters.
|
||||
|
||||
INTERNAL:
|
||||
|
||||
- Fixed a couple minor bugs in the included popt library (ones which I
|
||||
sent to the official popt project for inclusion in the 1.14 release).
|
||||
|
||||
- Fixed a stat() call that should have been do_stat() so that the proper
|
||||
normal/64-bit stat() function gets called. (Was in an area that should
|
||||
not have caused problems, though.)
|
||||
|
||||
- Changed the file-glob code to do a directory scan without using the
|
||||
"glob" and "glob.h". This lets us do the globbing with less memory
|
||||
churn, and also avoid adding daemon-excluded items to the returned
|
||||
args.
|
||||
|
||||
DEVELOPER RELATED:
|
||||
|
||||
- The configure script tries to get the user's compiler to not warn about
|
||||
unused function parameters if the build is not including one or more of
|
||||
the ACL/xattrs/iconv features.
|
||||
|
||||
- The configure script now has better checks for figuring out if the
|
||||
included popt code should be used or not.
|
||||
|
||||
- Fixed two testsuite glitches: avoid a failure if someone's "cd" command
|
||||
outputs the current directory when cd-ing to a relative path, and made
|
||||
the itemized test query how rsync was built to determine if it should
|
||||
expect hard-linked symlinks or not.
|
||||
|
||||
- Updated the testsuite to verify that various bug fixes remain fixed.
|
||||
|
||||
- The RPM spec file was updated to have: (1) comments for how to use the
|
||||
rsync-patch tar file, and (2) an /etc/xinetd.d/rsync file.
|
||||
|
||||
- Updated the build scripts to work with a revised FTP directory
|
||||
structure.
|
||||
|
||||
|
||||
NEWS for rsync 3.0.0 (1 Mar 2008)
|
||||
Protocol: 30 (changed)
|
||||
Changes since 2.6.9:
|
||||
|
||||
NOTABLE CHANGES IN BEHAVIOR:
|
||||
|
||||
- The handling of implied directories when using --relative has changed to
|
||||
send them as directories (e.g. no implied dir is ever sent as a symlink).
|
||||
This avoids unexpected behavior and should not adversely affect most
|
||||
people. If you're one of those rare individuals who relied upon having
|
||||
an implied dir be duplicated as a symlink, you should specify the
|
||||
transfer of the symlink and the transfer of the referent directory as
|
||||
separate args. (See also --keep-dirlinks and --no-implied-dirs.)
|
||||
Also, exclude rules no longer have a partial effect on implied dirs.
|
||||
|
||||
- Requesting a remote file-listing without specifying -r (--recursive) now
|
||||
sends the -d (--dirs) option to the remote rsync rather than sending -r
|
||||
along with an extra exclude of /*/*. If the remote rsync does not
|
||||
understand the -d option (i.e. it is 2.6.3 or older), you will need to
|
||||
either turn off -d (--no-d), or specify -r --exclude='/*/*' manually.
|
||||
|
||||
- In --dry-run mode, the last line of the verbose summary text is output
|
||||
with a "(DRY RUN)" suffix to help remind you that no updates were made.
|
||||
Similarly, --only-write-batch outputs "(BATCH ONLY)".
|
||||
|
||||
- A writable rsync daemon with "use chroot" disabled now defaults to a
|
||||
symlink-munging behavior designed to make symlinks safer while also
|
||||
allowing absolute symlinks to be stored and retrieved. This also has
|
||||
the effect of making symlinks unusable while they're in the daemon's
|
||||
hierarchy. See the daemon's "munge symlinks" parameter for details.
|
||||
|
||||
- Starting up an extra copy of an rsync daemon will not clobber the pidfile
|
||||
for the running daemon -- if the pidfile exists, the new daemon will exit
|
||||
with an error. This means that your wrapper script that starts the rsync
|
||||
daemon should be made to handle lock-breaking (if you want any automatic
|
||||
breaking of locks to be done).
|
||||
|
||||
BUG FIXES:
|
||||
|
||||
- A daemon with "use chroot = no" and excluded items listed in the daemon
|
||||
config file now properly checks an absolute-path arg specified for these
|
||||
options: --compare-dest, --link-dest, --copy-dest, --partial-dir,
|
||||
--backup-dir, --temp-dir, and --files-from.
|
||||
|
||||
- A daemon can now be told to disable all user- and group-name translation
|
||||
on a per-module basis. This avoids a potential problem with a writable
|
||||
daemon module that has "use chroot" enabled -- if precautions weren't
|
||||
taken, a user could try to add a missing library and get rsync to use
|
||||
it. This makes rsync safer by default, and more configurable when id-
|
||||
translation is not desired. See the daemon's "numeric ids" parameter
|
||||
for full details.
|
||||
|
||||
- A chroot daemon can now indicate which part of its path should affect the
|
||||
chroot call, and which part should become an inside-chroot path for the
|
||||
module. This allows you to have outside-the-transfer paths (such as for
|
||||
libraries) even when you enable chroot protection. The idiom used in the
|
||||
rsyncd.conf file is: path = /chroot/dirs/./dirs/inside
|
||||
|
||||
- If a file's data arrived successfully on the receiving side but the
|
||||
rename of the temporary file to the destination file failed AND the
|
||||
--remove-source-files (or the deprecated --remove-sent-files) option
|
||||
was specified, rsync no longer erroneously removes the associated
|
||||
source file.
|
||||
|
||||
- Fixed the output of -ii when combined with one of the --*-dest options:
|
||||
it now itemizes all the items, not just the changed ones.
|
||||
|
||||
- Made the output of all file types consistent when using a --*-dest
|
||||
option. Prior versions would output too many creation events for
|
||||
matching items.
|
||||
|
||||
- The code that waits for a child pid now handles being interrupted by a
|
||||
signal. This fixes a problem with the pre-xfer exec function not being
|
||||
able to get the exit status from the script.
|
||||
|
||||
- A negated filter rule (i.e. with a '!' modifier) no longer loses the
|
||||
negation when sending the filter rules to the remote rsync.
|
||||
|
||||
- Fixed a problem with the --out-format (aka --log-format) option %f: it
|
||||
no longer outputs superfluous directory info for a non-daemon rsync.
|
||||
|
||||
- Fixed a problem with -vv (double --verbose) and --stats when "pushing"
|
||||
files (which includes local copies). Version 2.6.9 would complete the
|
||||
copy, but exit with an error when the receiver output its memory stats.
|
||||
|
||||
- If --password-file is used on a non-daemon transfer, rsync now complains
|
||||
and exits. This should help users figure out that they can't use this
|
||||
option to control a remote shell's password prompt.
|
||||
|
||||
- Make sure that directory permissions of a newly-created destination
|
||||
directory are handled right when --perms is left off.
|
||||
|
||||
- The itemized output of a newly-created destination directory is now
|
||||
output as a creation event, not a change event.
|
||||
|
||||
- Improved --hard-link so that more corner cases are handled correctly
|
||||
when combined with options such as --link-dest and/or --ignore-existing.
|
||||
|
||||
- The --append option no longer updates a file that has the same size.
|
||||
|
||||
- Fixed a bug when combining --backup and --backup-dir with --inplace:
|
||||
any missing backup directories are now created.
|
||||
|
||||
- Fixed a bug when using --backup and --inplace with --whole-file or
|
||||
--read-batch: backup files are actually created now.
|
||||
|
||||
- The daemon pidfile is checked and created sooner in the startup sequence.
|
||||
|
||||
- If a daemon module's "path" value is not an absolute pathname, the code
|
||||
now makes it absolute internally (making it work properly).
|
||||
|
||||
- Ensure that a temporary file always has owner-write permission while we
|
||||
are writing to it. This avoids problems with some network filesystems
|
||||
when transfering read-only files.
|
||||
|
||||
- Any errors output about password-file reading no longer cause an error at
|
||||
the end of the run about a partial transfer.
|
||||
|
||||
- The --read-batch option for protocol 30 now ensures that several more
|
||||
options are set correctly for the current batch file: --iconv, --acls,
|
||||
--xattrs, --inplace, --append, and --append-verify.
|
||||
|
||||
- Using --only-write-batch to a daemon receiver now works properly (older
|
||||
versions would update some files while writing the batch).
|
||||
|
||||
- Avoid outputting a "file has vanished" message when the file is a broken
|
||||
symlink and --copy-unsafe-links or --copy-dirlinks is used (the code
|
||||
already handled this for --copy-links).
|
||||
|
||||
- Fixed the combination of --only-write-batch and --dry-run.
|
||||
|
||||
- Fixed rsync's ability to remove files that are not writable by the file's
|
||||
owner when rsync is running as the same user.
|
||||
|
||||
- When transferring large files, the sender's hashtable of checksums is
|
||||
kept at a more reasonable state of fullness (no more than 80% full) so
|
||||
that the scanning of the hashtable will not bog down as the number of
|
||||
blocks increases.
|
||||
|
||||
ENHANCEMENTS:
|
||||
|
||||
- A new incremental-recursion algorithm is now used when rsync is talking
|
||||
to another 3.x version. This starts the transfer going more quickly
|
||||
(before all the files have been found), and requires much less memory.
|
||||
See the --recursive option in the manpage for some restrictions.
|
||||
|
||||
- Lowered memory use in the non-incremental-recursion algorithm for typical
|
||||
option values (usually saving from 21-29 bytes per file).
|
||||
|
||||
- The default --delete algorithm is now --delete-during when talking to a
|
||||
3.x rsync. This is a faster scan than using --delete-before (which is
|
||||
the default when talking to older rsync versions), and is compatible with
|
||||
the new incremental recursion mode.
|
||||
|
||||
- Rsync now allows multiple remote-source args to be specified rather than
|
||||
having to rely on a special space-splitting side-effect of the remote-
|
||||
shell. Additional remote args must specify the same host or an empty one
|
||||
(e.g. empty: :file1 or ::module/file2). For example, this means that
|
||||
local use of brace expansion now works: rsync -av host:dir/{f1,f2} .
|
||||
|
||||
- Added the --protect-args (-s) option, that tells rsync to send most of
|
||||
the command-line args at the start of the transfer rather than as args
|
||||
to the remote-shell command. This protects them from space-splitting,
|
||||
and only interprets basic wildcard special shell characters (*?[).
|
||||
|
||||
- Added the --delete-delay option, which is a more efficient way to delete
|
||||
files at the end of the transfer without needing a separate delete pass.
|
||||
|
||||
- Added the --acls (-A) option to preserve Access Control Lists. This is
|
||||
an improved version of the prior patch that was available, and it even
|
||||
supports OS X ACLs. If you need to have backward compatibility with old,
|
||||
ACL-patched versions of rsync, apply the acls.diff file from the patches
|
||||
dir.
|
||||
|
||||
- Added the --xattrs (-X) option to preserve extended attributes. This is
|
||||
an improved version of the prior patch that was available, and it even
|
||||
supports OS X xattrs (which includes their resource fork data). If you
|
||||
need to have backward compatibility with old, xattr-patched versions of
|
||||
rsync, apply the xattrs.diff file from the patches dir.
|
||||
|
||||
- Added the --fake-super option that allows a non-super user to preserve
|
||||
all attributes of a file by using a special extended-attribute idiom.
|
||||
It even supports the storing of foreign ACL data on your backup server.
|
||||
There is also an analogous "fake super" parameter for an rsync daemon.
|
||||
|
||||
- Added the --iconv option, which allows rsync to convert filenames from
|
||||
one character-set to another during the transfer. The default is to
|
||||
make this feature available as long as your system has iconv_open().
|
||||
If compilation fails, specify --disable-iconv to configure, and then
|
||||
rebuild. If you want rsync to perform character-set conversions by
|
||||
default, you can specify --enable-iconv=CONVERT_STRING with the default
|
||||
value for the --iconv option that you wish to use. For example,
|
||||
"--enable-iconv=." is a good choice. See the rsync manpage for an
|
||||
explanation of the --iconv option's settings.
|
||||
|
||||
- A new daemon config parameter, "charset", lets you control the character-
|
||||
set that is used during an --iconv transfer to/from a daemon module. You
|
||||
can also set your daemon to refuse "no-iconv" if you want to force the
|
||||
client to use an --iconv transfer (requiring an rsync 3.x client).
|
||||
|
||||
- Added the --skip-compress=LIST option to override the default list of
|
||||
file suffixes that will not be compressed when using --compress (-z).
|
||||
|
||||
- The daemon's default for "dont compress" was extended to include:
|
||||
*.7z *.mp[34] *.mov *.avi *.ogg *.jpg *.jpeg
|
||||
The name-matching routine was also optimized to run more quickly.
|
||||
|
||||
- The --max-delete option now outputs a warning if it skipped any file
|
||||
deletions, including a count of how many deletions were skipped. (Older
|
||||
versions just silently stopped deleting things.)
|
||||
|
||||
- You may specify --max-delete=0 to a 3.0.0 client to request that it warn
|
||||
about extraneous files without deleting anything. If you're not sure
|
||||
what version the client is, you can use the less-obvious --max-delete=-1,
|
||||
as both old and new versions will treat that as the same request (though
|
||||
older versions don't warn).
|
||||
|
||||
- The --hard-link option now uses less memory on both the sending and
|
||||
receiving side for all protocol versions. For protocol 30, the use of a
|
||||
hashtable on the sending side allows us to more efficiently convey to the
|
||||
receiver what files are linked together. This reduces the amount of data
|
||||
sent over the socket by a considerable margin (rather than adding more
|
||||
data), and limits the in-memory storage of the device+inode information
|
||||
to just the sending side for the new protocol 30, or to the receiving
|
||||
side when speaking an older protocol (note that older rsync versions kept
|
||||
the device+inode information on both sides).
|
||||
|
||||
- The filter rules now support a perishable ("p") modifier that marks rules
|
||||
that should not have an effect in a directory that is being deleted. e.g.
|
||||
-f '-p .svn/' would only affect "live" .svn directories.
|
||||
|
||||
- Rsync checks all the alternate-destination args for validity (e.g.
|
||||
--link-dest). This lets the user know when they specified a directory
|
||||
that does not exist.
|
||||
|
||||
- If we get an ENOSYS error setting the time on a symlink, we don't
|
||||
complain about it anymore (for those systems that even support the
|
||||
setting of the modify-time on a symlink).
|
||||
|
||||
- Protocol 30 now uses MD5 checksums instead of MD4.
|
||||
|
||||
- Changed the --append option to not checksum the existing data in the
|
||||
destination file, which speeds up file appending.
|
||||
|
||||
- Added the --append-verify option, which works like the older --append
|
||||
option (verifying the existing data in the destination file). For
|
||||
compatibility with older rsync versions, any use of --append that is
|
||||
talking protocol 29 or older will revert to the --append-verify method.
|
||||
|
||||
- Added the --contimeout=SECONDS option that lets the user specify a
|
||||
connection timeout for rsync daemon access.
|
||||
|
||||
- Documented and extended the support for the RSYNC_CONNECT_PROG variable
|
||||
that can be used to enhance the client side of a daemon connection.
|
||||
|
||||
- Improved the dashes and double-quotes in the nroff manpage output.
|
||||
|
||||
- Rsync now supports a lot more --no-OPTION override options.
|
||||
|
||||
INTERNAL:
|
||||
|
||||
- The file-list sorting algorithm now uses a sort that keeps any same-
|
||||
named items in the same order as they were specified. This allows
|
||||
rsync to always ensure that the first of the duplicates is the one
|
||||
that will be included in the copy. The new sort is also faster
|
||||
than the glibc version of qsort() and mergesort().
|
||||
|
||||
- Rsync now supports the transfer of 64-bit timestamps (time_t values).
|
||||
|
||||
- Made the file-deletion code use a little less stack when recursing
|
||||
through a directory hierarchy of extraneous files.
|
||||
|
||||
- Fixed a build problem with older (2.x) versions of gcc.
|
||||
|
||||
- Added some isType() functions that make dealing with signed characters
|
||||
easier without forcing variables via casts.
|
||||
|
||||
- Changed strcat/strcpy/sprintf function calls to use safer versions.
|
||||
|
||||
- Upgraded the included popt version to 1.10.2 and improved its use of
|
||||
string-handling functions.
|
||||
|
||||
- Added missing prototypes for compatibility functions from the lib dir.
|
||||
|
||||
- Configure determines if iconv() has a const arg, allowing us to avoid a
|
||||
compiler warning.
|
||||
|
||||
- Made the sending of some numbers more efficient for protocol 30.
|
||||
|
||||
- Make sure that a daemon process doesn't mind if the client was weird and
|
||||
omitted the --server option.
|
||||
|
||||
- There are more internal logging categories available in protocol 30 than
|
||||
the age-old FINFO and FERROR, including FERROR_XFER and FWARN. These new
|
||||
categories allow some errors and warnings to go to stderr without causing
|
||||
an erroneous end-of-run warning about some files not being able to be
|
||||
transferred.
|
||||
|
||||
- Improved the use of "const" on pointers.
|
||||
|
||||
- Improved J.W.'s pool_alloc routines to add a way of incrementally freeing
|
||||
older sections of a pool's memory.
|
||||
|
||||
- The getaddrinfo.c compatibility code in the "lib" dir was replaced with
|
||||
some new code (derived from samba, derived from PostgreSQL) that has a
|
||||
better license than the old code.
|
||||
|
||||
DEVELOPER RELATED:
|
||||
|
||||
- Rsync is now licensed under the GPLv3 or later.
|
||||
|
||||
- Rsync is now being maintained in a "git" repository instead of CVS
|
||||
(though the old CVS repository still exists for historical access).
|
||||
Several maintenance scripts were updated to work with git.
|
||||
|
||||
- Generated files are no longer committed into the source repository. The
|
||||
autoconf and autoheader commands are now automatically run during the
|
||||
normal use of "configure" and "make". The latest dev versions of all
|
||||
generated files can also be copied from the samba.org web site (see the
|
||||
prepare-source script's fetch option).
|
||||
|
||||
- The "patches" directory of diff files is now built from branches in the
|
||||
rsync git repository (branch patch/FOO creates file patches/FOO.diff).
|
||||
This directory is now distributed in a separate separate tar file named
|
||||
rsync-patches-VERSION.tar.gz instead of the main rsync-VERSION.tar.gz.
|
||||
|
||||
- The proto.h file is now built using a simple perl script rather than a
|
||||
complex awk script, which proved to be more widely compatible.
|
||||
|
||||
- When running the tests, we now put our per-test temp dirs into a sub-
|
||||
directory named testtmp (which is created, if missing). This allows
|
||||
someone to symlink the testtmp directory to another filesystem (which is
|
||||
useful if the build dir's filesystem does not support ACLs and xattrs,
|
||||
but another filesystem does).
|
||||
|
||||
- Rsync now has a way of handling protocol-version changes during the
|
||||
development of a new protocol version. This causes any out-of-sync
|
||||
versions to speak an older protocol rather than fail in a cryptic manner.
|
||||
This addition makes it safer to deploy a pre-release version that may
|
||||
interact with the public. This new exchange of sub-version info does not
|
||||
interfere with the {MIN,MAX}_PROTOCOL_VERSION checking algorithm (which
|
||||
does not have enough range to allow the main protocol number to be
|
||||
incremented for every minor tweak in that happens during development).
|
||||
|
||||
- The csprotocol.txt file was updated to mention the daemon protocol change
|
||||
in the 3.0.0 release.
|
||||
|
||||
|
||||
NEWS for rsync 2.6.9 (6 Nov 2006)
|
||||
Protocol: 29 (unchanged)
|
||||
Changes since 2.6.8:
|
||||
@@ -2244,7 +2907,12 @@ Changes since 2.4.6:
|
||||
|
||||
Partial Protocol History
|
||||
RELEASE DATE VER. DATE OF COMMIT* PROTOCOL
|
||||
?? ??? 2008 3.0.0 11 Nov 2006 30
|
||||
28 Dec 2008 3.0.5 30
|
||||
06 Sep 2008 3.0.4 30
|
||||
29 Jun 2008 3.0.3 30
|
||||
08 Apr 2008 3.0.2 30
|
||||
03 Apr 2008 3.0.1 30
|
||||
01 Mar 2008 3.0.0 11 Nov 2006 30
|
||||
06 Nov 2006 2.6.9 29
|
||||
22 Apr 2006 2.6.8 29
|
||||
11 Mar 2006 2.6.7 29
|
||||
|
||||
123
README
123
README
@@ -1,122 +1,135 @@
|
||||
WHAT IS RSYNC?
|
||||
--------------
|
||||
|
||||
rsync is a replacement for scp/rcp that has many more features.
|
||||
Rsync is a fast and extraordinarily versatile file copying tool for
|
||||
both remote and local files.
|
||||
|
||||
rsync uses the "rsync algorithm" which provides a very fast method for
|
||||
bringing remote files into sync. It does this by sending just the
|
||||
Rsync uses a delta-transfer algorithm which provides a very fast method
|
||||
for bringing remote files into sync. It does this by sending just the
|
||||
differences in the files across the link, without requiring that both
|
||||
sets of files are present at one of the ends of the link beforehand.
|
||||
At first glance this may seem impossible because the calculation of
|
||||
diffs between two files normally requires local access to both
|
||||
files.
|
||||
sets of files are present at one of the ends of the link beforehand. At
|
||||
first glance this may seem impossible because the calculation of diffs
|
||||
between two files normally requires local access to both files.
|
||||
|
||||
A technical report describing the rsync algorithm is included with
|
||||
this package.
|
||||
A technical report describing the rsync algorithm is included with this
|
||||
package.
|
||||
|
||||
|
||||
USAGE
|
||||
-----
|
||||
|
||||
Basically you use rsync just like rcp, but rsync has many additional
|
||||
options. To get a complete list of supported options type
|
||||
Basically you use rsync just like scp, but rsync has many additional
|
||||
options. To get a complete list of supported options type:
|
||||
|
||||
rsync --help
|
||||
rsync --help
|
||||
|
||||
and see the manual for more information.
|
||||
See the manpage for more detailed information.
|
||||
|
||||
|
||||
SETUP
|
||||
-----
|
||||
|
||||
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 ssh or rsh system. Using ssh is
|
||||
recommended for its security features.
|
||||
Rsync normally uses ssh or rsh for communication with remote systems.
|
||||
It does not need to be setuid and requires no special privileges for
|
||||
installation. You 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.
|
||||
This is generally used for public file distribution, although
|
||||
authentication and access control are available.
|
||||
|
||||
To install rsync, first run the "configure" script. This will create a
|
||||
Makefile and config.h appropriate for your system. Then type
|
||||
"make".
|
||||
To install rsync, first run the "configure" script. This will create a
|
||||
Makefile and config.h appropriate for your system. Then type "make".
|
||||
|
||||
Note that on some systems you will have to force configure not to use
|
||||
gcc because gcc may not support some features (such as 64 bit file
|
||||
offsets) that your system may support. Set the environment variable CC
|
||||
offsets) that your system may support. Set the environment variable CC
|
||||
to the name of your native compiler before running configure in this
|
||||
case.
|
||||
case.
|
||||
|
||||
Once built put a copy of rsync in your search path on the local and
|
||||
remote systems (or use "make install"). That's it!
|
||||
remote systems (or use "make install"). That's it!
|
||||
|
||||
|
||||
RSYNC DAEMONS
|
||||
-------------
|
||||
|
||||
rsync can also talk to "rsync daemons" which can provide anonymous or
|
||||
authenticated rsync. See the rsyncd.conf(5) man page for details on how
|
||||
to setup an rsync daemon. See the rsync(1) man page for info on how to
|
||||
Rsync can also talk to "rsync daemons" which can provide anonymous or
|
||||
authenticated rsync. See the rsyncd.conf(5) man page for details on how
|
||||
to setup an rsync daemon. See the rsync(1) man page for info on how to
|
||||
connect to an rsync daemon.
|
||||
|
||||
|
||||
MAILING LIST
|
||||
------------
|
||||
WEB SITE
|
||||
--------
|
||||
|
||||
There is a mailing list for the discussion of rsync and its
|
||||
applications. It is open to anyone to join. I will announce new
|
||||
versions on this list.
|
||||
The main rsync web site is here:
|
||||
|
||||
To join the mailing list see the web page at http://lists.samba.org/
|
||||
http://rsync.samba.org/
|
||||
|
||||
To send mail to everyone on the list send it to rsync@lists.samba.org
|
||||
You'll find a FAQ list, downloads, resources, HTML versions of the
|
||||
manpages, etc.
|
||||
|
||||
|
||||
MAILING LISTS
|
||||
-------------
|
||||
|
||||
There is a mailing list for the discussion of rsync and its applications
|
||||
that is open to anyone to join. New releases are announced on this
|
||||
list, and there is also an announcement-only mailing list for those that
|
||||
want official announcements. See the mailing-list page for full
|
||||
details:
|
||||
|
||||
http://rsync.samba.org/lists.html
|
||||
|
||||
|
||||
BUG REPORTS
|
||||
-----------
|
||||
|
||||
If you have web access then please look at
|
||||
To visit this web page for full the details on bug reporting:
|
||||
|
||||
http://rsync.samba.org/
|
||||
http://rsync.samba.org/bugzilla.html
|
||||
|
||||
That page contains links to the current bug list, and information on
|
||||
how to report a bug well. You might also like to try searching the
|
||||
internet for the error message you've received, or looking in the
|
||||
mailing list archives at
|
||||
That page contains links to the current bug list, and information on how
|
||||
to report a bug well. You might also like to try searching the Internet
|
||||
for the error message you've received, or looking in the mailing list
|
||||
archives at:
|
||||
|
||||
http://mail-archive.com/rsync@lists.samba.org/
|
||||
http://mail-archive.com/rsync@lists.samba.org/
|
||||
|
||||
To send a bug report, follow the instructions on the bug-tracking
|
||||
page of the web site.
|
||||
|
||||
If you don't have web access, email your bug report to
|
||||
rsync@lists.samba.org.
|
||||
Alternately, email your bug report to rsync@lists.samba.org .
|
||||
|
||||
|
||||
CVS TREE
|
||||
--------
|
||||
GIT REPOSITORY
|
||||
--------------
|
||||
|
||||
If you want to get the very latest version of rsync direct from the
|
||||
source code repository then you can use anonymous cvs. You will need a
|
||||
recent version of cvs then use the following commands:
|
||||
source code repository then you can use git:
|
||||
|
||||
cvs -d :pserver:cvs@pserver.samba.org:/cvsroot login
|
||||
Password: cvs
|
||||
git clone git://git.samba.org/rsync.git
|
||||
|
||||
cvs -d :pserver:cvs@pserver.samba.org:/cvsroot co rsync
|
||||
See the download page for full details on all the ways to grab the
|
||||
source, including nightly tar files, web-browsing of the git repository,
|
||||
etc.:
|
||||
|
||||
Look at the cvs documentation for more details.
|
||||
http://rsync.samba.org/download.html
|
||||
|
||||
|
||||
COPYRIGHT
|
||||
---------
|
||||
|
||||
rsync was originally written by Andrew Tridgell and has been improved
|
||||
by many developers around the world. rsync may be used, modified and
|
||||
redistributed only under the terms of the GNU General Public License,
|
||||
found in the file COPYING in this distribution, or at
|
||||
Rsync was originally written by Andrew Tridgell and is currently
|
||||
maintained by Wayne Davison. It has been improved by many developers
|
||||
from around the world.
|
||||
|
||||
http://www.fsf.org/licenses/gpl.html
|
||||
Rsync may be used, modified and redistributed only under the terms of
|
||||
the GNU General Public License, found in the file COPYING in this
|
||||
distribution, or at:
|
||||
|
||||
http://www.fsf.org/licenses/gpl.html
|
||||
|
||||
|
||||
AVAILABILITY
|
||||
|
||||
2
access.c
2
access.c
@@ -2,7 +2,7 @@
|
||||
* Routines to authenticate access to a daemon (hosts allow/deny).
|
||||
*
|
||||
* Copyright (C) 1998 Andrew Tridgell
|
||||
* Copyright (C) 2004-2007 Wayne Davison
|
||||
* Copyright (C) 2004-2008 Wayne Davison
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
|
||||
20
acls.c
20
acls.c
@@ -3,7 +3,7 @@
|
||||
*
|
||||
* Copyright (C) 1996 Andrew Tridgell
|
||||
* Copyright (C) 1996 Paul Mackerras
|
||||
* Copyright (C) 2006 Wayne Davison
|
||||
* Copyright (C) 2006-2008 Wayne Davison
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
@@ -92,9 +92,19 @@ static item_list default_acl_list = EMPTY_ITEM_LIST;
|
||||
|
||||
static const char *str_acl_type(SMB_ACL_TYPE_T type)
|
||||
{
|
||||
return type == SMB_ACL_TYPE_ACCESS ? "SMB_ACL_TYPE_ACCESS"
|
||||
: type == SMB_ACL_TYPE_DEFAULT ? "SMB_ACL_TYPE_DEFAULT"
|
||||
: "unknown SMB_ACL_TYPE_T";
|
||||
switch (type) {
|
||||
case SMB_ACL_TYPE_ACCESS:
|
||||
#ifdef HAVE_OSX_ACLS
|
||||
return "ACL_TYPE_EXTENDED";
|
||||
#else
|
||||
return "ACL_TYPE_ACCESS";
|
||||
#endif
|
||||
case SMB_ACL_TYPE_DEFAULT:
|
||||
return "ACL_TYPE_DEFAULT";
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return "unknown ACL type!";
|
||||
}
|
||||
|
||||
static int calc_sacl_entries(const rsync_acl *racl)
|
||||
@@ -933,7 +943,7 @@ static int set_rsync_acl(const char *fname, acl_duo *duo_item,
|
||||
#endif
|
||||
if (sys_acl_set_file(fname, type, duo_item->sacl) < 0) {
|
||||
rsyserr(FERROR_XFER, errno, "set_acl: sys_acl_set_file(%s, %s)",
|
||||
fname, str_acl_type(type));
|
||||
fname, str_acl_type(type));
|
||||
return -1;
|
||||
}
|
||||
if (type == SMB_ACL_TYPE_ACCESS)
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
* Support rsync daemon authentication.
|
||||
*
|
||||
* Copyright (C) 1998-2000 Andrew Tridgell
|
||||
* Copyright (C) 2002-2007 Wayne Davison
|
||||
* Copyright (C) 2002-2008 Wayne Davison
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
|
||||
80
backup.c
80
backup.c
@@ -2,7 +2,7 @@
|
||||
* Backup handling code.
|
||||
*
|
||||
* Copyright (C) 1999 Andrew Tridgell
|
||||
* Copyright (C) 2003-2007 Wayne Davison
|
||||
* Copyright (C) 2003-2008 Wayne Davison
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
@@ -180,10 +180,19 @@ int make_bak_dir(const char *fullpath)
|
||||
/* robustly move a file, creating new directory structures if necessary */
|
||||
static int robust_move(const char *src, char *dst)
|
||||
{
|
||||
if (robust_rename(src, dst, NULL, 0755) < 0
|
||||
&& (errno != ENOENT || make_bak_dir(dst) < 0
|
||||
|| robust_rename(src, dst, NULL, 0755) < 0))
|
||||
return -1;
|
||||
if (robust_rename(src, dst, NULL, 0755) < 0) {
|
||||
int save_errno = errno ? errno : EINVAL; /* 0 paranoia */
|
||||
if (errno == ENOENT && make_bak_dir(dst) == 0) {
|
||||
if (robust_rename(src, dst, NULL, 0755) < 0)
|
||||
save_errno = errno ? errno : save_errno;
|
||||
else
|
||||
save_errno = 0;
|
||||
}
|
||||
if (save_errno) {
|
||||
errno = save_errno;
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -195,6 +204,7 @@ static int keep_backup(const char *fname)
|
||||
stat_x sx;
|
||||
struct file_struct *file;
|
||||
char *buf;
|
||||
int save_preserve_xattrs = preserve_xattrs;
|
||||
int kept = 0;
|
||||
int ret_code;
|
||||
|
||||
@@ -234,15 +244,23 @@ static int keep_backup(const char *fname)
|
||||
/* Check to see if this is a device file, or link */
|
||||
if ((am_root && preserve_devices && IS_DEVICE(file->mode))
|
||||
|| (preserve_specials && IS_SPECIAL(file->mode))) {
|
||||
uint32 *devp = F_RDEV_P(file);
|
||||
dev_t rdev = MAKEDEV(DEV_MAJOR(devp), DEV_MINOR(devp));
|
||||
int save_errno;
|
||||
do_unlink(buf);
|
||||
if (do_mknod(buf, file->mode, rdev) < 0
|
||||
&& (errno != ENOENT || make_bak_dir(buf) < 0
|
||||
|| do_mknod(buf, file->mode, rdev) < 0)) {
|
||||
rsyserr(FERROR, errno, "mknod %s failed",
|
||||
full_fname(buf));
|
||||
} else if (verbose > 2) {
|
||||
if (do_mknod(buf, file->mode, sx.st.st_rdev) < 0) {
|
||||
save_errno = errno ? errno : EINVAL; /* 0 paranoia */
|
||||
if (errno == ENOENT && make_bak_dir(buf) == 0) {
|
||||
if (do_mknod(buf, file->mode, sx.st.st_rdev) < 0)
|
||||
save_errno = errno ? errno : save_errno;
|
||||
else
|
||||
save_errno = 0;
|
||||
}
|
||||
if (save_errno) {
|
||||
rsyserr(FERROR, save_errno, "mknod %s failed",
|
||||
full_fname(buf));
|
||||
}
|
||||
} else
|
||||
save_errno = 0;
|
||||
if (verbose > 2 && save_errno == 0) {
|
||||
rprintf(FINFO, "make_backup: DEVICE %s successful.\n",
|
||||
fname);
|
||||
}
|
||||
@@ -252,11 +270,18 @@ static int keep_backup(const char *fname)
|
||||
|
||||
if (!kept && S_ISDIR(file->mode)) {
|
||||
/* make an empty directory */
|
||||
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));
|
||||
if (do_mkdir(buf, file->mode) < 0) {
|
||||
int save_errno = errno ? errno : EINVAL; /* 0 paranoia */
|
||||
if (errno == ENOENT && make_bak_dir(buf) == 0) {
|
||||
if (do_mkdir(buf, file->mode) < 0)
|
||||
save_errno = errno ? errno : save_errno;
|
||||
else
|
||||
save_errno = 0;
|
||||
}
|
||||
if (save_errno) {
|
||||
rsyserr(FINFO, save_errno, "mkdir %s failed",
|
||||
full_fname(buf));
|
||||
}
|
||||
}
|
||||
|
||||
ret_code = do_rmdir(fname);
|
||||
@@ -278,11 +303,18 @@ static int keep_backup(const char *fname)
|
||||
kept = 1;
|
||||
} else {
|
||||
do_unlink(buf);
|
||||
if (do_symlink(sl, buf) < 0
|
||||
&& (errno != ENOENT || make_bak_dir(buf) < 0
|
||||
|| do_symlink(sl, buf) < 0)) {
|
||||
rsyserr(FERROR, errno, "link %s -> \"%s\"",
|
||||
full_fname(buf), sl);
|
||||
if (do_symlink(sl, buf) < 0) {
|
||||
int save_errno = errno ? errno : EINVAL; /* 0 paranoia */
|
||||
if (errno == ENOENT && make_bak_dir(buf) == 0) {
|
||||
if (do_symlink(sl, buf) < 0)
|
||||
save_errno = errno ? errno : save_errno;
|
||||
else
|
||||
save_errno = 0;
|
||||
}
|
||||
if (save_errno) {
|
||||
rsyserr(FERROR, save_errno, "link %s -> \"%s\"",
|
||||
full_fname(buf), sl);
|
||||
}
|
||||
}
|
||||
do_unlink(fname);
|
||||
kept = 1;
|
||||
@@ -308,7 +340,9 @@ static int keep_backup(const char *fname)
|
||||
robust_unlink(fname); /* Just in case... */
|
||||
}
|
||||
}
|
||||
preserve_xattrs = 0;
|
||||
set_file_attrs(buf, file, NULL, fname, 0);
|
||||
preserve_xattrs = save_preserve_xattrs;
|
||||
unmake_file(file);
|
||||
|
||||
if (verbose > 1) {
|
||||
|
||||
59
batch.c
59
batch.c
@@ -3,7 +3,7 @@
|
||||
*
|
||||
* Copyright (C) 1999 Weiss
|
||||
* Copyright (C) 2004 Chris Shoemaker
|
||||
* Copyright (C) 2004-2007 Wayne Davison
|
||||
* Copyright (C) 2004-2008 Wayne Davison
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
@@ -156,27 +156,37 @@ void check_batch_flags(void)
|
||||
append_mode = 2;
|
||||
}
|
||||
|
||||
static void write_arg(int fd, char *arg)
|
||||
static int write_arg(int fd, char *arg)
|
||||
{
|
||||
char *x, *s;
|
||||
int len, ret = 0;
|
||||
|
||||
if (*arg == '-' && (x = strchr(arg, '=')) != NULL) {
|
||||
write(fd, arg, x - arg + 1);
|
||||
if (write(fd, arg, x - arg + 1) != x - arg + 1)
|
||||
ret = -1;
|
||||
arg += x - arg + 1;
|
||||
}
|
||||
|
||||
if (strpbrk(arg, " \"'&;|[]()$#!*?^\\") != NULL) {
|
||||
write(fd, "'", 1);
|
||||
if (write(fd, "'", 1) != 1)
|
||||
ret = -1;
|
||||
for (s = arg; (x = strchr(s, '\'')) != NULL; s = x + 1) {
|
||||
write(fd, s, x - s + 1);
|
||||
write(fd, "'", 1);
|
||||
if (write(fd, s, x - s + 1) != x - s + 1
|
||||
|| write(fd, "'", 1) != 1)
|
||||
ret = -1;
|
||||
}
|
||||
write(fd, s, strlen(s));
|
||||
write(fd, "'", 1);
|
||||
return;
|
||||
len = strlen(s);
|
||||
if (write(fd, s, len) != len
|
||||
|| write(fd, "'", 1) != 1)
|
||||
ret = -1;
|
||||
return ret;
|
||||
}
|
||||
|
||||
write(fd, arg, strlen(arg));
|
||||
len = strlen(arg);
|
||||
if (write(fd, arg, len) != len)
|
||||
ret = -1;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void write_filter_rules(int fd)
|
||||
@@ -205,7 +215,7 @@ static void write_filter_rules(int fd)
|
||||
* (hopefully) work. */
|
||||
void write_batch_shell_file(int argc, char *argv[], int file_arg_cnt)
|
||||
{
|
||||
int fd, i, len;
|
||||
int fd, i, len, err = 0;
|
||||
char *p, filename[MAXPATHLEN];
|
||||
|
||||
stringjoin(filename, sizeof filename,
|
||||
@@ -219,7 +229,8 @@ void write_batch_shell_file(int argc, char *argv[], int file_arg_cnt)
|
||||
}
|
||||
|
||||
/* Write argvs info to BATCH.sh file */
|
||||
write_arg(fd, argv[0]);
|
||||
if (write_arg(fd, argv[0]) < 0)
|
||||
err = 1;
|
||||
if (filter_list.head) {
|
||||
if (protocol_version >= 29)
|
||||
write_sbuf(fd, " --filter=._-");
|
||||
@@ -240,25 +251,31 @@ void write_batch_shell_file(int argc, char *argv[], int file_arg_cnt)
|
||||
i++;
|
||||
continue;
|
||||
}
|
||||
write(fd, " ", 1);
|
||||
if (write(fd, " ", 1) != 1)
|
||||
err = 1;
|
||||
if (strncmp(p, "--write-batch", len = 13) == 0
|
||||
|| strncmp(p, "--only-write-batch", len = 18) == 0) {
|
||||
write(fd, "--read-batch", 12);
|
||||
if (write(fd, "--read-batch", 12) != 12)
|
||||
err = 1;
|
||||
if (p[len] == '=') {
|
||||
write(fd, "=", 1);
|
||||
write_arg(fd, p + len + 1);
|
||||
if (write(fd, "=", 1) != 1
|
||||
|| write_arg(fd, p + len + 1) < 0)
|
||||
err = 1;
|
||||
}
|
||||
} else
|
||||
write_arg(fd, p);
|
||||
} else {
|
||||
if (write_arg(fd, p) < 0)
|
||||
err = 1;
|
||||
}
|
||||
}
|
||||
if (!(p = check_for_hostspec(argv[argc - 1], &p, &i)))
|
||||
p = argv[argc - 1];
|
||||
write(fd, " ${1:-", 6);
|
||||
write_arg(fd, p);
|
||||
if (write(fd, " ${1:-", 6) != 6
|
||||
|| write_arg(fd, p) < 0)
|
||||
err = 1;
|
||||
write_byte(fd, '}');
|
||||
if (filter_list.head)
|
||||
write_filter_rules(fd);
|
||||
if (write(fd, "\n", 1) != 1 || close(fd) < 0) {
|
||||
if (write(fd, "\n", 1) != 1 || close(fd) < 0 || err) {
|
||||
rsyserr(FERROR, errno, "Batch file %s write error",
|
||||
filename);
|
||||
exit_cleanup(RERR_FILEIO);
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
* Simple byteorder handling.
|
||||
*
|
||||
* Copyright (C) 1992-1995 Andrew Tridgell
|
||||
* Copyright (C) 2007 Wayne Davison
|
||||
* Copyright (C) 2007-2008 Wayne Davison
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
|
||||
2
case_N.h
2
case_N.h
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* End-of-run cleanup helper code used by cleanup.c.
|
||||
*
|
||||
* Copyright (C) 2006-2007 Wayne Davison
|
||||
* Copyright (C) 2006-2008 Wayne Davison
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
*
|
||||
* Copyright (C) 1996 Andrew Tridgell
|
||||
* Copyright (C) 1996 Paul Mackerras
|
||||
* Copyright (C) 2004-2007 Wayne Davison
|
||||
* Copyright (C) 2004-2008 Wayne Davison
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
|
||||
2
chmod.c
2
chmod.c
@@ -2,7 +2,7 @@
|
||||
* Implement the core of the --chmod option.
|
||||
*
|
||||
* Copyright (C) 2002 Scott Howard
|
||||
* Copyright (C) 2005-2007 Wayne Davison
|
||||
* Copyright (C) 2005-2008 Wayne Davison
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
* Copyright (C) 1996-2000 Andrew Tridgell
|
||||
* Copyright (C) 1996 Paul Mackerras
|
||||
* Copyright (C) 2002 Martin Pool
|
||||
* Copyright (C) 2003-2007 Wayne Davison
|
||||
* Copyright (C) 2003-2008 Wayne Davison
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
*
|
||||
* Copyright (C) 1992-2001 Andrew Tridgell <tridge@samba.org>
|
||||
* Copyright (C) 2001, 2002 Martin Pool <mbp@samba.org>
|
||||
* Copyright (C) 2002-2007 Wayne Davison
|
||||
* Copyright (C) 2002-2008 Wayne Davison
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
@@ -108,6 +108,9 @@ char *client_name(int fd)
|
||||
struct addrinfo hint, *answer;
|
||||
int err;
|
||||
|
||||
if (strcmp(addr, "0.0.0.0") == 0)
|
||||
return name_buf;
|
||||
|
||||
memset(&hint, 0, sizeof hint);
|
||||
|
||||
#ifdef AI_NUMERICHOST
|
||||
@@ -266,7 +269,7 @@ int compare_addrinfo_sockaddr(const struct addrinfo *ai,
|
||||
|
||||
if (ai->ai_addrlen < sizeof (struct sockaddr_in6)) {
|
||||
rprintf(FLOG, "%s: too short sockaddr_in6; length=%d\n",
|
||||
fn, ai->ai_addrlen);
|
||||
fn, (int)ai->ai_addrlen);
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
206
clientserver.c
206
clientserver.c
@@ -3,7 +3,7 @@
|
||||
*
|
||||
* Copyright (C) 1998-2001 Andrew Tridgell <tridge@samba.org>
|
||||
* Copyright (C) 2001-2002 Martin Pool <mbp@samba.org>
|
||||
* Copyright (C) 2002-2007 Wayne Davison
|
||||
* Copyright (C) 2002-2008 Wayne Davison
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
@@ -22,6 +22,7 @@
|
||||
#include "rsync.h"
|
||||
#include "ifuncs.h"
|
||||
|
||||
extern int quiet;
|
||||
extern int verbose;
|
||||
extern int dry_run;
|
||||
extern int output_motd;
|
||||
@@ -31,7 +32,9 @@ extern int am_server;
|
||||
extern int am_daemon;
|
||||
extern int am_root;
|
||||
extern int rsync_port;
|
||||
extern int protect_args;
|
||||
extern int ignore_errors;
|
||||
extern int preserve_xattrs;
|
||||
extern int kluge_around_eof;
|
||||
extern int daemon_over_rsh;
|
||||
extern int sanitize_paths;
|
||||
@@ -53,7 +56,7 @@ extern char *logfile_format;
|
||||
extern char *files_from;
|
||||
extern char *tmpdir;
|
||||
extern struct chmod_mode_struct *chmod_modes;
|
||||
extern struct filter_list_struct server_filter_list;
|
||||
extern struct filter_list_struct daemon_filter_list;
|
||||
extern char curr_dir[];
|
||||
#ifdef ICONV_OPTION
|
||||
extern char *iconv_opt;
|
||||
@@ -72,6 +75,8 @@ struct chmod_mode_struct *daemon_chmod_modes;
|
||||
char *module_dir = NULL;
|
||||
unsigned int module_dirlen = 0;
|
||||
|
||||
char *full_module_path;
|
||||
|
||||
static int rl_nulls = 0;
|
||||
|
||||
#ifdef HAVE_SIGACTION
|
||||
@@ -118,7 +123,9 @@ int start_socket_client(char *host, int remote_argc, char *remote_argv[],
|
||||
if (fd == -1)
|
||||
exit_cleanup(RERR_SOCKETIO);
|
||||
|
||||
set_socket_options(fd, sockopts);
|
||||
#ifdef ICONV_CONST
|
||||
setup_iconv();
|
||||
#endif
|
||||
|
||||
ret = start_inband_exchange(fd, fd, user, remote_argc, remote_argv);
|
||||
|
||||
@@ -207,7 +214,7 @@ int start_inband_exchange(int f_in, int f_out, const char *user, int argc, char
|
||||
int sargc = 0;
|
||||
char *p, *modname;
|
||||
|
||||
assert(argc > 0);
|
||||
assert(argc > 0 && *argv != NULL);
|
||||
|
||||
if (**argv == '/') {
|
||||
rprintf(FERROR,
|
||||
@@ -309,6 +316,8 @@ int start_inband_exchange(int f_in, int f_out, const char *user, int argc, char
|
||||
|
||||
if (rl_nulls) {
|
||||
for (i = 0; i < sargc; i++) {
|
||||
if (!sargs[i]) /* stop at --protect-args NULL */
|
||||
break;
|
||||
write_sbuf(f_out, sargs[i]);
|
||||
write_byte(f_out, 0);
|
||||
}
|
||||
@@ -319,6 +328,9 @@ int start_inband_exchange(int f_in, int f_out, const char *user, int argc, char
|
||||
write_sbuf(f_out, "\n");
|
||||
}
|
||||
|
||||
if (protect_args)
|
||||
send_protected_args(f_out, sargs);
|
||||
|
||||
if (protocol_version < 23) {
|
||||
if (protocol_version == 22 || !am_sender)
|
||||
io_start_multiplex_in();
|
||||
@@ -330,16 +342,24 @@ int start_inband_exchange(int f_in, int f_out, const char *user, int argc, char
|
||||
}
|
||||
|
||||
static char *finish_pre_exec(pid_t pid, int fd, char *request,
|
||||
int argc, char *argv[])
|
||||
char **early_argv, char **argv)
|
||||
{
|
||||
int j, status = -1;
|
||||
int j = 0, status = -1;
|
||||
|
||||
if (!request)
|
||||
request = "(NONE)";
|
||||
|
||||
write_buf(fd, request, strlen(request)+1);
|
||||
for (j = 0; j < argc; j++)
|
||||
if (early_argv) {
|
||||
for ( ; *early_argv; early_argv++)
|
||||
write_buf(fd, *early_argv, strlen(*early_argv)+1);
|
||||
j = 1; /* Skip arg0 name in argv. */
|
||||
}
|
||||
for ( ; argv[j]; j++) {
|
||||
write_buf(fd, argv[j], strlen(argv[j])+1);
|
||||
if (argv[j][0] == '.' && argv[j][1] == '\0')
|
||||
break;
|
||||
}
|
||||
write_byte(fd, 0);
|
||||
|
||||
close(fd);
|
||||
@@ -377,10 +397,20 @@ static int read_arg_from_pipe(int fd, char *buf, int limit)
|
||||
return bp - buf;
|
||||
}
|
||||
|
||||
static int path_failure(int f_out, const char *dir, BOOL was_chdir)
|
||||
{
|
||||
if (was_chdir)
|
||||
rsyserr(FLOG, errno, "chdir %s failed\n", dir);
|
||||
else
|
||||
rprintf(FLOG, "normalize_path(%s) failed\n", dir);
|
||||
io_printf(f_out, "@ERROR: chdir failed\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int rsync_module(int f_in, int f_out, int i, char *addr, char *host)
|
||||
{
|
||||
int argc, opt_cnt;
|
||||
char **argv, *chroot_path = NULL;
|
||||
int argc;
|
||||
char **argv, **orig_argv, **orig_early_argv, *module_chdir;
|
||||
char line[BIGPATHBUFLEN];
|
||||
uid_t uid = (uid_t)-2; /* canonically "nobody" */
|
||||
gid_t gid = (gid_t)-2;
|
||||
@@ -483,28 +513,28 @@ static int rsync_module(int f_in, int f_out, int i, char *addr, char *host)
|
||||
module_dir = lp_path(i);
|
||||
if (use_chroot) {
|
||||
if ((p = strstr(module_dir, "/./")) != NULL) {
|
||||
*p = '\0';
|
||||
p += 2;
|
||||
} else if ((p = strdup("/")) == NULL)
|
||||
out_of_memory("rsync_module");
|
||||
*p = '\0'; /* Temporary... */
|
||||
if (!(module_chdir = normalize_path(module_dir, True, NULL)))
|
||||
return path_failure(f_out, module_dir, False);
|
||||
*p = '/';
|
||||
if (!(p = normalize_path(p + 2, True, &module_dirlen)))
|
||||
return path_failure(f_out, strstr(module_dir, "/./"), False);
|
||||
if (!(full_module_path = normalize_path(module_dir, False, NULL)))
|
||||
full_module_path = module_dir;
|
||||
module_dir = p;
|
||||
} else {
|
||||
if (!(module_chdir = normalize_path(module_dir, False, NULL)))
|
||||
return path_failure(f_out, module_dir, False);
|
||||
full_module_path = module_chdir;
|
||||
module_dir = "/";
|
||||
module_dirlen = 1;
|
||||
}
|
||||
} else {
|
||||
if (!(module_chdir = normalize_path(module_dir, False, &module_dirlen)))
|
||||
return path_failure(f_out, module_dir, False);
|
||||
full_module_path = module_dir = module_chdir;
|
||||
}
|
||||
|
||||
/* We do a push_dir() that doesn't actually call chdir()
|
||||
* just to make a relative path absolute. */
|
||||
strlcpy(line, curr_dir, sizeof line);
|
||||
if (!push_dir(module_dir, 1))
|
||||
goto chdir_failed;
|
||||
if (strcmp(curr_dir, module_dir) != 0
|
||||
&& (module_dir = strdup(curr_dir)) == NULL)
|
||||
out_of_memory("rsync_module");
|
||||
push_dir(line, 1); /* Restore curr_dir. */
|
||||
|
||||
if (use_chroot) {
|
||||
chroot_path = module_dir;
|
||||
module_dir = p; /* p is "/" or our inside-chroot path */
|
||||
}
|
||||
module_dirlen = clean_fname(module_dir, CFN_COLLAPSE_DOT_DOT_DIRS | CFN_DROP_TRAILING_DOT_DIR);
|
||||
|
||||
if (module_dirlen == 1) {
|
||||
module_dirlen = 0;
|
||||
set_filter_dir("/", 1);
|
||||
@@ -512,25 +542,25 @@ static int rsync_module(int f_in, int f_out, int i, char *addr, char *host)
|
||||
set_filter_dir(module_dir, module_dirlen);
|
||||
|
||||
p = lp_filter(i);
|
||||
parse_rule(&server_filter_list, p, MATCHFLG_WORD_SPLIT,
|
||||
XFLG_ABS_IF_SLASH);
|
||||
parse_rule(&daemon_filter_list, p, MATCHFLG_WORD_SPLIT,
|
||||
XFLG_ABS_IF_SLASH | XFLG_DIR2WILD3);
|
||||
|
||||
p = lp_include_from(i);
|
||||
parse_filter_file(&server_filter_list, p, MATCHFLG_INCLUDE,
|
||||
XFLG_ABS_IF_SLASH | XFLG_OLD_PREFIXES | XFLG_FATAL_ERRORS);
|
||||
parse_filter_file(&daemon_filter_list, p, MATCHFLG_INCLUDE,
|
||||
XFLG_ABS_IF_SLASH | XFLG_DIR2WILD3 | XFLG_OLD_PREFIXES | XFLG_FATAL_ERRORS);
|
||||
|
||||
p = lp_include(i);
|
||||
parse_rule(&server_filter_list, p,
|
||||
parse_rule(&daemon_filter_list, p,
|
||||
MATCHFLG_INCLUDE | MATCHFLG_WORD_SPLIT,
|
||||
XFLG_ABS_IF_SLASH | XFLG_OLD_PREFIXES);
|
||||
XFLG_ABS_IF_SLASH | XFLG_DIR2WILD3 | XFLG_OLD_PREFIXES);
|
||||
|
||||
p = lp_exclude_from(i);
|
||||
parse_filter_file(&server_filter_list, p, 0,
|
||||
XFLG_ABS_IF_SLASH | XFLG_OLD_PREFIXES | XFLG_FATAL_ERRORS);
|
||||
parse_filter_file(&daemon_filter_list, p, 0,
|
||||
XFLG_ABS_IF_SLASH | XFLG_DIR2WILD3 | XFLG_OLD_PREFIXES | XFLG_FATAL_ERRORS);
|
||||
|
||||
p = lp_exclude(i);
|
||||
parse_rule(&server_filter_list, p, MATCHFLG_WORD_SPLIT,
|
||||
XFLG_ABS_IF_SLASH | XFLG_OLD_PREFIXES);
|
||||
parse_rule(&daemon_filter_list, p, MATCHFLG_WORD_SPLIT,
|
||||
XFLG_ABS_IF_SLASH | XFLG_DIR2WILD3 | XFLG_OLD_PREFIXES);
|
||||
|
||||
log_init(1);
|
||||
|
||||
@@ -539,16 +569,8 @@ static int rsync_module(int f_in, int f_out, int i, char *addr, char *host)
|
||||
char *modname, *modpath, *hostaddr, *hostname, *username;
|
||||
int status;
|
||||
|
||||
if (!use_chroot)
|
||||
p = module_dir;
|
||||
else if (module_dirlen) {
|
||||
pathjoin(line, sizeof line, chroot_path, module_dir+1);
|
||||
p = line;
|
||||
} else
|
||||
p = chroot_path;
|
||||
|
||||
if (asprintf(&modname, "RSYNC_MODULE_NAME=%s", name) < 0
|
||||
|| asprintf(&modpath, "RSYNC_MODULE_PATH=%s", p) < 0
|
||||
|| asprintf(&modpath, "RSYNC_MODULE_PATH=%s", full_module_path) < 0
|
||||
|| asprintf(&hostaddr, "RSYNC_HOST_ADDR=%s", addr) < 0
|
||||
|| asprintf(&hostname, "RSYNC_HOST_NAME=%s", host) < 0
|
||||
|| asprintf(&username, "RSYNC_USER_NAME=%s", auth_user) < 0)
|
||||
@@ -582,7 +604,8 @@ static int rsync_module(int f_in, int f_out, int i, char *addr, char *host)
|
||||
status = -1;
|
||||
if (asprintf(&p, "RSYNC_EXIT_STATUS=%d", status) > 0)
|
||||
putenv(p);
|
||||
system(lp_postxfer_exec(i));
|
||||
if (system(lp_postxfer_exec(i)) < 0)
|
||||
status = -1;
|
||||
_exit(status);
|
||||
}
|
||||
}
|
||||
@@ -648,30 +671,24 @@ static int rsync_module(int f_in, int f_out, int i, char *addr, char *host)
|
||||
* a warning, unless a "require chroot" flag is set,
|
||||
* in which case we fail.
|
||||
*/
|
||||
if (chroot(chroot_path)) {
|
||||
rsyserr(FLOG, errno, "chroot %s failed", chroot_path);
|
||||
if (chroot(module_chdir)) {
|
||||
rsyserr(FLOG, errno, "chroot %s failed", module_chdir);
|
||||
io_printf(f_out, "@ERROR: chroot failed\n");
|
||||
return -1;
|
||||
}
|
||||
if (!push_dir(module_dir, 0))
|
||||
goto chdir_failed;
|
||||
if (module_dirlen)
|
||||
sanitize_paths = 1;
|
||||
} else {
|
||||
if (!push_dir(module_dir, 0)) {
|
||||
chdir_failed:
|
||||
rsyserr(FLOG, errno, "chdir %s failed\n", module_dir);
|
||||
io_printf(f_out, "@ERROR: chdir failed\n");
|
||||
return -1;
|
||||
}
|
||||
sanitize_paths = 1;
|
||||
module_chdir = module_dir;
|
||||
}
|
||||
|
||||
if (!change_dir(module_chdir, CD_NORMAL))
|
||||
return path_failure(f_out, module_chdir, True);
|
||||
if (module_dirlen || !use_chroot)
|
||||
sanitize_paths = 1;
|
||||
|
||||
if ((munge_symlinks = lp_munge_symlinks(i)) < 0)
|
||||
munge_symlinks = !use_chroot || module_dirlen;
|
||||
if (munge_symlinks) {
|
||||
STRUCT_STAT st;
|
||||
if (stat(SYMLINK_PREFIX, &st) == 0 && S_ISDIR(st.st_mode)) {
|
||||
if (do_stat(SYMLINK_PREFIX, &st) == 0 && S_ISDIR(st.st_mode)) {
|
||||
rprintf(FLOG, "Symlink munging is unsupported when a %s directory exists.\n",
|
||||
SYMLINK_PREFIX);
|
||||
io_printf(f_out, "@ERROR: daemon security issue -- contact admin\n", name);
|
||||
@@ -726,24 +743,40 @@ static int rsync_module(int f_in, int f_out, int i, char *addr, char *host)
|
||||
|
||||
io_printf(f_out, "@RSYNCD: OK\n");
|
||||
|
||||
opt_cnt = read_args(f_in, name, line, sizeof line, rl_nulls, &argv, &argc, &request);
|
||||
read_args(f_in, name, line, sizeof line, rl_nulls, &argv, &argc, &request);
|
||||
orig_argv = argv;
|
||||
|
||||
verbose = 0; /* future verbosity is controlled by client options */
|
||||
ret = parse_arguments(&argc, (const char ***) &argv);
|
||||
if (protect_args && ret) {
|
||||
orig_early_argv = orig_argv;
|
||||
protect_args = 2;
|
||||
read_args(f_in, name, line, sizeof line, 1, &argv, &argc, &request);
|
||||
orig_argv = argv;
|
||||
ret = parse_arguments(&argc, (const char ***) &argv);
|
||||
} else
|
||||
orig_early_argv = NULL;
|
||||
|
||||
if (pre_exec_pid) {
|
||||
err_msg = finish_pre_exec(pre_exec_pid, pre_exec_fd, request,
|
||||
opt_cnt, argv);
|
||||
orig_early_argv, orig_argv);
|
||||
}
|
||||
|
||||
verbose = 0; /* future verbosity is controlled by client options */
|
||||
ret = parse_arguments(&argc, (const char ***) &argv, 0);
|
||||
if (orig_early_argv)
|
||||
free(orig_early_argv);
|
||||
|
||||
am_server = 1; /* Don't let someone try to be tricky. */
|
||||
quiet = 0;
|
||||
if (lp_ignore_errors(module_id))
|
||||
ignore_errors = 1;
|
||||
if (write_batch < 0)
|
||||
dry_run = 1;
|
||||
|
||||
if (lp_fake_super(i))
|
||||
if (lp_fake_super(i)) {
|
||||
if (preserve_xattrs > 1)
|
||||
preserve_xattrs = 1;
|
||||
am_root = -1;
|
||||
else if (am_root < 0) /* Treat --fake-super from client as --super. */
|
||||
} else if (am_root < 0) /* Treat --fake-super from client as --super. */
|
||||
am_root = 2;
|
||||
|
||||
if (filesfrom_fd == 0)
|
||||
@@ -860,6 +893,17 @@ static void send_listing(int fd)
|
||||
io_printf(fd,"@RSYNCD: EXIT\n");
|
||||
}
|
||||
|
||||
static int load_config(int globals_only)
|
||||
{
|
||||
if (!config_file) {
|
||||
if (am_server && am_root <= 0)
|
||||
config_file = RSYNCD_USERCONF;
|
||||
else
|
||||
config_file = RSYNCD_SYSCONF;
|
||||
}
|
||||
return lp_load(config_file, globals_only);
|
||||
}
|
||||
|
||||
/* this is called when a connection is established to a client
|
||||
and we want to start talking. The setup of the system is done from
|
||||
here */
|
||||
@@ -875,7 +919,7 @@ int start_daemon(int f_in, int f_out)
|
||||
* might cause log-file output to occur. This ensures that the
|
||||
* "log file" param gets honored for the 2 non-forked use-cases
|
||||
* (when rsync is run by init and run by a remote shell). */
|
||||
if (!lp_load(config_file, 0))
|
||||
if (!load_config(0))
|
||||
exit_cleanup(RERR_SYNTAX);
|
||||
|
||||
addr = client_addr(f_in);
|
||||
@@ -884,10 +928,6 @@ int start_daemon(int f_in, int f_out)
|
||||
|
||||
if (!am_server) {
|
||||
set_socket_options(f_in, "SO_KEEPALIVE");
|
||||
if (sockopts)
|
||||
set_socket_options(f_in, sockopts);
|
||||
else
|
||||
set_socket_options(f_in, lp_socket_options());
|
||||
set_nonblocking(f_in);
|
||||
}
|
||||
|
||||
@@ -931,20 +971,23 @@ static void create_pid_file(void)
|
||||
char *pid_file = lp_pid_file();
|
||||
char pidbuf[16];
|
||||
pid_t pid = getpid();
|
||||
int fd;
|
||||
int fd, len;
|
||||
|
||||
if (!pid_file || !*pid_file)
|
||||
return;
|
||||
|
||||
cleanup_set_pid(pid);
|
||||
if ((fd = do_open(pid_file, O_WRONLY|O_CREAT|O_EXCL, 0666 & ~orig_umask)) == -1) {
|
||||
failure:
|
||||
cleanup_set_pid(0);
|
||||
fprintf(stderr, "failed to create pid file %s: %s\n", pid_file, strerror(errno));
|
||||
rsyserr(FLOG, errno, "failed to create pid file %s", pid_file);
|
||||
exit_cleanup(RERR_FILEIO);
|
||||
}
|
||||
snprintf(pidbuf, sizeof pidbuf, "%ld\n", (long)pid);
|
||||
write(fd, pidbuf, strlen(pidbuf));
|
||||
len = strlen(pidbuf);
|
||||
if (write(fd, pidbuf, len) != len)
|
||||
goto failure;
|
||||
close(fd);
|
||||
}
|
||||
|
||||
@@ -984,13 +1027,6 @@ static void become_daemon(void)
|
||||
|
||||
int daemon_main(void)
|
||||
{
|
||||
if (!config_file) {
|
||||
if (am_server && am_root <= 0)
|
||||
config_file = RSYNCD_USERCONF;
|
||||
else
|
||||
config_file = RSYNCD_SYSCONF;
|
||||
}
|
||||
|
||||
if (is_a_socket(STDIN_FILENO)) {
|
||||
int i;
|
||||
|
||||
@@ -1005,7 +1041,7 @@ int daemon_main(void)
|
||||
return start_daemon(STDIN_FILENO, STDIN_FILENO);
|
||||
}
|
||||
|
||||
if (!lp_load(config_file, 1)) {
|
||||
if (!load_config(1)) {
|
||||
fprintf(stderr, "Failed to parse config file: %s\n", config_file);
|
||||
exit_cleanup(RERR_SYNTAX);
|
||||
}
|
||||
|
||||
17
compat.c
17
compat.c
@@ -3,7 +3,7 @@
|
||||
*
|
||||
* Copyright (C) Andrew Tridgell 1996
|
||||
* Copyright (C) Paul Mackerras 1996
|
||||
* Copyright (C) 2004-2007 Wayne Davison
|
||||
* Copyright (C) 2004-2008 Wayne Davison
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
@@ -57,12 +57,14 @@ extern struct filter_list_struct filter_list;
|
||||
extern int need_unsorted_flist;
|
||||
#ifdef ICONV_OPTION
|
||||
extern iconv_t ic_send, ic_recv;
|
||||
extern char *iconv_opt;
|
||||
#endif
|
||||
|
||||
/* These index values are for the file-list's extra-attribute array. */
|
||||
int uid_ndx, gid_ndx, acls_ndx, xattrs_ndx, unsort_ndx;
|
||||
|
||||
int receiver_symlink_times = 0; /* receiver can set the time on a symlink */
|
||||
int sender_symlink_iconv = 0; /* sender should convert symlink content */
|
||||
|
||||
#ifdef ICONV_OPTION
|
||||
int filesfrom_convert = 0;
|
||||
@@ -70,6 +72,7 @@ int filesfrom_convert = 0;
|
||||
|
||||
#define CF_INC_RECURSE (1<<0)
|
||||
#define CF_SYMLINK_TIMES (1<<1)
|
||||
#define CF_SYMLINK_ICONV (1<<2)
|
||||
|
||||
static const char *client_info;
|
||||
|
||||
@@ -248,6 +251,9 @@ void setup_protocol(int f_out,int f_in)
|
||||
compat_flags = allow_inc_recurse ? CF_INC_RECURSE : 0;
|
||||
#if defined HAVE_LUTIMES && defined HAVE_UTIMES
|
||||
compat_flags |= CF_SYMLINK_TIMES;
|
||||
#endif
|
||||
#ifdef ICONV_OPTION
|
||||
compat_flags |= CF_SYMLINK_ICONV;
|
||||
#endif
|
||||
write_byte(f_out, compat_flags);
|
||||
} else
|
||||
@@ -262,6 +268,11 @@ void setup_protocol(int f_out,int f_in)
|
||||
#if defined HAVE_LUTIMES && defined HAVE_UTIMES
|
||||
else
|
||||
receiver_symlink_times = 1;
|
||||
#endif
|
||||
#ifdef ICONV_OPTION
|
||||
sender_symlink_iconv = iconv_opt && (am_server
|
||||
? strchr(client_info, 's') != NULL
|
||||
: !!(compat_flags & CF_SYMLINK_ICONV));
|
||||
#endif
|
||||
if (inc_recurse && !allow_inc_recurse) {
|
||||
/* This should only be able to happen in a batch. */
|
||||
@@ -271,6 +282,10 @@ void setup_protocol(int f_out,int f_in)
|
||||
exit_cleanup(RERR_SYNTAX);
|
||||
}
|
||||
need_messages_from_generator = 1;
|
||||
#if defined HAVE_LUTIMES && defined HAVE_UTIMES
|
||||
} else if (!am_sender) {
|
||||
receiver_symlink_times = 1;
|
||||
#endif
|
||||
}
|
||||
|
||||
if (need_unsorted_flist && (!am_sender || inc_recurse))
|
||||
|
||||
41
configure.in
41
configure.in
@@ -5,7 +5,7 @@ AC_CONFIG_SRCDIR([byteorder.h])
|
||||
AC_CONFIG_HEADER(config.h)
|
||||
AC_PREREQ(2.59)
|
||||
|
||||
RSYNC_VERSION=3.0.0pre10
|
||||
RSYNC_VERSION=3.0.5
|
||||
AC_SUBST(RSYNC_VERSION)
|
||||
AC_MSG_NOTICE([Configuring rsync $RSYNC_VERSION])
|
||||
|
||||
@@ -311,8 +311,10 @@ AC_HEADER_SYS_WAIT
|
||||
AC_CHECK_HEADERS(sys/fcntl.h sys/select.h fcntl.h sys/time.h sys/unistd.h \
|
||||
unistd.h utime.h grp.h compat.h sys/param.h ctype.h sys/wait.h \
|
||||
sys/ioctl.h sys/filio.h string.h stdlib.h sys/socket.h sys/mode.h \
|
||||
sys/un.h sys/attr.h glob.h mcheck.h arpa/inet.h arpa/nameser.h locale.h \
|
||||
netdb.h malloc.h float.h limits.h iconv.h libcharset.h langinfo.h)
|
||||
sys/un.h sys/attr.h mcheck.h arpa/inet.h arpa/nameser.h locale.h \
|
||||
netdb.h malloc.h float.h limits.h iconv.h libcharset.h langinfo.h \
|
||||
sys/acl.h acl/libacl.h attr/xattr.h sys/xattr.h sys/extattr.h \
|
||||
popt.h popt/popt.h)
|
||||
AC_HEADER_MAJOR
|
||||
|
||||
AC_CACHE_CHECK([if makedev takes 3 args],rsync_cv_MAKEDEV_TAKES_3_ARGS,[
|
||||
@@ -548,7 +550,7 @@ AC_FUNC_UTIME_NULL
|
||||
AC_FUNC_ALLOCA
|
||||
AC_CHECK_FUNCS(waitpid wait4 getcwd strdup chown chmod lchmod mknod mkfifo \
|
||||
fchmod fstat ftruncate strchr readlink link utime utimes lutimes strftime \
|
||||
memmove lchown vsnprintf snprintf vasprintf asprintf setsid glob strpbrk \
|
||||
memmove lchown vsnprintf snprintf vasprintf asprintf setsid strpbrk \
|
||||
strlcat strlcpy strtol mallinfo getgroups setgroups geteuid getegid \
|
||||
setlocale setmode open64 lseek64 mkstemp64 mtrace va_copy __va_copy \
|
||||
strerror putenv iconv_open locale_charset nl_langinfo getxattr \
|
||||
@@ -654,6 +656,15 @@ fi
|
||||
if test x"$with_included_popt" != x"yes"; then
|
||||
AC_CHECK_LIB(popt, poptGetContext, , [with_included_popt=yes])
|
||||
fi
|
||||
if test x"$ac_cv_header_popt_popt_h" = x"yes"; then
|
||||
# If the system has /usr/include/popt/popt.h, we enable the
|
||||
# included popt because an attempt to "#include <popt/popt.h>"
|
||||
# would use our included header file anyway (due to -I.), and
|
||||
# might conflict with the system popt.
|
||||
with_included_popt=yes
|
||||
elif test x"$ac_cv_header_popt_h" != x"yes"; then
|
||||
with_included_popt=yes
|
||||
fi
|
||||
|
||||
AC_MSG_CHECKING([whether to use included libpopt])
|
||||
if test x"$with_included_popt" = x"yes"; then
|
||||
@@ -825,7 +836,6 @@ AC_SUBST(CC_SHOBJ_FLAG)
|
||||
AC_SUBST(BUILD_POPT)
|
||||
AC_SUBST(MAKE_MAN)
|
||||
|
||||
AC_CHECK_HEADERS(sys/acl.h acl/libacl.h)
|
||||
AC_CHECK_FUNCS(_acl __acl _facl __facl)
|
||||
#################################################
|
||||
# check for ACL support
|
||||
@@ -907,10 +917,6 @@ samba_cv_HAVE_ACL_GET_PERM_NP=yes,samba_cv_HAVE_ACL_GET_PERM_NP=no)])
|
||||
esac
|
||||
fi
|
||||
|
||||
AC_CHECK_HEADERS(attr/xattr.h)
|
||||
AC_CHECK_HEADERS(sys/xattr.h)
|
||||
AC_CHECK_HEADERS(sys/extattr.h)
|
||||
|
||||
#################################################
|
||||
# check for extended attribute support
|
||||
AC_MSG_CHECKING(whether to support extended attributes)
|
||||
@@ -952,6 +958,23 @@ else
|
||||
esac
|
||||
fi
|
||||
|
||||
if test x"$enable_acl_support" = x"no" -o x"$enable_xattr_support" = x"no" -o x"$enable_iconv" = x"no"; then
|
||||
AC_MSG_CHECKING([whether $CC supports -Wno-unused-parameter])
|
||||
OLD_CFLAGS="$CFLAGS"
|
||||
CFLAGS="$CFLAGS -Wno-unused-parameter"
|
||||
AC_COMPILE_IFELSE([ ], [rsync_warn_flag=yes], [rsync_warn_flag=no])
|
||||
AC_MSG_RESULT([$rsync_warn_flag])
|
||||
if test x"$rsync_warn_flag" = x"no"; then
|
||||
CFLAGS="$OLD_CFLAGS"
|
||||
fi
|
||||
fi
|
||||
|
||||
case "$CC" in
|
||||
' checker'*|checker*)
|
||||
AC_DEFINE(FORCE_FD_ZERO_MEMSET, 1, [Used to make "checker" understand that FD_ZERO() clears memory.])
|
||||
;;
|
||||
esac
|
||||
|
||||
AC_CONFIG_FILES([Makefile lib/dummy zlib/dummy popt/dummy shconfig])
|
||||
AC_OUTPUT
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
* Error codes returned by rsync.
|
||||
*
|
||||
* Copyright (C) 1998-2000 Andrew Tridgell
|
||||
* Copyright (C) 2003-2007 Wayne Davison
|
||||
* Copyright (C) 2003-2008 Wayne Davison
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
|
||||
100
exclude.c
100
exclude.c
@@ -4,7 +4,7 @@
|
||||
* Copyright (C) 1996-2001 Andrew Tridgell <tridge@samba.org>
|
||||
* Copyright (C) 1996 Paul Mackerras
|
||||
* Copyright (C) 2002 Martin Pool
|
||||
* Copyright (C) 2003-2007 Wayne Davison
|
||||
* Copyright (C) 2003-2008 Wayne Davison
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
@@ -43,7 +43,7 @@ extern unsigned int module_dirlen;
|
||||
|
||||
struct filter_list_struct filter_list = { 0, 0, "" };
|
||||
struct filter_list_struct cvs_filter_list = { 0, 0, " [global CVS]" };
|
||||
struct filter_list_struct server_filter_list = { 0, 0, " [daemon]" };
|
||||
struct filter_list_struct daemon_filter_list = { 0, 0, " [daemon]" };
|
||||
|
||||
/* Need room enough for ":MODS " prefix plus some room to grow. */
|
||||
#define MAX_RULE_PREFIX (16)
|
||||
@@ -52,6 +52,8 @@ struct filter_list_struct server_filter_list = { 0, 0, " [daemon]" };
|
||||
#define MODIFIERS_INCL_EXCL "/!Crsp"
|
||||
#define MODIFIERS_HIDE_PROTECT "/!p"
|
||||
|
||||
#define SLASH_WILD3_SUFFIX "/***"
|
||||
|
||||
/* The dirbuf is set by push_local_filters() to the current subdirectory
|
||||
* relative to curr_dir that is being processed. The path always has a
|
||||
* trailing slash appended, and the variable dirbuf_len contains the length
|
||||
@@ -119,7 +121,7 @@ static void add_rule(struct filter_list_struct *listp, const char *pat,
|
||||
{
|
||||
struct filter_struct *ret;
|
||||
const char *cp;
|
||||
unsigned int ex_len;
|
||||
unsigned int pre_len, suf_len, slash_cnt = 0;
|
||||
|
||||
if (verbose > 2) {
|
||||
rprintf(FINFO, "[%s] add_rule(%s%.*s%s)%s\n",
|
||||
@@ -145,22 +147,51 @@ static void add_rule(struct filter_list_struct *listp, const char *pat,
|
||||
if (!(ret = new0(struct filter_struct)))
|
||||
out_of_memory("add_rule");
|
||||
|
||||
if (pat_len > 1 && pat[pat_len-1] == '/') {
|
||||
pat_len--;
|
||||
mflags |= MATCHFLG_DIRECTORY;
|
||||
}
|
||||
|
||||
for (cp = pat; cp < pat + pat_len; cp++) {
|
||||
if (*cp == '/')
|
||||
slash_cnt++;
|
||||
}
|
||||
|
||||
if (!(mflags & (MATCHFLG_ABS_PATH | MATCHFLG_MERGE_FILE))
|
||||
&& ((xflags & (XFLG_ANCHORED2ABS|XFLG_ABS_IF_SLASH) && *pat == '/')
|
||||
|| (xflags & XFLG_ABS_IF_SLASH && strchr(pat, '/') != NULL))) {
|
||||
|| (xflags & XFLG_ABS_IF_SLASH && slash_cnt))) {
|
||||
mflags |= MATCHFLG_ABS_PATH;
|
||||
if (*pat == '/')
|
||||
ex_len = dirbuf_len - module_dirlen - 1;
|
||||
pre_len = dirbuf_len - module_dirlen - 1;
|
||||
else
|
||||
ex_len = 0;
|
||||
pre_len = 0;
|
||||
} else
|
||||
ex_len = 0;
|
||||
if (!(ret->pattern = new_array(char, ex_len + pat_len + 1)))
|
||||
pre_len = 0;
|
||||
|
||||
/* The daemon wants dir-exclude rules to get an appended "/" + "***". */
|
||||
if (xflags & XFLG_DIR2WILD3
|
||||
&& BITS_SETnUNSET(mflags, MATCHFLG_DIRECTORY, MATCHFLG_INCLUDE)) {
|
||||
mflags &= ~MATCHFLG_DIRECTORY;
|
||||
suf_len = sizeof SLASH_WILD3_SUFFIX - 1;
|
||||
} else
|
||||
suf_len = 0;
|
||||
|
||||
if (!(ret->pattern = new_array(char, pre_len + pat_len + suf_len + 1)))
|
||||
out_of_memory("add_rule");
|
||||
if (ex_len)
|
||||
memcpy(ret->pattern, dirbuf + module_dirlen, ex_len);
|
||||
strlcpy(ret->pattern + ex_len, pat, pat_len + 1);
|
||||
pat_len += ex_len;
|
||||
if (pre_len) {
|
||||
memcpy(ret->pattern, dirbuf + module_dirlen, pre_len);
|
||||
for (cp = ret->pattern; cp < ret->pattern + pre_len; cp++) {
|
||||
if (*cp == '/')
|
||||
slash_cnt++;
|
||||
}
|
||||
}
|
||||
strlcpy(ret->pattern + pre_len, pat, pat_len + 1);
|
||||
pat_len += pre_len;
|
||||
if (suf_len) {
|
||||
memcpy(ret->pattern + pat_len, SLASH_WILD3_SUFFIX, suf_len+1);
|
||||
pat_len += suf_len;
|
||||
slash_cnt++;
|
||||
}
|
||||
|
||||
if (strpbrk(ret->pattern, "*[?")) {
|
||||
mflags |= MATCHFLG_WILD;
|
||||
@@ -178,11 +209,6 @@ static void add_rule(struct filter_list_struct *listp, const char *pat,
|
||||
}
|
||||
}
|
||||
|
||||
if (pat_len > 1 && ret->pattern[pat_len-1] == '/') {
|
||||
ret->pattern[pat_len-1] = 0;
|
||||
mflags |= MATCHFLG_DIRECTORY;
|
||||
}
|
||||
|
||||
if (mflags & MATCHFLG_PERDIR_MERGE) {
|
||||
struct filter_list_struct *lp;
|
||||
unsigned int len;
|
||||
@@ -226,10 +252,8 @@ static void add_rule(struct filter_list_struct *listp, const char *pat,
|
||||
out_of_memory("add_rule");
|
||||
}
|
||||
mergelist_parents[mergelist_cnt++] = ret;
|
||||
} else {
|
||||
for (cp = ret->pattern; (cp = strchr(cp, '/')) != NULL; cp++)
|
||||
ret->u.slash_cnt++;
|
||||
}
|
||||
} else
|
||||
ret->u.slash_cnt = slash_cnt;
|
||||
|
||||
ret->match_flags = mflags;
|
||||
|
||||
@@ -295,7 +319,7 @@ static char *parse_merge_name(const char *merge_file, unsigned int *len_ptr,
|
||||
strlcpy(to, merge_file, *len_ptr + 1);
|
||||
merge_file = to;
|
||||
}
|
||||
if (!sanitize_path(fn, merge_file, r, dirbuf_depth)) {
|
||||
if (!sanitize_path(fn, merge_file, r, dirbuf_depth, SP_DEFAULT)) {
|
||||
rprintf(FERROR, "merge-file name overflows: %s\n",
|
||||
merge_file);
|
||||
return NULL;
|
||||
@@ -308,12 +332,13 @@ static char *parse_merge_name(const char *merge_file, unsigned int *len_ptr,
|
||||
|
||||
/* If the name isn't in buf yet, it's wasn't absolute. */
|
||||
if (fn != buf) {
|
||||
if (dirbuf_len + fn_len >= MAXPATHLEN) {
|
||||
int d_len = dirbuf_len - prefix_skip;
|
||||
if (d_len + fn_len >= MAXPATHLEN) {
|
||||
rprintf(FERROR, "merge-file name overflows: %s\n", fn);
|
||||
return NULL;
|
||||
}
|
||||
memcpy(buf, dirbuf + prefix_skip, dirbuf_len - prefix_skip);
|
||||
memcpy(buf + dirbuf_len - prefix_skip, fn, fn_len + 1);
|
||||
memcpy(buf, dirbuf + prefix_skip, d_len);
|
||||
memcpy(buf + d_len, fn, fn_len + 1);
|
||||
fn_len = clean_fname(buf, CFN_COLLAPSE_DOT_DOT_DIRS);
|
||||
}
|
||||
|
||||
@@ -451,7 +476,7 @@ void *push_local_filters(const char *dir, unsigned int dirlen)
|
||||
XFLG_ANCHORED2ABS);
|
||||
} else {
|
||||
io_error |= IOERR_GENERAL;
|
||||
rprintf(FINFO,
|
||||
rprintf(FERROR,
|
||||
"cannot add local filter rules in long-named directory: %s\n",
|
||||
full_fname(dirbuf));
|
||||
}
|
||||
@@ -517,13 +542,13 @@ void change_local_filter_dir(const char *dname, int dlen, int dir_depth)
|
||||
filt_array[cur_depth] = push_local_filters(dname, dlen);
|
||||
}
|
||||
|
||||
static int rule_matches(char *fname, struct filter_struct *ex, int name_is_dir)
|
||||
static int rule_matches(const char *fname, struct filter_struct *ex, int name_is_dir)
|
||||
{
|
||||
int slash_handling, str_cnt = 0, anchored_match = 0;
|
||||
int ret_match = ex->match_flags & MATCHFLG_NEGATE ? 0 : 1;
|
||||
char *p, *pattern = ex->pattern;
|
||||
const char *strings[16]; /* more than enough */
|
||||
char *name = fname + (*fname == '/');
|
||||
const char *name = fname + (*fname == '/');
|
||||
|
||||
if (!*name)
|
||||
return 0;
|
||||
@@ -596,7 +621,7 @@ static int rule_matches(char *fname, struct filter_struct *ex, int name_is_dir)
|
||||
}
|
||||
|
||||
|
||||
static void report_filter_result(char const *name,
|
||||
static void report_filter_result(enum logcode code, char const *name,
|
||||
struct filter_struct const *ent,
|
||||
int name_is_dir, const char *type)
|
||||
{
|
||||
@@ -608,7 +633,7 @@ static void report_filter_result(char const *name,
|
||||
static char *actions[2][2]
|
||||
= { {"show", "hid"}, {"risk", "protect"} };
|
||||
const char *w = who_am_i();
|
||||
rprintf(FINFO, "[%s] %sing %s %s because of pattern %s%s%s\n",
|
||||
rprintf(code, "[%s] %sing %s %s because of pattern %s%s%s\n",
|
||||
w, actions[*w!='s'][!(ent->match_flags&MATCHFLG_INCLUDE)],
|
||||
name_is_dir ? "directory" : "file", name, ent->pattern,
|
||||
ent->match_flags & MATCHFLG_DIRECTORY ? "/" : "", type);
|
||||
@@ -620,7 +645,8 @@ static void report_filter_result(char const *name,
|
||||
* Return -1 if file "name" is defined to be excluded by the specified
|
||||
* exclude list, 1 if it is included, and 0 if it was not matched.
|
||||
*/
|
||||
int check_filter(struct filter_list_struct *listp, char *name, int name_is_dir)
|
||||
int check_filter(struct filter_list_struct *listp, enum logcode code,
|
||||
const char *name, int name_is_dir)
|
||||
{
|
||||
struct filter_struct *ent;
|
||||
|
||||
@@ -628,22 +654,22 @@ int check_filter(struct filter_list_struct *listp, char *name, int name_is_dir)
|
||||
if (ignore_perishable && ent->match_flags & MATCHFLG_PERISHABLE)
|
||||
continue;
|
||||
if (ent->match_flags & MATCHFLG_PERDIR_MERGE) {
|
||||
int rc = check_filter(ent->u.mergelist, name,
|
||||
int rc = check_filter(ent->u.mergelist, code, name,
|
||||
name_is_dir);
|
||||
if (rc)
|
||||
return rc;
|
||||
continue;
|
||||
}
|
||||
if (ent->match_flags & MATCHFLG_CVS_IGNORE) {
|
||||
int rc = check_filter(&cvs_filter_list, name,
|
||||
int rc = check_filter(&cvs_filter_list, code, name,
|
||||
name_is_dir);
|
||||
if (rc)
|
||||
return rc;
|
||||
continue;
|
||||
}
|
||||
if (rule_matches(name, ent, name_is_dir)) {
|
||||
report_filter_result(name, ent, name_is_dir,
|
||||
listp->debug_type);
|
||||
report_filter_result(code, name, ent, name_is_dir,
|
||||
listp->debug_type);
|
||||
return ent->match_flags & MATCHFLG_INCLUDE ? 1 : -1;
|
||||
}
|
||||
}
|
||||
@@ -1009,10 +1035,10 @@ void parse_filter_file(struct filter_list_struct *listp, const char *fname,
|
||||
return;
|
||||
|
||||
if (*fname != '-' || fname[1] || am_server) {
|
||||
if (server_filter_list.head) {
|
||||
if (daemon_filter_list.head) {
|
||||
strlcpy(line, fname, sizeof line);
|
||||
clean_fname(line, CFN_COLLAPSE_DOT_DOT_DIRS);
|
||||
if (check_filter(&server_filter_list, line, 0) < 0)
|
||||
if (check_filter(&daemon_filter_list, FLOG, line, 0) < 0)
|
||||
fp = NULL;
|
||||
else
|
||||
fp = fopen(line, "rb");
|
||||
|
||||
12
fileio.c
12
fileio.c
@@ -3,7 +3,7 @@
|
||||
*
|
||||
* Copyright (C) 1998 Andrew Tridgell
|
||||
* Copyright (C) 2002 Martin Pool
|
||||
* Copyright (C) 2004-2007 Wayne Davison
|
||||
* Copyright (C) 2004-2008 Wayne Davison
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
@@ -28,7 +28,7 @@
|
||||
extern int sparse_files;
|
||||
|
||||
static char last_byte;
|
||||
static size_t sparse_seek = 0;
|
||||
static OFF_T sparse_seek = 0;
|
||||
|
||||
int sparse_end(int f)
|
||||
{
|
||||
@@ -48,9 +48,9 @@ int sparse_end(int f)
|
||||
}
|
||||
|
||||
|
||||
static int write_sparse(int f, char *buf, size_t len)
|
||||
static int write_sparse(int f, char *buf, int len)
|
||||
{
|
||||
size_t l1 = 0, l2 = 0;
|
||||
int l1 = 0, l2 = 0;
|
||||
int ret;
|
||||
|
||||
for (l1 = 0; l1 < len && buf[l1] == 0; l1++) {}
|
||||
@@ -108,7 +108,7 @@ int flush_write_file(int f)
|
||||
* write_file does not allow incomplete writes. It loops internally
|
||||
* until len bytes are written or errno is set.
|
||||
*/
|
||||
int write_file(int f,char *buf,size_t len)
|
||||
int write_file(int f, char *buf, int len)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
@@ -125,7 +125,7 @@ int write_file(int f,char *buf,size_t len)
|
||||
if (!wf_writeBuf)
|
||||
out_of_memory("write_file");
|
||||
}
|
||||
r1 = MIN(len, wf_writeBufSize - wf_writeBufCnt);
|
||||
r1 = (int)MIN((size_t)len, wf_writeBufSize - wf_writeBufCnt);
|
||||
if (r1) {
|
||||
memcpy(wf_writeBuf + wf_writeBufCnt, buf, r1);
|
||||
wf_writeBufCnt += r1;
|
||||
|
||||
475
generator.c
475
generator.c
@@ -4,7 +4,7 @@
|
||||
* Copyright (C) 1996-2000 Andrew Tridgell
|
||||
* Copyright (C) 1996 Paul Mackerras
|
||||
* Copyright (C) 2002 Martin Pool <mbp@samba.org>
|
||||
* Copyright (C) 2003-2007 Wayne Davison
|
||||
* Copyright (C) 2003-2008 Wayne Davison
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
@@ -27,7 +27,6 @@ extern int dry_run;
|
||||
extern int do_xfers;
|
||||
extern int stdout_format_has_i;
|
||||
extern int logfile_format_has_i;
|
||||
extern int receiver_symlink_times;
|
||||
extern int am_root;
|
||||
extern int am_server;
|
||||
extern int am_daemon;
|
||||
@@ -98,7 +97,7 @@ extern char *backup_dir;
|
||||
extern char *backup_suffix;
|
||||
extern int backup_suffix_len;
|
||||
extern struct file_list *cur_flist, *first_flist, *dir_flist;
|
||||
extern struct filter_list_struct server_filter_list;
|
||||
extern struct filter_list_struct daemon_filter_list;
|
||||
|
||||
int ignore_perishable = 0;
|
||||
int non_perishable_cnt = 0;
|
||||
@@ -109,14 +108,15 @@ static int deletion_count = 0; /* used to implement --max-delete */
|
||||
static int deldelay_size = 0, deldelay_cnt = 0;
|
||||
static char *deldelay_buf = NULL;
|
||||
static int deldelay_fd = -1;
|
||||
static int lull_mod;
|
||||
static int loopchk_limit;
|
||||
static int dir_tweaking;
|
||||
static int symlink_timeset_failed_flags;
|
||||
static int need_retouch_dir_times;
|
||||
static int need_retouch_dir_perms;
|
||||
static const char *solo_file = NULL;
|
||||
|
||||
/* For calling delete_item() and delete_dir_contents(). */
|
||||
#define DEL_OWNED_BY_US (1<<0) /* file/dir has our uid */
|
||||
#define DEL_NO_UID_WRITE (1<<0) /* file/dir has our uid w/o write perm */
|
||||
#define DEL_RECURSE (1<<1) /* if dir, delete all contents */
|
||||
#define DEL_DIR_IS_EMPTY (1<<2) /* internal delete_FUNCTIONS use only */
|
||||
#define DEL_FOR_FILE (1<<3) /* making room for a replacement file */
|
||||
@@ -135,8 +135,12 @@ enum delret {
|
||||
DR_SUCCESS = 0, DR_FAILURE, DR_AT_LIMIT, DR_NOT_EMPTY
|
||||
};
|
||||
|
||||
/* Forward declaration for delete_item(). */
|
||||
static enum delret delete_dir_contents(char *fname, int flags);
|
||||
/* Forward declarations. */
|
||||
static enum delret delete_dir_contents(char *fname, uint16 flags);
|
||||
#ifdef SUPPORT_HARD_LINKS
|
||||
static void handle_skipped_hlink(struct file_struct *file, int itemizing,
|
||||
enum logcode code, int f_out);
|
||||
#endif
|
||||
|
||||
static int is_backup_file(char *fn)
|
||||
{
|
||||
@@ -150,7 +154,7 @@ static int is_backup_file(char *fn)
|
||||
* Note that fbuf must point to a MAXPATHLEN buffer if the mode indicates it's
|
||||
* a directory! (The buffer is used for recursion, but returned unchanged.)
|
||||
*/
|
||||
static enum delret delete_item(char *fbuf, int mode, int flags)
|
||||
static enum delret delete_item(char *fbuf, uint16 mode, uint16 flags)
|
||||
{
|
||||
enum delret ret;
|
||||
char *what;
|
||||
@@ -158,17 +162,26 @@ static enum delret delete_item(char *fbuf, int mode, int flags)
|
||||
|
||||
if (verbose > 2) {
|
||||
rprintf(FINFO, "delete_item(%s) mode=%o flags=%d\n",
|
||||
fbuf, mode, flags);
|
||||
fbuf, (int)mode, (int)flags);
|
||||
}
|
||||
|
||||
if (!am_root && !(mode & S_IWUSR) && flags & DEL_OWNED_BY_US)
|
||||
do_chmod(fbuf, mode |= S_IWUSR);
|
||||
if (flags & DEL_NO_UID_WRITE)
|
||||
do_chmod(fbuf, mode | S_IWUSR);
|
||||
|
||||
if (S_ISDIR(mode) && !(flags & DEL_DIR_IS_EMPTY)) {
|
||||
int save_uid_ndx = uid_ndx;
|
||||
/* This only happens on the first call to delete_item() since
|
||||
* delete_dir_contents() always calls us w/DEL_DIR_IS_EMPTY. */
|
||||
if (!uid_ndx)
|
||||
uid_ndx = ++file_extra_cnt;
|
||||
ignore_perishable = 1;
|
||||
/* If DEL_RECURSE is not set, this just reports emptiness. */
|
||||
ret = delete_dir_contents(fbuf, flags);
|
||||
ignore_perishable = 0;
|
||||
if (!save_uid_ndx) {
|
||||
--file_extra_cnt;
|
||||
uid_ndx = 0;
|
||||
}
|
||||
if (ret == DR_NOT_EMPTY || ret == DR_AT_LIMIT)
|
||||
goto check_ret;
|
||||
/* OK: try to delete the directory. */
|
||||
@@ -229,7 +242,7 @@ static enum delret delete_item(char *fbuf, int mode, int flags)
|
||||
* DR_NOT_EMPTY. Note that fname must point to a MAXPATHLEN buffer! (The
|
||||
* buffer is used for recursion, but returned unchanged.)
|
||||
*/
|
||||
static enum delret delete_dir_contents(char *fname, int flags)
|
||||
static enum delret delete_dir_contents(char *fname, uint16 flags)
|
||||
{
|
||||
struct file_list *dirlist;
|
||||
enum delret ret;
|
||||
@@ -264,12 +277,13 @@ static enum delret delete_dir_contents(char *fname, int flags)
|
||||
remainder = MAXPATHLEN - (p - fname);
|
||||
|
||||
/* We do our own recursion, so make delete_item() non-recursive. */
|
||||
flags = (flags & ~(DEL_RECURSE|DEL_MAKE_ROOM)) | DEL_DIR_IS_EMPTY;
|
||||
flags = (flags & ~(DEL_RECURSE|DEL_MAKE_ROOM|DEL_NO_UID_WRITE))
|
||||
| DEL_DIR_IS_EMPTY;
|
||||
|
||||
for (j = dirlist->used; j--; ) {
|
||||
struct file_struct *fp = dirlist->files[j];
|
||||
|
||||
if (fp->flags & FLAG_MOUNT_DIR) {
|
||||
if (fp->flags & FLAG_MOUNT_DIR && S_ISDIR(fp->mode)) {
|
||||
if (verbose > 1) {
|
||||
rprintf(FINFO,
|
||||
"mount point, %s, pins parent directory\n",
|
||||
@@ -280,14 +294,10 @@ static enum delret delete_dir_contents(char *fname, int flags)
|
||||
}
|
||||
|
||||
strlcpy(p, fp->basename, remainder);
|
||||
if (!uid_ndx || (uid_t)F_OWNER(fp) == our_uid)
|
||||
flags |= DEL_OWNED_BY_US;
|
||||
else
|
||||
flags &= ~DEL_OWNED_BY_US;
|
||||
if (!(fp->mode & S_IWUSR) && !am_root && (uid_t)F_OWNER(fp) == our_uid)
|
||||
do_chmod(fname, fp->mode | S_IWUSR);
|
||||
/* Save stack by recursing to ourself directly. */
|
||||
if (S_ISDIR(fp->mode)) {
|
||||
if (!am_root && !(fp->mode & S_IWUSR) && flags & DEL_OWNED_BY_US)
|
||||
do_chmod(fname, fp->mode |= S_IWUSR);
|
||||
if (delete_dir_contents(fname, flags | DEL_RECURSE) != DR_SUCCESS)
|
||||
ret = DR_NOT_EMPTY;
|
||||
}
|
||||
@@ -330,10 +340,12 @@ static int start_delete_delay_temp(void)
|
||||
|
||||
static int flush_delete_delay(void)
|
||||
{
|
||||
if (deldelay_fd < 0 && !start_delete_delay_temp())
|
||||
return 0;
|
||||
if (write(deldelay_fd, deldelay_buf, deldelay_cnt) != deldelay_cnt) {
|
||||
rsyserr(FERROR, errno, "flush of delete-delay buffer");
|
||||
delete_during = 0;
|
||||
delete_after = 1;
|
||||
delete_after = !inc_recurse;
|
||||
close(deldelay_fd);
|
||||
return 0;
|
||||
}
|
||||
@@ -343,19 +355,21 @@ static int flush_delete_delay(void)
|
||||
|
||||
static int remember_delete(struct file_struct *file, const char *fname, int flags)
|
||||
{
|
||||
const char *plus = (!am_root && !(file->mode & S_IWUSR) && flags & DEL_OWNED_BY_US)
|
||||
? "+" : "";
|
||||
int len;
|
||||
|
||||
if (deldelay_cnt == deldelay_size && !flush_delete_delay())
|
||||
return 0;
|
||||
|
||||
if (flags & DEL_NO_UID_WRITE)
|
||||
deldelay_buf[deldelay_cnt++] = '!';
|
||||
|
||||
while (1) {
|
||||
len = snprintf(deldelay_buf + deldelay_cnt,
|
||||
deldelay_size - deldelay_cnt,
|
||||
"%s%x %s%c",
|
||||
plus, (int)file->mode, fname, '\0');
|
||||
"%x %s%c",
|
||||
(int)file->mode, fname, '\0');
|
||||
if ((deldelay_cnt += len) <= deldelay_size)
|
||||
break;
|
||||
if (deldelay_fd < 0 && !start_delete_delay_temp())
|
||||
return 0;
|
||||
deldelay_cnt -= len;
|
||||
if (!flush_delete_delay())
|
||||
return 0;
|
||||
@@ -364,7 +378,7 @@ static int remember_delete(struct file_struct *file, const char *fname, int flag
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int read_delay_line(char *buf, int *own_flag_p)
|
||||
static int read_delay_line(char *buf, int *flags_p)
|
||||
{
|
||||
static int read_pos = 0;
|
||||
int j, len, mode;
|
||||
@@ -405,11 +419,11 @@ static int read_delay_line(char *buf, int *own_flag_p)
|
||||
}
|
||||
|
||||
bp = deldelay_buf + read_pos;
|
||||
if (*bp == '+') {
|
||||
if (*bp == '!') {
|
||||
bp++;
|
||||
*own_flag_p = DEL_OWNED_BY_US;
|
||||
*flags_p = DEL_NO_UID_WRITE;
|
||||
} else
|
||||
*own_flag_p = 0;
|
||||
*flags_p = 0;
|
||||
|
||||
if (sscanf(bp, "%x ", &mode) != 1) {
|
||||
invalid_data:
|
||||
@@ -434,15 +448,15 @@ static int read_delay_line(char *buf, int *own_flag_p)
|
||||
|
||||
static void do_delayed_deletions(char *delbuf)
|
||||
{
|
||||
int mode, own_flag;
|
||||
int mode, flags;
|
||||
|
||||
if (deldelay_fd >= 0) {
|
||||
if (deldelay_cnt && !flush_delete_delay())
|
||||
return;
|
||||
lseek(deldelay_fd, 0, 0);
|
||||
}
|
||||
while ((mode = read_delay_line(delbuf, &own_flag)) >= 0)
|
||||
delete_item(delbuf, mode, own_flag | DEL_RECURSE);
|
||||
while ((mode = read_delay_line(delbuf, &flags)) >= 0)
|
||||
delete_item(delbuf, mode, flags | DEL_RECURSE);
|
||||
if (deldelay_fd >= 0)
|
||||
close(deldelay_fd);
|
||||
}
|
||||
@@ -458,6 +472,7 @@ static void delete_in_dir(char *fbuf, struct file_struct *file, dev_t *fs_dev)
|
||||
struct file_list *dirlist;
|
||||
char delbuf[MAXPATHLEN];
|
||||
int dlen, i;
|
||||
int save_uid_ndx = uid_ndx;
|
||||
|
||||
if (!fbuf) {
|
||||
change_local_filter_dir(NULL, 0, 0);
|
||||
@@ -489,6 +504,9 @@ static void delete_in_dir(char *fbuf, struct file_struct *file, dev_t *fs_dev)
|
||||
return;
|
||||
}
|
||||
|
||||
if (!uid_ndx)
|
||||
uid_ndx = ++file_extra_cnt;
|
||||
|
||||
dirlist = get_dirlist(fbuf, dlen, 0);
|
||||
|
||||
/* If an item in dirlist is not found in flist, delete it
|
||||
@@ -497,15 +515,19 @@ static void delete_in_dir(char *fbuf, struct file_struct *file, dev_t *fs_dev)
|
||||
struct file_struct *fp = dirlist->files[i];
|
||||
if (!F_IS_ACTIVE(fp))
|
||||
continue;
|
||||
if (fp->flags & FLAG_MOUNT_DIR) {
|
||||
if (fp->flags & FLAG_MOUNT_DIR && S_ISDIR(fp->mode)) {
|
||||
if (verbose > 1)
|
||||
rprintf(FINFO, "cannot delete mount point: %s\n",
|
||||
f_name(fp, NULL));
|
||||
continue;
|
||||
}
|
||||
if (flist_find(cur_flist, fp) < 0) {
|
||||
int flags = DEL_RECURSE
|
||||
| (!uid_ndx || (uid_t)F_OWNER(fp) == our_uid ? DEL_OWNED_BY_US : 0);
|
||||
/* Here we want to match regardless of file type. Replacement
|
||||
* of a file with one of another type is handled separately by
|
||||
* a delete_item call with a DEL_MAKE_ROOM flag. */
|
||||
if (flist_find_ignore_dirness(cur_flist, fp) < 0) {
|
||||
int flags = DEL_RECURSE;
|
||||
if (!(fp->mode & S_IWUSR) && !am_root && (uid_t)F_OWNER(fp) == our_uid)
|
||||
flags |= DEL_NO_UID_WRITE;
|
||||
f_name(fp, delbuf);
|
||||
if (delete_during == 2) {
|
||||
if (!remember_delete(fp, delbuf, flags))
|
||||
@@ -516,6 +538,11 @@ static void delete_in_dir(char *fbuf, struct file_struct *file, dev_t *fs_dev)
|
||||
}
|
||||
|
||||
flist_free(dirlist);
|
||||
|
||||
if (!save_uid_ndx) {
|
||||
--file_extra_cnt;
|
||||
uid_ndx = 0;
|
||||
}
|
||||
}
|
||||
|
||||
/* This deletes any files on the receiving side that are not present on the
|
||||
@@ -533,10 +560,13 @@ static void do_delete_pass(void)
|
||||
for (j = 0; j < cur_flist->used; j++) {
|
||||
struct file_struct *file = cur_flist->sorted[j];
|
||||
|
||||
if (!(file->flags & FLAG_CONTENT_DIR))
|
||||
continue;
|
||||
|
||||
f_name(file, fbuf);
|
||||
|
||||
if (!(file->flags & FLAG_CONTENT_DIR)) {
|
||||
change_local_filter_dir(fbuf, strlen(fbuf), F_DEPTH(file));
|
||||
continue;
|
||||
}
|
||||
|
||||
if (verbose > 1 && file->flags & FLAG_TOP_DIR)
|
||||
rprintf(FINFO, "deleting in %s\n", fbuf);
|
||||
|
||||
@@ -562,10 +592,11 @@ int unchanged_attrs(const char *fname, struct file_struct *file, stat_x *sxp)
|
||||
if (preserve_times && cmp_time(sxp->st.st_mtime, file->modtime) != 0)
|
||||
return 0;
|
||||
|
||||
if (preserve_perms && !BITS_EQUAL(sxp->st.st_mode, file->mode, CHMOD_BITS))
|
||||
return 0;
|
||||
|
||||
if (preserve_executability && ((sxp->st.st_mode & 0111 ? 1 : 0) ^ (file->mode & 0111 ? 1 : 0)))
|
||||
if (preserve_perms) {
|
||||
if (!BITS_EQUAL(sxp->st.st_mode, file->mode, CHMOD_BITS))
|
||||
return 0;
|
||||
} else if (preserve_executability
|
||||
&& ((sxp->st.st_mode & 0111 ? 1 : 0) ^ (file->mode & 0111 ? 1 : 0)))
|
||||
return 0;
|
||||
|
||||
if (am_root && uid_ndx && sxp->st.st_uid != (uid_t)F_OWNER(file))
|
||||
@@ -602,24 +633,31 @@ void itemize(const char *fnamecmp, struct file_struct *file, int ndx, int statre
|
||||
int keep_time = !preserve_times ? 0
|
||||
: S_ISDIR(file->mode) ? preserve_times > 1 :
|
||||
#if defined HAVE_LUTIMES && defined HAVE_UTIMES
|
||||
(receiver_symlink_times && !(file->flags & FLAG_TIME_FAILED)) ||
|
||||
#endif
|
||||
1;
|
||||
#else
|
||||
!S_ISLNK(file->mode);
|
||||
#endif
|
||||
|
||||
if (S_ISREG(file->mode) && F_LENGTH(file) != sxp->st.st_size)
|
||||
iflags |= ITEM_REPORT_SIZE;
|
||||
if ((iflags & (ITEM_TRANSFER|ITEM_LOCAL_CHANGE) && !keep_time
|
||||
&& !(iflags & ITEM_MATCHED)
|
||||
if (file->flags & FLAG_TIME_FAILED) { /* symlinks only */
|
||||
if (iflags & ITEM_LOCAL_CHANGE)
|
||||
iflags |= symlink_timeset_failed_flags;
|
||||
} else if (keep_time
|
||||
? cmp_time(file->modtime, sxp->st.st_mtime) != 0
|
||||
: iflags & (ITEM_TRANSFER|ITEM_LOCAL_CHANGE) && !(iflags & ITEM_MATCHED)
|
||||
&& (!(iflags & ITEM_XNAME_FOLLOWS) || *xname))
|
||||
|| (keep_time && cmp_time(file->modtime, sxp->st.st_mtime) != 0))
|
||||
iflags |= ITEM_REPORT_TIME;
|
||||
#if !defined HAVE_LCHMOD && !defined HAVE_SETATTRLIST
|
||||
if (S_ISLNK(file->mode)) {
|
||||
;
|
||||
} else
|
||||
#endif
|
||||
if ((preserve_perms || preserve_executability)
|
||||
&& !BITS_EQUAL(sxp->st.st_mode, file->mode, CHMOD_BITS))
|
||||
if (preserve_perms) {
|
||||
if (!BITS_EQUAL(sxp->st.st_mode, file->mode, CHMOD_BITS))
|
||||
iflags |= ITEM_REPORT_PERMS;
|
||||
} else if (preserve_executability
|
||||
&& ((sxp->st.st_mode & 0111 ? 1 : 0) ^ (file->mode & 0111 ? 1 : 0)))
|
||||
iflags |= ITEM_REPORT_PERMS;
|
||||
if (uid_ndx && am_root && (uid_t)F_OWNER(file) != sxp->st.st_uid)
|
||||
iflags |= ITEM_REPORT_OWNER;
|
||||
@@ -662,8 +700,11 @@ void itemize(const char *fnamecmp, struct file_struct *file, int ndx, int statre
|
||||
if (iflags & ITEM_XNAME_FOLLOWS)
|
||||
write_vstring(sock_f_out, xname, strlen(xname));
|
||||
#ifdef SUPPORT_XATTRS
|
||||
if (iflags & ITEM_REPORT_XATTR && !dry_run)
|
||||
send_xattr_request(NULL, file, sock_f_out);
|
||||
if (preserve_xattrs && !dry_run
|
||||
&& iflags & (ITEM_REPORT_XATTR|ITEM_TRANSFER)) {
|
||||
send_xattr_request(NULL, file,
|
||||
iflags & ITEM_REPORT_XATTR ? sock_f_out : -1);
|
||||
}
|
||||
#endif
|
||||
} else if (ndx >= 0) {
|
||||
enum logcode code = logfile_format_has_i ? FINFO : FCLIENT;
|
||||
@@ -718,18 +759,19 @@ static void sum_sizes_sqroot(struct sum_struct *sum, int64 len)
|
||||
{
|
||||
int32 blength;
|
||||
int s2length;
|
||||
int64 l;
|
||||
|
||||
if (block_size)
|
||||
blength = block_size;
|
||||
else if (len <= BLOCK_SIZE * BLOCK_SIZE)
|
||||
blength = BLOCK_SIZE;
|
||||
else {
|
||||
int32 max_blength = protocol_version < 30 ? OLD_MAX_BLOCK_SIZE : MAX_BLOCK_SIZE;
|
||||
int32 c;
|
||||
int64 l;
|
||||
int cnt;
|
||||
for (c = 1, l = len, cnt = 0; l >>= 2; c <<= 1, cnt++) {}
|
||||
if (cnt >= 31 || c >= MAX_BLOCK_SIZE)
|
||||
blength = MAX_BLOCK_SIZE;
|
||||
if (c < 0 || c >= max_blength)
|
||||
blength = max_blength;
|
||||
else {
|
||||
blength = 0;
|
||||
do {
|
||||
@@ -748,7 +790,6 @@ static void sum_sizes_sqroot(struct sum_struct *sum, int64 len)
|
||||
s2length = SUM_LENGTH;
|
||||
} else {
|
||||
int32 c;
|
||||
int64 l;
|
||||
int b = BLOCKSUM_BIAS;
|
||||
for (l = len; l >>= 1; b += 2) {}
|
||||
for (c = blength; (c >>= 1) && b; b--) {}
|
||||
@@ -762,7 +803,10 @@ static void sum_sizes_sqroot(struct sum_struct *sum, int64 len)
|
||||
sum->blength = blength;
|
||||
sum->s2length = s2length;
|
||||
sum->remainder = (int32)(len % blength);
|
||||
sum->count = (int32)(len / blength) + (sum->remainder != 0);
|
||||
sum->count = (int32)(l = (len / blength) + (sum->remainder != 0));
|
||||
|
||||
if ((int64)sum->count != l)
|
||||
sum->count = -1;
|
||||
|
||||
if (sum->count && verbose > 2) {
|
||||
rprintf(FINFO,
|
||||
@@ -778,7 +822,7 @@ static void sum_sizes_sqroot(struct sum_struct *sum, int64 len)
|
||||
*
|
||||
* Generate approximately one checksum every block_len bytes.
|
||||
*/
|
||||
static void generate_and_send_sums(int fd, OFF_T len, int f_out, int f_copy)
|
||||
static int generate_and_send_sums(int fd, OFF_T len, int f_out, int f_copy)
|
||||
{
|
||||
int32 i;
|
||||
struct map_struct *mapbuf;
|
||||
@@ -786,10 +830,12 @@ static void generate_and_send_sums(int fd, OFF_T len, int f_out, int f_copy)
|
||||
OFF_T offset = 0;
|
||||
|
||||
sum_sizes_sqroot(&sum, len);
|
||||
if (sum.count < 0)
|
||||
return -1;
|
||||
write_sum_head(f_out, &sum);
|
||||
|
||||
if (append_mode > 0 && f_copy < 0)
|
||||
return;
|
||||
return 0;
|
||||
|
||||
if (len > 0)
|
||||
mapbuf = map_file(fd, len, MAX_MAP_SIZE, sum.blength);
|
||||
@@ -826,6 +872,8 @@ static void generate_and_send_sums(int fd, OFF_T len, int f_out, int f_copy)
|
||||
|
||||
if (mapbuf)
|
||||
unmap_file(mapbuf);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
@@ -887,6 +935,7 @@ static int copy_altdest_file(const char *src, const char *dest, struct file_stru
|
||||
{
|
||||
char buf[MAXPATHLEN];
|
||||
const char *copy_to, *partialptr;
|
||||
int save_preserve_xattrs = preserve_xattrs;
|
||||
int ok, fd_w;
|
||||
|
||||
if (inplace) {
|
||||
@@ -911,7 +960,9 @@ static int copy_altdest_file(const char *src, const char *dest, struct file_stru
|
||||
return -1;
|
||||
}
|
||||
partialptr = partial_dir ? partial_dir_fname(dest) : NULL;
|
||||
preserve_xattrs = 0; /* xattrs were copied with file */
|
||||
ok = finish_transfer(dest, copy_to, src, partialptr, file, 1, 0);
|
||||
preserve_xattrs = save_preserve_xattrs;
|
||||
cleanup_disable();
|
||||
return ok ? 0 : -1;
|
||||
}
|
||||
@@ -1135,8 +1186,7 @@ static int try_dests_non(struct file_struct *file, char *fname, int ndx,
|
||||
if (itemizing && stdout_format_has_i
|
||||
&& (verbose > 1 || stdout_format_has_i > 1)) {
|
||||
int chg = compare_dest && type != TYPE_DIR ? 0
|
||||
: ITEM_LOCAL_CHANGE
|
||||
+ (match_level == 3 ? ITEM_XNAME_FOLLOWS : 0);
|
||||
: ITEM_LOCAL_CHANGE + (match_level == 3 ? ITEM_XNAME_FOLLOWS : 0);
|
||||
char *lp = match_level == 3 ? "" : NULL;
|
||||
itemize(cmpbuf, file, ndx, 0, sxp, chg + ITEM_MATCHED, 0, lp);
|
||||
}
|
||||
@@ -1182,22 +1232,34 @@ static void list_file_entry(struct file_struct *f)
|
||||
static int phase = 0;
|
||||
static int dflt_perms;
|
||||
|
||||
static int implied_dirs_are_missing;
|
||||
/* Helper for recv_generator's skip_dir and dry_missing_dir tests. */
|
||||
static BOOL is_below(struct file_struct *file, struct file_struct *subtree)
|
||||
{
|
||||
return F_DEPTH(file) > F_DEPTH(subtree)
|
||||
&& (!implied_dirs_are_missing || f_name_has_prefix(file, subtree));
|
||||
}
|
||||
|
||||
/* Acts on the indicated item in cur_flist whose name is fname. If a dir,
|
||||
* make sure it exists, and has the right permissions/timestamp info. For
|
||||
* all other non-regular files (symlinks, etc.) we create them here. For
|
||||
* regular files that have changed, we try to find a basis file and then
|
||||
* start sending checksums. The ndx is the file's unique index value.
|
||||
*
|
||||
* When fname is non-null, it must point to a MAXPATHLEN buffer!
|
||||
* The fname parameter must point to a MAXPATHLEN buffer! (e.g it gets
|
||||
* passed to delete_item(), which can use it during a recursive delete.)
|
||||
*
|
||||
* Note that f_out is set to -1 when doing final directory-permission and
|
||||
* modification-time repair. */
|
||||
static void recv_generator(char *fname, struct file_struct *file, int ndx,
|
||||
int itemizing, enum logcode code, int f_out)
|
||||
{
|
||||
static int missing_below = -1, excluded_below = -1;
|
||||
static const char *parent_dirname = "";
|
||||
static struct file_struct *missing_dir = NULL, *excluded_dir = NULL;
|
||||
/* Missing dir not created due to --dry-run; will still be scanned. */
|
||||
static struct file_struct *dry_missing_dir = NULL;
|
||||
/* Missing dir whose contents are skipped altogether due to
|
||||
* --ignore-non-existing, daemon exclude, or mkdir failure. */
|
||||
static struct file_struct *skip_dir = NULL;
|
||||
static struct file_list *fuzzy_dirlist = NULL;
|
||||
static int need_fuzzy_dirlist = 0;
|
||||
struct file_struct *fuzzy_file = NULL;
|
||||
@@ -1209,7 +1271,6 @@ static void recv_generator(char *fname, struct file_struct *file, int ndx,
|
||||
char *fnamecmp, *partialptr, *backupptr = NULL;
|
||||
char fnamecmpbuf[MAXPATHLEN];
|
||||
uchar fnamecmp_type;
|
||||
int implied_dirs_are_missing = relative_paths && !implied_dirs && protocol_version < 30;
|
||||
int del_opts = delete_mode || force_delete ? DEL_RECURSE : 0;
|
||||
int is_dir = !S_ISDIR(file->mode) ? 0
|
||||
: inc_recurse && ndx != cur_flist->ndx_start - 1 ? -1
|
||||
@@ -1226,48 +1287,44 @@ static void recv_generator(char *fname, struct file_struct *file, int ndx,
|
||||
return;
|
||||
}
|
||||
|
||||
if (server_filter_list.head) {
|
||||
int filtered = check_filter(&server_filter_list, fname, is_dir) < 0;
|
||||
if (is_dir < 0 && filtered)
|
||||
if (skip_dir) {
|
||||
if (is_below(file, skip_dir)) {
|
||||
if (is_dir)
|
||||
file->flags |= FLAG_MISSING_DIR;
|
||||
#ifdef SUPPORT_HARD_LINKS
|
||||
else if (F_IS_HLINKED(file))
|
||||
handle_skipped_hlink(file, itemizing, code, f_out);
|
||||
#endif
|
||||
return;
|
||||
if (excluded_below >= 0) {
|
||||
if (F_DEPTH(file) > excluded_below
|
||||
&& (!implied_dirs_are_missing || f_name_has_prefix(file, excluded_dir)))
|
||||
goto skipping;
|
||||
excluded_below = -1;
|
||||
}
|
||||
if (filtered) {
|
||||
if (is_dir) {
|
||||
excluded_below = F_DEPTH(file);
|
||||
excluded_dir = file;
|
||||
}
|
||||
skipping:
|
||||
skip_dir = NULL;
|
||||
}
|
||||
|
||||
if (daemon_filter_list.head && (*fname != '.' || fname[1])) {
|
||||
if (check_filter(&daemon_filter_list, FLOG, fname, is_dir) < 0) {
|
||||
if (is_dir < 0)
|
||||
return;
|
||||
#ifdef SUPPORT_HARD_LINKS
|
||||
if (F_IS_HLINKED(file))
|
||||
handle_skipped_hlink(file, itemizing, code, f_out);
|
||||
#endif
|
||||
rprintf(FERROR_XFER,
|
||||
"skipping daemon-excluded file \"%s\"\n",
|
||||
fname);
|
||||
"skipping daemon-excluded %s \"%s\"\n",
|
||||
is_dir ? "directory" : "file", fname);
|
||||
if (is_dir)
|
||||
goto skipping_dir_contents;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (missing_below >= 0) {
|
||||
if (F_DEPTH(file) <= missing_below
|
||||
|| (implied_dirs_are_missing && !f_name_has_prefix(file, missing_dir))) {
|
||||
if (dry_run)
|
||||
dry_run--;
|
||||
missing_below = -1;
|
||||
} else if (!dry_run) {
|
||||
if (is_dir)
|
||||
file->flags |= FLAG_MISSING_DIR;
|
||||
return;
|
||||
}
|
||||
}
|
||||
#ifdef SUPPORT_ACLS
|
||||
sx.acc_acl = sx.def_acl = NULL;
|
||||
#endif
|
||||
#ifdef SUPPORT_XATTRS
|
||||
sx.xattr = NULL;
|
||||
#endif
|
||||
if (dry_run > 1) {
|
||||
if (dry_run > 1 || (dry_missing_dir && is_below(file, dry_missing_dir))) {
|
||||
parent_is_dry_missing:
|
||||
if (fuzzy_dirlist) {
|
||||
flist_free(fuzzy_dirlist);
|
||||
fuzzy_dirlist = NULL;
|
||||
@@ -1277,13 +1334,17 @@ static void recv_generator(char *fname, struct file_struct *file, int ndx,
|
||||
stat_errno = ENOENT;
|
||||
} else {
|
||||
const char *dn = file->dirname ? file->dirname : ".";
|
||||
dry_missing_dir = NULL;
|
||||
if (parent_dirname != dn && strcmp(parent_dirname, dn) != 0) {
|
||||
if (relative_paths && !implied_dirs
|
||||
&& do_stat(dn, &sx.st) < 0
|
||||
&& create_directory_path(fname) < 0) {
|
||||
rsyserr(FERROR_XFER, errno,
|
||||
"recv_generator: mkdir %s failed",
|
||||
full_fname(dn));
|
||||
&& do_stat(dn, &sx.st) < 0) {
|
||||
if (dry_run)
|
||||
goto parent_is_dry_missing;
|
||||
if (create_directory_path(fname) < 0) {
|
||||
rsyserr(FERROR_XFER, errno,
|
||||
"recv_generator: mkdir %s failed",
|
||||
full_fname(dn));
|
||||
}
|
||||
}
|
||||
if (fuzzy_dirlist) {
|
||||
flist_free(fuzzy_dirlist);
|
||||
@@ -1312,14 +1373,13 @@ static void recv_generator(char *fname, struct file_struct *file, int ndx,
|
||||
if (is_dir) {
|
||||
if (is_dir < 0)
|
||||
return;
|
||||
if (missing_below < 0) {
|
||||
if (dry_run)
|
||||
dry_run++;
|
||||
missing_below = F_DEPTH(file);
|
||||
missing_dir = file;
|
||||
}
|
||||
skip_dir = file;
|
||||
file->flags |= FLAG_MISSING_DIR;
|
||||
}
|
||||
#ifdef SUPPORT_HARD_LINKS
|
||||
else if (F_IS_HLINKED(file))
|
||||
handle_skipped_hlink(file, itemizing, code, f_out);
|
||||
#endif
|
||||
if (verbose > 1) {
|
||||
rprintf(FINFO, "not creating new %s \"%s\"\n",
|
||||
is_dir ? "directory" : "file", fname);
|
||||
@@ -1327,8 +1387,20 @@ static void recv_generator(char *fname, struct file_struct *file, int ndx,
|
||||
return;
|
||||
}
|
||||
|
||||
if (statret == 0 && sx.st.st_uid == our_uid)
|
||||
del_opts |= DEL_OWNED_BY_US;
|
||||
if (statret == 0 && !(sx.st.st_mode & S_IWUSR)
|
||||
&& !am_root && sx.st.st_uid == our_uid)
|
||||
del_opts |= DEL_NO_UID_WRITE;
|
||||
|
||||
if (ignore_existing > 0 && statret == 0
|
||||
&& (!is_dir || !S_ISDIR(sx.st.st_mode))) {
|
||||
if (verbose > 1 && is_dir >= 0)
|
||||
rprintf(FINFO, "%s exists\n", fname);
|
||||
#ifdef SUPPORT_HARD_LINKS
|
||||
if (F_IS_HLINKED(file))
|
||||
handle_skipped_hlink(file, itemizing, code, f_out);
|
||||
#endif
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
if (is_dir) {
|
||||
if (!implied_dirs && file->flags & FLAG_IMPLIED_DIR)
|
||||
@@ -1357,10 +1429,10 @@ static void recv_generator(char *fname, struct file_struct *file, int ndx,
|
||||
goto skipping_dir_contents;
|
||||
statret = -1;
|
||||
}
|
||||
if (dry_run && statret != 0 && missing_below < 0) {
|
||||
missing_below = F_DEPTH(file);
|
||||
missing_dir = file;
|
||||
dry_run++;
|
||||
if (dry_run && statret != 0) {
|
||||
if (!dry_missing_dir)
|
||||
dry_missing_dir = file;
|
||||
file->flags |= FLAG_MISSING_DIR;
|
||||
}
|
||||
real_ret = statret;
|
||||
real_sx = sx;
|
||||
@@ -1376,6 +1448,7 @@ static void recv_generator(char *fname, struct file_struct *file, int ndx,
|
||||
if (j == -2) {
|
||||
itemizing = 0;
|
||||
code = FNONE;
|
||||
statret = 1;
|
||||
} else if (j >= 0)
|
||||
statret = 1;
|
||||
}
|
||||
@@ -1393,12 +1466,15 @@ static void recv_generator(char *fname, struct file_struct *file, int ndx,
|
||||
skipping_dir_contents:
|
||||
rprintf(FERROR,
|
||||
"*** Skipping any contents from this failed directory ***\n");
|
||||
missing_below = F_DEPTH(file);
|
||||
missing_dir = file;
|
||||
skip_dir = file;
|
||||
file->flags |= FLAG_MISSING_DIR;
|
||||
goto cleanup;
|
||||
}
|
||||
}
|
||||
#ifdef SUPPORT_XATTRS
|
||||
if (preserve_xattrs && statret == 1)
|
||||
copy_xattrs(fnamecmpbuf, fname);
|
||||
#endif
|
||||
if (set_file_attrs(fname, file, real_ret ? NULL : &real_sx, NULL, 0)
|
||||
&& verbose && code != FNONE && f_out != -1)
|
||||
rprintf(code, "%s/\n", fname);
|
||||
@@ -1427,9 +1503,13 @@ static void recv_generator(char *fname, struct file_struct *file, int ndx,
|
||||
DEV_MINOR(devp) = minor(real_sx.st.st_dev);
|
||||
}
|
||||
}
|
||||
else if (delete_during && f_out != -1 && !phase && dry_run < 2
|
||||
&& (file->flags & FLAG_CONTENT_DIR))
|
||||
delete_in_dir(fname, file, &real_sx.st.st_dev);
|
||||
else if (delete_during && f_out != -1 && !phase
|
||||
&& !(file->flags & FLAG_MISSING_DIR)) {
|
||||
if (file->flags & FLAG_CONTENT_DIR)
|
||||
delete_in_dir(fname, file, &real_sx.st.st_dev);
|
||||
else
|
||||
change_local_filter_dir(fname, strlen(fname), F_DEPTH(file));
|
||||
}
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
@@ -1513,7 +1593,7 @@ static void recv_generator(char *fname, struct file_struct *file, int ndx,
|
||||
set_file_attrs(fname, file, NULL, NULL, 0);
|
||||
if (itemizing) {
|
||||
itemize(fname, file, ndx, statret, &sx,
|
||||
ITEM_LOCAL_CHANGE, 0, NULL);
|
||||
ITEM_LOCAL_CHANGE|ITEM_REPORT_CHANGE, 0, NULL);
|
||||
}
|
||||
if (code != FNONE && verbose)
|
||||
rprintf(code, "%s -> %s\n", fname, sl);
|
||||
@@ -1597,7 +1677,7 @@ static void recv_generator(char *fname, struct file_struct *file, int ndx,
|
||||
set_file_attrs(fname, file, NULL, NULL, 0);
|
||||
if (itemizing) {
|
||||
itemize(fname, file, ndx, statret, &sx,
|
||||
ITEM_LOCAL_CHANGE, 0, NULL);
|
||||
ITEM_LOCAL_CHANGE|ITEM_REPORT_CHANGE, 0, NULL);
|
||||
}
|
||||
if (code != FNONE && verbose)
|
||||
rprintf(code, "%s\n", fname);
|
||||
@@ -1635,16 +1715,14 @@ static void recv_generator(char *fname, struct file_struct *file, int ndx,
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
if (ignore_existing > 0 && statret == 0) {
|
||||
if (verbose > 1)
|
||||
rprintf(FINFO, "%s exists\n", fname);
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
if (update_only > 0 && statret == 0
|
||||
&& cmp_time(sx.st.st_mtime, file->modtime) > 0) {
|
||||
if (verbose > 1)
|
||||
rprintf(FINFO, "%s is newer\n", fname);
|
||||
#ifdef SUPPORT_HARD_LINKS
|
||||
if (F_IS_HLINKED(file))
|
||||
handle_skipped_hlink(file, itemizing, code, f_out);
|
||||
#endif
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
@@ -1684,7 +1762,7 @@ static void recv_generator(char *fname, struct file_struct *file, int ndx,
|
||||
} else
|
||||
partialptr = NULL;
|
||||
|
||||
if (statret != 0 && fuzzy_dirlist && dry_run <= 1) {
|
||||
if (statret != 0 && fuzzy_dirlist) {
|
||||
int j = find_fuzzy(file, fuzzy_dirlist);
|
||||
if (j >= 0) {
|
||||
fuzzy_file = fuzzy_dirlist->files[j];
|
||||
@@ -1714,9 +1792,6 @@ static void recv_generator(char *fname, struct file_struct *file, int ndx,
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
if (append_mode > 0 && sx.st.st_size >= F_LENGTH(file))
|
||||
goto cleanup;
|
||||
|
||||
if (fnamecmp_type <= FNAMECMP_BASIS_DIR_HIGH)
|
||||
;
|
||||
else if (fnamecmp_type == FNAMECMP_FUZZY)
|
||||
@@ -1741,6 +1816,14 @@ static void recv_generator(char *fname, struct file_struct *file, int ndx,
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
if (append_mode > 0 && sx.st.st_size >= F_LENGTH(file)) {
|
||||
#ifdef SUPPORT_HARD_LINKS
|
||||
if (F_IS_HLINKED(file))
|
||||
handle_skipped_hlink(file, itemizing, code, f_out);
|
||||
#endif
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
prepare_to_open:
|
||||
if (partialptr) {
|
||||
sx.st = partial_st;
|
||||
@@ -1806,15 +1889,21 @@ static void recv_generator(char *fname, struct file_struct *file, int ndx,
|
||||
close(fd);
|
||||
goto cleanup;
|
||||
}
|
||||
if ((f_copy = do_open(backupptr, O_WRONLY | O_CREAT | O_TRUNC | O_EXCL, 0600)) < 0
|
||||
&& (errno != ENOENT || make_bak_dir(backupptr) < 0
|
||||
|| (f_copy = do_open(backupptr, O_WRONLY | O_CREAT | O_TRUNC | O_EXCL, 0600)) < 0)) {
|
||||
rsyserr(FERROR_XFER, errno, "open %s",
|
||||
full_fname(backupptr));
|
||||
unmake_file(back_file);
|
||||
back_file = NULL;
|
||||
close(fd);
|
||||
goto cleanup;
|
||||
if ((f_copy = do_open(backupptr, O_WRONLY | O_CREAT | O_TRUNC | O_EXCL, 0600)) < 0) {
|
||||
int save_errno = errno ? errno : EINVAL; /* 0 paranoia */
|
||||
if (errno == ENOENT && make_bak_dir(backupptr) == 0) {
|
||||
if ((f_copy = do_open(backupptr, O_WRONLY | O_CREAT | O_TRUNC | O_EXCL, 0600)) < 0)
|
||||
save_errno = errno ? errno : save_errno;
|
||||
else
|
||||
save_errno = 0;
|
||||
}
|
||||
if (save_errno) {
|
||||
rsyserr(FERROR_XFER, save_errno, "open %s", full_fname(backupptr));
|
||||
unmake_file(back_file);
|
||||
back_file = NULL;
|
||||
close(fd);
|
||||
goto cleanup;
|
||||
}
|
||||
}
|
||||
fnamecmp_type = FNAMECMP_BACKUP;
|
||||
}
|
||||
@@ -1828,7 +1917,7 @@ static void recv_generator(char *fname, struct file_struct *file, int ndx,
|
||||
rprintf(FINFO, "generating and sending sums for %d\n", ndx);
|
||||
|
||||
notify_others:
|
||||
if (remove_source_files && !delay_updates && !phase)
|
||||
if (remove_source_files && !delay_updates && !phase && !dry_run)
|
||||
increment_active_files(ndx, itemizing, code);
|
||||
if (inc_recurse && !dry_run)
|
||||
cur_flist->in_progress++;
|
||||
@@ -1840,7 +1929,7 @@ static void recv_generator(char *fname, struct file_struct *file, int ndx,
|
||||
if (itemizing) {
|
||||
int iflags = ITEM_TRANSFER;
|
||||
if (always_checksum > 0)
|
||||
iflags |= ITEM_REPORT_CHECKSUM;
|
||||
iflags |= ITEM_REPORT_CHANGE;
|
||||
if (fnamecmp_type != FNAMECMP_FNAME)
|
||||
iflags |= ITEM_BASIS_TYPE_FOLLOWS;
|
||||
if (fnamecmp_type == FNAMECMP_FUZZY)
|
||||
@@ -1869,16 +1958,32 @@ static void recv_generator(char *fname, struct file_struct *file, int ndx,
|
||||
|
||||
if (statret != 0 || whole_file)
|
||||
write_sum_head(f_out, NULL);
|
||||
else {
|
||||
generate_and_send_sums(fd, sx.st.st_size, f_out, f_copy);
|
||||
else if (sx.st.st_size <= 0) {
|
||||
write_sum_head(f_out, NULL);
|
||||
close(fd);
|
||||
} else {
|
||||
if (generate_and_send_sums(fd, sx.st.st_size, f_out, f_copy) < 0) {
|
||||
rprintf(FWARNING,
|
||||
"WARNING: file is too large for checksum sending: %s\n",
|
||||
fnamecmp);
|
||||
write_sum_head(f_out, NULL);
|
||||
}
|
||||
close(fd);
|
||||
}
|
||||
|
||||
cleanup:
|
||||
if (back_file) {
|
||||
int save_preserve_xattrs = preserve_xattrs;
|
||||
if (f_copy >= 0)
|
||||
close(f_copy);
|
||||
#ifdef SUPPORT_XATTRS
|
||||
if (preserve_xattrs) {
|
||||
copy_xattrs(fname, backupptr);
|
||||
preserve_xattrs = 0;
|
||||
}
|
||||
#endif
|
||||
set_file_attrs(backupptr, back_file, NULL, NULL, 0);
|
||||
preserve_xattrs = save_preserve_xattrs;
|
||||
if (verbose > 1) {
|
||||
rprintf(FINFO, "backed up %s to %s\n",
|
||||
fname, backupptr);
|
||||
@@ -1897,6 +2002,28 @@ static void recv_generator(char *fname, struct file_struct *file, int ndx,
|
||||
return;
|
||||
}
|
||||
|
||||
#ifdef SUPPORT_HARD_LINKS
|
||||
static void handle_skipped_hlink(struct file_struct *file, int itemizing,
|
||||
enum logcode code, int f_out)
|
||||
{
|
||||
char fbuf[MAXPATHLEN];
|
||||
int new_last_ndx;
|
||||
struct file_list *save_flist = cur_flist;
|
||||
|
||||
/* If we skip the last item in a chain of links and there was a
|
||||
* prior non-skipped hard-link waiting to finish, finish it now. */
|
||||
if ((new_last_ndx = skip_hard_link(file, &cur_flist)) < 0)
|
||||
return;
|
||||
|
||||
file = cur_flist->files[new_last_ndx - cur_flist->ndx_start];
|
||||
cur_flist->in_progress--; /* undo prior increment */
|
||||
f_name(file, fbuf);
|
||||
recv_generator(fbuf, file, new_last_ndx, itemizing, code, f_out);
|
||||
|
||||
cur_flist = save_flist;
|
||||
}
|
||||
#endif
|
||||
|
||||
static void touch_up_dirs(struct file_list *flist, int ndx)
|
||||
{
|
||||
static int counter = 0;
|
||||
@@ -1928,12 +2055,19 @@ static void touch_up_dirs(struct file_list *flist, int ndx)
|
||||
fname = f_name(file, NULL);
|
||||
if (!(file->mode & S_IWUSR))
|
||||
do_chmod(fname, file->mode);
|
||||
if (need_retouch_dir_times)
|
||||
set_modtime(fname, file->modtime, file->mode);
|
||||
if (allowed_lull && !(counter % lull_mod))
|
||||
maybe_send_keepalive();
|
||||
else if (!(counter & 0xFF))
|
||||
maybe_flush_socket(0);
|
||||
if (need_retouch_dir_times) {
|
||||
STRUCT_STAT st;
|
||||
if (link_stat(fname, &st, 0) == 0
|
||||
&& cmp_time(st.st_mtime, file->modtime) != 0)
|
||||
set_modtime(fname, file->modtime, file->mode);
|
||||
}
|
||||
if (counter >= loopchk_limit) {
|
||||
if (allowed_lull)
|
||||
maybe_send_keepalive();
|
||||
else
|
||||
maybe_flush_socket(0);
|
||||
counter = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1947,8 +2081,7 @@ void check_for_finished_files(int itemizing, enum logcode code, int check_redo)
|
||||
while (1) {
|
||||
#ifdef SUPPORT_HARD_LINKS
|
||||
if (preserve_hard_links && (ndx = get_hlink_num()) != -1) {
|
||||
flist = flist_for_ndx(ndx);
|
||||
assert(flist != NULL);
|
||||
flist = flist_for_ndx(ndx, "check_for_finished_files.1");
|
||||
file = flist->files[ndx - flist->ndx_start];
|
||||
assert(file->flags & FLAG_HLINKED);
|
||||
finish_hard_link(file, f_name(file, fbuf), ndx, NULL, itemizing, code, -1);
|
||||
@@ -1971,7 +2104,7 @@ void check_for_finished_files(int itemizing, enum logcode code, int check_redo)
|
||||
ignore_times++;
|
||||
|
||||
flist = cur_flist;
|
||||
cur_flist = flist_for_ndx(ndx);
|
||||
cur_flist = flist_for_ndx(ndx, "check_for_finished_files.2");
|
||||
|
||||
file = cur_flist->files[ndx - cur_flist->ndx_start];
|
||||
if (solo_file)
|
||||
@@ -2020,7 +2153,7 @@ void check_for_finished_files(int itemizing, enum logcode code, int check_redo)
|
||||
|
||||
void generate_files(int f_out, const char *local_name)
|
||||
{
|
||||
int i, ndx;
|
||||
int i, ndx, next_loopchk = 0;
|
||||
char fbuf[MAXPATHLEN];
|
||||
int itemizing;
|
||||
enum logcode code;
|
||||
@@ -2046,7 +2179,10 @@ void generate_files(int f_out, const char *local_name)
|
||||
solo_file = local_name;
|
||||
dir_tweaking = !(list_only || solo_file || dry_run);
|
||||
need_retouch_dir_times = preserve_times > 1;
|
||||
lull_mod = allowed_lull * 5;
|
||||
loopchk_limit = allowed_lull ? allowed_lull * 5 : 200;
|
||||
symlink_timeset_failed_flags = ITEM_REPORT_TIME
|
||||
| (protocol_version >= 30 || !am_server ? ITEM_REPORT_TIMEFAIL : 0);
|
||||
implied_dirs_are_missing = relative_paths && !implied_dirs && protocol_version < 30;
|
||||
|
||||
if (verbose > 2)
|
||||
rprintf(FINFO, "generator starting pid=%ld\n", (long)getpid());
|
||||
@@ -2088,19 +2224,24 @@ void generate_files(int f_out, const char *local_name)
|
||||
|
||||
if (inc_recurse && cur_flist->parent_ndx >= 0) {
|
||||
struct file_struct *fp = dir_flist->files[cur_flist->parent_ndx];
|
||||
f_name(fp, fbuf);
|
||||
if (solo_file)
|
||||
strlcpy(fbuf, solo_file, sizeof fbuf);
|
||||
else
|
||||
f_name(fp, fbuf);
|
||||
ndx = cur_flist->ndx_start - 1;
|
||||
recv_generator(fbuf, fp, ndx, itemizing, code, f_out);
|
||||
if (delete_during && dry_run < 2 && !list_only) {
|
||||
if (BITS_SETnUNSET(fp->flags, FLAG_CONTENT_DIR, FLAG_MISSING_DIR)) {
|
||||
if (delete_during && dry_run < 2 && !list_only
|
||||
&& !(fp->flags & FLAG_MISSING_DIR)) {
|
||||
if (fp->flags & FLAG_CONTENT_DIR) {
|
||||
dev_t dirdev;
|
||||
if (one_file_system) {
|
||||
uint32 *devp = F_DIR_DEV_P(fp);
|
||||
dirdev = MAKEDEV(DEV_MAJOR(devp), DEV_MINOR(devp));
|
||||
} else
|
||||
dirdev = MAKEDEV(0, 0);
|
||||
delete_in_dir(f_name(fp, fbuf), fp, &dirdev);
|
||||
}
|
||||
delete_in_dir(fbuf, fp, &dirdev);
|
||||
} else
|
||||
change_local_filter_dir(fbuf, strlen(fbuf), F_DEPTH(fp));
|
||||
}
|
||||
}
|
||||
for (i = cur_flist->low; i <= cur_flist->high; i++) {
|
||||
@@ -2122,10 +2263,13 @@ void generate_files(int f_out, const char *local_name)
|
||||
|
||||
check_for_finished_files(itemizing, code, 0);
|
||||
|
||||
if (allowed_lull && !(i % lull_mod))
|
||||
maybe_send_keepalive();
|
||||
else if (!(i & 0xFF))
|
||||
maybe_flush_socket(0);
|
||||
if (i + cur_flist->ndx_start >= next_loopchk) {
|
||||
if (allowed_lull)
|
||||
maybe_send_keepalive();
|
||||
else
|
||||
maybe_flush_socket(0);
|
||||
next_loopchk += loopchk_limit;
|
||||
}
|
||||
}
|
||||
|
||||
if (!inc_recurse) {
|
||||
@@ -2141,6 +2285,9 @@ void generate_files(int f_out, const char *local_name)
|
||||
}
|
||||
} while ((cur_flist = cur_flist->next) != NULL);
|
||||
|
||||
if (read_batch && inc_recurse)
|
||||
write_ndx(f_out, NDX_DONE);
|
||||
|
||||
if (delete_during)
|
||||
delete_in_dir(NULL, NULL, &dev_zero);
|
||||
phase++;
|
||||
@@ -2193,7 +2340,7 @@ void generate_files(int f_out, const char *local_name)
|
||||
touch_up_dirs(dir_flist, -1);
|
||||
|
||||
if (max_delete >= 0 && deletion_count > max_delete) {
|
||||
rprintf(FINFO,
|
||||
rprintf(FWARNING,
|
||||
"Deletions stopped due to --max-delete limit (%d skipped)\n",
|
||||
deletion_count - max_delete);
|
||||
io_error |= IOERR_DEL_LIMIT;
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
* `id -G` on Linux, but it's too hard to find a portable equivalent.
|
||||
*
|
||||
* Copyright (C) 2002 Martin Pool
|
||||
* Copyright (C) 2003-2007 Wayne Davison
|
||||
* Copyright (C) 2003-2008 Wayne Davison
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 3 as
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* Routines to provide a memory-efficient hashtable.
|
||||
*
|
||||
* Copyright (C) 2007 Wayne Davison
|
||||
* Copyright (C) 2007-2008 Wayne Davison
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
@@ -104,7 +104,9 @@ void *hashtable_find(struct hashtable *tbl, int64 key, int allocate_if_missing)
|
||||
a = b = c = 0xdeadbeef + (8 << 2);
|
||||
|
||||
#define rot(x,k) (((x)<<(k)) ^ ((x)>>(32-(k))))
|
||||
#if SIZEOF_INT64 >= 8
|
||||
b += (uint32)(key >> 32);
|
||||
#endif
|
||||
a += (uint32)key;
|
||||
c ^= b; c -= rot(b, 14);
|
||||
a ^= c; a -= rot(c, 11);
|
||||
|
||||
149
hlink.c
149
hlink.c
@@ -4,7 +4,7 @@
|
||||
* Copyright (C) 1996 Andrew Tridgell
|
||||
* Copyright (C) 1996 Paul Mackerras
|
||||
* Copyright (C) 2002 Martin Pool <mbp@samba.org>
|
||||
* Copyright (C) 2004-2007 Wayne Davison
|
||||
* Copyright (C) 2004-2008 Wayne Davison
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
@@ -30,6 +30,7 @@ extern int inc_recurse;
|
||||
extern int do_xfers;
|
||||
extern int link_dest;
|
||||
extern int preserve_acls;
|
||||
extern int preserve_xattrs;
|
||||
extern int make_backups;
|
||||
extern int protocol_version;
|
||||
extern int remove_source_files;
|
||||
@@ -119,18 +120,23 @@ static void match_gnums(int32 *ndx_list, int ndx_count)
|
||||
if (inc_recurse) {
|
||||
node = hashtable_find(prior_hlinks, gnum, 1);
|
||||
if (!node->data) {
|
||||
node->data = new_array0(char, 5);
|
||||
if (!(node->data = new_array0(char, 5)))
|
||||
out_of_memory("match_gnums");
|
||||
assert(gnum >= hlink_flist->ndx_start);
|
||||
file->flags |= FLAG_HLINK_FIRST;
|
||||
prev = -1;
|
||||
} else if (CVAL(node->data, 0) == 0) {
|
||||
struct file_list *flist;
|
||||
struct file_struct *fp;
|
||||
prev = IVAL(node->data, 1);
|
||||
flist = flist_for_ndx(prev);
|
||||
assert(flist != NULL);
|
||||
fp = flist->files[prev - flist->ndx_start];
|
||||
fp->flags &= ~FLAG_HLINK_LAST;
|
||||
flist = flist_for_ndx(prev, NULL);
|
||||
if (flist)
|
||||
flist->files[prev - flist->ndx_start]->flags &= ~FLAG_HLINK_LAST;
|
||||
else {
|
||||
/* We skipped all prior files in this
|
||||
* group, so mark this as a "first". */
|
||||
file->flags |= FLAG_HLINK_FIRST;
|
||||
prev = -1;
|
||||
}
|
||||
} else
|
||||
prev = -1;
|
||||
} else {
|
||||
@@ -175,7 +181,7 @@ static void match_gnums(int32 *ndx_list, int ndx_count)
|
||||
* to first when we're done. */
|
||||
void match_hard_links(struct file_list *flist)
|
||||
{
|
||||
if (!list_only) {
|
||||
if (!list_only && flist->used) {
|
||||
int i, ndx_count = 0;
|
||||
int32 *ndx_list;
|
||||
|
||||
@@ -240,21 +246,43 @@ static int maybe_hard_link(struct file_struct *file, int ndx,
|
||||
}
|
||||
|
||||
/* Figure out if a prior entry is still there or if we just have a
|
||||
* cached name for it. Never called with a FLAG_HLINK_FIRST entry. */
|
||||
static char *check_prior(int prev_ndx, int gnum, struct file_list **flist_p)
|
||||
* cached name for it. */
|
||||
static char *check_prior(struct file_struct *file, int gnum,
|
||||
int *prev_ndx_p, struct file_list **flist_p)
|
||||
{
|
||||
struct file_list *flist = flist_for_ndx(prev_ndx);
|
||||
struct file_struct *fp;
|
||||
struct ht_int32_node *node;
|
||||
int prev_ndx = F_HL_PREV(file);
|
||||
|
||||
if (flist) {
|
||||
*flist_p = flist;
|
||||
return NULL;
|
||||
while (1) {
|
||||
struct file_list *flist;
|
||||
if (prev_ndx < 0
|
||||
|| (flist = flist_for_ndx(prev_ndx, NULL)) == NULL)
|
||||
break;
|
||||
fp = flist->files[prev_ndx - flist->ndx_start];
|
||||
if (!(fp->flags & FLAG_SKIP_HLINK)) {
|
||||
*prev_ndx_p = prev_ndx;
|
||||
*flist_p = flist;
|
||||
return NULL;
|
||||
}
|
||||
F_HL_PREV(file) = prev_ndx = F_HL_PREV(fp);
|
||||
}
|
||||
|
||||
node = hashtable_find(prior_hlinks, gnum, 0);
|
||||
assert(node != NULL && node->data);
|
||||
assert(CVAL(node->data, 0) != 0);
|
||||
return node->data;
|
||||
if (inc_recurse
|
||||
&& (node = hashtable_find(prior_hlinks, gnum, 0)) != NULL) {
|
||||
assert(node->data != NULL);
|
||||
if (CVAL(node->data, 0) != 0) {
|
||||
*prev_ndx_p = -1;
|
||||
*flist_p = NULL;
|
||||
return node->data;
|
||||
}
|
||||
/* The prior file must have been skipped. */
|
||||
F_HL_PREV(file) = -1;
|
||||
}
|
||||
|
||||
*prev_ndx_p = -1;
|
||||
*flist_p = NULL;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Only called if FLAG_HLINKED is set and FLAG_HLINK_FIRST is not. Returns:
|
||||
@@ -268,12 +296,20 @@ int hard_link_check(struct file_struct *file, int ndx, const char *fname,
|
||||
char *realname, *prev_name;
|
||||
struct file_list *flist;
|
||||
int gnum = inc_recurse ? F_HL_GNUM(file) : -1;
|
||||
int prev_ndx = F_HL_PREV(file);
|
||||
int prev_ndx;
|
||||
|
||||
prev_name = realname = check_prior(prev_ndx, gnum, &flist);
|
||||
prev_name = realname = check_prior(file, gnum, &prev_ndx, &flist);
|
||||
|
||||
if (!prev_name) {
|
||||
struct file_struct *prev_file = flist->files[prev_ndx - flist->ndx_start];
|
||||
struct file_struct *prev_file;
|
||||
|
||||
if (!flist) {
|
||||
/* The previous file was skipped, so this one is
|
||||
* treated as if it were the first in its group. */
|
||||
return 0;
|
||||
}
|
||||
|
||||
prev_file = flist->files[prev_ndx - flist->ndx_start];
|
||||
|
||||
/* Is the previous link not complete yet? */
|
||||
if (!(prev_file->flags & FLAG_HLINK_DONE)) {
|
||||
@@ -294,8 +330,8 @@ int hard_link_check(struct file_struct *file, int ndx, const char *fname,
|
||||
/* There is a finished file to link with! */
|
||||
if (!(prev_file->flags & FLAG_HLINK_FIRST)) {
|
||||
/* The previous previous is FIRST when prev is not. */
|
||||
prev_ndx = F_HL_PREV(prev_file);
|
||||
prev_name = realname = check_prior(prev_ndx, gnum, &flist);
|
||||
prev_name = realname = check_prior(prev_file, gnum, &prev_ndx, &flist);
|
||||
assert(prev_name != NULL || flist != NULL);
|
||||
/* Update our previous pointer to point to the FIRST. */
|
||||
F_HL_PREV(file) = prev_ndx;
|
||||
}
|
||||
@@ -332,6 +368,9 @@ int hard_link_check(struct file_struct *file, int ndx, const char *fname,
|
||||
int j = 0;
|
||||
#ifdef SUPPORT_ACLS
|
||||
alt_sx.acc_acl = alt_sx.def_acl = NULL;
|
||||
#endif
|
||||
#ifdef SUPPORT_XATTRS
|
||||
alt_sx.xattr = NULL;
|
||||
#endif
|
||||
do {
|
||||
pathjoin(cmpbuf, MAXPATHLEN, basis_dir[j], fname);
|
||||
@@ -361,19 +400,37 @@ int hard_link_check(struct file_struct *file, int ndx, const char *fname,
|
||||
sxp->st = alt_sx.st;
|
||||
#ifdef SUPPORT_ACLS
|
||||
if (preserve_acls && !S_ISLNK(file->mode)) {
|
||||
if (!ACL_READY(*sxp))
|
||||
free_acl(sxp);
|
||||
if (!ACL_READY(alt_sx))
|
||||
get_acl(cmpbuf, sxp);
|
||||
else {
|
||||
sxp->acc_acl = alt_sx.acc_acl;
|
||||
sxp->def_acl = alt_sx.def_acl;
|
||||
alt_sx.acc_acl = alt_sx.def_acl = NULL;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
#ifdef SUPPORT_ACLS
|
||||
else if (preserve_acls)
|
||||
free_acl(&alt_sx);
|
||||
#ifdef SUPPORT_XATTRS
|
||||
if (preserve_xattrs) {
|
||||
free_xattr(sxp);
|
||||
if (!XATTR_READY(alt_sx))
|
||||
get_xattr(cmpbuf, sxp);
|
||||
else {
|
||||
sxp->xattr = alt_sx.xattr;
|
||||
alt_sx.xattr = NULL;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
} else {
|
||||
#ifdef SUPPORT_ACLS
|
||||
if (preserve_acls)
|
||||
free_acl(&alt_sx);
|
||||
#endif
|
||||
#ifdef SUPPORT_XATTRS
|
||||
if (preserve_xattrs)
|
||||
free_xattr(&alt_sx);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
if (maybe_hard_link(file, ndx, fname, statret, sxp, prev_name, &prev_st,
|
||||
@@ -413,7 +470,7 @@ void finish_hard_link(struct file_struct *file, const char *fname, int fin_ndx,
|
||||
{
|
||||
stat_x prev_sx;
|
||||
STRUCT_STAT st;
|
||||
char alt_name[MAXPATHLEN], *prev_name;
|
||||
char prev_name[MAXPATHLEN], alt_name[MAXPATHLEN];
|
||||
const char *our_name;
|
||||
struct file_list *flist;
|
||||
int prev_statret, ndx, prev_ndx = F_HL_PREV(file);
|
||||
@@ -440,23 +497,28 @@ void finish_hard_link(struct file_struct *file, const char *fname, int fin_ndx,
|
||||
#ifdef SUPPORT_ACLS
|
||||
prev_sx.acc_acl = prev_sx.def_acl = NULL;
|
||||
#endif
|
||||
#ifdef SUPPORT_XATTRS
|
||||
prev_sx.xattr = NULL;
|
||||
#endif
|
||||
|
||||
while ((ndx = prev_ndx) >= 0) {
|
||||
int val;
|
||||
flist = flist_for_ndx(ndx);
|
||||
assert(flist != NULL);
|
||||
flist = flist_for_ndx(ndx, "finish_hard_link");
|
||||
file = flist->files[ndx - flist->ndx_start];
|
||||
file->flags = (file->flags & ~FLAG_HLINK_FIRST) | FLAG_HLINK_DONE;
|
||||
prev_ndx = F_HL_PREV(file);
|
||||
F_HL_PREV(file) = fin_ndx;
|
||||
prev_name = f_name(file, NULL);
|
||||
prev_statret = link_stat(prev_name, &prev_sx.st, 0);
|
||||
prev_statret = link_stat(f_name(file, prev_name), &prev_sx.st, 0);
|
||||
val = maybe_hard_link(file, ndx, prev_name, prev_statret, &prev_sx,
|
||||
our_name, stp, fname, itemizing, code);
|
||||
flist->in_progress--;
|
||||
#ifdef SUPPORT_ACLS
|
||||
if (preserve_acls)
|
||||
free_acl(&prev_sx);
|
||||
#endif
|
||||
#ifdef SUPPORT_XATTRS
|
||||
if (preserve_xattrs)
|
||||
free_xattr(&prev_sx);
|
||||
#endif
|
||||
if (val < 0)
|
||||
continue;
|
||||
@@ -474,4 +536,25 @@ void finish_hard_link(struct file_struct *file, const char *fname, int fin_ndx,
|
||||
out_of_memory("finish_hard_link");
|
||||
}
|
||||
}
|
||||
|
||||
int skip_hard_link(struct file_struct *file, struct file_list **flist_p)
|
||||
{
|
||||
struct file_list *flist;
|
||||
int prev_ndx;
|
||||
|
||||
file->flags |= FLAG_SKIP_HLINK;
|
||||
if (!(file->flags & FLAG_HLINK_LAST))
|
||||
return -1;
|
||||
|
||||
check_prior(file, F_HL_GNUM(file), &prev_ndx, &flist);
|
||||
if (prev_ndx >= 0) {
|
||||
file = flist->files[prev_ndx - flist->ndx_start];
|
||||
if (file->flags & (FLAG_HLINK_DONE|FLAG_FILE_SENT))
|
||||
return -1;
|
||||
file->flags |= FLAG_HLINK_LAST;
|
||||
*flist_p = flist;
|
||||
}
|
||||
|
||||
return prev_ndx;
|
||||
}
|
||||
#endif
|
||||
|
||||
12
ifuncs.h
12
ifuncs.h
@@ -1,6 +1,6 @@
|
||||
/* Inline functions for rsync.
|
||||
*
|
||||
* Copyright (C) 2007 Wayne Davison
|
||||
* Copyright (C) 2007-2008 Wayne Davison
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
@@ -57,6 +57,16 @@ from_wire_mode(int mode)
|
||||
return mode;
|
||||
}
|
||||
|
||||
static inline char *
|
||||
d_name(struct dirent *di)
|
||||
{
|
||||
#ifdef HAVE_BROKEN_READDIR
|
||||
return (di->d_name - 2);
|
||||
#else
|
||||
return di->d_name;
|
||||
#endif
|
||||
}
|
||||
|
||||
static inline int
|
||||
isDigit(const char *ptr)
|
||||
{
|
||||
|
||||
211
io.c
211
io.c
@@ -4,7 +4,7 @@
|
||||
* Copyright (C) 1996-2001 Andrew Tridgell
|
||||
* Copyright (C) 1996 Paul Mackerras
|
||||
* Copyright (C) 2001, 2002 Martin Pool <mbp@samba.org>
|
||||
* Copyright (C) 2003-2007 Wayne Davison
|
||||
* Copyright (C) 2003-2008 Wayne Davison
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
@@ -45,6 +45,7 @@ extern int inc_recurse;
|
||||
extern int io_error;
|
||||
extern int eol_nulls;
|
||||
extern int flist_eof;
|
||||
extern int list_only;
|
||||
extern int read_batch;
|
||||
extern int csum_length;
|
||||
extern int protect_args;
|
||||
@@ -100,10 +101,11 @@ static char ff_lastchar;
|
||||
#ifdef ICONV_OPTION
|
||||
static xbuf iconv_buf = EMPTY_XBUF;
|
||||
#endif
|
||||
static int defer_forwarding_messages = 0, defer_forwarding_keep = 0;
|
||||
static int defer_forwarding_messages = 0, keep_defer_forwarding = 0;
|
||||
static int select_timeout = SELECT_TIMEOUT;
|
||||
static int active_filecnt = 0;
|
||||
static OFF_T active_bytecnt = 0;
|
||||
static int first_message = 1;
|
||||
|
||||
static char int_byte_extra[64] = {
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* (00 - 3F)/4 */
|
||||
@@ -112,6 +114,9 @@ static char int_byte_extra[64] = {
|
||||
2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 4, 4, 5, 6, /* (C0 - FF)/4 */
|
||||
};
|
||||
|
||||
#define REMOTE_OPTION_ERROR "rsync: on remote machine: -"
|
||||
#define REMOTE_OPTION_ERROR2 ": unknown option"
|
||||
|
||||
enum festatus { FES_SUCCESS, FES_REDO, FES_NO_SEND };
|
||||
|
||||
static void readfd(int fd, char *buffer, size_t N);
|
||||
@@ -119,16 +124,7 @@ static void writefd(int fd, const char *buf, size_t len);
|
||||
static void writefd_unbuffered(int fd, const char *buf, size_t len);
|
||||
static void mplex_write(int fd, enum msgcode code, const char *buf, size_t len, int convert);
|
||||
|
||||
struct flist_ndx_item {
|
||||
struct flist_ndx_item *next;
|
||||
int ndx;
|
||||
};
|
||||
|
||||
struct flist_ndx_list {
|
||||
struct flist_ndx_item *head, *tail;
|
||||
};
|
||||
|
||||
static struct flist_ndx_list redo_list, hlink_list;
|
||||
static flist_ndx_list redo_list, hlink_list;
|
||||
|
||||
struct msg_list_item {
|
||||
struct msg_list_item *next;
|
||||
@@ -142,45 +138,10 @@ struct msg_list {
|
||||
|
||||
static struct msg_list msg_queue;
|
||||
|
||||
static void flist_ndx_push(struct flist_ndx_list *lp, int ndx)
|
||||
{
|
||||
struct flist_ndx_item *item;
|
||||
|
||||
if (!(item = new(struct flist_ndx_item)))
|
||||
out_of_memory("flist_ndx_push");
|
||||
item->next = NULL;
|
||||
item->ndx = ndx;
|
||||
if (lp->tail)
|
||||
lp->tail->next = item;
|
||||
else
|
||||
lp->head = item;
|
||||
lp->tail = item;
|
||||
}
|
||||
|
||||
static int flist_ndx_pop(struct flist_ndx_list *lp)
|
||||
{
|
||||
struct flist_ndx_item *next;
|
||||
int ndx;
|
||||
|
||||
if (!lp->head)
|
||||
return -1;
|
||||
|
||||
ndx = lp->head->ndx;
|
||||
next = lp->head->next;
|
||||
free(lp->head);
|
||||
lp->head = next;
|
||||
if (!next)
|
||||
lp->tail = NULL;
|
||||
|
||||
return ndx;
|
||||
}
|
||||
|
||||
static void got_flist_entry_status(enum festatus status, const char *buf)
|
||||
{
|
||||
int ndx = IVAL(buf, 0);
|
||||
struct file_list *flist = flist_for_ndx(ndx);
|
||||
|
||||
assert(flist != NULL);
|
||||
struct file_list *flist = flist_for_ndx(ndx, "got_flist_entry_status");
|
||||
|
||||
if (remove_source_files) {
|
||||
active_filecnt--;
|
||||
@@ -203,6 +164,11 @@ static void got_flist_entry_status(enum festatus status, const char *buf)
|
||||
}
|
||||
break;
|
||||
case FES_REDO:
|
||||
if (read_batch) {
|
||||
if (inc_recurse)
|
||||
flist->in_progress++;
|
||||
break;
|
||||
}
|
||||
if (inc_recurse)
|
||||
flist->to_redo++;
|
||||
flist_ndx_push(&redo_list, ndx);
|
||||
@@ -291,33 +257,62 @@ static void msg_list_add(struct msg_list *lst, int code, const char *buf, int le
|
||||
lst->tail = m;
|
||||
}
|
||||
|
||||
static inline int flush_a_msg(int fd)
|
||||
{
|
||||
struct msg_list_item *m = msg_queue.head;
|
||||
int len = IVAL(m->buf, 0) & 0xFFFFFF;
|
||||
int tag = *((uchar*)m->buf+3) - MPLEX_BASE;
|
||||
|
||||
if (!(msg_queue.head = m->next))
|
||||
msg_queue.tail = NULL;
|
||||
|
||||
defer_forwarding_messages++;
|
||||
mplex_write(fd, tag, m->buf + 4, len, m->convert);
|
||||
defer_forwarding_messages--;
|
||||
|
||||
free(m);
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
static void msg_flush(void)
|
||||
{
|
||||
if (am_generator) {
|
||||
while (msg_queue.head && io_multiplexing_out) {
|
||||
struct msg_list_item *m = msg_queue.head;
|
||||
int len = IVAL(m->buf, 0) & 0xFFFFFF;
|
||||
int tag = *((uchar*)m->buf+3) - MPLEX_BASE;
|
||||
if (!(msg_queue.head = m->next))
|
||||
msg_queue.tail = NULL;
|
||||
stats.total_written += len + 4;
|
||||
defer_forwarding_messages++;
|
||||
mplex_write(sock_f_out, tag, m->buf + 4, len, m->convert);
|
||||
defer_forwarding_messages--;
|
||||
free(m);
|
||||
}
|
||||
while (msg_queue.head && io_multiplexing_out)
|
||||
stats.total_written += flush_a_msg(sock_f_out) + 4;
|
||||
} else {
|
||||
while (msg_queue.head) {
|
||||
struct msg_list_item *m = msg_queue.head;
|
||||
int len = IVAL(m->buf, 0) & 0xFFFFFF;
|
||||
int tag = *((uchar*)m->buf+3) - MPLEX_BASE;
|
||||
if (!(msg_queue.head = m->next))
|
||||
msg_queue.tail = NULL;
|
||||
defer_forwarding_messages++;
|
||||
mplex_write(msg_fd_out, tag, m->buf + 4, len, m->convert);
|
||||
defer_forwarding_messages--;
|
||||
free(m);
|
||||
}
|
||||
while (msg_queue.head)
|
||||
(void)flush_a_msg(msg_fd_out);
|
||||
}
|
||||
}
|
||||
|
||||
static void check_for_d_option_error(const char *msg)
|
||||
{
|
||||
static char rsync263_opts[] = "BCDHIKLPRSTWabceghlnopqrtuvxz";
|
||||
char *colon;
|
||||
int saw_d = 0;
|
||||
|
||||
if (*msg != 'r'
|
||||
|| strncmp(msg, REMOTE_OPTION_ERROR, sizeof REMOTE_OPTION_ERROR - 1) != 0)
|
||||
return;
|
||||
|
||||
msg += sizeof REMOTE_OPTION_ERROR - 1;
|
||||
if (*msg == '-' || (colon = strchr(msg, ':')) == NULL
|
||||
|| strncmp(colon, REMOTE_OPTION_ERROR2, sizeof REMOTE_OPTION_ERROR2 - 1) != 0)
|
||||
return;
|
||||
|
||||
for ( ; *msg != ':'; msg++) {
|
||||
if (*msg == 'd')
|
||||
saw_d = 1;
|
||||
else if (*msg == 'e')
|
||||
break;
|
||||
else if (strchr(rsync263_opts, *msg) == NULL)
|
||||
return;
|
||||
}
|
||||
|
||||
if (saw_d) {
|
||||
rprintf(FWARNING,
|
||||
"*** Try using \"--old-d\" if remote rsync is <= 2.6.3 ***\n");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -414,6 +409,7 @@ static void read_msg_fd(void)
|
||||
got_flist_entry_status(FES_NO_SEND, buf);
|
||||
break;
|
||||
case MSG_ERROR_SOCKET:
|
||||
case MSG_ERROR_UTF8:
|
||||
case MSG_CLIENT:
|
||||
if (!am_generator)
|
||||
goto invalid_msg;
|
||||
@@ -451,9 +447,14 @@ static void read_msg_fd(void)
|
||||
* this, sender-side deletions were mostly happening at the end. */
|
||||
void increment_active_files(int ndx, int itemizing, enum logcode code)
|
||||
{
|
||||
/* TODO: tune these limits? */
|
||||
while (active_filecnt >= (active_bytecnt >= 128*1024 ? 10 : 50)) {
|
||||
while (1) {
|
||||
/* TODO: tune these limits? */
|
||||
int limit = active_bytecnt >= 128*1024 ? 10 : 50;
|
||||
if (active_filecnt < limit)
|
||||
break;
|
||||
check_for_finished_files(itemizing, code, 0);
|
||||
if (active_filecnt < limit)
|
||||
break;
|
||||
if (iobuf_out_cnt)
|
||||
io_flush(NORMAL_FLUSH);
|
||||
else
|
||||
@@ -496,9 +497,9 @@ static void mplex_write(int fd, enum msgcode code, const char *buf, size_t len,
|
||||
|
||||
SIVAL(buffer, 0, ((MPLEX_BASE + (int)code)<<24) + len);
|
||||
|
||||
defer_forwarding_keep = 1; /* defer_forwarding_messages++ on return */
|
||||
keep_defer_forwarding++; /* defer_forwarding_messages++ on return */
|
||||
writefd_unbuffered(fd, buffer, n+4);
|
||||
defer_forwarding_keep = 0;
|
||||
keep_defer_forwarding--;
|
||||
|
||||
if (len > n)
|
||||
writefd_unbuffered(fd, buf+n, len-n);
|
||||
@@ -533,10 +534,9 @@ void send_msg_int(enum msgcode code, int num)
|
||||
|
||||
void wait_for_receiver(void)
|
||||
{
|
||||
if (iobuf_out_cnt)
|
||||
io_flush(NORMAL_FLUSH);
|
||||
else
|
||||
read_msg_fd();
|
||||
if (io_flush(NORMAL_FLUSH))
|
||||
return;
|
||||
read_msg_fd();
|
||||
}
|
||||
|
||||
int get_redo_num(void)
|
||||
@@ -838,8 +838,8 @@ int read_line(int fd, char *buf, size_t bufsiz, int flags)
|
||||
return s - buf;
|
||||
}
|
||||
|
||||
int read_args(int f_in, char *mod_name, char *buf, size_t bufsiz, int rl_nulls,
|
||||
char ***argv_p, int *argc_p, char **request_p)
|
||||
void read_args(int f_in, char *mod_name, char *buf, size_t bufsiz, int rl_nulls,
|
||||
char ***argv_p, int *argc_p, char **request_p)
|
||||
{
|
||||
int maxargs = MAX_ARGS;
|
||||
int dot_pos = 0;
|
||||
@@ -853,14 +853,14 @@ int read_args(int f_in, char *mod_name, char *buf, size_t bufsiz, int rl_nulls,
|
||||
|
||||
if (!(argv = new_array(char *, maxargs)))
|
||||
out_of_memory("read_args");
|
||||
if (mod_name)
|
||||
if (mod_name && !protect_args)
|
||||
argv[argc++] = "rsyncd";
|
||||
|
||||
while (1) {
|
||||
if (read_line(f_in, buf, bufsiz, rl_flags) == 0)
|
||||
break;
|
||||
|
||||
if (argc == maxargs) {
|
||||
if (argc == maxargs-1) {
|
||||
maxargs += MAX_ARGS;
|
||||
if (!(argv = realloc_array(argv, char *, maxargs)))
|
||||
out_of_memory("read_args");
|
||||
@@ -883,11 +883,12 @@ int read_args(int f_in, char *mod_name, char *buf, size_t bufsiz, int rl_nulls,
|
||||
dot_pos = argc;
|
||||
}
|
||||
}
|
||||
argv[argc] = NULL;
|
||||
|
||||
glob_expand(NULL, NULL, NULL, NULL);
|
||||
|
||||
*argc_p = argc;
|
||||
*argv_p = argv;
|
||||
|
||||
return dot_pos ? dot_pos : argc;
|
||||
}
|
||||
|
||||
int io_start_buffering_out(int f_out)
|
||||
@@ -1119,6 +1120,13 @@ static int readfd_unbuffered(int fd, char *buf, size_t len)
|
||||
}
|
||||
read_loop(fd, line, msg_bytes);
|
||||
rwrite((enum logcode)tag, line, msg_bytes, 1);
|
||||
if (first_message) {
|
||||
if (list_only && !am_sender && tag == 1) {
|
||||
line[msg_bytes] = '\0';
|
||||
check_for_d_option_error(line);
|
||||
}
|
||||
first_message = 0;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
rprintf(FERROR, "unexpected tag %d [%s]\n",
|
||||
@@ -1311,6 +1319,7 @@ int read_vstring(int f, char *buf, int bufsize)
|
||||
* called by both the sender and the receiver. */
|
||||
void read_sum_head(int f, struct sum_struct *sum)
|
||||
{
|
||||
int32 max_blength = protocol_version < 30 ? OLD_MAX_BLOCK_SIZE : MAX_BLOCK_SIZE;
|
||||
sum->count = read_int(f);
|
||||
if (sum->count < 0) {
|
||||
rprintf(FERROR, "Invalid checksum count %ld [%s]\n",
|
||||
@@ -1318,7 +1327,7 @@ void read_sum_head(int f, struct sum_struct *sum)
|
||||
exit_cleanup(RERR_PROTOCOL);
|
||||
}
|
||||
sum->blength = read_int(f);
|
||||
if (sum->blength < 0 || sum->blength > MAX_BLOCK_SIZE) {
|
||||
if (sum->blength < 0 || sum->blength > max_blength) {
|
||||
rprintf(FERROR, "Invalid block length %ld [%s]\n",
|
||||
(long)sum->blength, who_am_i());
|
||||
exit_cleanup(RERR_PROTOCOL);
|
||||
@@ -1511,24 +1520,34 @@ static void writefd_unbuffered(int fd, const char *buf, size_t len)
|
||||
}
|
||||
|
||||
no_flush--;
|
||||
defer_inc -= defer_forwarding_keep;
|
||||
if (keep_defer_forwarding)
|
||||
defer_inc--;
|
||||
if (!(defer_forwarding_messages -= defer_inc) && !no_flush)
|
||||
msg_flush();
|
||||
}
|
||||
|
||||
void io_flush(int flush_it_all)
|
||||
int io_flush(int flush_it_all)
|
||||
{
|
||||
if (!iobuf_out_cnt || no_flush)
|
||||
return;
|
||||
int flushed_something = 0;
|
||||
|
||||
if (io_multiplexing_out)
|
||||
mplex_write(sock_f_out, MSG_DATA, iobuf_out, iobuf_out_cnt, 0);
|
||||
else
|
||||
writefd_unbuffered(iobuf_f_out, iobuf_out, iobuf_out_cnt);
|
||||
iobuf_out_cnt = 0;
|
||||
if (no_flush)
|
||||
return 0;
|
||||
|
||||
if (flush_it_all && !defer_forwarding_messages)
|
||||
if (iobuf_out_cnt) {
|
||||
if (io_multiplexing_out)
|
||||
mplex_write(sock_f_out, MSG_DATA, iobuf_out, iobuf_out_cnt, 0);
|
||||
else
|
||||
writefd_unbuffered(iobuf_f_out, iobuf_out, iobuf_out_cnt);
|
||||
iobuf_out_cnt = 0;
|
||||
flushed_something = 1;
|
||||
}
|
||||
|
||||
if (flush_it_all && !defer_forwarding_messages && msg_queue.head) {
|
||||
msg_flush();
|
||||
flushed_something = 1;
|
||||
}
|
||||
|
||||
return flushed_something;
|
||||
}
|
||||
|
||||
static void writefd(int fd, const char *buf, size_t len)
|
||||
|
||||
2
io.h
2
io.h
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2007 Wayne Davison
|
||||
* Copyright (C) 2007-2008 Wayne Davison
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
|
||||
@@ -492,13 +492,10 @@ int getnameinfo(const struct sockaddr *sa, socklen_t salen,
|
||||
return EAI_FAIL;
|
||||
}
|
||||
|
||||
/* We don't support those. */
|
||||
if ((node && !(flags & NI_NUMERICHOST))
|
||||
|| (service && !(flags & NI_NUMERICSERV)))
|
||||
return EAI_FAIL;
|
||||
|
||||
if (node) {
|
||||
return gethostnameinfo(sa, node, nodelen, flags);
|
||||
int ret = gethostnameinfo(sa, node, nodelen, flags);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (service) {
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
* An implementation of MD4 designed for use in the SMB authentication protocol.
|
||||
*
|
||||
* Copyright (C) 1997-1998 Andrew Tridgell
|
||||
* Copyright (C) 2005-2007 Wayne Davison
|
||||
* Copyright (C) 2005-2008 Wayne Davison
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
|
||||
@@ -295,24 +295,30 @@ pool_boundary(alloc_pool_t p, size_t len)
|
||||
}
|
||||
|
||||
#define FDPRINT(label, value) \
|
||||
snprintf(buf, sizeof buf, label, value), \
|
||||
write(fd, buf, strlen(buf))
|
||||
do { \
|
||||
int len = snprintf(buf, sizeof buf, label, value); \
|
||||
if (write(fd, buf, len) != len) \
|
||||
ret = -1; \
|
||||
} while (0)
|
||||
|
||||
#define FDEXTSTAT(ext) \
|
||||
snprintf(buf, sizeof buf, " %12ld %5ld\n", \
|
||||
(long) ext->free, \
|
||||
(long) ext->bound), \
|
||||
write(fd, buf, strlen(buf))
|
||||
do { \
|
||||
int len = snprintf(buf, sizeof buf, " %12ld %5ld\n", \
|
||||
(long)ext->free, (long)ext->bound); \
|
||||
if (write(fd, buf, len) != len) \
|
||||
ret = -1; \
|
||||
} while (0)
|
||||
|
||||
void
|
||||
int
|
||||
pool_stats(alloc_pool_t p, int fd, int summarize)
|
||||
{
|
||||
struct alloc_pool *pool = (struct alloc_pool *) p;
|
||||
struct pool_extent *cur;
|
||||
char buf[BUFSIZ];
|
||||
int ret = 0;
|
||||
|
||||
if (!pool)
|
||||
return;
|
||||
return ret;
|
||||
|
||||
FDPRINT(" Extent size: %12ld\n", (long) pool->size);
|
||||
FDPRINT(" Alloc quantum: %12ld\n", (long) pool->quantum);
|
||||
@@ -324,13 +330,16 @@ pool_stats(alloc_pool_t p, int fd, int summarize)
|
||||
FDPRINT(" Bytes freed: %12.0f\n", (double) pool->b_freed);
|
||||
|
||||
if (summarize)
|
||||
return;
|
||||
return ret;
|
||||
|
||||
if (!pool->extents)
|
||||
return;
|
||||
return ret;
|
||||
|
||||
write(fd, "\n", 1);
|
||||
if (write(fd, "\n", 1) != 1)
|
||||
ret = -1;
|
||||
|
||||
for (cur = pool->extents; cur; cur = cur->next)
|
||||
FDEXTSTAT(cur);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
* Unix SMB/CIFS implementation.
|
||||
* Based on the Samba ACL support code.
|
||||
* Copyright (C) Jeremy Allison 2000.
|
||||
* Copyright (C) 2007-2008 Wayne Davison
|
||||
*
|
||||
* The permission functions have been changed to get/set all bits via
|
||||
* one call. Some functions that rsync doesn't need were also removed.
|
||||
@@ -550,7 +551,7 @@ SMB_ACL_T sys_acl_init(int count)
|
||||
* acl[] array, this actually allocates an ACL with room
|
||||
* for (count+1) entries
|
||||
*/
|
||||
if ((a = (SMB_ACL_T)SMB_MALLOC(sizeof(struct SMB_ACL_T) + count * sizeof(struct acl))) == NULL) {
|
||||
if ((a = (SMB_ACL_T)SMB_MALLOC(sizeof a[0] + count * sizeof (struct acl))) == NULL) {
|
||||
errno = ENOMEM;
|
||||
return NULL;
|
||||
}
|
||||
@@ -1006,7 +1007,7 @@ SMB_ACL_T sys_acl_init(int count)
|
||||
* acl[] array, this actually allocates an ACL with room
|
||||
* for (count+1) entries
|
||||
*/
|
||||
if ((a = SMB_MALLOC(sizeof(struct SMB_ACL_T) + count * sizeof(struct acl))) == NULL) {
|
||||
if ((a = (SMB_ACL_T)SMB_MALLOC(sizeof a[0] + count * sizeof(struct acl))) == NULL) {
|
||||
errno = ENOMEM;
|
||||
return NULL;
|
||||
}
|
||||
@@ -1637,14 +1638,14 @@ SMB_ACL_T sys_acl_init(int count)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if ((a = SMB_MALLOC(sizeof(struct SMB_ACL_T) + sizeof(struct acl))) == NULL) {
|
||||
if ((a = (SMB_ACL_T)SMB_MALLOC(sizeof a[0] + sizeof (struct acl))) == NULL) {
|
||||
errno = ENOMEM;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
a->next = -1;
|
||||
a->freeaclp = False;
|
||||
a->aclp = (struct acl *)(&a->aclp + sizeof(struct acl *));
|
||||
a->aclp = (struct acl *)((char *)a + sizeof a[0]);
|
||||
a->aclp->acl_cnt = 0;
|
||||
|
||||
return a;
|
||||
@@ -2703,6 +2704,8 @@ int sys_acl_set_info(SMB_ACL_ENTRY_T entry, SMB_ACL_TAG_T tag_type, uint32 bits,
|
||||
rc = mbr_uid_to_uuid(u_g_id, uu);
|
||||
else
|
||||
rc = mbr_gid_to_uuid(u_g_id, uu);
|
||||
if (rc != 0)
|
||||
return rc;
|
||||
|
||||
if (acl_set_tag_type(entry, tag_type) != 0
|
||||
|| acl_set_qualifier(entry, &uu) != 0
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
* Version 2.2.x
|
||||
* Portable SMB ACL interface
|
||||
* Copyright (C) Jeremy Allison 2000
|
||||
* Copyright (C) 2007-2008 Wayne Davison
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
* Extended attribute support for rsync.
|
||||
*
|
||||
* Copyright (C) 2004 Red Hat, Inc.
|
||||
* Copyright (C) 2003-2008 Wayne Davison
|
||||
* Written by Jay Fenlason.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
|
||||
46
log.c
46
log.c
@@ -3,7 +3,7 @@
|
||||
*
|
||||
* Copyright (C) 1998-2001 Andrew Tridgell <tridge@samba.org>
|
||||
* Copyright (C) 2000-2001 Martin Pool <mbp@samba.org>
|
||||
* Copyright (C) 2003-2007 Wayne Davison
|
||||
* Copyright (C) 2003-2008 Wayne Davison
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
@@ -37,6 +37,7 @@ extern int protocol_version;
|
||||
extern int preserve_times;
|
||||
extern int uid_ndx;
|
||||
extern int gid_ndx;
|
||||
extern int progress_is_active;
|
||||
extern int stdout_format_has_i;
|
||||
extern int stdout_format_has_o_or_i;
|
||||
extern int logfile_format_has_i;
|
||||
@@ -54,7 +55,7 @@ extern iconv_t ic_chck;
|
||||
extern iconv_t ic_send, ic_recv;
|
||||
#endif
|
||||
extern char curr_dir[];
|
||||
extern char *module_dir;
|
||||
extern char *full_module_path;
|
||||
extern unsigned int module_dirlen;
|
||||
|
||||
static int log_initialised;
|
||||
@@ -84,7 +85,7 @@ struct {
|
||||
{ RERR_SIGNAL , "received SIGINT, SIGTERM, or SIGHUP" },
|
||||
{ RERR_WAITCHILD , "waitpid() failed" },
|
||||
{ RERR_MALLOC , "error allocating core memory buffers" },
|
||||
{ RERR_PARTIAL , "some files could not be transferred" },
|
||||
{ RERR_PARTIAL , "some files/attrs were not transferred (see previous errors)" },
|
||||
{ RERR_VANISHED , "some files vanished before they could be transferred" },
|
||||
{ RERR_TIMEOUT , "timeout in data send/receive" },
|
||||
{ RERR_CONTIMEOUT , "timeout waiting for daemon connection" },
|
||||
@@ -256,13 +257,17 @@ void rwrite(enum logcode code, const char *buf, int len, int is_utf8)
|
||||
|
||||
if (am_server && msg_fd_out >= 0) {
|
||||
assert(!is_utf8);
|
||||
/* Pass the message to our sibling. */
|
||||
/* Pass the message to our sibling in native charset. */
|
||||
send_msg((enum msgcode)code, buf, len, 0);
|
||||
return;
|
||||
}
|
||||
|
||||
if (code == FERROR_SOCKET) /* This gets simplified for a non-sibling. */
|
||||
code = FERROR;
|
||||
else if (code == FERROR_UTF8) {
|
||||
is_utf8 = 1;
|
||||
code = FERROR;
|
||||
}
|
||||
|
||||
if (code == FCLIENT)
|
||||
code = FINFO;
|
||||
@@ -320,6 +325,11 @@ void rwrite(enum logcode code, const char *buf, int len, int is_utf8)
|
||||
exit_cleanup(RERR_MESSAGEIO);
|
||||
}
|
||||
|
||||
if (progress_is_active && !am_server) {
|
||||
fputc('\n', f);
|
||||
progress_is_active = 0;
|
||||
}
|
||||
|
||||
trailing_CR_or_NL = len && (buf[len-1] == '\n' || buf[len-1] == '\r')
|
||||
? buf[--len] : 0;
|
||||
|
||||
@@ -517,7 +527,7 @@ static void log_formatted(enum logcode code, const char *format, const char *op,
|
||||
break;
|
||||
case 'M':
|
||||
n = c = timestring(file->modtime);
|
||||
while ((c = strchr(p, ' ')) != NULL)
|
||||
while ((c = strchr(c, ' ')) != NULL)
|
||||
*c = '-';
|
||||
break;
|
||||
case 'B':
|
||||
@@ -593,7 +603,7 @@ static void log_formatted(enum logcode code, const char *format, const char *op,
|
||||
n = timestring(time(NULL));
|
||||
break;
|
||||
case 'P':
|
||||
n = module_dir;
|
||||
n = full_module_path;
|
||||
break;
|
||||
case 'u':
|
||||
n = auth_user;
|
||||
@@ -632,15 +642,21 @@ static void log_formatted(enum logcode code, const char *format, const char *op,
|
||||
? iflags & ITEM_XNAME_FOLLOWS ? 'h' : 'c'
|
||||
: !(iflags & ITEM_TRANSFER) ? '.'
|
||||
: !local_server && *op == 's' ? '<' : '>';
|
||||
c[1] = S_ISDIR(file->mode) ? 'd'
|
||||
: IS_SPECIAL(file->mode) ? 'S'
|
||||
: IS_DEVICE(file->mode) ? 'D'
|
||||
: S_ISLNK(file->mode) ? 'L' : 'f';
|
||||
c[2] = !(iflags & ITEM_REPORT_CHECKSUM) ? '.' : 'c';
|
||||
c[3] = !(iflags & ITEM_REPORT_SIZE) ? '.' : 's';
|
||||
c[4] = !(iflags & ITEM_REPORT_TIME) ? '.'
|
||||
: !preserve_times || (!receiver_symlink_times && S_ISLNK(file->mode))
|
||||
? 'T' : 't';
|
||||
if (S_ISLNK(file->mode)) {
|
||||
c[1] = 'L';
|
||||
c[3] = '.';
|
||||
c[4] = !(iflags & ITEM_REPORT_TIME) ? '.'
|
||||
: !preserve_times || !receiver_symlink_times
|
||||
|| (iflags & ITEM_REPORT_TIMEFAIL) ? 'T' : 't';
|
||||
} else {
|
||||
c[1] = S_ISDIR(file->mode) ? 'd'
|
||||
: IS_SPECIAL(file->mode) ? 'S'
|
||||
: IS_DEVICE(file->mode) ? 'D' : 'f';
|
||||
c[3] = !(iflags & ITEM_REPORT_SIZE) ? '.' : 's';
|
||||
c[4] = !(iflags & ITEM_REPORT_TIME) ? '.'
|
||||
: !preserve_times ? 'T' : 't';
|
||||
}
|
||||
c[2] = !(iflags & ITEM_REPORT_CHANGE) ? '.' : 'c';
|
||||
c[5] = !(iflags & ITEM_REPORT_PERMS) ? '.' : 'p';
|
||||
c[6] = !(iflags & ITEM_REPORT_OWNER) ? '.' : 'o';
|
||||
c[7] = !(iflags & ITEM_REPORT_GROUP) ? '.' : 'g';
|
||||
|
||||
130
main.c
130
main.c
@@ -4,7 +4,7 @@
|
||||
* Copyright (C) 1996-2001 Andrew Tridgell <tridge@samba.org>
|
||||
* Copyright (C) 1996 Paul Mackerras
|
||||
* Copyright (C) 2001, 2002 Martin Pool <mbp@samba.org>
|
||||
* Copyright (C) 2003-2007 Wayne Davison
|
||||
* Copyright (C) 2003-2008 Wayne Davison
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
@@ -78,10 +78,7 @@ extern char *batch_name;
|
||||
extern char *password_file;
|
||||
extern char curr_dir[MAXPATHLEN];
|
||||
extern struct file_list *first_flist;
|
||||
extern struct filter_list_struct server_filter_list;
|
||||
#ifdef ICONV_OPTION
|
||||
extern iconv_t ic_send;
|
||||
#endif
|
||||
extern struct filter_list_struct daemon_filter_list;
|
||||
|
||||
uid_t our_uid;
|
||||
int local_server = 0;
|
||||
@@ -334,7 +331,7 @@ static pid_t do_cmd(char *cmd, char *machine, char *user, char **remote_argv, in
|
||||
{
|
||||
int i, argc = 0;
|
||||
char *args[MAX_ARGS];
|
||||
pid_t ret;
|
||||
pid_t pid;
|
||||
int dash_l_set = 0;
|
||||
|
||||
if (!read_batch && !local_server) {
|
||||
@@ -344,7 +341,7 @@ static pid_t do_cmd(char *cmd, char *machine, char *user, char **remote_argv, in
|
||||
cmd = rsh_env;
|
||||
if (!cmd)
|
||||
cmd = RSYNC_RSH;
|
||||
cmd = strdup(cmd);
|
||||
cmd = strdup(cmd); /* MEMORY LEAK */
|
||||
if (!cmd)
|
||||
goto oom;
|
||||
|
||||
@@ -453,7 +450,7 @@ static pid_t do_cmd(char *cmd, char *machine, char *user, char **remote_argv, in
|
||||
batch_gen_fd = from_gen_pipe[0];
|
||||
*f_out_p = from_gen_pipe[1];
|
||||
*f_in_p = batch_fd;
|
||||
ret = -1; /* no child pid */
|
||||
pid = (pid_t)-1; /* no child pid */
|
||||
#ifdef ICONV_CONST
|
||||
setup_iconv();
|
||||
#endif
|
||||
@@ -463,54 +460,20 @@ static pid_t do_cmd(char *cmd, char *machine, char *user, char **remote_argv, in
|
||||
if (whole_file < 0 && !write_batch)
|
||||
whole_file = 1;
|
||||
set_allow_inc_recurse();
|
||||
ret = local_child(argc, args, f_in_p, f_out_p, child_main);
|
||||
pid = local_child(argc, args, f_in_p, f_out_p, child_main);
|
||||
#ifdef ICONV_CONST
|
||||
setup_iconv();
|
||||
#endif
|
||||
} else {
|
||||
pid = piped_child(args, f_in_p, f_out_p);
|
||||
#ifdef ICONV_CONST
|
||||
setup_iconv();
|
||||
#endif
|
||||
if (protect_args) {
|
||||
int fd;
|
||||
#ifdef ICONV_OPTION
|
||||
int convert = ic_send != (iconv_t)-1;
|
||||
xbuf outbuf, inbuf;
|
||||
|
||||
if (convert)
|
||||
alloc_xbuf(&outbuf, 1024);
|
||||
#endif
|
||||
|
||||
ret = piped_child(args, f_in_p, f_out_p);
|
||||
|
||||
for (i = 0; args[i]; i++) {} /* find first NULL */
|
||||
args[i] = "rsync"; /* set a new arg0 */
|
||||
if (verbose > 1)
|
||||
print_child_argv("protected args:", args + i + 1);
|
||||
fd = *f_out_p;
|
||||
do {
|
||||
#ifdef ICONV_OPTION
|
||||
if (convert) {
|
||||
INIT_XBUF_STRLEN(inbuf, args[i]);
|
||||
iconvbufs(ic_send, &inbuf, &outbuf,
|
||||
ICB_EXPAND_OUT | ICB_INCLUDE_BAD | ICB_INCLUDE_INCOMPLETE);
|
||||
outbuf.buf[outbuf.len] = '\0';
|
||||
write_buf(fd, outbuf.buf, outbuf.len + 1);
|
||||
outbuf.len = 0;
|
||||
} else
|
||||
#endif
|
||||
write_buf(fd, args[i], strlen(args[i]) + 1);
|
||||
} while (args[++i]);
|
||||
write_byte(fd, 0);
|
||||
#ifdef ICONV_OPTION
|
||||
if (convert)
|
||||
free(outbuf.buf);
|
||||
#endif
|
||||
} else
|
||||
ret = piped_child(args, f_in_p, f_out_p);
|
||||
if (protect_args && !daemon_over_rsh)
|
||||
send_protected_args(*f_out_p, args);
|
||||
}
|
||||
|
||||
return ret;
|
||||
return pid;
|
||||
|
||||
oom:
|
||||
out_of_memory("do_cmd");
|
||||
@@ -544,12 +507,29 @@ static char *get_local_name(struct file_list *flist, char *dest_path)
|
||||
if (!dest_path || list_only)
|
||||
return NULL;
|
||||
|
||||
if (daemon_filter_list.head) {
|
||||
char *slash = strrchr(dest_path, '/');
|
||||
if (slash && (slash[1] == '\0' || (slash[1] == '.' && slash[2] == '\0')))
|
||||
*slash = '\0';
|
||||
else
|
||||
slash = NULL;
|
||||
if ((*dest_path != '.' || dest_path[1] != '\0')
|
||||
&& (check_filter(&daemon_filter_list, FLOG, dest_path, 0) < 0
|
||||
|| check_filter(&daemon_filter_list, FLOG, dest_path, 1) < 0)) {
|
||||
rprintf(FERROR, "skipping daemon-excluded destination \"%s\"\n",
|
||||
dest_path);
|
||||
exit_cleanup(RERR_FILESELECT);
|
||||
}
|
||||
if (slash)
|
||||
*slash = '/';
|
||||
}
|
||||
|
||||
/* See what currently exists at the destination. */
|
||||
if ((statret = do_stat(dest_path, &st)) == 0) {
|
||||
/* If the destination is a dir, enter it and use mode 1. */
|
||||
if (S_ISDIR(st.st_mode)) {
|
||||
if (!push_dir(dest_path, 0)) {
|
||||
rsyserr(FERROR, errno, "push_dir#1 %s failed",
|
||||
if (!change_dir(dest_path, CD_NORMAL)) {
|
||||
rsyserr(FERROR, errno, "change_dir#1 %s failed",
|
||||
full_fname(dest_path));
|
||||
exit_cleanup(RERR_FILESELECT);
|
||||
}
|
||||
@@ -608,8 +588,8 @@ static char *get_local_name(struct file_list *flist, char *dest_path)
|
||||
dry_run++;
|
||||
}
|
||||
|
||||
if (!push_dir(dest_path, dry_run > 1)) {
|
||||
rsyserr(FERROR, errno, "push_dir#2 %s failed",
|
||||
if (!change_dir(dest_path, dry_run > 1 ? CD_SKIP_CHDIR : CD_NORMAL)) {
|
||||
rsyserr(FERROR, errno, "change_dir#2 %s failed",
|
||||
full_fname(dest_path));
|
||||
exit_cleanup(RERR_FILESELECT);
|
||||
}
|
||||
@@ -628,8 +608,8 @@ static char *get_local_name(struct file_list *flist, char *dest_path)
|
||||
dest_path = "/";
|
||||
|
||||
*cp = '\0';
|
||||
if (!push_dir(dest_path, 0)) {
|
||||
rsyserr(FERROR, errno, "push_dir#3 %s failed",
|
||||
if (!change_dir(dest_path, CD_NORMAL)) {
|
||||
rsyserr(FERROR, errno, "change_dir#3 %s failed",
|
||||
full_fname(dest_path));
|
||||
exit_cleanup(RERR_FILESELECT);
|
||||
}
|
||||
@@ -721,8 +701,8 @@ static void do_server_sender(int f_in, int f_out, int argc, char *argv[])
|
||||
}
|
||||
|
||||
if (!relative_paths) {
|
||||
if (!push_dir(dir, 0)) {
|
||||
rsyserr(FERROR, errno, "push_dir#3 %s failed",
|
||||
if (!change_dir(dir, CD_NORMAL)) {
|
||||
rsyserr(FERROR, errno, "change_dir#3 %s failed",
|
||||
full_fname(dir));
|
||||
exit_cleanup(RERR_FILESELECT);
|
||||
}
|
||||
@@ -891,8 +871,8 @@ static void do_server_recv(int f_in, int f_out, int argc, char *argv[])
|
||||
char *dir = argv[0];
|
||||
argc--;
|
||||
argv++;
|
||||
if (!am_daemon && !push_dir(dir, 0)) {
|
||||
rsyserr(FERROR, errno, "push_dir#4 %s failed",
|
||||
if (!am_daemon && !change_dir(dir, CD_NORMAL)) {
|
||||
rsyserr(FERROR, errno, "change_dir#4 %s failed",
|
||||
full_fname(dir));
|
||||
exit_cleanup(RERR_FILESELECT);
|
||||
}
|
||||
@@ -931,25 +911,25 @@ static void do_server_recv(int f_in, int f_out, int argc, char *argv[])
|
||||
if (sanitize_paths) {
|
||||
char **dir_p;
|
||||
for (dir_p = basis_dir; *dir_p; dir_p++)
|
||||
*dir_p = sanitize_path(NULL, *dir_p, NULL, curr_dir_depth);
|
||||
*dir_p = sanitize_path(NULL, *dir_p, NULL, curr_dir_depth, SP_DEFAULT);
|
||||
if (partial_dir)
|
||||
partial_dir = sanitize_path(NULL, partial_dir, NULL, curr_dir_depth);
|
||||
partial_dir = sanitize_path(NULL, partial_dir, NULL, curr_dir_depth, SP_DEFAULT);
|
||||
}
|
||||
check_alt_basis_dirs();
|
||||
|
||||
if (server_filter_list.head) {
|
||||
if (daemon_filter_list.head) {
|
||||
char **dir_p;
|
||||
struct filter_list_struct *elp = &server_filter_list;
|
||||
struct filter_list_struct *elp = &daemon_filter_list;
|
||||
|
||||
for (dir_p = basis_dir; *dir_p; dir_p++) {
|
||||
char *dir = *dir_p;
|
||||
if (*dir == '/')
|
||||
dir += module_dirlen;
|
||||
if (check_filter(elp, dir, 1) < 0)
|
||||
if (check_filter(elp, FLOG, dir, 1) < 0)
|
||||
goto options_rejected;
|
||||
}
|
||||
if (partial_dir && *partial_dir == '/'
|
||||
&& check_filter(elp, partial_dir + module_dirlen, 1) < 0) {
|
||||
&& check_filter(elp, FLOG, partial_dir + module_dirlen, 1) < 0) {
|
||||
options_rejected:
|
||||
rprintf(FERROR,
|
||||
"Your options have been rejected by the server.\n");
|
||||
@@ -1067,11 +1047,6 @@ int client_run(int f_in, int f_out, pid_t pid, int argc, char *argv[])
|
||||
io_start_multiplex_out();
|
||||
}
|
||||
|
||||
if (argc == 0) {
|
||||
list_only |= 1;
|
||||
xfer_dirs |= 1;
|
||||
}
|
||||
|
||||
send_filter_list(read_batch ? -1 : f_out);
|
||||
|
||||
if (filesfrom_fd >= 0) {
|
||||
@@ -1182,8 +1157,6 @@ static int start_client(int argc, char *argv[])
|
||||
static char *dotarg[1] = { "." };
|
||||
p = dotarg[0];
|
||||
remote_argv = dotarg;
|
||||
list_only |= 1;
|
||||
xfer_dirs |= 1;
|
||||
}
|
||||
remote_argc = 1;
|
||||
|
||||
@@ -1214,8 +1187,8 @@ static int start_client(int argc, char *argv[])
|
||||
rprintf(FERROR, "remote destination is not allowed with --read-batch\n");
|
||||
exit_cleanup(RERR_SYNTAX);
|
||||
}
|
||||
remote_argv = argv + argc - 1;
|
||||
remote_argc = 1;
|
||||
remote_argv = argv += argc - 1;
|
||||
remote_argc = argc = 1;
|
||||
}
|
||||
|
||||
if (am_sender) {
|
||||
@@ -1255,10 +1228,6 @@ static int start_client(int argc, char *argv[])
|
||||
}
|
||||
remote_argv[i] = arg;
|
||||
}
|
||||
if (argc == 0) {
|
||||
list_only |= 1;
|
||||
xfer_dirs |= 1;
|
||||
}
|
||||
}
|
||||
|
||||
if (daemon_over_rsh < 0)
|
||||
@@ -1447,7 +1416,7 @@ int main(int argc,char *argv[])
|
||||
setlocale(LC_CTYPE, "");
|
||||
#endif
|
||||
|
||||
if (!parse_arguments(&argc, (const char ***) &argv, 1)) {
|
||||
if (!parse_arguments(&argc, (const char ***) &argv)) {
|
||||
/* FIXME: We ought to call the same error-handling
|
||||
* code here, rather than relying on getopt. */
|
||||
option_error();
|
||||
@@ -1468,11 +1437,11 @@ int main(int argc,char *argv[])
|
||||
SIGACTION(SIGXFSZ, SIG_IGN);
|
||||
#endif
|
||||
|
||||
/* Initialize push_dir here because on some old systems getcwd
|
||||
/* Initialize change_dir() here because on some old systems getcwd
|
||||
* (implemented by forking "pwd" and reading its output) doesn't
|
||||
* work when there are other child processes. Also, on all systems
|
||||
* that implement getcwd that way "pwd" can't be found after chroot. */
|
||||
push_dir(NULL, 0);
|
||||
change_dir(NULL, CD_NORMAL);
|
||||
|
||||
init_flist();
|
||||
|
||||
@@ -1496,7 +1465,6 @@ int main(int argc,char *argv[])
|
||||
read_stream_flags(batch_fd);
|
||||
else
|
||||
write_stream_flags(batch_fd);
|
||||
|
||||
}
|
||||
if (write_batch < 0)
|
||||
dry_run = 1;
|
||||
@@ -1512,7 +1480,7 @@ int main(int argc,char *argv[])
|
||||
char buf[MAXPATHLEN];
|
||||
protect_args = 2;
|
||||
read_args(STDIN_FILENO, NULL, buf, sizeof buf, 1, &argv, &argc, NULL);
|
||||
if (!parse_arguments(&argc, (const char ***) &argv, 1)) {
|
||||
if (!parse_arguments(&argc, (const char ***) &argv)) {
|
||||
option_error();
|
||||
exit_cleanup(RERR_SYNTAX);
|
||||
}
|
||||
|
||||
2
match.c
2
match.c
@@ -3,7 +3,7 @@
|
||||
*
|
||||
* Copyright (C) 1996 Andrew Tridgell
|
||||
* Copyright (C) 1996 Paul Mackerras
|
||||
* Copyright (C) 2003-2007 Wayne Davison
|
||||
* Copyright (C) 2003-2008 Wayne Davison
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
|
||||
166
options.c
166
options.c
@@ -3,7 +3,7 @@
|
||||
*
|
||||
* Copyright (C) 1998-2001 Andrew Tridgell <tridge@samba.org>
|
||||
* Copyright (C) 2000, 2001, 2002 Martin Pool <mbp@samba.org>
|
||||
* Copyright (C) 2002-2007 Wayne Davison
|
||||
* Copyright (C) 2002-2008 Wayne Davison
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
@@ -25,11 +25,12 @@
|
||||
#include "zlib/zlib.h"
|
||||
|
||||
extern int module_id;
|
||||
extern int local_server;
|
||||
extern int sanitize_paths;
|
||||
extern int daemon_over_rsh;
|
||||
extern unsigned int module_dirlen;
|
||||
extern struct filter_list_struct filter_list;
|
||||
extern struct filter_list_struct server_filter_list;
|
||||
extern struct filter_list_struct daemon_filter_list;
|
||||
|
||||
int make_backups = 0;
|
||||
|
||||
@@ -227,7 +228,8 @@ static void print_rsync_version(enum logcode f)
|
||||
STRUCT_STAT *dumstat;
|
||||
|
||||
#if SUBPROTOCOL_VERSION != 0
|
||||
asprintf(&subprotocol, ".PR%d", SUBPROTOCOL_VERSION);
|
||||
if (asprintf(&subprotocol, ".PR%d", SUBPROTOCOL_VERSION) < 0)
|
||||
out_of_memory("print_rsync_version");
|
||||
#endif
|
||||
#ifdef HAVE_SOCKETPAIR
|
||||
got_socketpair = "";
|
||||
@@ -259,7 +261,7 @@ static void print_rsync_version(enum logcode f)
|
||||
|
||||
rprintf(f, "%s version %s protocol version %d%s\n",
|
||||
RSYNC_NAME, RSYNC_VERSION, PROTOCOL_VERSION, subprotocol);
|
||||
rprintf(f, "Copyright (C) 1996-2007 by Andrew Tridgell, Wayne Davison, and others.\n");
|
||||
rprintf(f, "Copyright (C) 1996-2008 by Andrew Tridgell, Wayne Davison, and others.\n");
|
||||
rprintf(f, "Web site: http://rsync.samba.org/\n");
|
||||
rprintf(f, "Capabilities:\n");
|
||||
rprintf(f, " %d-bit files, %d-bit inums, %d-bit timestamps, %d-bit long ints,\n",
|
||||
@@ -474,6 +476,8 @@ static struct poptOption long_options[] = {
|
||||
{"dirs", 'd', POPT_ARG_VAL, &xfer_dirs, 2, 0, 0 },
|
||||
{"no-dirs", 0, POPT_ARG_VAL, &xfer_dirs, 0, 0, 0 },
|
||||
{"no-d", 0, POPT_ARG_VAL, &xfer_dirs, 0, 0, 0 },
|
||||
{"old-dirs", 0, POPT_ARG_VAL, &xfer_dirs, 4, 0, 0 },
|
||||
{"old-d", 0, POPT_ARG_VAL, &xfer_dirs, 4, 0, 0 },
|
||||
{"perms", 'p', POPT_ARG_VAL, &preserve_perms, 1, 0, 0 },
|
||||
{"no-perms", 0, POPT_ARG_VAL, &preserve_perms, 0, 0, 0 },
|
||||
{"no-p", 0, POPT_ARG_VAL, &preserve_perms, 0, 0, 0 },
|
||||
@@ -536,8 +540,11 @@ static struct poptOption long_options[] = {
|
||||
{"ignore-existing", 0, POPT_ARG_NONE, &ignore_existing, 0, 0, 0 },
|
||||
{"max-size", 0, POPT_ARG_STRING, &max_size_arg, OPT_MAX_SIZE, 0, 0 },
|
||||
{"min-size", 0, POPT_ARG_STRING, &min_size_arg, OPT_MIN_SIZE, 0, 0 },
|
||||
{"sparse", 'S', POPT_ARG_NONE, &sparse_files, 0, 0, 0 },
|
||||
{"inplace", 0, POPT_ARG_NONE, &inplace, 0, 0, 0 },
|
||||
{"sparse", 'S', POPT_ARG_VAL, &sparse_files, 1, 0, 0 },
|
||||
{"no-sparse", 0, POPT_ARG_VAL, &sparse_files, 0, 0, 0 },
|
||||
{"no-S", 0, POPT_ARG_VAL, &sparse_files, 0, 0, 0 },
|
||||
{"inplace", 0, POPT_ARG_VAL, &inplace, 1, 0, 0 },
|
||||
{"no-inplace", 0, POPT_ARG_VAL, &inplace, 0, 0, 0 },
|
||||
{"append", 0, POPT_ARG_NONE, 0, OPT_APPEND, 0, 0 },
|
||||
{"append-verify", 0, POPT_ARG_VAL, &append_mode, 2, 0, 0 },
|
||||
{"no-append", 0, POPT_ARG_VAL, &append_mode, 0, 0, 0 },
|
||||
@@ -550,8 +557,10 @@ static struct poptOption long_options[] = {
|
||||
{"delete-excluded", 0, POPT_ARG_NONE, &delete_excluded, 0, 0, 0 },
|
||||
{"remove-sent-files",0, POPT_ARG_VAL, &remove_source_files, 2, 0, 0 }, /* deprecated */
|
||||
{"remove-source-files",0,POPT_ARG_VAL, &remove_source_files, 1, 0, 0 },
|
||||
{"force", 0, POPT_ARG_NONE, &force_delete, 0, 0, 0 },
|
||||
{"ignore-errors", 0, POPT_ARG_NONE, &ignore_errors, 0, 0, 0 },
|
||||
{"force", 0, POPT_ARG_VAL, &force_delete, 1, 0, 0 },
|
||||
{"no-force", 0, POPT_ARG_VAL, &force_delete, 0, 0, 0 },
|
||||
{"ignore-errors", 0, POPT_ARG_VAL, &ignore_errors, 1, 0, 0 },
|
||||
{"no-ignore-errors", 0, POPT_ARG_VAL, &ignore_errors, 0, 0, 0 },
|
||||
{"max-delete", 0, POPT_ARG_INT, &max_delete, 0, 0, 0 },
|
||||
{0, 'F', POPT_ARG_NONE, 0, 'F', 0, 0 },
|
||||
{"filter", 'f', POPT_ARG_STRING, 0, OPT_FILTER, 0, 0 },
|
||||
@@ -570,11 +579,13 @@ static struct poptOption long_options[] = {
|
||||
{"compare-dest", 0, POPT_ARG_STRING, 0, OPT_COMPARE_DEST, 0, 0 },
|
||||
{"copy-dest", 0, POPT_ARG_STRING, 0, OPT_COPY_DEST, 0, 0 },
|
||||
{"link-dest", 0, POPT_ARG_STRING, 0, OPT_LINK_DEST, 0, 0 },
|
||||
{"fuzzy", 'y', POPT_ARG_NONE, &fuzzy_basis, 0, 0, 0 },
|
||||
{"fuzzy", 'y', POPT_ARG_VAL, &fuzzy_basis, 1, 0, 0 },
|
||||
{"no-fuzzy", 0, POPT_ARG_VAL, &fuzzy_basis, 0, 0, 0 },
|
||||
{"no-y", 0, POPT_ARG_VAL, &fuzzy_basis, 0, 0, 0 },
|
||||
{"compress", 'z', POPT_ARG_NONE, 0, 'z', 0, 0 },
|
||||
{"no-compress", 0, POPT_ARG_VAL, &do_compression, 0, 0, 0 },
|
||||
{"skip-compress", 0, POPT_ARG_STRING, &skip_compress, 0, 0, 0 },
|
||||
{"no-z", 0, POPT_ARG_VAL, &do_compression, 0, 0, 0 },
|
||||
{"skip-compress", 0, POPT_ARG_STRING, &skip_compress, 0, 0, 0 },
|
||||
{"compress-level", 0, POPT_ARG_INT, &def_compress_level, 'z', 0, 0 },
|
||||
{0, 'P', POPT_ARG_NONE, 0, 'P', 0, 0 },
|
||||
{"progress", 0, POPT_ARG_VAL, &do_progress, 1, 0, 0 },
|
||||
@@ -584,7 +595,9 @@ static struct poptOption long_options[] = {
|
||||
{"partial-dir", 0, POPT_ARG_STRING, &partial_dir, 0, 0, 0 },
|
||||
{"delay-updates", 0, POPT_ARG_VAL, &delay_updates, 1, 0, 0 },
|
||||
{"no-delay-updates", 0, POPT_ARG_VAL, &delay_updates, 0, 0, 0 },
|
||||
{"prune-empty-dirs",'m', POPT_ARG_NONE, &prune_empty_dirs, 0, 0, 0 },
|
||||
{"prune-empty-dirs",'m', POPT_ARG_VAL, &prune_empty_dirs, 1, 0, 0 },
|
||||
{"no-prune-empty-dirs",0,POPT_ARG_VAL, &prune_empty_dirs, 0, 0, 0 },
|
||||
{"no-m", 0, POPT_ARG_VAL, &prune_empty_dirs, 0, 0, 0 },
|
||||
{"log-file", 0, POPT_ARG_STRING, &logfile_name, 0, 0, 0 },
|
||||
{"log-file-format", 0, POPT_ARG_STRING, &logfile_format, 0, 0, 0 },
|
||||
{"out-format", 0, POPT_ARG_STRING, &stdout_format, 0, 0, 0 },
|
||||
@@ -613,6 +626,7 @@ static struct poptOption long_options[] = {
|
||||
{"timeout", 0, POPT_ARG_INT, &io_timeout, 0, 0, 0 },
|
||||
{"no-timeout", 0, POPT_ARG_VAL, &io_timeout, 0, 0, 0 },
|
||||
{"contimeout", 0, POPT_ARG_INT, &connect_timeout, 0, 0, 0 },
|
||||
{"no-contimeout", 0, POPT_ARG_VAL, &connect_timeout, 0, 0, 0 },
|
||||
{"rsh", 'e', POPT_ARG_STRING, &shell_cmd, 0, 0, 0 },
|
||||
{"rsync-path", 0, POPT_ARG_STRING, &rsync_path, 0, 0, 0 },
|
||||
{"temp-dir", 'T', POPT_ARG_STRING, &tmpdir, 0, 0, 0 },
|
||||
@@ -622,7 +636,9 @@ static struct poptOption long_options[] = {
|
||||
#endif
|
||||
{"ipv4", '4', POPT_ARG_VAL, &default_af_hint, AF_INET, 0, 0 },
|
||||
{"ipv6", '6', POPT_ARG_VAL, &default_af_hint, AF_INET6, 0, 0 },
|
||||
{"8-bit-output", '8', POPT_ARG_NONE, &allow_8bit_chars, 0, 0, 0 },
|
||||
{"8-bit-output", '8', POPT_ARG_VAL, &allow_8bit_chars, 1, 0, 0 },
|
||||
{"no-8-bit-output", 0, POPT_ARG_VAL, &allow_8bit_chars, 0, 0, 0 },
|
||||
{"no-8", 0, POPT_ARG_VAL, &allow_8bit_chars, 0, 0, 0 },
|
||||
{"qsort", 0, POPT_ARG_NONE, &use_qsort, 0, 0, 0 },
|
||||
{"address", 0, POPT_ARG_STRING, &bind_address, 0, 0, 0 },
|
||||
{"port", 0, POPT_ARG_INT, &rsync_port, 0, 0, 0 },
|
||||
@@ -877,7 +893,7 @@ static void create_refuse_error(int which)
|
||||
*
|
||||
* @retval 0 on error, with err_buf containing an explanation
|
||||
**/
|
||||
int parse_arguments(int *argc_p, const char ***argv_p, int frommain)
|
||||
int parse_arguments(int *argc_p, const char ***argv_p)
|
||||
{
|
||||
static poptContext pc;
|
||||
char *ref = lp_refuse_options(module_id);
|
||||
@@ -889,8 +905,10 @@ int parse_arguments(int *argc_p, const char ***argv_p, int frommain)
|
||||
set_refuse_options(ref);
|
||||
if (am_daemon) {
|
||||
set_refuse_options("log-file*");
|
||||
#ifdef ICONV_OPTION
|
||||
if (!*lp_charset(module_id))
|
||||
set_refuse_options("iconv");
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifdef ICONV_OPTION
|
||||
@@ -1017,8 +1035,8 @@ int parse_arguments(int *argc_p, const char ***argv_p, int frommain)
|
||||
case OPT_INCLUDE_FROM:
|
||||
arg = poptGetOptArg(pc);
|
||||
if (sanitize_paths)
|
||||
arg = sanitize_path(NULL, arg, NULL, 0);
|
||||
if (server_filter_list.head) {
|
||||
arg = sanitize_path(NULL, arg, NULL, 0, SP_DEFAULT);
|
||||
if (daemon_filter_list.head) {
|
||||
int rej;
|
||||
char *dir, *cp = strdup(arg);
|
||||
if (!cp)
|
||||
@@ -1027,7 +1045,7 @@ int parse_arguments(int *argc_p, const char ***argv_p, int frommain)
|
||||
goto options_rejected;
|
||||
dir = cp + (*cp == '/' ? module_dirlen : 0);
|
||||
clean_fname(dir, CFN_COLLAPSE_DOT_DOT_DIRS);
|
||||
rej = check_filter(&server_filter_list, dir, 0) < 0;
|
||||
rej = check_filter(&daemon_filter_list, FLOG, dir, 0) < 0;
|
||||
free(cp);
|
||||
if (rej)
|
||||
goto options_rejected;
|
||||
@@ -1080,8 +1098,7 @@ int parse_arguments(int *argc_p, const char ***argv_p, int frommain)
|
||||
break;
|
||||
|
||||
case 'q':
|
||||
if (frommain)
|
||||
quiet++;
|
||||
quiet++;
|
||||
break;
|
||||
|
||||
case 'x':
|
||||
@@ -1259,7 +1276,7 @@ int parse_arguments(int *argc_p, const char ***argv_p, int frommain)
|
||||
}
|
||||
}
|
||||
|
||||
if (human_readable && argc == 2) {
|
||||
if (human_readable && argc == 2 && !am_server) {
|
||||
/* Allow the old meaning of 'h' (--help) on its own. */
|
||||
usage(FINFO);
|
||||
exit_cleanup(0);
|
||||
@@ -1278,12 +1295,11 @@ int parse_arguments(int *argc_p, const char ***argv_p, int frommain)
|
||||
}
|
||||
#endif
|
||||
|
||||
if (protect_args == 1) {
|
||||
if (!frommain)
|
||||
protect_args = 0;
|
||||
else if (am_server)
|
||||
return 1;
|
||||
}
|
||||
if (protect_args == 1 && am_server)
|
||||
return 1;
|
||||
|
||||
*argv_p = argv = poptGetArgs(pc);
|
||||
*argc_p = argc = count_args(argv);
|
||||
|
||||
#ifndef SUPPORT_LINKS
|
||||
if (preserve_links && !am_sender) {
|
||||
@@ -1303,7 +1319,13 @@ int parse_arguments(int *argc_p, const char ***argv_p, int frommain)
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifndef SUPPORT_XATTRS
|
||||
#ifdef SUPPORT_XATTRS
|
||||
if (am_root < 0 && preserve_xattrs > 1) {
|
||||
snprintf(err_buf, sizeof err_buf,
|
||||
"--fake-super conflicts with -XX\n");
|
||||
return 0;
|
||||
}
|
||||
#else
|
||||
if (am_root < 0) {
|
||||
snprintf(err_buf, sizeof err_buf,
|
||||
"--fake-super requires an rsync with extended attributes enabled\n");
|
||||
@@ -1366,8 +1388,16 @@ int parse_arguments(int *argc_p, const char ***argv_p, int frommain)
|
||||
xfer_dirs = 1;
|
||||
}
|
||||
|
||||
if (xfer_dirs < 1)
|
||||
xfer_dirs = recurse || list_only;
|
||||
if (argc < 2 && !read_batch && !am_server)
|
||||
list_only |= 1;
|
||||
|
||||
if (xfer_dirs >= 4) {
|
||||
parse_rule(&filter_list, "- /*/*", 0, 0);
|
||||
recurse = xfer_dirs = 1;
|
||||
} else if (recurse)
|
||||
xfer_dirs = 1;
|
||||
else if (xfer_dirs < 0)
|
||||
xfer_dirs = list_only ? 1 : 0;
|
||||
|
||||
if (relative_paths < 0)
|
||||
relative_paths = files_from? 1 : 0;
|
||||
@@ -1416,27 +1446,24 @@ int parse_arguments(int *argc_p, const char ***argv_p, int frommain)
|
||||
need_messages_from_generator = 1;
|
||||
}
|
||||
|
||||
*argv_p = argv = poptGetArgs(pc);
|
||||
*argc_p = argc = count_args(argv);
|
||||
|
||||
if (sanitize_paths) {
|
||||
int i;
|
||||
for (i = argc; i-- > 0; )
|
||||
argv[i] = sanitize_path(NULL, argv[i], "", 0);
|
||||
argv[i] = sanitize_path(NULL, argv[i], "", 0, SP_KEEP_DOT_DIRS);
|
||||
if (tmpdir)
|
||||
tmpdir = sanitize_path(NULL, tmpdir, NULL, 0);
|
||||
tmpdir = sanitize_path(NULL, tmpdir, NULL, 0, SP_DEFAULT);
|
||||
if (backup_dir)
|
||||
backup_dir = sanitize_path(NULL, backup_dir, NULL, 0);
|
||||
backup_dir = sanitize_path(NULL, backup_dir, NULL, 0, SP_DEFAULT);
|
||||
}
|
||||
if (server_filter_list.head && !am_sender) {
|
||||
struct filter_list_struct *elp = &server_filter_list;
|
||||
if (daemon_filter_list.head && !am_sender) {
|
||||
struct filter_list_struct *elp = &daemon_filter_list;
|
||||
if (tmpdir) {
|
||||
char *dir;
|
||||
if (!*tmpdir)
|
||||
goto options_rejected;
|
||||
dir = tmpdir + (*tmpdir == '/' ? module_dirlen : 0);
|
||||
clean_fname(dir, CFN_COLLAPSE_DOT_DOT_DIRS);
|
||||
if (check_filter(elp, dir, 1) < 0)
|
||||
if (check_filter(elp, FLOG, dir, 1) < 0)
|
||||
goto options_rejected;
|
||||
}
|
||||
if (backup_dir) {
|
||||
@@ -1445,7 +1472,7 @@ int parse_arguments(int *argc_p, const char ***argv_p, int frommain)
|
||||
goto options_rejected;
|
||||
dir = backup_dir + (*backup_dir == '/' ? module_dirlen : 0);
|
||||
clean_fname(dir, CFN_COLLAPSE_DOT_DOT_DIRS);
|
||||
if (check_filter(elp, dir, 1) < 0)
|
||||
if (check_filter(elp, FLOG, dir, 1) < 0)
|
||||
goto options_rejected;
|
||||
}
|
||||
}
|
||||
@@ -1634,14 +1661,14 @@ int parse_arguments(int *argc_p, const char ***argv_p, int frommain)
|
||||
}
|
||||
} else {
|
||||
if (sanitize_paths)
|
||||
files_from = sanitize_path(NULL, files_from, NULL, 0);
|
||||
if (server_filter_list.head) {
|
||||
files_from = sanitize_path(NULL, files_from, NULL, 0, SP_DEFAULT);
|
||||
if (daemon_filter_list.head) {
|
||||
char *dir;
|
||||
if (!*files_from)
|
||||
goto options_rejected;
|
||||
dir = files_from + (*files_from == '/' ? module_dirlen : 0);
|
||||
clean_fname(dir, CFN_COLLAPSE_DOT_DOT_DIRS);
|
||||
if (check_filter(&server_filter_list, dir, 0) < 0)
|
||||
if (check_filter(&daemon_filter_list, FLOG, dir, 0) < 0)
|
||||
goto options_rejected;
|
||||
}
|
||||
filesfrom_fd = open(files_from, O_RDONLY|O_BINARY);
|
||||
@@ -1711,8 +1738,8 @@ void server_options(char **args, int *argc_p)
|
||||
argstr[x++] = 'n';
|
||||
if (preserve_links)
|
||||
argstr[x++] = 'l';
|
||||
if ((list_only && !recurse) || xfer_dirs > 1
|
||||
|| (xfer_dirs && !recurse && delete_mode && am_sender))
|
||||
if ((xfer_dirs >= 2 && xfer_dirs < 4)
|
||||
|| (xfer_dirs && !recurse && (list_only || (delete_mode && am_sender))))
|
||||
argstr[x++] = 'd';
|
||||
if (am_sender) {
|
||||
if (keep_dirlinks)
|
||||
@@ -1782,25 +1809,40 @@ void server_options(char **args, int *argc_p)
|
||||
if (do_compression)
|
||||
argstr[x++] = 'z';
|
||||
|
||||
/* We make use of the -e option to let the server know about any
|
||||
* pre-release protocol version && some behavior flags. */
|
||||
argstr[x++] = 'e';
|
||||
#if SUBPROTOCOL_VERSION != 0
|
||||
if (protocol_version == PROTOCOL_VERSION) {
|
||||
x += snprintf(argstr+x, sizeof argstr - x,
|
||||
"%d.%d", PROTOCOL_VERSION, SUBPROTOCOL_VERSION);
|
||||
} else
|
||||
#endif
|
||||
argstr[x++] = '.';
|
||||
set_allow_inc_recurse();
|
||||
if (allow_inc_recurse)
|
||||
argstr[x++] = 'i';
|
||||
#if defined HAVE_LUTIMES && defined HAVE_UTIMES
|
||||
argstr[x++] = 'L';
|
||||
|
||||
/* Checking the pre-negotiated value allows --protocol=29 override. */
|
||||
if (protocol_version >= 30) {
|
||||
/* We make use of the -e option to let the server know about
|
||||
* any pre-release protocol version && some behavior flags. */
|
||||
argstr[x++] = 'e';
|
||||
#if SUBPROTOCOL_VERSION != 0
|
||||
if (protocol_version == PROTOCOL_VERSION) {
|
||||
x += snprintf(argstr+x, sizeof argstr - x,
|
||||
"%d.%d",
|
||||
PROTOCOL_VERSION, SUBPROTOCOL_VERSION);
|
||||
} else
|
||||
#endif
|
||||
argstr[x++] = '.';
|
||||
if (allow_inc_recurse)
|
||||
argstr[x++] = 'i';
|
||||
#if defined HAVE_LUTIMES && defined HAVE_UTIMES
|
||||
argstr[x++] = 'L';
|
||||
#endif
|
||||
#ifdef ICONV_OPTION
|
||||
argstr[x++] = 's';
|
||||
#endif
|
||||
}
|
||||
|
||||
if (x >= (int)sizeof argstr) { /* Not possible... */
|
||||
rprintf(FERROR, "argstr overflow in server_options().\n");
|
||||
exit_cleanup(RERR_MALLOC);
|
||||
}
|
||||
|
||||
argstr[x] = '\0';
|
||||
|
||||
args[ac++] = argstr;
|
||||
if (x > 1)
|
||||
args[ac++] = argstr;
|
||||
|
||||
#ifdef ICONV_OPTION
|
||||
if (iconv_opt) {
|
||||
@@ -1815,7 +1857,7 @@ void server_options(char **args, int *argc_p)
|
||||
}
|
||||
#endif
|
||||
|
||||
if (protect_args) /* initial args break here */
|
||||
if (protect_args && !local_server) /* unprotected args stop here */
|
||||
args[ac++] = NULL;
|
||||
|
||||
if (list_only > 1)
|
||||
@@ -1982,7 +2024,6 @@ void server_options(char **args, int *argc_p)
|
||||
* and it may be an older version that doesn't know this
|
||||
* option, so don't send it if client is the sender.
|
||||
*/
|
||||
int i;
|
||||
for (i = 0; i < basis_dir_cnt; i++) {
|
||||
args[ac++] = dest_option;
|
||||
args[ac++] = basis_dir[i];
|
||||
@@ -2022,6 +2063,11 @@ void server_options(char **args, int *argc_p)
|
||||
else if (remove_source_files)
|
||||
args[ac++] = "--remove-sent-files";
|
||||
|
||||
if (ac > MAX_SERVER_ARGS) { /* Not possible... */
|
||||
rprintf(FERROR, "argc overflow in server_options().\n");
|
||||
exit_cleanup(RERR_MALLOC);
|
||||
}
|
||||
|
||||
*argc_p = ac;
|
||||
return;
|
||||
|
||||
|
||||
6
packaging/bin/gpg
Executable file
6
packaging/bin/gpg
Executable file
@@ -0,0 +1,6 @@
|
||||
#!/bin/sh -e
|
||||
# This script gets git to run gpg with a --passphrase-file option.
|
||||
|
||||
PATH=`echo $PATH | sed 's/^[^:]*://'`
|
||||
|
||||
gpg --batch --passphrase-file=$GPG_PASSFILE "${@}"
|
||||
@@ -4,13 +4,19 @@
|
||||
# is included in the rrsync script.
|
||||
use strict;
|
||||
|
||||
our(%short_no_arg, %short_with_num, %long_opt);
|
||||
our %short_no_arg;
|
||||
our %short_with_num;
|
||||
our %long_opt = (
|
||||
'no-i-r' => 0,
|
||||
'fake-super' => 0,
|
||||
'log-file' => 3,
|
||||
);
|
||||
our $last_long_opt;
|
||||
|
||||
open(IN, '../options.c') or die "Unable to open ../options.c: $!\n";
|
||||
|
||||
while (<IN>) {
|
||||
if (/\Qargstr[x++]\E = '(.)'/) {
|
||||
if (/\Qargstr[x++]\E = '([^.ie])'/) {
|
||||
$short_no_arg{$1} = 1;
|
||||
undef $last_long_opt;
|
||||
} elsif (/\Qasprintf(\E[^,]+, "-([a-zA-Z0-9])\%l?[ud]"/) {
|
||||
@@ -1,9 +1,12 @@
|
||||
Summary: A fast, versatile, remote (and local) file-copying tool
|
||||
Name: rsync
|
||||
Version: 3.0.0pre10
|
||||
Version: 3.0.5
|
||||
%define fullversion %{version}
|
||||
Release: 1
|
||||
%define srcdir src
|
||||
Group: Applications/Internet
|
||||
Source: http://rsync.samba.org/ftp/rsync/rsync-%{version}.tar.gz
|
||||
Source0: http://rsync.samba.org/ftp/rsync/%{srcdir}/rsync-%{fullversion}.tar.gz
|
||||
#Source1: http://rsync.samba.org/ftp/rsync/%{srcdir}/rsync-patches-%{fullversion}.tar.gz
|
||||
URL: http://rsync.samba.org/
|
||||
|
||||
Prefix: %{_prefix}
|
||||
@@ -22,9 +25,21 @@ destination. Rsync is widely used for backups and mirroring and as an
|
||||
improved copy command for everyday use.
|
||||
|
||||
%prep
|
||||
%setup -q
|
||||
# Choose one -- setup source only, or setup source + rsync-patches:
|
||||
%setup -q -n rsync-%{fullversion}
|
||||
#%setup -q -b1 -n rsync-%{fullversion}
|
||||
|
||||
# If you you used "%setup -q -b1", choose the patches you wish to apply:
|
||||
#patch -p1 <patches/acls.diff
|
||||
#patch -p1 <patches/xattrs.diff
|
||||
#patch -p1 <patches/remote-option.diff
|
||||
#patch -p1 <patches/db.diff
|
||||
|
||||
# Avoid extra perl dependencies for scripts going into doc dir.
|
||||
chmod -x support/*
|
||||
|
||||
%build
|
||||
#./prepare-source
|
||||
%configure
|
||||
|
||||
make
|
||||
@@ -34,16 +49,26 @@ rm -rf $RPM_BUILD_ROOT
|
||||
|
||||
%makeinstall
|
||||
|
||||
mkdir -p $RPM_BUILD_ROOT/etc/xinetd.d
|
||||
install -m 644 packaging/lsb/rsync.xinetd $RPM_BUILD_ROOT/etc/xinetd.d/rsync
|
||||
|
||||
#install -p -m 755 support/rsyncdb $RPM_BUILD_ROOT/usr/bin/rsyncdb
|
||||
|
||||
%clean
|
||||
rm -rf $RPM_BUILD_ROOT
|
||||
|
||||
%files
|
||||
%defattr(-,root,root)
|
||||
%doc COPYING README tech_report.tex
|
||||
%{_prefix}/bin/rsync
|
||||
%doc COPYING NEWS OLDNEWS README support/ tech_report.tex
|
||||
%config(noreplace) /etc/xinetd.d/rsync
|
||||
%{_prefix}/bin/rsync*
|
||||
%{_mandir}/man1/rsync.1*
|
||||
%{_mandir}/man5/rsyncd.conf.5*
|
||||
|
||||
%changelog
|
||||
* Tue Feb 19 2008 Wayne Davison <wayned@samba.org>
|
||||
Released 3.0.0pre10.
|
||||
* Sun Dec 28 2008 Wayne Davison <wayned@samba.org>
|
||||
Released 3.0.5.
|
||||
|
||||
* Fri Mar 21 2008 Wayne Davison <wayned@samba.org>
|
||||
Added installation of /etc/xinetd.d/rsync file and some commented-out
|
||||
lines that demonstrate how to use the rsync-patches tar file.
|
||||
|
||||
13
packaging/lsb/rsync.xinetd
Normal file
13
packaging/lsb/rsync.xinetd
Normal file
@@ -0,0 +1,13 @@
|
||||
# default: off
|
||||
# description: The rsync server is a good addition to an ftp server, as it
|
||||
# allows crc checksumming etc.
|
||||
service rsync
|
||||
{
|
||||
disable = yes
|
||||
socket_type = stream
|
||||
wait = no
|
||||
user = root
|
||||
server = /usr/bin/rsync
|
||||
server_args = --daemon
|
||||
log_on_failure += USERID
|
||||
}
|
||||
@@ -14,8 +14,8 @@ use strict;
|
||||
use Getopt::Long;
|
||||
use Date::Format;
|
||||
|
||||
# Where the local copy of /home/ftp/pub/rsync/nightly should be updated.
|
||||
our $dest = $ENV{HOME} . '/samba-rsync-ftp/nightly';
|
||||
# Where the local copy of /home/ftp/pub/rsync/dev/nightly should be updated.
|
||||
our $dest = $ENV{HOME} . '/samba-rsync-ftp/dev/nightly';
|
||||
our $nightly_symlink = "$dest/rsync-HEAD.tar.gz";
|
||||
|
||||
our($make_tar, $upload, $help_opt);
|
||||
@@ -104,7 +104,7 @@ if ($upload) {
|
||||
if (defined $ENV{RSYNC_PARTIAL_DIR}) {
|
||||
$opt = " -f 'R $ENV{RSYNC_PARTIAL_DIR}'";
|
||||
}
|
||||
system "rsync$opt -aviHP --delete-after . samba.org:/home/ftp/pub/rsync/nightly";
|
||||
system "rsync$opt -aviHP --delete-after . samba.org:/home/ftp/pub/rsync/dev/nightly";
|
||||
}
|
||||
|
||||
exit;
|
||||
|
||||
@@ -13,7 +13,9 @@ my $tmp_dir = "patches.$$";
|
||||
|
||||
&Getopt::Long::Configure('bundling');
|
||||
&usage if !&GetOptions(
|
||||
'branch|b=s' => \( my $master_branch = 'master' ),
|
||||
'skip-check' => \( my $skip_branch_check ),
|
||||
'shell|s' => \( my $launch_shell ),
|
||||
'gen:s' => \( my $incl_generated_files ),
|
||||
'help|h' => \( my $help_opt ),
|
||||
);
|
||||
@@ -27,12 +29,9 @@ if (defined $incl_generated_files) {
|
||||
die "No '$patches_dir' directory was found.\n" unless -d $patches_dir;
|
||||
die "No '.git' directory present in the current dir.\n" unless -d '.git';
|
||||
|
||||
unless ($skip_branch_check) {
|
||||
open(IN, '-|', 'git status') or die $!;
|
||||
my $status = join('', <IN>);
|
||||
close IN;
|
||||
die "The checkout is not clean:\n", $status unless $status =~ /\nnothing to commit \(working directory clean\)/;
|
||||
die "The checkout is not on the master branch.\n" unless $status =~ /^# On branch master\n/;
|
||||
my($status, $is_clean, $starting_branch) = &check_git_status;
|
||||
if (!$skip_branch_check && !$is_clean) {
|
||||
die "The checkout is not clean:\n", $status;
|
||||
}
|
||||
|
||||
my @extra_files;
|
||||
@@ -53,36 +52,40 @@ if ($incl_generated_files) {
|
||||
mkdir($tmp_dir, 0700) or die "Unable to mkdir($tmp_dir): $!\n";
|
||||
system "./config.status Makefile && make gen && rsync -a @extra_files $tmp_dir/master/" and exit 1;
|
||||
}
|
||||
my $last_touch = time;
|
||||
our $last_touch = time;
|
||||
|
||||
my(@patches, %local_patch);
|
||||
my %patches;
|
||||
|
||||
# Start by finding all patches so that we can load all possible parents.
|
||||
open(PIPE, '-|', 'git', 'branch', '-a') or die $!;
|
||||
open(PIPE, '-|', 'git', 'branch', '-l') or die $!;
|
||||
while (<PIPE>) {
|
||||
if (m# origin/patch/(.*)#) {
|
||||
push(@patches, $1);
|
||||
} elsif (m# patch/(.*)#) {
|
||||
$local_patch{$1} = 1;
|
||||
if (m# patch/(.*)#) {
|
||||
$patches{$1} = 1;
|
||||
}
|
||||
}
|
||||
close PIPE;
|
||||
|
||||
my @patches = sort keys %patches;
|
||||
|
||||
my(%parent, %description);
|
||||
foreach my $patch (@patches) {
|
||||
my $branch = ($local_patch{$patch} ? '' : 'origin/') . "patch/$patch";
|
||||
my $branch = "patch/$patch";
|
||||
my $desc = '';
|
||||
open(PIPE, '-|', 'git', 'diff', '-U1000', "master...$branch", '--', "PATCH.$patch") or die $!;
|
||||
open(PIPE, '-|', 'git', 'diff', '-U1000', "$master_branch...$branch", '--', "PATCH.$patch") or die $!;
|
||||
while (<PIPE>) {
|
||||
last if /^@@ /;
|
||||
}
|
||||
while (<PIPE>) {
|
||||
next unless s/^[ +]//;
|
||||
if (m#patch -p1 <patches/(\S+)\.diff# && $1 ne $patch) {
|
||||
$parent{$patch} = $1;
|
||||
my $parent = $parent{$patch} = $1;
|
||||
if (!$patches{$parent}) {
|
||||
die "Parent of $patch is not a local branch: $parent\n";
|
||||
}
|
||||
}
|
||||
$desc .= $_;
|
||||
}
|
||||
close PIPE;
|
||||
$description{$patch} = $desc;
|
||||
}
|
||||
|
||||
@@ -90,8 +93,11 @@ if (@ARGV) {
|
||||
# Limit the list of patches to actually process based on @ARGV.
|
||||
@patches = ( );
|
||||
foreach (@ARGV) {
|
||||
s{^(patches|patch|origin/patch)/} {};
|
||||
s{^patch(es)?/} {};
|
||||
s{\.diff$} {};
|
||||
if (!$patches{$_}) {
|
||||
die "Local branch not available for patch: $_\n";
|
||||
}
|
||||
push(@patches, $_);
|
||||
}
|
||||
}
|
||||
@@ -99,15 +105,15 @@ if (@ARGV) {
|
||||
my %completed;
|
||||
foreach my $patch (@patches) {
|
||||
next if $completed{$patch}++;
|
||||
update_patch($patch);
|
||||
last unless update_patch($patch);
|
||||
}
|
||||
|
||||
if ($incl_generated_files) {
|
||||
system "rm -rf $tmp_dir";
|
||||
}
|
||||
|
||||
sleep 1 if $last_touch == time;
|
||||
system "git checkout master" and exit 1;
|
||||
sleep 1 while $last_touch >= time;
|
||||
system "git checkout $starting_branch" and exit 1;
|
||||
|
||||
exit;
|
||||
|
||||
@@ -123,27 +129,34 @@ sub update_patch
|
||||
}
|
||||
$parent = "patch/$parent";
|
||||
} else {
|
||||
$parent = 'master';
|
||||
$parent = $master_branch;
|
||||
}
|
||||
|
||||
print "======== $patch ========\n";
|
||||
|
||||
sleep 1 if $incl_generated_files && $last_touch == time;
|
||||
if ($local_patch{$patch}) {
|
||||
system "git checkout patch/$patch" and exit 1;
|
||||
} else {
|
||||
system "git checkout --track -b patch/$patch origin/patch/$patch" and exit 1;
|
||||
sleep 1 while $incl_generated_files && $last_touch >= time;
|
||||
system "git checkout patch/$patch" and return 0;
|
||||
|
||||
my $ok = system("git merge $parent") == 0;
|
||||
if (!$ok || $launch_shell) {
|
||||
print qq|"git merge $parent" incomplete -- please fix.\n| if !$ok;
|
||||
$ENV{PS1} = "[$parent] patch/$patch: ";
|
||||
while (1) {
|
||||
if (system($ENV{SHELL}) != 0) {
|
||||
print "Abort? [n/y] ";
|
||||
$_ = <STDIN>;
|
||||
next unless /^y/i;
|
||||
return 0;
|
||||
}
|
||||
($status, $is_clean) = &check_git_status;
|
||||
last if $is_clean;
|
||||
print $status;
|
||||
}
|
||||
}
|
||||
|
||||
open(OUT, '>', "$patches_dir/$patch.diff") or die $!;
|
||||
print OUT $description{$patch}, "\n";
|
||||
|
||||
if (system("git merge $parent") != 0) {
|
||||
print qq|"git merge $parent" incomplete -- please fix.\n|;
|
||||
$ENV{PS1} = "[$parent] patch/$patch: ";
|
||||
system $ENV{SHELL} and exit 1;
|
||||
}
|
||||
|
||||
if ($incl_generated_files) {
|
||||
system "./config.status Makefile && make gen && rsync -a @extra_files $tmp_dir/$patch/" and exit 1;
|
||||
}
|
||||
@@ -163,8 +176,13 @@ sub update_patch
|
||||
close PIPE;
|
||||
|
||||
if ($incl_generated_files) {
|
||||
$parent =~ s#.*/##;
|
||||
open(PIPE, '-|', 'diff', '-up', "$tmp_dir/$parent", "$tmp_dir/$patch") or die $!;
|
||||
my $parent_dir;
|
||||
if ($parent eq $master_branch) {
|
||||
$parent_dir = 'master';
|
||||
} else {
|
||||
($parent_dir) = $parent =~ m{([^/]+)$};
|
||||
}
|
||||
open(PIPE, '-|', 'diff', '-up', "$tmp_dir/$parent_dir", "$tmp_dir/$patch") or die $!;
|
||||
while (<PIPE>) {
|
||||
s#^(diff -up) $tmp_dir/[^/]+/(.*?) $tmp_dir/[^/]+/(.*)#$1 a/$2 b/$3#o;
|
||||
s#^\Q---\E $tmp_dir/[^/]+/([^\t]+)\t.*#--- a/$1#o;
|
||||
@@ -175,16 +193,28 @@ sub update_patch
|
||||
}
|
||||
|
||||
close OUT;
|
||||
|
||||
1;
|
||||
}
|
||||
|
||||
exit;
|
||||
|
||||
sub check_git_status
|
||||
{
|
||||
open(IN, '-|', 'git status') or die $!;
|
||||
my $status = join('', <IN>);
|
||||
close IN;
|
||||
my $is_clean = $status =~ /\nnothing to commit \(working directory clean\)/;
|
||||
my($starting_branch) = $status =~ /^# On branch (.+)\n/;
|
||||
($status, $is_clean, $starting_branch);
|
||||
}
|
||||
|
||||
sub usage
|
||||
{
|
||||
die <<EOT;
|
||||
Usage: patch-update [OPTIONS]
|
||||
|
||||
--gen[=DIR] Include generated files. Optional dest DIR overrides "patches".
|
||||
--skip-check Skip the check that ensures starting with a clean master branch.
|
||||
--skip-check Skip the check that ensures starting with a clean branch.
|
||||
EOT
|
||||
}
|
||||
@@ -7,16 +7,33 @@ use strict;
|
||||
# ~/samba-rsync-ftp dir will be ready to be rsynced to samba.org.
|
||||
|
||||
use Cwd;
|
||||
use Getopt::Long;
|
||||
use Term::ReadKey;
|
||||
use Date::Format;
|
||||
|
||||
my $dest = $ENV{HOME} . '/samba-rsync-ftp';
|
||||
my $passfile = $ENV{HOME} . '/.rsyncpass';
|
||||
my $path = $ENV{PATH};
|
||||
|
||||
my $cl_today = time2str('* %a %b %d %Y', time);
|
||||
my $ztoday = time2str('%d %b %Y', time);
|
||||
&Getopt::Long::Configure('bundling');
|
||||
&usage if !&GetOptions(
|
||||
'branch|b=s' => \( my $master_branch = 'master' ),
|
||||
'help|h' => \( my $help_opt ),
|
||||
);
|
||||
&usage if $help_opt;
|
||||
|
||||
my $now = time;
|
||||
my $cl_today = time2str('* %a %b %d %Y', $now);
|
||||
my $year = time2str('%Y', $now);
|
||||
my $ztoday = time2str('%d %b %Y', $now);
|
||||
(my $today = $ztoday) =~ s/^0//;
|
||||
|
||||
my $curdir = Cwd::cwd;
|
||||
|
||||
END {
|
||||
unlink($passfile);
|
||||
}
|
||||
|
||||
my @extra_files;
|
||||
open(IN, '<', 'Makefile.in') or die "Couldn't open Makefile.in: $!\n";
|
||||
while (<IN>) {
|
||||
@@ -47,25 +64,25 @@ open(IN, '-|', 'git status') or die $!;
|
||||
my $status = join('', <IN>);
|
||||
close IN;
|
||||
die "The checkout is not clean:\n", $status unless $status =~ /\nnothing to commit \(working directory clean\)/;
|
||||
die "The checkout is not on the master branch.\n" unless $status =~ /^# On branch master\n/;
|
||||
die "The checkout is not on the $master_branch branch.\n" unless $status =~ /^# On branch $master_branch\n/;
|
||||
|
||||
my $lastversion;
|
||||
my $confversion;
|
||||
open(IN, '<', 'configure.in') or die $!;
|
||||
while (<IN>) {
|
||||
if (/^RSYNC_VERSION=(.*)/) {
|
||||
$lastversion = $1;
|
||||
$confversion = $1;
|
||||
last;
|
||||
}
|
||||
}
|
||||
close IN;
|
||||
if ($lastversion =~ /dev$/) {
|
||||
open(IN, '<', 'OLDNEWS') or die $!;
|
||||
$_ = <IN>;
|
||||
close IN;
|
||||
($lastversion) = /(\d+\.\d+\.\d+)/;
|
||||
}
|
||||
die "Unable to find RSYNC_VERSION in configure.in\n" unless defined $confversion;
|
||||
|
||||
my $version = $lastversion;
|
||||
open(IN, '<', 'OLDNEWS') or die $!;
|
||||
$_ = <IN>;
|
||||
close IN;
|
||||
my($lastversion) = /(\d+\.\d+\.\d+)/;
|
||||
|
||||
my $version = $confversion;
|
||||
$version =~ s/dev/pre1/ || $version =~ s/pre(\d+)/ 'pre' . ($1 + 1) /e;
|
||||
|
||||
print "Please enter the version number of this release: [$version] ";
|
||||
@@ -75,31 +92,46 @@ if ($_ eq '.') {
|
||||
} elsif ($_ ne '') {
|
||||
$version = $_;
|
||||
}
|
||||
$version =~ s/[-.]*pre[-.]*/pre/;
|
||||
die "Invalid version: `$version'\n" unless $version =~ /^[\d.]+(pre\d+)?$/;
|
||||
|
||||
if (`git tag -l v$version` ne '') {
|
||||
print "Tag v$version already exists.\n\nDelete tag or quit? [q/del] ";
|
||||
$_ = <STDIN>;
|
||||
exit 1 unless /^del/i;
|
||||
system "git tag -d v$version";
|
||||
}
|
||||
|
||||
if ($version =~ s/[-.]*pre[-.]*/pre/ && $confversion !~ /dev$/) {
|
||||
$lastversion = $confversion;
|
||||
}
|
||||
|
||||
print "Enter the previous version to produce a patch against: [$lastversion] ";
|
||||
chomp($_ = <STDIN>);
|
||||
$lastversion = $_ if $_ ne '';
|
||||
$lastversion =~ s/[-.]*pre[-.]*/pre/;
|
||||
|
||||
my $release = 1;
|
||||
my $pre = $version =~ /(pre\d+)/ ? $1 : '';
|
||||
|
||||
my $release = $pre ? '0.1' : '1';
|
||||
print "Please enter the RPM release number of this release: [$release] ";
|
||||
chomp($_ = <STDIN>);
|
||||
$release = $_ if $_ ne '';
|
||||
$release .= ".$pre" if $pre;
|
||||
|
||||
my $diffdir;
|
||||
my $skipping;
|
||||
my($srcdir,$srcdiffdir,$lastsrcdir,$skipping);
|
||||
if ($lastversion =~ /pre/) {
|
||||
if ($version !~ /pre/) {
|
||||
if (!$pre) {
|
||||
die "You should not diff a release version against a pre-release version.\n";
|
||||
}
|
||||
$diffdir = "$dest/old-previews";
|
||||
$srcdir = $srcdiffdir = $lastsrcdir = 'src-previews';
|
||||
$skipping = ' ** SKIPPING **';
|
||||
} elsif ($version =~ /pre/) {
|
||||
$diffdir = $dest;
|
||||
} elsif ($pre) {
|
||||
$srcdir = $srcdiffdir = 'src-previews';
|
||||
$lastsrcdir = 'src';
|
||||
$skipping = ' ** SKIPPING **';
|
||||
} else {
|
||||
$diffdir = "$dest/old-versions";
|
||||
$srcdir = $lastsrcdir = 'src';
|
||||
$srcdiffdir = 'src-diffs';
|
||||
$skipping = '';
|
||||
}
|
||||
|
||||
@@ -108,14 +140,16 @@ print "\n", $break, <<EOT;
|
||||
\$lastversion is "$lastversion"
|
||||
\$dest is "$dest"
|
||||
\$curdir is "$curdir"
|
||||
\$diffdir is "$diffdir"
|
||||
\$srcdir is "$srcdir"
|
||||
\$srcdiffdir is "$srcdiffdir"
|
||||
\$lastsrcdir is "$lastsrcdir"
|
||||
\$release is "$release"
|
||||
|
||||
About to:
|
||||
- make sure that SUBPROTOCOL_VERSION is 0$skipping
|
||||
- tweak the version in configure.in and the spec files
|
||||
- tweak NEWS and OLDNEWS to update the release date$skipping
|
||||
- tweak the date in the *.yo files and generate the man pages
|
||||
- tweak the date in the *.yo files and generate the manpages
|
||||
- generate configure.sh, config.h.in, and proto.h
|
||||
- page through the differences
|
||||
|
||||
@@ -123,34 +157,54 @@ EOT
|
||||
print "<Press Enter to continue> ";
|
||||
$_ = <STDIN>;
|
||||
|
||||
my @tweak_files = ( glob('packaging/*.spec'), glob('packaging/*/*.spec'),
|
||||
glob('*.yo'), qw( configure.in ) );
|
||||
(my $finalversion = $version) =~ s/pre\d+//;
|
||||
my %specvars = ( 'Version:' => $finalversion, 'Release:' => $release,
|
||||
'%define fullversion' => "\%{version}$pre", 'Released' => "$version.",
|
||||
'%define srcdir' => $srcdir );
|
||||
my @tweak_files = ( glob('packaging/*.spec'), glob('packaging/*/*.spec'), glob('*.yo'),
|
||||
qw( configure.in rsync.h NEWS OLDNEWS options.c ) );
|
||||
|
||||
if ($version !~ /pre/) {
|
||||
push(@tweak_files, qw( rsync.h NEWS OLDNEWS ));
|
||||
}
|
||||
foreach my $fn (@tweak_files) {
|
||||
open(IN, '<', $fn) or die $!;
|
||||
undef $/; $_ = <IN>; $/ = "\n";
|
||||
close IN;
|
||||
if ($fn =~ /configure/) {
|
||||
s/^RSYNC_VERSION=.*/RSYNC_VERSION=$version/m;
|
||||
s/^RSYNC_VERSION=.*/RSYNC_VERSION=$version/m
|
||||
or die "Unable to update RSYNC_VERSION in $fn\n";
|
||||
} elsif ($fn =~ /\.spec/) {
|
||||
s/^(Version:) .*/$1 $version/m;
|
||||
s/^(Release:) .*/$1 $release/m;
|
||||
s/^(Released) .*/$1 $version./m;
|
||||
s/^\* \w\w\w \w\w\w \d\d \d\d\d\d (.*)/$cl_today $1/m;
|
||||
while (my($str, $val) = each %specvars) {
|
||||
s/^\Q$str\E .*/$str $val/m
|
||||
or die "Unable to update $str in $fn\n";
|
||||
}
|
||||
s/^\* \w\w\w \w\w\w \d\d \d\d\d\d (.*)/$cl_today $1/m
|
||||
or die "Unable to update ChangeLog header in $fn\n";
|
||||
} elsif ($fn =~ /\.yo/) {
|
||||
s/^(manpage\([^)]+\)\(\d+\)\()[^)]+(\).*)/$1$today$2/m;
|
||||
s/^(This man ?page is current for version) \S+ (of rsync)/$1 $version $2/m;
|
||||
} elsif ($fn eq 'NEWS') {
|
||||
s/^(NEWS for rsync \Q$version\E) \(UNRELEASED\)\s*\n/$1 ($today)\n/mi
|
||||
or die "Couldn't update NEWS file with release date!\n";
|
||||
s/^(manpage\([^)]+\)\(\d+\)\()[^)]+(\).*)/$1$today$2/m
|
||||
or die "Unable to update date in manpage() header in $fn\n";
|
||||
s/^(This man ?page is current for version) \S+ (of rsync)/$1 $version $2/m
|
||||
or die "Unable to update current version info in $fn\n";
|
||||
} elsif ($fn eq 'rsync.h') {
|
||||
s/(#define\s+SUBPROTOCOL_VERSION)\s+\d+/$1 0/;
|
||||
s/(#define\s+SUBPROTOCOL_VERSION)\s+\d+/$1 0/
|
||||
or die "Unable to find SUBPROTOCOL_VERSION define in $fn\n";
|
||||
next if $pre;
|
||||
} elsif ($fn eq 'NEWS') {
|
||||
s/^(NEWS for rsync \Q$finalversion\E) \(UNRELEASED\)\s*\n/$1 ($today)\n/mi
|
||||
or die "The first line of $fn is not in the right format. It must be:\n"
|
||||
. "NEWS for rsync $finalversion (UNRELEASED)\n";
|
||||
next if $pre;
|
||||
} elsif ($fn eq 'OLDNEWS') {
|
||||
s/^\t\S\S\s\S\S\S\s\d\d\d\d(\t\Q$version\E)/\t$ztoday$1/m
|
||||
or die "Couldn't update OLDNEWS file with release date!\n";
|
||||
s/^\t\S\S\s\S\S\S\s\d\d\d\d(\t\Q$finalversion\E)/\t$ztoday$1/m
|
||||
or die "Unable to find \"?? ??? $year\t$finalversion\" line in $fn\n";
|
||||
next if $pre;
|
||||
} elsif ($fn eq 'options.c') {
|
||||
if (s/(Copyright \(C\) 2002-)(\d+)( Wayne Davison)/$1$year$3/
|
||||
&& $2 ne $year) {
|
||||
die "Copyright comments need to be updated to $year in all files!\n";
|
||||
}
|
||||
# Adjust the year in the --version output.
|
||||
s/(rprintf\(f, "Copyright \(C\) 1996-)(\d+)/$1$year/
|
||||
or die "Unable to find Copyright string in --version output of $fn\n";
|
||||
next if $2 eq $year;
|
||||
} else {
|
||||
die "Unrecognized file in \@tweak_files: $fn\n";
|
||||
}
|
||||
@@ -165,83 +219,89 @@ system "git diff --color | less -p '^diff .*'";
|
||||
my $srctar_name = "rsync-$version.tar.gz";
|
||||
my $pattar_name = "rsync-patches-$version.tar.gz";
|
||||
my $diff_name = "rsync-$lastversion-$version.diffs.gz";
|
||||
my $srctar_file = "$dest/$srctar_name";
|
||||
my $pattar_file = "$dest/$pattar_name";
|
||||
my $diff_file = "$dest/$diff_name";
|
||||
my $lasttar_file = "$dest/rsync-$lastversion.tar.gz";
|
||||
my $srctar_file = "$dest/$srcdir/$srctar_name";
|
||||
my $pattar_file = "$dest/$srcdir/$pattar_name";
|
||||
my $diff_file = "$dest/$srcdiffdir/$diff_name";
|
||||
my $news_file = "$dest/$srcdir/rsync-$version-NEWS";
|
||||
my $lasttar_file = "$dest/$lastsrcdir/rsync-$lastversion.tar.gz";
|
||||
|
||||
print $break, <<EOT;
|
||||
|
||||
About to:
|
||||
- commit all changes
|
||||
- tag this release as v$version
|
||||
- move the old tar/diff files into the appropriate old-* dirs
|
||||
- hard-link the moved tar/diff files on samba.org
|
||||
- create release tar, "$srctar_name"
|
||||
- create patches tar, "$pattar_name"
|
||||
- commit all version changes
|
||||
- merge the $master_branch branch into the patch/* branches
|
||||
- update the files in the "patches" dir and OPTIONALLY
|
||||
(if you type 'y') to launch a shell for each patch
|
||||
|
||||
EOT
|
||||
print "<Press Enter OR 'y' to continue> ";
|
||||
my $ans = <STDIN>;
|
||||
|
||||
system "git commit -a -m 'Preparing for release of $version'" and exit 1;
|
||||
|
||||
print "Updating files in \"patches\" dir ...\n";
|
||||
system "packaging/patch-update --branch=$master_branch";
|
||||
|
||||
if ($ans =~ /^y/i) {
|
||||
print "\nVisiting all \"patch/*\" branches ...\n";
|
||||
system "packaging/patch-update --branch=$master_branch --shell";
|
||||
}
|
||||
|
||||
print $break, <<EOT;
|
||||
|
||||
About to:
|
||||
- create signed tag for this release: v$version
|
||||
- create release diffs, "$diff_name"
|
||||
- update patch branches and generate patch/* files
|
||||
- update README, *NEWS, TODO, and ChangeLog
|
||||
- update rsync*.html man pages
|
||||
- create release tar, "$srctar_name"
|
||||
- generate rsync-$version/patches/* files
|
||||
- create patches tar, "$pattar_name"
|
||||
- update top-level README, *NEWS, TODO, and ChangeLog
|
||||
- update top-level rsync*.html manpages
|
||||
- gpg-sign the release files
|
||||
- update hard-linked top-level release files$skipping
|
||||
|
||||
EOT
|
||||
print "<Press Enter to continue> ";
|
||||
$_ = <STDIN>;
|
||||
|
||||
system "git commit -a -m 'Preparing for release of $version'" and exit 1;
|
||||
system "git tag -s -m 'Version $version.' v$version" and exit 1;
|
||||
my $passphrase;
|
||||
while (1) {
|
||||
ReadMode('noecho');
|
||||
print "\nEnter your GPG pass-phrase: ";
|
||||
chomp($passphrase = <STDIN>);
|
||||
ReadMode(0);
|
||||
print "\n";
|
||||
|
||||
# Extract some files from the old tar before we do the shuffle.
|
||||
# Briefly create a temp file with the passphrase for git's tagging use.
|
||||
my $oldmask = umask 077;
|
||||
unlink($passfile);
|
||||
open(OUT, '>', $passfile) or die $!;
|
||||
print OUT $passphrase, "\n";
|
||||
close OUT;
|
||||
umask $oldmask;
|
||||
$ENV{'GPG_PASSFILE'} = $passfile;
|
||||
|
||||
# We want to use our passphrase-providing "gpg" script, so modify the PATH.
|
||||
$ENV{PATH} = "packaging/bin:$path";
|
||||
$_ = `git tag -s -m 'Version $version.' v$version 2>&1`;
|
||||
$ENV{PATH} = $path;
|
||||
unlink($passfile);
|
||||
print $_;
|
||||
next if /bad passphrase/;
|
||||
last unless /failed/;
|
||||
exit 1;
|
||||
}
|
||||
|
||||
# Extract the generated files from the old tar.
|
||||
@_ = @extra_files;
|
||||
map { s#^#rsync-$lastversion/# } @_;
|
||||
system "tar xzf $lasttar_file @_";
|
||||
rename("rsync-$lastversion", 'a');
|
||||
|
||||
# When creating a pre-release after a normal release, there's nothing to move.
|
||||
if ($diffdir ne $dest) {
|
||||
chdir($dest) or die $!;
|
||||
|
||||
print "Shuffling old files ...\n";
|
||||
|
||||
# We need to run this regardless of $lastversion's "pre"ness.
|
||||
my @moved_files;
|
||||
foreach my $fn (glob('rsync*pre*.tar.gz*'), glob('rsync*pre*-NEWS')) {
|
||||
link($fn, "old-previews/$fn") or die $!;
|
||||
push(@moved_files, $fn);
|
||||
}
|
||||
|
||||
if ($version !~ /pre/) {
|
||||
foreach my $fn (glob('rsync*.tar.gz*'), glob('rsync*-NEWS')) {
|
||||
next if $fn =~ /^rsync.*pre/;
|
||||
link($fn, "old-versions/$fn") or die $!;
|
||||
push(@moved_files, $fn);
|
||||
}
|
||||
|
||||
foreach my $fn (glob('rsync*pre*.diffs.gz*')) {
|
||||
unlink($fn);
|
||||
}
|
||||
|
||||
foreach my $fn (glob('rsync*.diffs.gz*')) {
|
||||
link($fn, "old-patches/$fn") or die $!;
|
||||
push(@moved_files, $fn);
|
||||
}
|
||||
}
|
||||
|
||||
# Optimize our future upload (in the absence of --detect-renamed) by
|
||||
# using rsync to hard-link the above files on samba.org.
|
||||
system "rsync -avHOC --include='rsync*.gz*' --include='old-*/' --exclude='*' . samba.org:/home/ftp/pub/rsync";
|
||||
foreach (@moved_files) {
|
||||
unlink($_);
|
||||
}
|
||||
|
||||
chdir($curdir) or die $!;
|
||||
}
|
||||
|
||||
print "Creating $diff_file ...\n";
|
||||
system "./config.status Makefile; make gen; rsync -a @extra_files b/";
|
||||
my $sed_script = 's:^((---|\+\+\+) [ab]/[^\t]+)\t.*:\1:';
|
||||
system "(git diff v$lastversion v$version; diff -up a b | sed -r '$sed_script') | gzip -9 >$diff_file";
|
||||
system "(git diff v$lastversion v$version; diff -upN a b | sed -r '$sed_script') | gzip -9 >$diff_file";
|
||||
system "rm -rf a";
|
||||
rename('b', "rsync-$version");
|
||||
|
||||
@@ -250,24 +310,56 @@ system "git archive --format=tar --prefix=rsync-$version/ v$version | tar xf -";
|
||||
system "support/git-set-file-times --prefix=rsync-$version/";
|
||||
system "fakeroot tar czf $srctar_file rsync-$version; rm -rf rsync-$version";
|
||||
|
||||
print "Updating files in \"rsync-$version/patches\" dir ...\n";
|
||||
mkdir("rsync-$version", 0755);
|
||||
mkdir("rsync-$version/patches", 0755);
|
||||
system "support/patch-update --skip-check --gen=rsync-$version/patches";
|
||||
system "packaging/patch-update --skip-check --branch=$master_branch --gen=rsync-$version/patches";
|
||||
|
||||
print "Creating $pattar_file ...\n";
|
||||
system "fakeroot tar chzf $pattar_file rsync-$version/patches; rm -rf rsync-$version";
|
||||
|
||||
print "Updating the other files in $dest ...\n";
|
||||
system "rsync -a README NEWS OLDNEWS TODO $dest";
|
||||
unlink("$dest/rsync-$version-NEWS");
|
||||
link("$dest/NEWS", "$dest/rsync-$version-NEWS");
|
||||
unlink($news_file);
|
||||
link("$dest/NEWS", $news_file);
|
||||
system "git log --name-status | gzip -9 >$dest/ChangeLog.gz";
|
||||
|
||||
system "yodl2html -o $dest/rsync.html rsync.yo";
|
||||
system "yodl2html -o $dest/rsyncd.conf.html rsyncd.conf.yo";
|
||||
|
||||
chdir($dest) or die $!;
|
||||
system "gpg -ba $srctar_name; gpg -ba $pattar_name; gpg -ba $diff_name";
|
||||
print $break, <<EOT;
|
||||
foreach my $fn ($srctar_file, $pattar_file, $diff_file) {
|
||||
unlink("$fn.asc");
|
||||
open(GPG, '|-', "gpg --batch --passphrase-fd=0 -ba $fn") or die $!;
|
||||
print GPG $passphrase, "\n";
|
||||
close GPG;
|
||||
}
|
||||
|
||||
All done. Remember to announce the release on *BOTH*
|
||||
rsync-announce\@lists.samba.org and rsync\@lists.samba.org!
|
||||
if (!$pre) {
|
||||
system "rm $dest/rsync-*.gz $dest/rsync-*.asc $dest/rsync-*-NEWS $dest/src-previews/rsync-*diffs.gz*";
|
||||
|
||||
foreach my $fn ($srctar_file, "$srctar_file.asc",
|
||||
$pattar_file, "$pattar_file.asc",
|
||||
$diff_file, "$diff_file.asc", $news_file) {
|
||||
(my $top_fn = $fn) =~ s#/src(-\w+)?/#/#;
|
||||
link($fn, $top_fn);
|
||||
}
|
||||
}
|
||||
|
||||
print $break, <<'EOT';
|
||||
|
||||
Local changes are done. When you're satisfied, push the git repository
|
||||
and rsync the release files. Remember to announce the release on *BOTH*
|
||||
rsync-announce@lists.samba.org and rsync@lists.samba.org (and the web)!
|
||||
EOT
|
||||
|
||||
exit;
|
||||
|
||||
sub usage
|
||||
{
|
||||
die <<EOT;
|
||||
Usage: release-rsync [OPTIONS]
|
||||
|
||||
-b, --branch=BRANCH The branch to release (default: master)
|
||||
-h, --help Display this help message
|
||||
EOT
|
||||
}
|
||||
|
||||
2
pipe.c
2
pipe.c
@@ -4,7 +4,7 @@
|
||||
* Copyright (C) 1996-2000 Andrew Tridgell
|
||||
* Copyright (C) 1996 Paul Mackerras
|
||||
* Copyright (C) 2001, 2002 Martin Pool <mbp@samba.org>
|
||||
* Copyright (C) 2004-2007 Wayne Davison
|
||||
* Copyright (C) 2004-2008 Wayne Davison
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
|
||||
@@ -809,16 +809,20 @@ int poptGetNextOpt(poptContext con)
|
||||
*oe++ = '\0';
|
||||
/* XXX longArg is mapped back to persistent storage. */
|
||||
longArg = origOptString + (oe - localOptString);
|
||||
}
|
||||
} else
|
||||
oe = NULL;
|
||||
|
||||
opt = findOption(con->options, optString, '\0', &cb, &cbData,
|
||||
singleDash);
|
||||
if (!opt && !singleDash)
|
||||
return POPT_ERROR_BADOPT;
|
||||
if (!opt && oe)
|
||||
oe[-1] = '='; /* restore overwritten '=' */
|
||||
}
|
||||
|
||||
if (!opt) {
|
||||
con->os->nextCharArg = origOptString + 1;
|
||||
longArg = NULL;
|
||||
} else {
|
||||
if (con->os == con->optionStack &&
|
||||
opt->argInfo & POPT_ARGFLAG_STRIP)
|
||||
@@ -856,7 +860,7 @@ int poptGetNextOpt(poptContext con)
|
||||
|
||||
origOptString++;
|
||||
if (*origOptString != '\0')
|
||||
con->os->nextCharArg = origOptString;
|
||||
con->os->nextCharArg = origOptString + (*origOptString == '=');
|
||||
}
|
||||
/*@=branchstate@*/
|
||||
|
||||
|
||||
@@ -121,7 +121,7 @@ getArgDescrip(const struct poptOption * opt,
|
||||
if (opt->argDescrip) return D_(translation_domain, opt->argDescrip);
|
||||
|
||||
switch (opt->argInfo & POPT_ARG_MASK) {
|
||||
case POPT_ARG_NONE: return POPT_("NONE");
|
||||
/*case POPT_ARG_NONE: return POPT_("NONE");*/ /* impossible */
|
||||
#ifdef DYING
|
||||
case POPT_ARG_VAL: return POPT_("VAL");
|
||||
#else
|
||||
@@ -767,6 +767,9 @@ static int showShortOptions(const struct poptOption * opt, FILE * fp,
|
||||
char * s = (str != NULL ? str : memset(alloca(300), 0, 300));
|
||||
int len = 0;
|
||||
|
||||
if (s == NULL)
|
||||
return 0;
|
||||
|
||||
/*@-boundswrite@*/
|
||||
if (opt != NULL)
|
||||
for (; (opt->longName || opt->shortName || opt->arg); opt++) {
|
||||
|
||||
@@ -163,8 +163,10 @@ int poptConfigFileToString(FILE *fp, char ** argstrp, /*@unused@*/ UNUSED(int fl
|
||||
p++;
|
||||
|
||||
linelen = strlen(p);
|
||||
if (linelen >= maxlinelen-1)
|
||||
if (linelen >= maxlinelen-1) {
|
||||
free(argstr);
|
||||
return POPT_ERROR_OVERFLOW; /* XXX line too long */
|
||||
}
|
||||
|
||||
if (*p == '\0' || *p == '\n') continue; /* line is empty */
|
||||
if (*p == '#') continue; /* comment line */
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
* Copyright (C) 1996-2000 Andrew Tridgell
|
||||
* Copyright (C) 1996 Paul Mackerras
|
||||
* Copyright (C) 2001, 2002 Martin Pool <mbp@samba.org>
|
||||
* Copyright (C) 2003-2007 Wayne Davison
|
||||
* Copyright (C) 2003-2008 Wayne Davison
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
@@ -40,6 +40,8 @@ struct progress_history {
|
||||
OFF_T ofs;
|
||||
};
|
||||
|
||||
int progress_is_active = 0;
|
||||
|
||||
static struct progress_history ph_start;
|
||||
static struct progress_history ph_list[PROGRESS_HISTORY_SECS];
|
||||
static int newest_hpos, oldest_hpos;
|
||||
@@ -111,8 +113,11 @@ static void rprint_progress(OFF_T ofs, OFF_T size, struct timeval *now,
|
||||
stats.num_files);
|
||||
} else
|
||||
strlcpy(eol, "\r", sizeof eol);
|
||||
progress_is_active = 0;
|
||||
rprintf(FCLIENT, "%12s %3d%% %7.2f%s %s%s",
|
||||
human_num(ofs), pct, rate, units, rembuf, eol);
|
||||
if (!is_last)
|
||||
progress_is_active = 1;
|
||||
}
|
||||
|
||||
void set_current_file_index(struct file_struct *file, int ndx)
|
||||
|
||||
138
receiver.c
138
receiver.c
@@ -3,7 +3,7 @@
|
||||
*
|
||||
* Copyright (C) 1996-2000 Andrew Tridgell
|
||||
* Copyright (C) 1996 Paul Mackerras
|
||||
* Copyright (C) 2003-2007 Wayne Davison
|
||||
* Copyright (C) 2003-2008 Wayne Davison
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
@@ -55,10 +55,11 @@ extern char *tmpdir;
|
||||
extern char *partial_dir;
|
||||
extern char *basis_dir[];
|
||||
extern struct file_list *cur_flist, *first_flist, *dir_flist;
|
||||
extern struct filter_list_struct server_filter_list;
|
||||
extern struct filter_list_struct daemon_filter_list;
|
||||
|
||||
static struct bitbag *delayed_bits = NULL;
|
||||
static int phase = 0, redoing = 0;
|
||||
static flist_ndx_list batch_redo_list;
|
||||
/* We're either updating the basis file or an identical copy: */
|
||||
static int updating_basis_or_equiv;
|
||||
|
||||
@@ -284,8 +285,11 @@ static int receive_data(int f_in, char *fname_r, int fd_r, OFF_T size_r,
|
||||
goto report_write_error;
|
||||
|
||||
#ifdef HAVE_FTRUNCATE
|
||||
if (inplace && fd != -1)
|
||||
ftruncate(fd, offset);
|
||||
if (inplace && fd != -1
|
||||
&& ftruncate(fd, offset) < 0) {
|
||||
rsyserr(FERROR_XFER, errno, "ftruncate failed on %s",
|
||||
full_fname(fname));
|
||||
}
|
||||
#endif
|
||||
|
||||
if (do_progress)
|
||||
@@ -348,25 +352,60 @@ static void handle_delayed_updates(char *local_name)
|
||||
}
|
||||
}
|
||||
|
||||
static int get_next_gen_ndx(int fd, int next_gen_ndx, int desired_ndx)
|
||||
static void no_batched_update(int ndx, BOOL is_redo)
|
||||
{
|
||||
while (next_gen_ndx < desired_ndx) {
|
||||
if (next_gen_ndx >= 0) {
|
||||
struct file_struct *file = cur_flist->files[next_gen_ndx];
|
||||
rprintf(FERROR_XFER,
|
||||
"(No batched update for%s \"%s\")\n",
|
||||
file->flags & FLAG_FILE_SENT ? " resend of" : "",
|
||||
f_name(file, NULL));
|
||||
}
|
||||
next_gen_ndx = read_int(fd);
|
||||
if (next_gen_ndx == -1) {
|
||||
if (inc_recurse)
|
||||
next_gen_ndx = first_flist->prev->used + first_flist->prev->ndx_start;
|
||||
else
|
||||
next_gen_ndx = cur_flist->used;
|
||||
struct file_list *flist = flist_for_ndx(ndx, "no_batched_update");
|
||||
struct file_struct *file = flist->files[ndx - flist->ndx_start];
|
||||
|
||||
rprintf(FERROR_XFER, "(No batched update for%s \"%s\")\n",
|
||||
is_redo ? " resend of" : "", f_name(file, NULL));
|
||||
|
||||
if (inc_recurse)
|
||||
send_msg_int(MSG_NO_SEND, ndx);
|
||||
}
|
||||
|
||||
static int we_want_redo(int desired_ndx)
|
||||
{
|
||||
static int redo_ndx = -1;
|
||||
|
||||
while (redo_ndx < desired_ndx) {
|
||||
if (redo_ndx >= 0)
|
||||
no_batched_update(redo_ndx, True);
|
||||
if ((redo_ndx = flist_ndx_pop(&batch_redo_list)) < 0)
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (redo_ndx == desired_ndx) {
|
||||
redo_ndx = -1;
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int gen_wants_ndx(int desired_ndx)
|
||||
{
|
||||
static int next_ndx = -1;
|
||||
static BOOL got_eof = 0;
|
||||
|
||||
if (got_eof)
|
||||
return 0;
|
||||
|
||||
while (next_ndx < desired_ndx) {
|
||||
if (next_ndx >= 0)
|
||||
no_batched_update(next_ndx, False);
|
||||
if ((next_ndx = read_int(batch_gen_fd)) < 0) {
|
||||
got_eof = True;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
return next_gen_ndx;
|
||||
|
||||
if (next_ndx == desired_ndx) {
|
||||
next_ndx = -1;
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -375,7 +414,6 @@ static int get_next_gen_ndx(int fd, int next_gen_ndx, int desired_ndx)
|
||||
* Receiver process runs on the same host as the generator process. */
|
||||
int recv_files(int f_in, char *local_name)
|
||||
{
|
||||
int next_gen_ndx = -1;
|
||||
int fd1,fd2;
|
||||
STRUCT_STAT st;
|
||||
int iflags, xlen;
|
||||
@@ -410,17 +448,13 @@ int recv_files(int f_in, char *local_name)
|
||||
xname, &xlen);
|
||||
if (ndx == NDX_DONE) {
|
||||
if (inc_recurse && first_flist) {
|
||||
if (read_batch)
|
||||
gen_wants_ndx(first_flist->used + first_flist->ndx_start);
|
||||
flist_free(first_flist);
|
||||
if (first_flist)
|
||||
continue;
|
||||
}
|
||||
if (read_batch && cur_flist) {
|
||||
int high = inc_recurse
|
||||
? first_flist->prev->used + first_flist->prev->ndx_start
|
||||
: cur_flist->used;
|
||||
get_next_gen_ndx(batch_gen_fd, next_gen_ndx, high);
|
||||
next_gen_ndx = -1;
|
||||
}
|
||||
} else if (read_batch && first_flist)
|
||||
gen_wants_ndx(first_flist->used);
|
||||
if (++phase > max_phase)
|
||||
break;
|
||||
if (verbose > 2)
|
||||
@@ -489,8 +523,8 @@ int recv_files(int f_in, char *local_name)
|
||||
|
||||
cleanup_got_literal = 0;
|
||||
|
||||
if (server_filter_list.head
|
||||
&& check_filter(&server_filter_list, fname, 0) < 0) {
|
||||
if (daemon_filter_list.head
|
||||
&& check_filter(&daemon_filter_list, FLOG, fname, 0) < 0) {
|
||||
rprintf(FERROR, "attempt to hack rsync failed.\n");
|
||||
exit_cleanup(RERR_PROTOCOL);
|
||||
}
|
||||
@@ -509,17 +543,15 @@ int recv_files(int f_in, char *local_name)
|
||||
}
|
||||
|
||||
if (read_batch) {
|
||||
next_gen_ndx = get_next_gen_ndx(batch_gen_fd, next_gen_ndx, ndx);
|
||||
if (ndx < next_gen_ndx) {
|
||||
if (!(redoing ? we_want_redo(ndx) : gen_wants_ndx(ndx))) {
|
||||
rprintf(FINFO,
|
||||
"(Skipping batched update for \"%s\")\n",
|
||||
"(Skipping batched update for%s \"%s\")\n",
|
||||
redoing ? " resend of" : "",
|
||||
fname);
|
||||
discard_receive_data(f_in, F_LENGTH(file));
|
||||
if (inc_recurse)
|
||||
send_msg_int(MSG_NO_SEND, ndx);
|
||||
file->flags |= FLAG_FILE_SENT;
|
||||
continue;
|
||||
}
|
||||
next_gen_ndx = -1;
|
||||
}
|
||||
|
||||
partialptr = partial_dir ? partial_dir_fname(fname) : fname;
|
||||
@@ -555,8 +587,8 @@ int recv_files(int f_in, char *local_name)
|
||||
fnamecmp = fnamecmpbuf;
|
||||
break;
|
||||
}
|
||||
if (!fnamecmp || (server_filter_list.head
|
||||
&& check_filter(&server_filter_list, fname, 0) < 0)) {
|
||||
if (!fnamecmp || (daemon_filter_list.head
|
||||
&& check_filter(&daemon_filter_list, FLOG, fname, 0) < 0)) {
|
||||
fnamecmp = fname;
|
||||
fnamecmp_type = FNAMECMP_FNAME;
|
||||
}
|
||||
@@ -698,23 +730,33 @@ int recv_files(int f_in, char *local_name)
|
||||
do_unlink(partialptr);
|
||||
handle_partial_dir(partialptr, PDIR_DELETE);
|
||||
}
|
||||
} else if (keep_partial && partialptr
|
||||
&& handle_partial_dir(partialptr, PDIR_CREATE)) {
|
||||
if (!finish_transfer(partialptr, fnametmp, fnamecmp, NULL,
|
||||
file, recv_ok, !partial_dir))
|
||||
} else if (keep_partial && partialptr) {
|
||||
if (!handle_partial_dir(partialptr, PDIR_CREATE)) {
|
||||
rprintf(FERROR,
|
||||
"Unable to create partial-dir for %s -- discarding %s.\n",
|
||||
local_name ? local_name : f_name(file, NULL),
|
||||
recv_ok ? "completed file" : "partial file");
|
||||
do_unlink(fnametmp);
|
||||
recv_ok = -1;
|
||||
} else if (!finish_transfer(partialptr, fnametmp, fnamecmp, NULL,
|
||||
file, recv_ok, !partial_dir))
|
||||
recv_ok = -1;
|
||||
else if (delay_updates && recv_ok) {
|
||||
bitbag_set_bit(delayed_bits, ndx);
|
||||
recv_ok = 2;
|
||||
}
|
||||
} else {
|
||||
partialptr = NULL;
|
||||
} else
|
||||
partialptr = NULL;
|
||||
} else
|
||||
do_unlink(fnametmp);
|
||||
}
|
||||
|
||||
cleanup_disable();
|
||||
|
||||
if (read_batch)
|
||||
file->flags |= FLAG_FILE_SENT;
|
||||
|
||||
switch (recv_ok) {
|
||||
case 2:
|
||||
break;
|
||||
case 1:
|
||||
if (remove_source_files || inc_recurse
|
||||
|| (preserve_hard_links && F_IS_HLINKED(file)))
|
||||
@@ -744,6 +786,8 @@ int recv_files(int f_in, char *local_name)
|
||||
keptstr, redostr);
|
||||
}
|
||||
if (!redoing) {
|
||||
if (read_batch)
|
||||
flist_ndx_push(&batch_redo_list, ndx);
|
||||
send_msg_int(MSG_REDO, ndx);
|
||||
file->flags |= FLAG_FILE_SENT;
|
||||
} else if (inc_recurse)
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* A pre-compilation helper program to aid in the creation of rounding.h.
|
||||
*
|
||||
* Copyright (C) 2007 Wayne Davison
|
||||
* Copyright (C) 2007-2008 Wayne Davison
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
|
||||
109
rsync.c
109
rsync.c
@@ -3,7 +3,7 @@
|
||||
*
|
||||
* Copyright (C) 1996 Andrew Tridgell
|
||||
* Copyright (C) 1996 Paul Mackerras
|
||||
* Copyright (C) 2003-2007 Wayne Davison
|
||||
* Copyright (C) 2003-2008 Wayne Davison
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
@@ -41,7 +41,6 @@ extern int am_generator;
|
||||
extern int am_starting_up;
|
||||
extern int allow_8bit_chars;
|
||||
extern int protocol_version;
|
||||
extern int receiver_symlink_times;
|
||||
extern int uid_ndx;
|
||||
extern int gid_ndx;
|
||||
extern int inc_recurse;
|
||||
@@ -206,6 +205,45 @@ int iconvbufs(iconv_t ic, xbuf *in, xbuf *out, int flags)
|
||||
}
|
||||
#endif
|
||||
|
||||
void send_protected_args(int fd, char *args[])
|
||||
{
|
||||
int i;
|
||||
#ifdef ICONV_OPTION
|
||||
int convert = ic_send != (iconv_t)-1;
|
||||
xbuf outbuf, inbuf;
|
||||
|
||||
if (convert)
|
||||
alloc_xbuf(&outbuf, 1024);
|
||||
#endif
|
||||
|
||||
for (i = 0; args[i]; i++) {} /* find first NULL */
|
||||
args[i] = "rsync"; /* set a new arg0 */
|
||||
if (verbose > 1)
|
||||
print_child_argv("protected args:", args + i + 1);
|
||||
do {
|
||||
if (!args[i][0])
|
||||
write_buf(fd, ".", 2);
|
||||
#ifdef ICONV_OPTION
|
||||
else if (convert) {
|
||||
INIT_XBUF_STRLEN(inbuf, args[i]);
|
||||
iconvbufs(ic_send, &inbuf, &outbuf,
|
||||
ICB_EXPAND_OUT | ICB_INCLUDE_BAD | ICB_INCLUDE_INCOMPLETE);
|
||||
outbuf.buf[outbuf.len] = '\0';
|
||||
write_buf(fd, outbuf.buf, outbuf.len + 1);
|
||||
outbuf.len = 0;
|
||||
}
|
||||
#endif
|
||||
else
|
||||
write_buf(fd, args[i], strlen(args[i]) + 1);
|
||||
} while (args[++i]);
|
||||
write_byte(fd, 0);
|
||||
|
||||
#ifdef ICONV_OPTION
|
||||
if (convert)
|
||||
free(outbuf.buf);
|
||||
#endif
|
||||
}
|
||||
|
||||
int read_ndx_and_attrs(int f_in, int *iflag_ptr, uchar *type_ptr,
|
||||
char *buf, int *len_ptr)
|
||||
{
|
||||
@@ -222,8 +260,17 @@ int read_ndx_and_attrs(int f_in, int *iflag_ptr, uchar *type_ptr,
|
||||
break;
|
||||
if (ndx == NDX_DONE)
|
||||
return ndx;
|
||||
if (!inc_recurse || am_sender)
|
||||
goto invalid_ndx;
|
||||
if (!inc_recurse || am_sender) {
|
||||
int last;
|
||||
if (first_flist)
|
||||
last = first_flist->prev->ndx_start + first_flist->prev->used - 1;
|
||||
else
|
||||
last = -1;
|
||||
rprintf(FERROR,
|
||||
"Invalid file index: %d (%d - %d) [%s]\n",
|
||||
ndx, NDX_DONE, last, who_am_i());
|
||||
exit_cleanup(RERR_PROTOCOL);
|
||||
}
|
||||
if (ndx == NDX_FLIST_EOF) {
|
||||
flist_eof = 1;
|
||||
send_msg(MSG_FLIST_EOF, "", 0, 0);
|
||||
@@ -233,9 +280,10 @@ int read_ndx_and_attrs(int f_in, int *iflag_ptr, uchar *type_ptr,
|
||||
if (ndx < 0 || ndx >= dir_flist->used) {
|
||||
ndx = NDX_FLIST_OFFSET - ndx;
|
||||
rprintf(FERROR,
|
||||
"[%s] Invalid dir index: %d (%d - %d)\n",
|
||||
who_am_i(), ndx, NDX_FLIST_OFFSET,
|
||||
NDX_FLIST_OFFSET - dir_flist->used + 1);
|
||||
"Invalid dir index: %d (%d - %d) [%s]\n",
|
||||
ndx, NDX_FLIST_OFFSET,
|
||||
NDX_FLIST_OFFSET - dir_flist->used + 1,
|
||||
who_am_i());
|
||||
exit_cleanup(RERR_PROTOCOL);
|
||||
}
|
||||
|
||||
@@ -264,17 +312,7 @@ int read_ndx_and_attrs(int f_in, int *iflag_ptr, uchar *type_ptr,
|
||||
goto read_loop;
|
||||
}
|
||||
|
||||
if (!(flist = flist_for_ndx(ndx))) {
|
||||
int start, used;
|
||||
invalid_ndx:
|
||||
start = first_flist ? first_flist->ndx_start : 0;
|
||||
used = first_flist ? first_flist->used : 0;
|
||||
rprintf(FERROR,
|
||||
"Invalid file index: %d (%d - %d) with iflags %x [%s]\n",
|
||||
ndx, start - 1, start + used -1, iflags, who_am_i());
|
||||
exit_cleanup(RERR_PROTOCOL);
|
||||
}
|
||||
cur_flist = flist;
|
||||
cur_flist = flist_for_ndx(ndx, "read_ndx_and_attrs");
|
||||
|
||||
if (iflags & ITEM_BASIS_TYPE_FOLLOWS)
|
||||
fnamecmp_type = read_byte(f_in);
|
||||
@@ -400,7 +438,7 @@ int set_file_attrs(const char *fname, struct file_struct *file, stat_x *sxp,
|
||||
}
|
||||
if (ret == 0) /* ret == 1 if symlink could not be set */
|
||||
updated = 1;
|
||||
else if (receiver_symlink_times)
|
||||
else
|
||||
file->flags |= FLAG_TIME_FAILED;
|
||||
}
|
||||
|
||||
@@ -526,8 +564,12 @@ int finish_transfer(const char *fname, const char *fnametmp,
|
||||
goto do_set_file_attrs;
|
||||
}
|
||||
|
||||
if (make_backups > 0 && overwriting_basis && !make_backup(fname))
|
||||
return 1;
|
||||
if (make_backups > 0 && overwriting_basis) {
|
||||
if (!make_backup(fname))
|
||||
return 1;
|
||||
if (fnamecmp == fname)
|
||||
fnamecmp = get_backup_name(fname);
|
||||
}
|
||||
|
||||
/* Change permissions before putting the file into place. */
|
||||
set_file_attrs(fnametmp, file, NULL, fnamecmp,
|
||||
@@ -571,23 +613,40 @@ int finish_transfer(const char *fname, const char *fnametmp,
|
||||
return 1;
|
||||
}
|
||||
|
||||
struct file_list *flist_for_ndx(int ndx)
|
||||
struct file_list *flist_for_ndx(int ndx, const char *fatal_error_loc)
|
||||
{
|
||||
struct file_list *flist = cur_flist;
|
||||
|
||||
if (!flist && !(flist = first_flist))
|
||||
return NULL;
|
||||
goto not_found;
|
||||
|
||||
while (ndx < flist->ndx_start-1) {
|
||||
if (flist == first_flist)
|
||||
return NULL;
|
||||
goto not_found;
|
||||
flist = flist->prev;
|
||||
}
|
||||
while (ndx >= flist->ndx_start + flist->used) {
|
||||
if (!(flist = flist->next))
|
||||
return NULL;
|
||||
goto not_found;
|
||||
}
|
||||
return flist;
|
||||
|
||||
not_found:
|
||||
if (fatal_error_loc) {
|
||||
int first, last;
|
||||
if (first_flist) {
|
||||
first = first_flist->ndx_start - 1;
|
||||
last = first_flist->prev->ndx_start + first_flist->prev->used - 1;
|
||||
} else {
|
||||
first = 0;
|
||||
last = -1;
|
||||
}
|
||||
rprintf(FERROR,
|
||||
"File-list index %d not in %d - %d (%s) [%s]\n",
|
||||
ndx, first, last, fatal_error_loc, who_am_i());
|
||||
exit_cleanup(RERR_PROTOCOL);
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
const char *who_am_i(void)
|
||||
|
||||
54
rsync.h
54
rsync.h
@@ -2,7 +2,7 @@
|
||||
* Copyright (C) 1996, 2000 Andrew Tridgell
|
||||
* Copyright (C) 1996 Paul Mackerras
|
||||
* Copyright (C) 2001, 2002 Martin Pool <mbp@samba.org>
|
||||
* Copyright (C) 2003-2007 Wayne Davison
|
||||
* Copyright (C) 2003-2008 Wayne Davison
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
@@ -67,7 +67,8 @@
|
||||
#define FLAG_FILE_SENT (1<<1) /* sender/receiver/generator */
|
||||
#define FLAG_DIR_CREATED (1<<1) /* generator */
|
||||
#define FLAG_CONTENT_DIR (1<<2) /* sender/receiver/generator */
|
||||
#define FLAG_MOUNT_DIR (1<<3) /* sender/generator */
|
||||
#define FLAG_MOUNT_DIR (1<<3) /* sender/generator (dirs only) */
|
||||
#define FLAG_SKIP_HLINK (1<<3) /* receiver/generator (w/FLAG_HLINKED) */
|
||||
#define FLAG_DUPLICATE (1<<4) /* sender */
|
||||
#define FLAG_MISSING_DIR (1<<4) /* generator */
|
||||
#define FLAG_HLINKED (1<<5) /* receiver/generator (checked on all types) */
|
||||
@@ -94,7 +95,7 @@
|
||||
/* This is used when working on a new protocol version in CVS, and should
|
||||
* be a new non-zero value for each CVS change that affects the protocol.
|
||||
* It must ALWAYS be 0 when the protocol goes final! */
|
||||
#define SUBPROTOCOL_VERSION 17
|
||||
#define SUBPROTOCOL_VERSION 0
|
||||
|
||||
/* We refuse to interoperate with versions that are not in this range.
|
||||
* Note that we assume we'll work with later versions: the onus is on
|
||||
@@ -128,6 +129,9 @@
|
||||
#define IO_BUFFER_SIZE (4092)
|
||||
#define MAX_BLOCK_SIZE ((int32)1 << 17)
|
||||
|
||||
/* For compatibility with older rsyncs */
|
||||
#define OLD_MAX_BLOCK_SIZE ((int32)1 << 29)
|
||||
|
||||
#define IOERR_GENERAL (1<<0) /* For backward compatibility, this must == 1 */
|
||||
#define IOERR_VANISHED (1<<1)
|
||||
#define IOERR_DEL_LIMIT (1<<2)
|
||||
@@ -144,8 +148,9 @@
|
||||
|
||||
#define XFLG_FATAL_ERRORS (1<<0)
|
||||
#define XFLG_OLD_PREFIXES (1<<1)
|
||||
#define XFLG_ANCHORED2ABS (1<<2)
|
||||
#define XFLG_ABS_IF_SLASH (1<<3)
|
||||
#define XFLG_ANCHORED2ABS (1<<2) /* leading slash indicates absolute */
|
||||
#define XFLG_ABS_IF_SLASH (1<<3) /* leading or interior slash is absolute */
|
||||
#define XFLG_DIR2WILD3 (1<<4) /* dir/ match gets trailing *** added */
|
||||
|
||||
#define ATTRS_REPORT (1<<0)
|
||||
#define ATTRS_SKIP_MTIME (1<<1)
|
||||
@@ -166,8 +171,9 @@
|
||||
|
||||
/* For use by the itemize_changes code */
|
||||
#define ITEM_REPORT_ATIME (1<<0)
|
||||
#define ITEM_REPORT_CHECKSUM (1<<1)
|
||||
#define ITEM_REPORT_SIZE (1<<2)
|
||||
#define ITEM_REPORT_CHANGE (1<<1)
|
||||
#define ITEM_REPORT_SIZE (1<<2) /* regular files only */
|
||||
#define ITEM_REPORT_TIMEFAIL (1<<2) /* symlinks only */
|
||||
#define ITEM_REPORT_TIME (1<<3)
|
||||
#define ITEM_REPORT_PERMS (1<<4)
|
||||
#define ITEM_REPORT_OWNER (1<<5)
|
||||
@@ -187,11 +193,17 @@
|
||||
#define SIGNIFICANT_ITEM_FLAGS (~(\
|
||||
ITEM_BASIS_TYPE_FOLLOWS | ITEM_XNAME_FOLLOWS | ITEM_LOCAL_CHANGE))
|
||||
|
||||
#define CFN_KEEP_LEADING_DOT_DIR (1<<0)
|
||||
#define CFN_KEEP_DOT_DIRS (1<<0)
|
||||
#define CFN_KEEP_TRAILING_SLASH (1<<1)
|
||||
#define CFN_DROP_TRAILING_DOT_DIR (1<<2)
|
||||
#define CFN_COLLAPSE_DOT_DOT_DIRS (1<<3)
|
||||
|
||||
#define SP_DEFAULT 0
|
||||
#define SP_KEEP_DOT_DIRS (1<<0)
|
||||
|
||||
#define CD_NORMAL 0
|
||||
#define CD_SKIP_CHDIR 1
|
||||
|
||||
/* Log-message categories. FLOG only goes to the log file, not the client;
|
||||
* FCLIENT is the opposite. */
|
||||
enum logcode {
|
||||
@@ -199,6 +211,7 @@ enum logcode {
|
||||
FERROR_XFER=1, FINFO=2, /* sent over socket for any protocol */
|
||||
FERROR=3, FWARNING=4, /* sent over socket for protocols >= 30 */
|
||||
FERROR_SOCKET=5, FLOG=6, /* only sent via receiver -> generator pipe */
|
||||
FERROR_UTF8=8, /* only sent via receiver -> generator pipe */
|
||||
FCLIENT=7 /* never transmitted (e.g. server converts to FINFO) */
|
||||
};
|
||||
|
||||
@@ -209,6 +222,7 @@ enum msgcode {
|
||||
MSG_ERROR_XFER=FERROR_XFER, MSG_INFO=FINFO, /* remote logging */
|
||||
MSG_ERROR=FERROR, MSG_WARNING=FWARNING, /* protocol-30 remote logging */
|
||||
MSG_ERROR_SOCKET=FERROR_SOCKET, /* sibling logging */
|
||||
MSG_ERROR_UTF8=FERROR_UTF8, /* sibling logging */
|
||||
MSG_LOG=FLOG, MSG_CLIENT=FCLIENT, /* sibling logging */
|
||||
MSG_REDO=9, /* reprocess indicated flist index */
|
||||
MSG_FLIST=20, /* extra file list over sibling socket */
|
||||
@@ -331,10 +345,6 @@ enum msgcode {
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_GLOB_H
|
||||
#include <glob.h>
|
||||
#endif
|
||||
|
||||
/* these are needed for the uid/gid mapping code */
|
||||
#include <pwd.h>
|
||||
#include <grp.h>
|
||||
@@ -409,13 +419,13 @@ enum msgcode {
|
||||
#include "lib/pool_alloc.h"
|
||||
|
||||
#ifndef HAVE_ID_T
|
||||
typedef int id_t;
|
||||
typedef unsigned int id_t;
|
||||
#endif
|
||||
#ifndef HAVE_PID_T
|
||||
typedef int pid_t;
|
||||
#endif
|
||||
#ifndef HAVE_MODE_T
|
||||
typedef int mode_t;
|
||||
typedef unsigned int mode_t;
|
||||
#endif
|
||||
#ifndef HAVE_OFF_T
|
||||
typedef long off_t;
|
||||
@@ -492,10 +502,12 @@ typedef unsigned int size_t;
|
||||
#if SIZEOF_OFF_T == 8 || !SIZEOF_OFF64_T || !defined HAVE_STRUCT_STAT64
|
||||
#define OFF_T off_t
|
||||
#define STRUCT_STAT struct stat
|
||||
#define SIZEOF_CAPITAL_OFF_T SIZEOF_OFF_T
|
||||
#else
|
||||
#define OFF_T off64_t
|
||||
#define STRUCT_STAT struct stat64
|
||||
#define USE_STAT64_FUNCS 1
|
||||
#define SIZEOF_CAPITAL_OFF_T SIZEOF_OFF64_T
|
||||
#endif
|
||||
|
||||
/* CAVEAT: on some systems, int64 will really be a 32-bit integer IFF
|
||||
@@ -820,6 +832,15 @@ struct stats {
|
||||
|
||||
struct chmod_mode_struct;
|
||||
|
||||
struct flist_ndx_item {
|
||||
struct flist_ndx_item *next;
|
||||
int ndx;
|
||||
};
|
||||
|
||||
typedef struct {
|
||||
struct flist_ndx_item *head, *tail;
|
||||
} flist_ndx_list;
|
||||
|
||||
#define EMPTY_ITEM_LIST {NULL, 0, 0}
|
||||
|
||||
typedef struct {
|
||||
@@ -1105,6 +1126,11 @@ size_t strlcat(char *d, const char *s, size_t bufsize);
|
||||
#define MY_GID() getgid()
|
||||
#endif
|
||||
|
||||
#ifdef FORCE_FD_ZERO_MEMSET
|
||||
#undef FD_ZERO
|
||||
#define FD_ZERO(fdsetp) memset(fdsetp, 0, sizeof (fd_set))
|
||||
#endif
|
||||
|
||||
extern int verbose;
|
||||
|
||||
#ifndef HAVE_INET_NTOP
|
||||
|
||||
158
rsync.yo
158
rsync.yo
@@ -1,5 +1,5 @@
|
||||
mailto(rsync-bugs@samba.org)
|
||||
manpage(rsync)(1)(19 Feb 2008)()()
|
||||
manpage(rsync)(1)(28 Dec 2008)()()
|
||||
manpagename(rsync)(a fast, versatile, remote (and local) file-copying tool)
|
||||
manpagesynopsis()
|
||||
|
||||
@@ -70,6 +70,10 @@ destination, the files are listed in an output format similar to "ls -l".
|
||||
As expected, if neither the source or destination path specify a remote
|
||||
host, the copy occurs locally (see also the bf(--list-only) option).
|
||||
|
||||
Rsync refers to the local side as the "client" and the remote side as the
|
||||
"server". Don't confuse "server" with an rsync daemon -- a daemon is always a
|
||||
server, but a server can be either a daemon or a remote-shell spawned process.
|
||||
|
||||
manpagesection(SETUP)
|
||||
|
||||
See the file README for installation instructions.
|
||||
@@ -464,9 +468,9 @@ dit(bf(--version)) print the rsync version number and exit.
|
||||
dit(bf(-v, --verbose)) This option increases the amount of information you
|
||||
are given during the transfer. By default, rsync works silently. A
|
||||
single bf(-v) will give you information about what files are being
|
||||
transferred and a brief summary at the end. Two bf(-v) flags will give you
|
||||
transferred and a brief summary at the end. Two bf(-v) options will give you
|
||||
information on what files are being skipped and slightly more
|
||||
information at the end. More than two bf(-v) flags should only be used if
|
||||
information at the end. More than two bf(-v) options should only be used if
|
||||
you are debugging rsync.
|
||||
|
||||
Note that the names of the transferred files that are output are done using
|
||||
@@ -480,7 +484,7 @@ any way. See the bf(--out-format) option for more details.
|
||||
|
||||
dit(bf(-q, --quiet)) This option decreases the amount of information you
|
||||
are given during the transfer, notably suppressing information messages
|
||||
from the remote server. This flag is useful when invoking rsync from
|
||||
from the remote server. This option is useful when invoking rsync from
|
||||
cron.
|
||||
|
||||
dit(bf(--no-motd)) This option affects the information that is output
|
||||
@@ -667,7 +671,7 @@ Note that if you don't specify bf(--backup-dir), (1) the
|
||||
bf(--omit-dir-times) option will be implied, and (2) if bf(--delete) is
|
||||
also in effect (without bf(--delete-excluded)), rsync will add a "protect"
|
||||
filter-rule for the backup suffix to the end of all your existing excludes
|
||||
(e.g. bf(-f "Pp *~")). This will prevent previously backed-up files from being
|
||||
(e.g. bf(-f "P *~")). This will prevent previously backed-up files from being
|
||||
deleted. Note that if you are supplying your own filter rules, you may
|
||||
need to manually insert your own exclude/protect rule somewhere higher up
|
||||
in the list so that it has a high enough priority to be effective (e.g., if
|
||||
@@ -697,13 +701,25 @@ date is on the objects. In other words, if the source has a directory
|
||||
where the destination has a file, the transfer would occur regardless of
|
||||
the timestamps.
|
||||
|
||||
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 accomplish the full amount of
|
||||
network reduction it might be able to otherwise (since it does not yet try
|
||||
to sort data matches). One exception to this is if you combine the option
|
||||
with bf(--backup), since rsync is smart enough to use the backup file as the
|
||||
basis file for the transfer.
|
||||
dit(bf(--inplace)) This option changes how rsync transfers a file when the
|
||||
file's data needs to be updated: instead of the default method of creating
|
||||
a new copy of the file and moving it into place when it is complete, rsync
|
||||
instead writes the updated data directly to the destination file.
|
||||
|
||||
This has several effects: (1) in-use binaries cannot be updated (either the
|
||||
OS will prevent this from happening, or binaries that attempt to swap-in
|
||||
their data will misbehave or crash), (2) the file's data will be in an
|
||||
inconsistent state during the transfer, (3) a file's data may be left in an
|
||||
inconsistent state after the transfer if the transfer is interrupted or if
|
||||
an update fails, (4) a file that does not have write permissions can not be
|
||||
updated, and (5) the efficiency of rsync's delta-transfer algorithm may be
|
||||
reduced if some data in the destination file is overwritten before it can
|
||||
be copied to a position later in the file (one exception to this is if you
|
||||
combine this option with bf(--backup), since rsync is smart enough to use
|
||||
the backup file as the basis file for the transfer).
|
||||
|
||||
WARNING: you should not use this option to update files that are being
|
||||
accessed by others, so be careful when choosing to use this for a copy.
|
||||
|
||||
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
|
||||
@@ -714,18 +730,15 @@ the file), but conflicts with bf(--partial-dir) and bf(--delay-updates).
|
||||
Prior to rsync 2.6.4 bf(--inplace) was also incompatible with bf(--compare-dest)
|
||||
and bf(--link-dest).
|
||||
|
||||
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 in-place that is not writable by the
|
||||
receiving user.
|
||||
|
||||
dit(bf(--append)) This causes rsync to update a file by appending data onto
|
||||
the end of the file, which presumes that the data that already exists on
|
||||
the receiving side is identical with the start of the file on the sending
|
||||
side. Any files that are the same size or shorter on the receiving size
|
||||
are skipped. Files that do not yet exist on the receiving side are also
|
||||
sent, since they are considered to have 0 length. Implies bf(--inplace),
|
||||
side. If a file needs to be transferred and its size on the receiver is
|
||||
the same or longer than the size on the sender, the file is skipped. This
|
||||
does not interfere with the updating of a file's non-content attributes
|
||||
(e.g. permissions, ownership, etc.) when the file does not need to be
|
||||
transferred, nor does it affect the updating of any non-regular files.
|
||||
Implies bf(--inplace),
|
||||
but does not conflict with bf(--sparse) (since it is always extending a
|
||||
file's length).
|
||||
|
||||
@@ -748,11 +761,15 @@ bf(--recursive) option, rsync will skip all directories it encounters (and
|
||||
output a message to that effect for each one). If you specify both
|
||||
bf(--dirs) and bf(--recursive), bf(--recursive) takes precedence.
|
||||
|
||||
This option is implied by the bf(--list-only) option (including an implied
|
||||
The bf(--dirs) option is implied by the bf(--files-from) option
|
||||
or the bf(--list-only) option (including an implied
|
||||
bf(--list-only) usage) if bf(--recursive) wasn't specified (so that
|
||||
directories are seen in the listing). Specify bf(--no-dirs) (or bf(--no-d))
|
||||
if you want to override this. This option is also implied by
|
||||
bf(--files-from).
|
||||
if you want to turn this off.
|
||||
|
||||
There is also a backward-compatibility helper option, bf(--old-dirs) (or
|
||||
bf(--old-d)) that tells rsync to use a hack of "-r --exclude='/*/*'" to get
|
||||
an older rsync to list a single directory without recursing.
|
||||
|
||||
dit(bf(-l, --links)) When symlinks are encountered, recreate the
|
||||
symlink on the destination.
|
||||
@@ -979,7 +996,7 @@ 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 bf(-t) or bf(-a) will
|
||||
cause the next transfer to behave as if it used bf(-I), causing all files to be
|
||||
updated (though the rsync algorithm will make the update fairly efficient
|
||||
updated (though rsync's delta-transfer algorithm will make the update fairly efficient
|
||||
if the files haven't actually changed, you're much better off using bf(-t)).
|
||||
|
||||
dit(bf(-O, --omit-dir-times)) This tells rsync to omit directories when
|
||||
@@ -1051,7 +1068,7 @@ the "bytes sent", "bytes received", "literal data", and "matched data"
|
||||
statistics are too small, and the "speedup" value is equivalent to a run
|
||||
where no file transfers are needed.
|
||||
|
||||
dit(bf(-W, --whole-file)) With this option the delta-transfer algorithm
|
||||
dit(bf(-W, --whole-file)) With this option rsync's delta-transfer 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
|
||||
destination machines is higher than the bandwidth to disk (especially when the
|
||||
@@ -1104,7 +1121,7 @@ directories that are being synchronized. You must have asked rsync to
|
||||
send the whole directory (e.g. "dir" or "dir/") without using a wildcard
|
||||
for the directory's contents (e.g. "dir/*") since the wildcard is expanded
|
||||
by the shell and rsync thus gets a request to transfer individual files, not
|
||||
the files' parent directory. Files that are excluded from transfer are
|
||||
the files' parent directory. Files that are excluded from the transfer are
|
||||
also excluded from being deleted unless you use the bf(--delete-excluded)
|
||||
option or mark the rules as only matching on the sending side (see the
|
||||
include/exclude modifiers in the FILTER RULES section).
|
||||
@@ -1126,7 +1143,7 @@ destination. You can override this with the bf(--ignore-errors) option.
|
||||
The bf(--delete) option may be combined with one of the --delete-WHEN options
|
||||
without conflict, as well as bf(--delete-excluded). However, if none of the
|
||||
--delete-WHEN options are specified, rsync will choose the
|
||||
bf(--delete-during) algorithm when talking to an rsync 3.0.0 or newer, and
|
||||
bf(--delete-during) algorithm when talking to rsync 3.0.0 or newer, and
|
||||
the bf(--delete-before) algorithm when talking to an older rsync. See also
|
||||
bf(--delete-delay) and bf(--delete-after).
|
||||
|
||||
@@ -1143,19 +1160,26 @@ algorithm that requires rsync to scan all the files in the transfer into
|
||||
memory at once (see bf(--recursive)).
|
||||
|
||||
dit(bf(--delete-during, --del)) Request that the file-deletions on the
|
||||
receiving side be done incrementally as the transfer happens. This is
|
||||
a faster method than choosing the before- or after-transfer algorithm,
|
||||
but it is only supported beginning with rsync version 2.6.4.
|
||||
receiving side be done incrementally as the transfer happens. The
|
||||
per-directory delete scan is done right before each directory is checked
|
||||
for updates, so it behaves like a more efficient bf(--delete-before),
|
||||
including doing the deletions prior to any per-directory filter files
|
||||
being updated. This option was first added in rsync version 2.6.4.
|
||||
See bf(--delete) (which is implied) for more details on file-deletion.
|
||||
|
||||
dit(bf(--delete-delay)) Request that the file-deletions on the receiving
|
||||
side be computed during the transfer, and then removed after the transfer
|
||||
completes. If the number of removed files overflows an internal buffer, a
|
||||
side be computed during the transfer (like bf(--delete-during)), and then
|
||||
removed after the transfer completes. This is useful when combined with
|
||||
bf(--delay-updates) and/or bf(--fuzzy), and is more efficient than using
|
||||
bf(--delete-after) (but can behave differently, since bf(--delete-after)
|
||||
computes the deletions in a separate pass after all updates are done).
|
||||
If the number of removed files overflows an internal buffer, a
|
||||
temporary file will be created on the receiving side to hold the names (it
|
||||
is removed while open, so you shouldn't see it during the transfer). If
|
||||
the creation of the temporary file fails, rsync will try to fall back to
|
||||
using bf(--delete-after) (which it cannot do if bf(--recursive) is doing an
|
||||
incremental scan).
|
||||
See bf(--delete) (which is implied) for more details on file-deletion.
|
||||
|
||||
dit(bf(--delete-after)) Request that the file-deletions on the receiving
|
||||
side be done after the transfer has completed. This is useful if you
|
||||
@@ -1218,7 +1242,7 @@ transferring small, junk files.
|
||||
See the bf(--max-size) option for a description of SIZE.
|
||||
|
||||
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
|
||||
rsync's delta-transfer 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
|
||||
@@ -1509,6 +1533,11 @@ An example:
|
||||
|
||||
quote(tt( rsync -av --link-dest=$PWD/prior_dir host:src_dir/ new_dir/))
|
||||
|
||||
If file's aren't linking, double-check their attributes. Also check if some
|
||||
attributes are getting forced outside of rsync's control, such a mount option
|
||||
that squishes root to a single user, or mounts a removable drive with generic
|
||||
ownership (such as OS X's "Ignore ownership on this volume" option).
|
||||
|
||||
Beginning in version 2.6.4, multiple bf(--link-dest) directories may be
|
||||
provided, which will cause rsync to search the list in the order specified
|
||||
for an exact match.
|
||||
@@ -1674,26 +1703,29 @@ a "?" (this can happen when talking to an older rsync).
|
||||
The attribute that is associated with each letter is as follows:
|
||||
|
||||
quote(itemization(
|
||||
it() A bf(c) means the checksum of the file is different and will be
|
||||
updated by the file transfer (requires bf(--checksum)).
|
||||
it() A bf(s) means the size of the file is different and will be updated
|
||||
it() A bf(c) means either that a regular file has a different checksum
|
||||
(requires bf(--checksum)) or that a symlink, device, or special file has
|
||||
a changed value.
|
||||
Note that if you are sending files to an rsync prior to 3.0.1, this
|
||||
change flag will be present only for checksum-differing regular files.
|
||||
it() A bf(s) means the size of a regular file is different and will be updated
|
||||
by the file transfer.
|
||||
it() A bf(t) means the modification time is different and is being updated
|
||||
to the sender's value (requires bf(--times)). An alternate value of bf(T)
|
||||
means that the modification time will be set to the transfer time, which happens
|
||||
when a file/symlink/device is updated without bf(--times) and when a
|
||||
symlink is changed and the receiver can't set its time.
|
||||
(Note: when using an rsync 3.0.0 client, you might see the bf(s) flag combined
|
||||
with bf(t) instead of the proper bf(T) flag for this time-setting failure.)
|
||||
it() A bf(p) means the permissions are different and are being updated to
|
||||
the sender's value (requires bf(--perms)).
|
||||
it() An bf(o) means the owner is different and is being updated to the
|
||||
sender's value (requires bf(--owner) and super-user privileges).
|
||||
it() A bf(g) means the group is different and is being updated to the
|
||||
sender's value (requires bf(--group) and the authority to set the group).
|
||||
it() The bf(u) slot is reserved for reporting update (access) time changes
|
||||
(a feature that is not yet released).
|
||||
it() The bf(u) slot is reserved for future use.
|
||||
it() The bf(a) means that the ACL information changed.
|
||||
it() The bf(x) slot is reserved for reporting extended attribute changes
|
||||
(a feature that is not yet released).
|
||||
it() The bf(x) means that the extended attribute information changed.
|
||||
))
|
||||
|
||||
One other output is possible: when deleting files, the "%i" will output
|
||||
@@ -1702,22 +1734,22 @@ you are talking to a recent enough rsync that it logs deletions instead of
|
||||
outputting them as a verbose message).
|
||||
|
||||
dit(bf(--out-format=FORMAT)) This allows you to specify exactly what the
|
||||
rsync client outputs to the user on a per-update basis. The format is a text
|
||||
string containing embedded single-character escape sequences prefixed with
|
||||
a percent (%) character. For a list of the possible escape characters, see
|
||||
the "log format" setting in the rsyncd.conf manpage.
|
||||
rsync client outputs to the user on a per-update basis. The format is a
|
||||
text string containing embedded single-character escape sequences prefixed
|
||||
with a percent (%) character. A default format of "%n%L" is assumed if
|
||||
bf(-v) is specified (which reports the name
|
||||
of the file and, if the item is a link, where it points). For a full list
|
||||
of the possible escape characters, see the "log format" setting in the
|
||||
rsyncd.conf manpage.
|
||||
|
||||
Specifying this option will mention each file, dir, etc. that gets updated
|
||||
in a significant way (a transferred file, a recreated symlink/device, or a
|
||||
touched directory). In addition, if the itemize-changes escape (%i) is
|
||||
included in the string, the logging of names increases to mention any
|
||||
item that is changed in any way (as long as the receiving side is at least
|
||||
2.6.4). See the bf(--itemize-changes) option for a description of the
|
||||
output of "%i".
|
||||
|
||||
The bf(--verbose) option implies a format of "%n%L", but you can use
|
||||
bf(--out-format) without bf(--verbose) if you like, or you can override
|
||||
the format of its per-file output using this option.
|
||||
Specifying the bf(--out-format) option
|
||||
will mention each file, dir, etc. that gets updated in a significant
|
||||
way (a transferred file, a recreated symlink/device, or a touched
|
||||
directory). In addition, if the itemize-changes escape (%i) is included in
|
||||
the string (e.g. if the bf(--itemize-changes) option was used), the logging
|
||||
of names increases to mention any item that is changed in any way (as long
|
||||
as the receiving side is at least 2.6.4). See the bf(--itemize-changes)
|
||||
option for a description of the output of "%i".
|
||||
|
||||
Rsync will output the out-format string prior to a file's transfer unless
|
||||
one of the transfer-statistic escapes is requested, in which case the
|
||||
@@ -1749,14 +1781,14 @@ For a list of the possible escape characters, see the "log format" setting
|
||||
in the rsyncd.conf manpage.
|
||||
|
||||
dit(bf(--stats)) This tells rsync to print a verbose set of statistics
|
||||
on the file transfer, allowing you to tell how effective the rsync
|
||||
on the file transfer, allowing you to tell how effective rsync's delta-transfer
|
||||
algorithm is for your data.
|
||||
|
||||
The current statistics are as follows: quote(itemization(
|
||||
it() bf(Number of files) is the count of all "files" (in the generic
|
||||
sense), which includes directories, symlinks, etc.
|
||||
it() bf(Number of files transferred) is the count of normal files that
|
||||
were updated via the rsync algorithm, which does not include created
|
||||
were updated via rsync's delta-transfer algorithm, which does not include created
|
||||
dirs, symlinks, etc.
|
||||
it() bf(Total file size) is the total sum of all file sizes in the transfer.
|
||||
This does not count any size for directories or special files, but does
|
||||
@@ -1817,7 +1849,7 @@ after it has served its purpose.
|
||||
Note that if bf(--whole-file) is specified (or implied), any partial-dir
|
||||
file that is found for a file that is being updated will simply be removed
|
||||
(since
|
||||
rsync is sending files without using the delta transfer algorithm).
|
||||
rsync is sending files without using rsync's delta-transfer algorithm).
|
||||
|
||||
Rsync will create the em(DIR) if it is missing (just the last dir -- not
|
||||
the whole path). This makes it easy to use a relative path (such as
|
||||
@@ -1935,7 +1967,7 @@ sender's file, which is being reconstructed at a rate of 110.64 kilobytes
|
||||
per second, and the transfer will finish in 4 seconds if the current rate
|
||||
is maintained until the end.
|
||||
|
||||
These statistics can be misleading if the delta transfer algorithm is
|
||||
These statistics can be misleading if rsync's delta-transfer algorithm is
|
||||
in use. For example, if the sender's file consists of the basis file
|
||||
followed by additional data, the reported rate will probably drop
|
||||
dramatically when the receiver gets to the literal data, and the transfer
|
||||
@@ -2077,7 +2109,7 @@ by the server and defaults to the current code(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 code(time())
|
||||
Setting NUM to 0 causes rsync to use the default of code(time())
|
||||
for checksum seed.
|
||||
enddit()
|
||||
|
||||
@@ -2248,7 +2280,7 @@ itemization(
|
||||
it() rsync chooses between doing a simple string match and wildcard
|
||||
matching by checking if the pattern contains one of these three wildcard
|
||||
characters: '*', '?', and '[' .
|
||||
it() a '*' matches any non-empty path component (it stops at slashes).
|
||||
it() a '*' matches any path component, but it stops at slashes.
|
||||
it() use '**' to match anything, including slashes.
|
||||
it() a '?' matches any character except a slash (/).
|
||||
it() a '[' introduces a character class, such as [a-z] or [[:alpha:]].
|
||||
@@ -2866,7 +2898,7 @@ url(http://rsync.samba.org/)(http://rsync.samba.org/)
|
||||
|
||||
manpagesection(VERSION)
|
||||
|
||||
This man page is current for version 3.0.0pre10 of rsync.
|
||||
This man page is current for version 3.0.5 of rsync.
|
||||
|
||||
manpagesection(INTERNAL OPTIONS)
|
||||
|
||||
|
||||
236
rsyncd.conf.yo
236
rsyncd.conf.yo
@@ -1,5 +1,5 @@
|
||||
mailto(rsync-bugs@samba.org)
|
||||
manpage(rsyncd.conf)(5)(19 Feb 2008)()()
|
||||
manpage(rsyncd.conf)(5)(28 Dec 2008)()()
|
||||
manpagename(rsyncd.conf)(configuration file for rsync in daemon mode)
|
||||
manpagesynopsis()
|
||||
|
||||
@@ -69,7 +69,7 @@ Note that you should bf(not) send the rsync daemon a HUP signal to force
|
||||
it to reread the tt(rsyncd.conf) file. The file is re-read on each client
|
||||
connection.
|
||||
|
||||
manpagesection(GLOBAL OPTIONS)
|
||||
manpagesection(GLOBAL PARAMETERS)
|
||||
|
||||
The first parameters in the file (before a [module] header) are the
|
||||
global parameters.
|
||||
@@ -79,12 +79,12 @@ config file in which case the supplied value will override the
|
||||
default for that parameter.
|
||||
|
||||
startdit()
|
||||
dit(bf(motd file)) The "motd file" option allows you to specify a
|
||||
dit(bf(motd file)) This parameter allows you to specify a
|
||||
"message of the day" to display to clients on each connect. This
|
||||
usually contains site information and any legal notices. The default
|
||||
is no motd file.
|
||||
|
||||
dit(bf(pid file)) The "pid file" option tells the rsync daemon to write
|
||||
dit(bf(pid file)) This parameter tells the rsync daemon to write
|
||||
its process ID to that file. If the file already exists, the rsync
|
||||
daemon will abort rather than overwrite the file.
|
||||
|
||||
@@ -96,23 +96,22 @@ dit(bf(address)) You can override the default IP address the daemon
|
||||
will listen on by specifying this value. This is ignored if the daemon is
|
||||
being run by inetd, and is superseded by the bf(--address) command-line option.
|
||||
|
||||
dit(bf(socket options)) This option can provide endless fun for people
|
||||
dit(bf(socket options)) This parameter can provide endless fun for people
|
||||
who like to tune their systems to the utmost degree. You can set all
|
||||
sorts of socket options which may make transfers faster (or
|
||||
slower!). Read the man page for the code(setsockopt()) system call for
|
||||
details on some of the options you may be able to set. By default no
|
||||
special socket options are set. These settings are superseded by the
|
||||
bf(--sockopts) command-line option.
|
||||
special socket options are set. These settings can also be specified
|
||||
via the bf(--sockopts) command-line option.
|
||||
|
||||
enddit()
|
||||
|
||||
manpagesection(MODULE PARAMETERS)
|
||||
|
||||
manpagesection(MODULE OPTIONS)
|
||||
|
||||
After the global options you should define a number of modules, each
|
||||
After the global parameters you should define a number of modules, each
|
||||
module exports a directory tree as a symbolic name. Modules are
|
||||
exported by specifying a module name in square brackets [module]
|
||||
followed by the options for that module.
|
||||
followed by the parameters for that module.
|
||||
The module name cannot contain a slash or a closing square bracket. If the
|
||||
name contains whitespace, each internal sequence of whitespace will be
|
||||
changed into a single space, while leading or trailing whitespace will be
|
||||
@@ -120,12 +119,12 @@ discarded.
|
||||
|
||||
startdit()
|
||||
|
||||
dit(bf(comment)) The "comment" option specifies a description string
|
||||
dit(bf(comment)) This parameter specifies a description string
|
||||
that is displayed next to the module name when clients obtain a list
|
||||
of available modules. The default is no comment.
|
||||
|
||||
dit(bf(path)) The "path" option specifies the directory in the daemon's
|
||||
filesystem to make available in this module. You must specify this option
|
||||
dit(bf(path)) This parameter specifies the directory in the daemon's
|
||||
filesystem to make available in this module. You must specify this parameter
|
||||
for each module in tt(rsyncd.conf).
|
||||
|
||||
dit(bf(use chroot)) If "use chroot" is true, the rsync daemon will chroot
|
||||
@@ -158,7 +157,7 @@ args if rsync believes they would escape the module hierarchy.
|
||||
The default for "use chroot" is true, and is the safer choice (especially
|
||||
if the module is not read-only).
|
||||
|
||||
When this option is enabled, rsync will not attempt to map users and groups
|
||||
When this parameter is enabled, rsync will not attempt to map users and groups
|
||||
by name (by default), but instead copy IDs as though bf(--numeric-ids) had
|
||||
been specified. In order to enable name-mapping, rsync needs to be able to
|
||||
use the standard library functions for looking up names and IDs (i.e.
|
||||
@@ -172,32 +171,32 @@ If you copy the necessary resources into the module's chroot area, you
|
||||
should protect them through your OS's normal user/group or ACL settings (to
|
||||
prevent the rsync module's user from being able to change them), and then
|
||||
hide them from the user's view via "exclude" (see how in the discussion of
|
||||
that option). At that point it will be safe to enable the mapping of users
|
||||
and groups by name using the "numeric ids" daemon option (see below).
|
||||
that parameter). At that point it will be safe to enable the mapping of users
|
||||
and groups by name using the "numeric ids" daemon parameter (see below).
|
||||
|
||||
Note also that you are free to setup custom user/group information in the
|
||||
chroot area that is different from your normal system. For example, you
|
||||
could abbreviate the list of users and groups.
|
||||
|
||||
dit(bf(numeric ids)) Enabling the "numeric ids" option disables the mapping
|
||||
dit(bf(numeric ids)) Enabling this parameter disables the mapping
|
||||
of users and groups by name for the current daemon module. This prevents
|
||||
the daemon from trying to load any user/group-related files or libraries.
|
||||
Enabling this option makes the transfer behave as if the client had passed
|
||||
This enabling makes the transfer behave as if the client had passed
|
||||
the bf(--numeric-ids) command-line option. By default, this parameter is
|
||||
enabled for chroot modules and disabled for non-chroot modules.
|
||||
|
||||
A chroot-enabled module should not have this option enabled unless you've
|
||||
A chroot-enabled module should not have this parameter enabled unless you've
|
||||
taken steps to ensure that the module has the necessary resources it needs
|
||||
to translate names, and that it is not possible for a user to change those
|
||||
resources.
|
||||
|
||||
dit(bf(munge symlinks)) The "munge symlinks" option tells rsync to modify
|
||||
dit(bf(munge symlinks)) This parameter tells rsync to modify
|
||||
all incoming symlinks in a way that makes them unusable but recoverable
|
||||
(see below). This should help protect your files from user trickery when
|
||||
your daemon module is writable. The default is disabled when "use chroot"
|
||||
is on and the inside-chroot path is "/", otherwise it is enabled.
|
||||
|
||||
If you disable this option on a daemon that is not read-only, there
|
||||
If you disable this parameter on a daemon that is not read-only, there
|
||||
are tricks that a user can play with uploaded symlinks to access
|
||||
daemon-excluded items (if your module has any), and, if "use chroot"
|
||||
is off, rsync can even be tricked into showing or changing data that
|
||||
@@ -205,27 +204,28 @@ is outside the module's path (as access-permissions allow).
|
||||
|
||||
The way rsync disables the use of symlinks is to prefix each one with
|
||||
the string "/rsyncd-munged/". This prevents the links from being used
|
||||
as long as that directory does not exist. When this option is enabled,
|
||||
as long as that directory does not exist. When this parameter is enabled,
|
||||
rsync will refuse to run if that path is a directory or a symlink to
|
||||
a directory. When using the "munge symlinks" option in a chroot area
|
||||
a directory. When using the "munge symlinks" parameter in a chroot area
|
||||
that has an inside-chroot path of "/", you should add "/rsyncd-munged/"
|
||||
to the exclude setting for the module so that
|
||||
a user can't try to create it.
|
||||
|
||||
Note: rsync makes no attempt to verify that any pre-existing symlinks in
|
||||
the hierarchy are as safe as you want them to be. If you setup an rsync
|
||||
the module's hierarchy are as safe as you want them to be (unless, of
|
||||
course, it just copied in the whole hierarchy). If you setup an rsync
|
||||
daemon on a new area or locally add symlinks, you can manually protect your
|
||||
symlinks from being abused by prefixing "/rsyncd-munged/" to the start of
|
||||
every symlink's value. There is a perl script in the support directory
|
||||
of the source code named "munge-symlinks" that can be used to add or remove
|
||||
this prefix from your symlinks.
|
||||
|
||||
When this option is disabled on a writable module and "use chroot" is off
|
||||
When this parameter is disabled on a writable module and "use chroot" is off
|
||||
(or the inside-chroot path is not "/"),
|
||||
incoming symlinks will be modified to drop a leading slash and to remove ".."
|
||||
path elements that rsync believes will allow a symlink to escape the module's
|
||||
hierarchy. There are tricky ways to work around this, though, so you had
|
||||
better trust your users if you choose this combination of options.
|
||||
better trust your users if you choose this combination of parameters.
|
||||
|
||||
dit(bf(charset)) This specifies the name of the character set in which the
|
||||
module's filenames are stored. If the client uses an bf(--iconv) option,
|
||||
@@ -240,14 +240,14 @@ If you wish to force users to always use bf(--iconv) for a particular
|
||||
module, add "no-iconv" to the "refuse options" parameter. Keep in mind
|
||||
that this will restrict access to your module to very new rsync clients.
|
||||
|
||||
dit(bf(max connections)) The "max connections" option allows you to
|
||||
dit(bf(max connections)) This parameter allows you to
|
||||
specify the maximum number of simultaneous connections you will allow.
|
||||
Any clients connecting when the maximum has been reached will receive a
|
||||
message telling them to try later. The default is 0, which means no limit.
|
||||
A negative value disables the module.
|
||||
See also the "lock file" option.
|
||||
See also the "lock file" parameter.
|
||||
|
||||
dit(bf(log file)) When the "log file" option is set to a non-empty
|
||||
dit(bf(log file)) When the "log file" parameter is set to a non-empty
|
||||
string, the rsync daemon will log messages to the indicated file rather
|
||||
than using syslog. This is particularly useful on systems (such as AIX)
|
||||
where code(syslog()) doesn't work for chrooted programs. The file is
|
||||
@@ -256,11 +256,11 @@ the transfer. If this value is set on a per-module basis instead of
|
||||
globally, the global log will still contain any authorization failures
|
||||
or config-file error messages.
|
||||
|
||||
If the daemon fails to open to specified file, it will fall back to
|
||||
If the daemon fails to open the specified file, it will fall back to
|
||||
using syslog and output an error about the failure. (Note that the
|
||||
failure to open the specified log file used to be a fatal error.)
|
||||
|
||||
dit(bf(syslog facility)) The "syslog facility" option allows you to
|
||||
dit(bf(syslog facility)) This parameter allows you to
|
||||
specify the syslog facility name to use when logging messages from the
|
||||
rsync daemon. You may use any standard syslog facility name which is
|
||||
defined on your system. Common names are auth, authpriv, cron, daemon,
|
||||
@@ -270,43 +270,43 @@ is daemon. This setting has no effect if the "log file" setting is a
|
||||
non-empty string (either set in the per-modules settings, or inherited
|
||||
from the global settings).
|
||||
|
||||
dit(bf(max verbosity)) The "max verbosity" option allows you to control
|
||||
dit(bf(max verbosity)) This parameter allows you to control
|
||||
the maximum amount of verbose information that you'll allow the daemon to
|
||||
generate (since the information goes into the log file). The default is 1,
|
||||
which allows the client to request one level of verbosity.
|
||||
|
||||
dit(bf(lock file)) The "lock file" option specifies the file to use to
|
||||
support the "max connections" option. The rsync daemon uses record
|
||||
dit(bf(lock file)) This parameter specifies the file to use to
|
||||
support the "max connections" parameter. The rsync daemon uses record
|
||||
locking on this file to ensure that the max connections limit is not
|
||||
exceeded for the modules sharing the lock file.
|
||||
The default is tt(/var/run/rsyncd.lock).
|
||||
|
||||
dit(bf(read only)) The "read only" option determines whether clients
|
||||
dit(bf(read only)) This parameter determines whether clients
|
||||
will be able to upload files or not. If "read only" is true then any
|
||||
attempted uploads will fail. If "read only" is false then uploads will
|
||||
be possible if file permissions on the daemon side allow them. The default
|
||||
is for all modules to be read only.
|
||||
|
||||
dit(bf(write only)) The "write only" option determines whether clients
|
||||
dit(bf(write only)) This parameter determines whether clients
|
||||
will be able to download files or not. If "write only" is true then any
|
||||
attempted downloads will fail. If "write only" is false then downloads
|
||||
will be possible if file permissions on the daemon side allow them. The
|
||||
default is for this option to be disabled.
|
||||
default is for this parameter to be disabled.
|
||||
|
||||
dit(bf(list)) The "list" option determines if this module should be
|
||||
dit(bf(list)) This parameter 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
|
||||
for modules to be listable.
|
||||
|
||||
dit(bf(uid)) The "uid" option specifies the user name or user ID that
|
||||
dit(bf(uid)) This parameter specifies the user name or user ID that
|
||||
file transfers to and from that module should take place as when the daemon
|
||||
was run as root. In combination with the "gid" option this determines what
|
||||
was run as root. In combination with the "gid" parameter this determines what
|
||||
file permissions are available. The default is uid -2, which is normally
|
||||
the user "nobody".
|
||||
|
||||
dit(bf(gid)) The "gid" option specifies the group name or group ID that
|
||||
dit(bf(gid)) This parameter specifies the group name or group ID that
|
||||
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,
|
||||
was run as root. This complements the "uid" parameter. The default is gid -2,
|
||||
which is normally the group "nobody".
|
||||
|
||||
dit(bf(fake super)) Setting "fake super = yes" for a module causes the
|
||||
@@ -314,58 +314,56 @@ daemon side to behave as if the bf(--fake-user) command-line option had
|
||||
been specified. This allows the full attributes of a file to be stored
|
||||
without having to have the daemon actually running as root.
|
||||
|
||||
dit(bf(filter)) The "filter" option allows you to specify a space-separated
|
||||
list of filter rules that the daemon will not allow to be read or written.
|
||||
This is only superficially equivalent to the client specifying these
|
||||
patterns with the bf(--filter) option. Only one "filter" option may be
|
||||
specified, but it may contain as many rules as you like, including
|
||||
merge-file rules. Note that per-directory merge-file rules do not provide
|
||||
as much protection as global rules, but they can be used to make bf(--delete)
|
||||
work better when a client downloads the daemon's files (if the per-dir
|
||||
merge files are included in the transfer).
|
||||
dit(bf(filter)) The daemon has its own filter chain that determines what files
|
||||
it will let the client access. This chain is not sent to the client and is
|
||||
independent of any filters the client may have specified. Files excluded by
|
||||
the daemon filter chain (bf(daemon-excluded) files) are treated as non-existent
|
||||
if the client tries to pull them, are skipped with an error message if the
|
||||
client tries to push them (triggering exit code 23), and are never deleted from
|
||||
the module. You can use daemon filters to prevent clients from downloading or
|
||||
tampering with private administrative files, such as files you may add to
|
||||
support uid/gid name translations.
|
||||
|
||||
dit(bf(exclude)) The "exclude" option allows you to specify a
|
||||
space-separated list of patterns that the daemon will not allow to be read
|
||||
or written. This is only superficially equivalent to the client
|
||||
specifying these patterns with the bf(--exclude) option. Only one "exclude"
|
||||
option may be specified, but you can use "-" and "+" before patterns to
|
||||
specify exclude/include.
|
||||
The daemon filter chain is built from the "filter", "include from", "include",
|
||||
"exclude from", and "exclude" parameters, in that order of priority. Anchored
|
||||
patterns are anchored at the root of the module. To prevent access to an
|
||||
entire subtree, for example, "/secret", you em(must) exclude everything in the
|
||||
subtree; the easiest way to do this is with a triple-star pattern like
|
||||
"/secret/***".
|
||||
|
||||
Because this exclude list is not passed to the client it only applies on
|
||||
the daemon: that is, it excludes files received by a client when receiving
|
||||
from a daemon and files deleted on a daemon when sending to a daemon, but
|
||||
it doesn't exclude files from being deleted on a client when receiving
|
||||
from a daemon.
|
||||
The "filter" parameter takes a space-separated list of daemon filter rules,
|
||||
though it is smart enough to know not to split a token at an internal space in
|
||||
a rule (e.g. "- /foo - /bar" is parsed as two rules). You may specify one or
|
||||
more merge-file rules using the normal syntax. Only one "filter" parameter can
|
||||
apply to a given module in the config file, so put all the rules you want in a
|
||||
single parameter. Note that per-directory merge-file rules do not provide as
|
||||
much protection as global rules, but they can be used to make bf(--delete) work
|
||||
better during a client download operation if the per-dir merge files are
|
||||
included in the transfer and the client requests that they be used.
|
||||
|
||||
When you want to exclude a directory and all its contents, it is safest to
|
||||
use a rule that does both, such as "/some/dir/***" (the three stars tells
|
||||
rsync to exclude the directory itself and everything inside it). This is
|
||||
better than just excluding the directory alone with "/some/dir/", as it
|
||||
helps to guard against attempts to trick rsync into accessing files deeper
|
||||
in the hierarchy.
|
||||
dit(bf(exclude)) This parameter takes a space-separated list of daemon
|
||||
exclude patterns. As with the client bf(--exclude) option, patterns can be
|
||||
qualified with "- " or "+ " to explicitly indicate exclude/include. Only one
|
||||
"exclude" parameter can apply to a given module. See the "filter" parameter
|
||||
for a description of how excluded files affect the daemon.
|
||||
|
||||
dit(bf(exclude from)) The "exclude from" option specifies a filename
|
||||
on the daemon that contains exclude patterns, one per line.
|
||||
This is only superficially equivalent
|
||||
to the client specifying the bf(--exclude-from) option with an equivalent file.
|
||||
See the "exclude" option above.
|
||||
dit(bf(include)) Use an "include" to override the effects of the "exclude"
|
||||
parameter. Only one "include" parameter can apply to a given module. See the
|
||||
"filter" parameter for a description of how excluded files affect the daemon.
|
||||
|
||||
dit(bf(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 bf(--include) option because it applies only on the daemon. 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(exclude from)) This parameter specifies the name of a file
|
||||
on the daemon that contains daemon exclude patterns, one per line. Only one
|
||||
"exclude from" parameter can apply to a given module; if you have multiple
|
||||
exclude-from files, you can specify them as a merge file in the "filter"
|
||||
parameter. See the "filter" parameter for a description of how excluded files
|
||||
affect the daemon.
|
||||
|
||||
dit(bf(include from)) The "include from" option specifies a filename
|
||||
on the daemon that contains include patterns, one per line. This is
|
||||
only superficially equivalent to the client specifying the
|
||||
bf(--include-from) option with a equivalent file.
|
||||
See the "exclude" option above.
|
||||
dit(bf(include from)) Analogue of "exclude from" for a file of daemon include
|
||||
patterns. Only one "include from" parameter can apply to a given module. See
|
||||
the "filter" parameter for a description of how excluded files affect the
|
||||
daemon.
|
||||
|
||||
dit(bf(incoming chmod)) This option allows you to specify a set of
|
||||
dit(bf(incoming chmod)) This parameter allows you to specify a set of
|
||||
comma-separated chmod strings that will affect the permissions of all
|
||||
incoming files (files that are being received by the daemon). These
|
||||
changes happen after all other permission calculations, and this will
|
||||
@@ -374,7 +372,7 @@ client does not specify bf(--perms).
|
||||
See the description of the bf(--chmod) rsync option and the bf(chmod)(1)
|
||||
manpage for information on the format of this string.
|
||||
|
||||
dit(bf(outgoing chmod)) This option allows you to specify a set of
|
||||
dit(bf(outgoing chmod)) This parameter allows you to specify a set of
|
||||
comma-separated chmod strings that will affect the permissions of all
|
||||
outgoing files (files that are being sent out from the daemon). These
|
||||
changes happen first, making the sent permissions appear to be different
|
||||
@@ -384,7 +382,7 @@ be on to the clients.
|
||||
See the description of the bf(--chmod) rsync option and the bf(chmod)(1)
|
||||
manpage for information on the format of this string.
|
||||
|
||||
dit(bf(auth users)) The "auth users" option specifies a comma and
|
||||
dit(bf(auth users)) This parameter specifies a comma and
|
||||
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
|
||||
@@ -392,7 +390,7 @@ system. The usernames may also contain shell wildcard characters. If
|
||||
username and password to connect to the module. A challenge response
|
||||
authentication protocol is used for this exchange. The plain text
|
||||
usernames and passwords are stored in the file specified by the
|
||||
"secrets file" option. The default is for all users to be able to
|
||||
"secrets file" parameter. The default is for all users to be able to
|
||||
connect without a password (this is called "anonymous rsync").
|
||||
|
||||
See also the "CONNECTING TO AN RSYNC DAEMON OVER A REMOTE SHELL
|
||||
@@ -400,28 +398,28 @@ PROGRAM" section in bf(rsync)(1) for information on how handle an
|
||||
rsyncd.conf-level username that differs from the remote-shell-level
|
||||
username when using a remote shell to connect to an rsync daemon.
|
||||
|
||||
dit(bf(secrets file)) The "secrets file" option specifies the name of
|
||||
dit(bf(secrets file)) This parameter specifies the name of
|
||||
a file that contains the username:password pairs used for
|
||||
authenticating this module. This file is only consulted if the "auth
|
||||
users" option is specified. The file is line based and contains
|
||||
users" parameter is specified. The file is line based and contains
|
||||
username:password pairs separated by a single colon. Any line starting
|
||||
with a hash (#) is considered a comment and is skipped. The passwords
|
||||
can contain any characters but be warned that many operating systems
|
||||
limit the length of passwords that can be typed at the client end, so
|
||||
you may find that passwords longer than 8 characters don't work.
|
||||
|
||||
There is no default for the "secrets file" option, you must choose a name
|
||||
There is no default for the "secrets file" parameter, you must choose a name
|
||||
(such as tt(/etc/rsyncd.secrets)). The file must normally not be readable
|
||||
by "other"; see "strict modes".
|
||||
|
||||
dit(bf(strict modes)) The "strict modes" option determines whether or not
|
||||
dit(bf(strict modes)) This parameter determines whether or not
|
||||
the permissions on the secrets file will be checked. If "strict modes" is
|
||||
true, then the secrets file must not be readable by any user ID other
|
||||
than the one that the rsync daemon is running under. If "strict modes" is
|
||||
false, the check is not performed. The default is true. This option
|
||||
false, the check is not performed. The default is true. This parameter
|
||||
was added to accommodate rsync running on the Windows operating system.
|
||||
|
||||
dit(bf(hosts allow)) The "hosts allow" option allows you to specify a
|
||||
dit(bf(hosts allow)) This parameter allows you to specify a
|
||||
list of patterns that are matched against a connecting clients
|
||||
hostname and IP address. If none of the patterns match then the
|
||||
connection is rejected.
|
||||
@@ -456,28 +454,28 @@ tt( fe80::%link1/ffff:ffff:ffff:ffff::)nl()
|
||||
)
|
||||
|
||||
You can also combine "hosts allow" with a separate "hosts deny"
|
||||
option. If both options are specified then the "hosts allow" option s
|
||||
parameter. If both parameters are specified then the "hosts allow" parameter is
|
||||
checked first and a match results in the client being able to
|
||||
connect. The "hosts deny" option is then checked and a match means
|
||||
connect. The "hosts deny" parameter is then checked and a match means
|
||||
that the host is rejected. If the host does not match either the
|
||||
"hosts allow" or the "hosts deny" patterns then it is allowed to
|
||||
connect.
|
||||
|
||||
The default is no "hosts allow" option, which means all hosts can connect.
|
||||
The default is no "hosts allow" parameter, which means all hosts can connect.
|
||||
|
||||
dit(bf(hosts deny)) The "hosts deny" option allows you to specify a
|
||||
dit(bf(hosts deny)) This parameter allows you to specify a
|
||||
list of patterns that are matched against a connecting clients
|
||||
hostname and IP address. If the pattern matches then the connection is
|
||||
rejected. See the "hosts allow" option for more information.
|
||||
rejected. See the "hosts allow" parameter for more information.
|
||||
|
||||
The default is no "hosts deny" option, which means all hosts can connect.
|
||||
The default is no "hosts deny" parameter, which means all hosts can connect.
|
||||
|
||||
dit(bf(ignore errors)) The "ignore errors" option tells rsyncd to
|
||||
dit(bf(ignore errors)) This parameter tells rsyncd to
|
||||
ignore I/O errors on the daemon when deciding whether to run the delete
|
||||
phase of the transfer. Normally rsync skips the bf(--delete) step if any
|
||||
I/O errors have occurred in order to prevent disastrous deletion due
|
||||
to a temporary resource shortage or other I/O error. In some cases this
|
||||
test is counter productive so you can use this option to turn off this
|
||||
test is counter productive so you can use this parameter to turn off this
|
||||
behavior.
|
||||
|
||||
dit(bf(ignore nonreadable)) This tells the rsync daemon to completely
|
||||
@@ -485,14 +483,14 @@ ignore files that are not readable by the user. This is useful for
|
||||
public archives that may have some non-readable files among the
|
||||
directories, and the sysadmin doesn't want those files to be seen at all.
|
||||
|
||||
dit(bf(transfer logging)) The "transfer logging" option enables per-file
|
||||
dit(bf(transfer logging)) This parameter enables per-file
|
||||
logging of downloads and uploads in a format somewhat similar to that
|
||||
used by ftp daemons. The daemon always logs the transfer at the end, so
|
||||
if a transfer is aborted, no mention will be made in the log file.
|
||||
|
||||
If you want to customize the log lines, see the "log format" option.
|
||||
If you want to customize the log lines, see the "log format" parameter.
|
||||
|
||||
dit(bf(log format)) The "log format" option allows you to specify the
|
||||
dit(bf(log format)) This parameter allows you to specify the
|
||||
format used for logging file transfers when transfer logging is enabled.
|
||||
The format is a text string containing embedded single-character escape
|
||||
sequences prefixed with a percent (%) character. An optional numeric
|
||||
@@ -500,7 +498,7 @@ field width may also be specified between the percent and the escape
|
||||
letter (e.g. "bf(%-50n %8l %07p)").
|
||||
|
||||
The default log format is "%o %h [%a] %m (%u) %f %l", and a "%t [%p] "
|
||||
is always prefixed when using the "log file" option.
|
||||
is always prefixed when using the "log file" parameter.
|
||||
(A perl script that will summarize this default log format is included
|
||||
in the rsync source code distribution in the "support" subdirectory:
|
||||
rsyncstats.)
|
||||
@@ -511,7 +509,7 @@ quote(itemization(
|
||||
it() %a the remote IP address
|
||||
it() %b the number of bytes actually transferred
|
||||
it() %B the permission bits of the file (e.g. rwxrwxrwt)
|
||||
it() %c the checksum bytes received for this file (only when sending)
|
||||
it() %c the total size of the block checksums received for the basis file (only when sending)
|
||||
it() %f the filename (long form on sender; no trailing "/")
|
||||
it() %G the gid of the file (decimal) or "DEFAULT"
|
||||
it() %h the remote host name
|
||||
@@ -536,14 +534,14 @@ Note that some of the logged output changes when talking with older
|
||||
rsync versions. For instance, deleted files were only output as verbose
|
||||
messages prior to rsync 2.6.4.
|
||||
|
||||
dit(bf(timeout)) The "timeout" option allows you to override the
|
||||
clients choice for I/O timeout for this module. Using this option you
|
||||
dit(bf(timeout)) This parameter allows you to override the
|
||||
clients choice for I/O timeout for this module. Using this parameter you
|
||||
can ensure that rsync won't wait on a dead client forever. The timeout
|
||||
is specified in seconds. A value of zero means no timeout and is the
|
||||
default. A good choice for anonymous rsync daemons may be 600 (giving
|
||||
a 10 minute timeout).
|
||||
|
||||
dit(bf(refuse options)) The "refuse options" option allows you to
|
||||
dit(bf(refuse options)) This parameter allows you to
|
||||
specify a space-separated list of rsync command line options that will
|
||||
be refused by your rsync daemon.
|
||||
You may specify the full option name, its one-letter abbreviation, or a
|
||||
@@ -566,21 +564,21 @@ you can use "dont compress = *" (see below)
|
||||
instead of "refuse options = compress" to avoid returning an error to a
|
||||
client that requests compression.
|
||||
|
||||
dit(bf(dont compress)) The "dont compress" option allows you to select
|
||||
dit(bf(dont compress)) This parameter allows you to select
|
||||
filenames based on wildcard patterns that should not be compressed
|
||||
when pulling files from the daemon (no analogous option exists to
|
||||
when pulling files from the daemon (no analogous parameter exists to
|
||||
govern the pushing of files to a daemon).
|
||||
Compression is expensive in terms of CPU usage, so it
|
||||
is usually good to not try to compress files that won't compress well,
|
||||
such as already compressed files.
|
||||
|
||||
The "dont compress" option takes a space-separated list of
|
||||
The "dont compress" parameter takes a space-separated list of
|
||||
case-insensitive wildcard patterns. Any source filename matching one
|
||||
of the patterns will not be compressed during transfer.
|
||||
|
||||
See the bf(--skip-compress) option in the bf(rsync)(1) manpage for the list
|
||||
See the bf(--skip-compress) parameter in the bf(rsync)(1) manpage for the list
|
||||
of file suffixes that are not compressed by default. Specifying a value
|
||||
for the "dont compress" option changes the default when the daemon is
|
||||
for the "dont compress" parameter changes the default when the daemon is
|
||||
the sender.
|
||||
|
||||
dit(bf(pre-xfer exec), bf(post-xfer exec)) You may specify a command to be run
|
||||
@@ -702,7 +700,7 @@ url(http://rsync.samba.org/)(http://rsync.samba.org/)
|
||||
|
||||
manpagesection(VERSION)
|
||||
|
||||
This man page is current for version 3.0.0pre10 of rsync.
|
||||
This man page is current for version 3.0.5 of rsync.
|
||||
|
||||
manpagesection(CREDITS)
|
||||
|
||||
|
||||
16
runtests.sh
16
runtests.sh
@@ -154,12 +154,21 @@ fi
|
||||
RSYNC="$rsync_bin $*"
|
||||
#RSYNC="valgrind $rsync_bin $*"
|
||||
|
||||
export POSIXLY_CORRECT TOOLDIR srcdir RSYNC
|
||||
TLS_ARGS=''
|
||||
if egrep '^#define HAVE_LUTIMES 1' config.h >/dev/null; then
|
||||
TLS_ARGS="$TLS_ARGS -l"
|
||||
fi
|
||||
if egrep '#undef CHOWN_MODIFIES_SYMLINK' config.h >/dev/null; then
|
||||
TLS_ARGS="$TLS_ARGS -L"
|
||||
fi
|
||||
|
||||
export POSIXLY_CORRECT TOOLDIR srcdir RSYNC TLS_ARGS
|
||||
|
||||
echo "============================================================"
|
||||
echo "$0 running in $TOOLDIR"
|
||||
echo " rsync_bin=$RSYNC"
|
||||
echo " srcdir=$srcdir"
|
||||
echo " TLS_ARGS=$TLS_ARGS"
|
||||
|
||||
if [ -f /usr/bin/whoami ]; then
|
||||
testuser=`/usr/bin/whoami`
|
||||
@@ -229,7 +238,10 @@ prep_scratch() {
|
||||
# Get rid of default ACLs and dir-setgid to avoid confusing some tests.
|
||||
$setfacl_nodef "$scratchdir" || true
|
||||
chmod g-s "$scratchdir"
|
||||
ln -s "$srcdir" "$scratchdir/src"
|
||||
case "$srcdir" in
|
||||
/*) ln -s "$srcdir" "$scratchdir/src" ;;
|
||||
*) ln -s "$TOOLDIR/$srcdir" "$scratchdir/src" ;;
|
||||
esac
|
||||
return 0
|
||||
}
|
||||
|
||||
|
||||
18
sender.c
18
sender.c
@@ -3,7 +3,7 @@
|
||||
*
|
||||
* Copyright (C) 1996 Andrew Tridgell
|
||||
* Copyright (C) 1996 Paul Mackerras
|
||||
* Copyright (C) 2003-2007 Wayne Davison
|
||||
* Copyright (C) 2003-2008 Wayne Davison
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
@@ -127,15 +127,9 @@ void successful_send(int ndx)
|
||||
if (!remove_source_files)
|
||||
return;
|
||||
|
||||
if (!(flist = flist_for_ndx(ndx))) {
|
||||
rprintf(FERROR,
|
||||
"INTERNAL ERROR: unable to find flist for item %d\n",
|
||||
ndx);
|
||||
return;
|
||||
}
|
||||
|
||||
flist = flist_for_ndx(ndx, "successful_send");
|
||||
file = flist->files[ndx - flist->ndx_start];
|
||||
if (!push_pathname(F_PATHNAME(file), -1))
|
||||
if (!change_pathname(file, NULL, 0))
|
||||
return;
|
||||
f_name(file, fname);
|
||||
|
||||
@@ -221,7 +215,7 @@ void send_files(int f_in, int f_out)
|
||||
} else {
|
||||
path = slash = "";
|
||||
}
|
||||
if (!push_pathname(F_PATHNAME(file), -1))
|
||||
if (!change_pathname(file, NULL, 0))
|
||||
continue;
|
||||
f_name(file, fname);
|
||||
|
||||
@@ -281,7 +275,7 @@ void send_files(int f_in, int f_out)
|
||||
|
||||
if (!(s = receive_sums(f_in))) {
|
||||
io_error |= IOERR_GENERAL;
|
||||
rprintf(FERROR, "receive_sums failed\n");
|
||||
rprintf(FERROR_XFER, "receive_sums failed\n");
|
||||
exit_cleanup(RERR_PROTOCOL);
|
||||
}
|
||||
|
||||
@@ -309,7 +303,7 @@ void send_files(int f_in, int f_out)
|
||||
/* map the local file */
|
||||
if (do_fstat(fd, &st) != 0) {
|
||||
io_error |= IOERR_GENERAL;
|
||||
rsyserr(FERROR, errno, "fstat failed");
|
||||
rsyserr(FERROR_XFER, errno, "fstat failed");
|
||||
free_sums(s);
|
||||
close(fd);
|
||||
exit_cleanup(RERR_PROTOCOL);
|
||||
|
||||
28
socket.c
28
socket.c
@@ -3,7 +3,7 @@
|
||||
*
|
||||
* Copyright (C) 1992-2001 Andrew Tridgell <tridge@samba.org>
|
||||
* Copyright (C) 2001, 2002 Martin Pool <mbp@samba.org>
|
||||
* Copyright (C) 2003-2007 Wayne Davison
|
||||
* Copyright (C) 2003-2008 Wayne Davison
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
@@ -31,6 +31,7 @@
|
||||
#include <netinet/tcp.h>
|
||||
|
||||
extern char *bind_address;
|
||||
extern char *sockopts;
|
||||
extern int default_af_hint;
|
||||
extern int connect_timeout;
|
||||
|
||||
@@ -272,6 +273,7 @@ int open_socket_out(char *host, int port, const char *bind_addr,
|
||||
alarm(connect_timeout);
|
||||
}
|
||||
|
||||
set_socket_options(s, sockopts);
|
||||
while (connect(s, res->ai_addr, res->ai_addrlen) < 0) {
|
||||
if (connect_timeout < 0)
|
||||
exit_cleanup(RERR_CONTIMEOUT);
|
||||
@@ -433,6 +435,10 @@ static int *open_socket_in(int type, int port, const char *bind_addr,
|
||||
|
||||
setsockopt(s, SOL_SOCKET, SO_REUSEADDR,
|
||||
(char *)&one, sizeof one);
|
||||
if (sockopts)
|
||||
set_socket_options(s, sockopts);
|
||||
else
|
||||
set_socket_options(s, lp_socket_options());
|
||||
|
||||
#ifdef IPV6_V6ONLY
|
||||
if (resp->ai_family == AF_INET6) {
|
||||
@@ -817,6 +823,7 @@ static int socketpair_tcp(int fd[2])
|
||||
**/
|
||||
int sock_exec(const char *prog)
|
||||
{
|
||||
pid_t pid;
|
||||
int fd[2];
|
||||
|
||||
if (socketpair_tcp(fd) != 0) {
|
||||
@@ -825,14 +832,23 @@ int sock_exec(const char *prog)
|
||||
}
|
||||
if (verbose >= 2)
|
||||
rprintf(FINFO, "Running socket program: \"%s\"\n", prog);
|
||||
if (fork() == 0) {
|
||||
|
||||
pid = fork();
|
||||
if (pid < 0) {
|
||||
rsyserr(FERROR, errno, "fork");
|
||||
exit_cleanup(RERR_IPC);
|
||||
}
|
||||
|
||||
if (pid == 0) {
|
||||
close(fd[0]);
|
||||
close(0);
|
||||
close(1);
|
||||
dup(fd[1]);
|
||||
dup(fd[1]);
|
||||
if (dup2(fd[1], STDIN_FILENO) < 0
|
||||
|| dup2(fd[1], STDOUT_FILENO) < 0) {
|
||||
fprintf(stderr, "Failed to run \"%s\"\n", prog);
|
||||
exit(1);
|
||||
}
|
||||
exit(system(prog));
|
||||
}
|
||||
|
||||
close(fd[1]);
|
||||
return fd[0];
|
||||
}
|
||||
|
||||
@@ -6,35 +6,49 @@
|
||||
# more details and some important caveats!**
|
||||
|
||||
use strict;
|
||||
use warnings;
|
||||
use Cwd 'abs_path';
|
||||
|
||||
my $RSYNC_PROG = '/usr/bin/rsync';
|
||||
my $RM_PROG = '/bin/rm';
|
||||
|
||||
my $dest_dir = $ARGV[-1];
|
||||
usage(1) if $dest_dir eq '' || $dest_dir =~ /^--/;
|
||||
&usage if !defined $dest_dir || $dest_dir =~ /(^-|^$)/ || grep(/^--help/, @ARGV);
|
||||
$dest_dir =~ s{(?<=.)/+$} {};
|
||||
|
||||
if (!-d $dest_dir) {
|
||||
print STDERR "$dest_dir is not a directory.\n\n";
|
||||
usage(1);
|
||||
die "$dest_dir is not a directory.\nUse --help for help.\n";
|
||||
}
|
||||
|
||||
if (@_ = grep(/^--(link|compare)-dest/, @ARGV)) {
|
||||
if (@_ = grep(/^--[a-z]+-dest\b/, @ARGV)) {
|
||||
$_ = join(' or ', @_);
|
||||
print STDERR "You may not use $_ as an rsync option.\n\n";
|
||||
usage(1);
|
||||
die "You cannot use the $_ option with atomic-rsync.\nUse --help for help.\n";
|
||||
}
|
||||
|
||||
my $symlink_content = readlink $dest_dir; # undef when a real dir
|
||||
|
||||
my $dest_arg = $dest_dir;
|
||||
# This gives us the real destination dir, with all symlinks dereferenced.
|
||||
$dest_dir = abs_path($dest_dir);
|
||||
if ($dest_dir eq '/') {
|
||||
print STDERR 'You must not use "/" as the destination directory.', "\n\n";
|
||||
usage(1);
|
||||
die qq|You must not use "/" as the destination directory.\nUse --help for help.\n|;
|
||||
}
|
||||
|
||||
my $old_dir = "$dest_dir~old~";
|
||||
my $new_dir = $ARGV[-1] = "$dest_dir~new~";
|
||||
my($old_dir, $new_dir);
|
||||
if (defined $symlink_content && $dest_dir =~ /-([12])$/) {
|
||||
my $num = 3 - $1;
|
||||
$old_dir = undef;
|
||||
($new_dir = $dest_dir) =~ s/-[12]$/-$num/;
|
||||
$symlink_content =~ s/-[12]$/-$num/;
|
||||
} else {
|
||||
$old_dir = "$dest_dir~old~";
|
||||
$new_dir = "$dest_dir~new~";
|
||||
}
|
||||
|
||||
system($RM_PROG, '-rf', $old_dir) if -d $old_dir;
|
||||
$ARGV[-1] = "$new_dir/";
|
||||
|
||||
system($RM_PROG, '-rf', $old_dir) if defined $old_dir && -d $old_dir;
|
||||
system($RM_PROG, '-rf', $new_dir) if -d $new_dir;
|
||||
|
||||
if (system($RSYNC_PROG, "--link-dest=$dest_dir", @ARGV)) {
|
||||
if ($? == -1) {
|
||||
@@ -48,17 +62,30 @@ if (system($RSYNC_PROG, "--link-dest=$dest_dir", @ARGV)) {
|
||||
exit $?;
|
||||
}
|
||||
|
||||
rename($dest_dir, $old_dir) or die "Unable to rename $new_dir to $old_dir: $!";
|
||||
if (!defined $old_dir) {
|
||||
atomic_symlink($symlink_content, $dest_arg);
|
||||
exit;
|
||||
}
|
||||
|
||||
rename($dest_dir, $old_dir) or die "Unable to rename $dest_dir to $old_dir: $!";
|
||||
rename($new_dir, $dest_dir) or die "Unable to rename $new_dir to $dest_dir: $!";
|
||||
|
||||
exit;
|
||||
|
||||
sub atomic_symlink
|
||||
{
|
||||
my($target, $link) = @_;
|
||||
my $newlink = "$link~new~";
|
||||
|
||||
unlink($newlink); # Just in case
|
||||
symlink($target, $newlink) or die "Unable to symlink $newlink -> $target: $!\n";
|
||||
rename($newlink, $link) or die "Unable to rename $newlink to $link: $!\n";
|
||||
}
|
||||
|
||||
|
||||
sub usage
|
||||
{
|
||||
my($ret) = @_;
|
||||
my $fh = $ret ? *STDERR : *STDOUT;
|
||||
print $fh <<EOT;
|
||||
die <<EOT;
|
||||
Usage: atomic-rsync [RSYNC-OPTIONS] HOST:/SOURCE/DIR/ /DEST/DIR/
|
||||
atomic-rsync [RSYNC-OPTIONS] HOST::MOD/DIR/ /DEST/DIR/
|
||||
|
||||
@@ -67,24 +94,29 @@ creating a new hierarchy (using hard-links to leverage the existing files),
|
||||
and then swapping the new hierarchy into place. You must be pulling files
|
||||
to a local directory, and that directory must already exist. For example:
|
||||
|
||||
mkdir /local/files-1
|
||||
ln -s files-1 /local/files
|
||||
atomic-rsync -av host:/remote/files/ /local/files/
|
||||
|
||||
This would make the transfer to the directory /local/files~new~ and then
|
||||
swap out /local/files at the end of the transfer by renaming it to
|
||||
/local/files~old~ and putting the new directory into its place. The
|
||||
/local/files~old~ directory will be preserved until the next update, at
|
||||
which point it will be deleted.
|
||||
If /local/files is a symlink to a directory that ends in -1 or -2, the
|
||||
copy will go to the alternate suffix and the symlink will be changed to
|
||||
point to the new dir. This is a fully atomic update. If the destination
|
||||
is not a symlink (or not a symlink to a *-1 or a *-2 directory), this
|
||||
will instead create a directory with "~new~" suffixed, move the current
|
||||
directory to a name with "~old~" suffixed, and then move the ~new~
|
||||
directory to the original destination name (this double rename is not
|
||||
fully atomic, but is rapid). In both cases, the prior destintaion
|
||||
directory will be preserved until the next update, at which point it
|
||||
will be deleted.
|
||||
|
||||
Do NOT specify this command:
|
||||
In all likelihood, you do NOT want to specify this command:
|
||||
|
||||
atomic-rsync -av host:/remote/files /local/
|
||||
|
||||
... UNLESS you want the entire /local dir to be swapped out!
|
||||
|
||||
See the "rsync" command for its list of options. You may not use the
|
||||
--link-dest or --compare-dest options (since this script uses --link-dest
|
||||
to make the transfer efficient). Also, the destination directory cannot
|
||||
be "/".
|
||||
--link-dest, --compare-dest, or --copy-dest options (since this script
|
||||
uses --link-dest to make the transfer efficient).
|
||||
EOT
|
||||
exit $ret;
|
||||
}
|
||||
|
||||
36
support/deny-rsync
Executable file
36
support/deny-rsync
Executable file
@@ -0,0 +1,36 @@
|
||||
#!/bin/bash
|
||||
# Send an error message via the rsync-protocol to a non-daemon client rsync.
|
||||
#
|
||||
# Usage: deny-rsync "message"
|
||||
|
||||
protocol_version=29
|
||||
exit_code=4 # same as a daemon that refuses an option
|
||||
|
||||
# e.g. byte_escape 29 => \035
|
||||
function byte_escape {
|
||||
echo -ne "\\0$(printf "%o" $1)"
|
||||
}
|
||||
|
||||
msg="$1"
|
||||
if [ "${#msg}" -gt 254 ]; then
|
||||
# truncate a message that is too long for this naive script to handle
|
||||
msg="${msg:0:251}..."
|
||||
fi
|
||||
msglen=$(( ${#msg} + 1 )) # add 1 for the newline we append below
|
||||
|
||||
# Send protocol version. All numbers are LSB-first 4-byte ints.
|
||||
echo -ne "$(byte_escape $protocol_version)\\000\\000\\000"
|
||||
|
||||
# Send a zero checksum seed.
|
||||
echo -ne "\\000\\000\\000\\000"
|
||||
|
||||
# The following is equivalent to rprintf(FERROR_XFER, "%s\n", $msg).
|
||||
# 1. Message header: ((MPLEX_BASE + FERROR_XFER) << 24) + $msglen.
|
||||
echo -ne "$(byte_escape $msglen)\\000\\000\\010"
|
||||
# 2. The actual data.
|
||||
echo -E "$msg"
|
||||
|
||||
# Make sure the client gets our message, not a write failure.
|
||||
sleep 1
|
||||
|
||||
exit $exit_code
|
||||
22
support/lsh
22
support/lsh
@@ -6,18 +6,30 @@
|
||||
# we get a -l USER option, we try to use "sudo -u USER" to run the
|
||||
# command.
|
||||
|
||||
user=''
|
||||
prefix=''
|
||||
|
||||
cd # Default path is home dir, just like ssh.
|
||||
do_cd=y # Default path is user's home dir, just like ssh.
|
||||
|
||||
while : ; do
|
||||
case "$1" in
|
||||
-l) shift ; prefix="sudo -u $1"; shift ;;
|
||||
-l*) prefix=`echo $1 | sed 's/-l/sudo -u /'`; shift ;;
|
||||
-l) user="$2"; shift; shift ;;
|
||||
-l*) user=`echo $1 | sed 's/^-l//'`; shift ;;
|
||||
--no-cd) do_cd=n; shift ;;
|
||||
-*) shift ;;
|
||||
localhost) shift; break ;;
|
||||
*) exit 1 ;;
|
||||
*) echo "lsh: unable to connect to host $1" 1>&2; exit 1 ;;
|
||||
esac
|
||||
done
|
||||
|
||||
if [ "$user" ]; then
|
||||
prefix="sudo -H -u $user"
|
||||
if [ $do_cd = y ]; then
|
||||
home=`perl -e "print((getpwnam("$user"))[7])"`
|
||||
# Yeah, this may fail, but attempts to get sudo to cd are harder.
|
||||
cd $home
|
||||
fi
|
||||
elif [ $do_cd = y ]; then
|
||||
cd
|
||||
fi
|
||||
|
||||
eval $prefix "${@}"
|
||||
|
||||
@@ -39,6 +39,7 @@ die "$0: Restricted directory does not exist!\n" if $subdir ne '/' && !-d $subdi
|
||||
my $command = $ENV{SSH_ORIGINAL_COMMAND};
|
||||
die "$0: Not invoked via sshd\n$Usage" unless defined $command;
|
||||
die "$0: SSH_ORIGINAL_COMMAND='$command' is not rsync\n" unless $command =~ s/^rsync\s+//;
|
||||
die "$0: --server option is not first\n" unless $command =~ /^--server\s/;
|
||||
our $am_sender = $command =~ /^--server\s+--sender\s/; # Restrictive on purpose!
|
||||
die "$0 -ro: sending to read-only server not allowed\n" if $ro && !$am_sender;
|
||||
|
||||
@@ -65,7 +66,7 @@ our %long_opt = (
|
||||
'compress-level' => 1,
|
||||
'copy-dest' => 2,
|
||||
'copy-unsafe-links' => 0,
|
||||
'daemon' => 0,
|
||||
'daemon' => -1,
|
||||
'delay-updates' => 0,
|
||||
'delete' => 0,
|
||||
'delete-after' => 0,
|
||||
@@ -74,6 +75,7 @@ our %long_opt = (
|
||||
'delete-during' => 0,
|
||||
'delete-excluded' => 0,
|
||||
'existing' => 0,
|
||||
'fake-super' => 0,
|
||||
'files-from' => 3,
|
||||
'force' => 0,
|
||||
'from0' => 0,
|
||||
@@ -84,6 +86,7 @@ our %long_opt = (
|
||||
'inplace' => 0,
|
||||
'link-dest' => 2,
|
||||
'list-only' => 0,
|
||||
'log-file' => 3,
|
||||
'log-format' => 1,
|
||||
'max-delete' => 1,
|
||||
'max-size' => 1,
|
||||
@@ -110,6 +113,7 @@ our %long_opt = (
|
||||
'super' => 0,
|
||||
'temp-dir' => 2,
|
||||
'timeout' => 1,
|
||||
'use-qsort' => 0,
|
||||
);
|
||||
|
||||
### END of options data produced by the cull_options script. ###
|
||||
@@ -139,7 +143,7 @@ while ($command =~ /((?:[^\s\\]+|\\.[^\s\\]*)+)/g) {
|
||||
if ($_ eq '.') {
|
||||
$in_options = 0;
|
||||
} else {
|
||||
next if /^-$short_no_arg+(e\d+\.\d+)?$/o || /^-$short_with_num\d+$/o;
|
||||
next if /^-$short_no_arg+(e\d*\.\w*)?$/o || /^-$short_with_num\d+$/o;
|
||||
|
||||
my($opt,$arg) = /^--([^=]+)(?:=(.*))?$/;
|
||||
my $disabled;
|
||||
|
||||
15
syscall.c
15
syscall.c
@@ -4,7 +4,7 @@
|
||||
*
|
||||
* Copyright (C) 1998 Andrew Tridgell
|
||||
* Copyright (C) 2002 Martin Pool
|
||||
* Copyright (C) 2003-2007 Wayne Davison
|
||||
* Copyright (C) 2003-2008 Wayne Davison
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
@@ -167,9 +167,9 @@ int do_chmod(const char *path, mode_t mode)
|
||||
code = 1;
|
||||
#endif
|
||||
} else
|
||||
code = chmod(path, mode & CHMOD_BITS);
|
||||
code = chmod(path, mode & CHMOD_BITS); /* DISCOURAGED FUNCTION */
|
||||
if (code != 0 && (preserve_perms || preserve_executability))
|
||||
return code;
|
||||
return code;
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
@@ -282,12 +282,3 @@ OFF_T do_lseek(int fd, OFF_T offset, int whence)
|
||||
return lseek(fd, offset, whence);
|
||||
#endif
|
||||
}
|
||||
|
||||
char *d_name(struct dirent *di)
|
||||
{
|
||||
#ifdef HAVE_BROKEN_READDIR
|
||||
return (di->d_name - 2);
|
||||
#else
|
||||
return di->d_name;
|
||||
#endif
|
||||
}
|
||||
|
||||
14
t_stub.c
14
t_stub.c
@@ -3,7 +3,7 @@
|
||||
* functions, so that module test harnesses can run standalone.
|
||||
*
|
||||
* Copyright (C) 2001, 2002 Martin Pool <mbp@samba.org>
|
||||
* Copyright (C) 2003-2007 Wayne Davison
|
||||
* Copyright (C) 2003-2008 Wayne Davison
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
@@ -26,10 +26,11 @@ int module_id = -1;
|
||||
int relative_paths = 0;
|
||||
int human_readable = 0;
|
||||
int module_dirlen = 0;
|
||||
int preserve_xattrs = 0;
|
||||
mode_t orig_umask = 002;
|
||||
char *partial_dir;
|
||||
char *module_dir;
|
||||
struct filter_list_struct server_filter_list;
|
||||
struct filter_list_struct daemon_filter_list;
|
||||
|
||||
void rprintf(UNUSED(enum logcode code), const char *format, ...)
|
||||
{
|
||||
@@ -56,8 +57,8 @@ struct filter_list_struct server_filter_list;
|
||||
exit(code);
|
||||
}
|
||||
|
||||
int check_filter(UNUSED(struct filter_list_struct *listp), UNUSED(char *name),
|
||||
UNUSED(int name_is_dir))
|
||||
int check_filter(UNUSED(struct filter_list_struct *listp), UNUSED(enum logcode code),
|
||||
UNUSED(const char *name), UNUSED(int name_is_dir))
|
||||
{
|
||||
/* This function doesn't really get called in this test context, so
|
||||
* just return 0. */
|
||||
@@ -69,6 +70,11 @@ struct filter_list_struct server_filter_list;
|
||||
return -1;
|
||||
}
|
||||
|
||||
int copy_xattrs(UNUSED(const char *source), UNUSED(const char *dest))
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
char *lp_name(UNUSED(int mod))
|
||||
{
|
||||
return NULL;
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
* Test harness for unsafe_symlink(). Not linked into rsync itself.
|
||||
*
|
||||
* Copyright (C) 2002 Martin Pool
|
||||
* Copyright (C) 2003-2007 Wayne Davison
|
||||
* Copyright (C) 2003-2008 Wayne Davison
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
|
||||
@@ -36,7 +36,7 @@ for fn in deep/name1 deep/name2; do
|
||||
done
|
||||
|
||||
echo deleted-file >"$todir/dname"
|
||||
cp -p "$todir/dname" "$chkdir"
|
||||
cp_touch "$todir/dname" "$chkdir"
|
||||
|
||||
checkit "$RSYNC -avv --no-whole-file --delete-delay \
|
||||
--backup --backup-dir='$bakdir' '$fromdir/' '$todir/'" "$fromdir" "$todir" \
|
||||
|
||||
@@ -41,6 +41,8 @@ runtest "--read-batch from daemon" 'checkit "$RSYNC -av --read-batch=BATCH \"$to
|
||||
rm -rf "$todir"
|
||||
runtest "BATCH.sh use of --read-batch" 'checkit "./BATCH.sh" "$chkdir" "$todir"'
|
||||
|
||||
runtest "do-nothing re-run of 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 "\"$ignore23\" $RSYNC -av --write-batch=BATCH \"$fromdir/\" rsync://localhost/test-to" "$chkdir" "$todir"'
|
||||
|
||||
@@ -17,7 +17,7 @@ case $0 in
|
||||
*fake*)
|
||||
$RSYNC --version | grep ", xattrs" >/dev/null || test_skipped "Rsync needs xattrs for fake device tests"
|
||||
RSYNC="$RSYNC --fake-super"
|
||||
TLS_ARGS=--fake-super
|
||||
TLS_ARGS="$TLS_ARGS --fake-super"
|
||||
case "`xattr 2>&1`" in
|
||||
*--list:*)
|
||||
chown() {
|
||||
|
||||
@@ -19,14 +19,72 @@
|
||||
# checking the log file
|
||||
# password authentication
|
||||
|
||||
# TODO: Put the common framework in a common file, so that we can have
|
||||
# subtests fail and keep going.
|
||||
|
||||
. "$suitedir/rsync.fns"
|
||||
|
||||
chkfile="$scratchdir/rsync.chk"
|
||||
outfile="$scratchdir/rsync.out"
|
||||
|
||||
SSH="src/support/lsh --no-cd"
|
||||
FILE_REPL='s/^\([^d][^ ]*\) *\(..........[0-9]\) /\1 \2 /'
|
||||
DIR_REPL='s/^\(d[^ ]*\) *[0-9][0-9]* /\1 DIR /'
|
||||
LS_REPL='s;[0-9][0-9][0-9][0-9]/[0-9][0-9]/[0-9][0-9] [0-9][0-9]:[0-9][0-9]:[0-9][0-9];####/##/## ##:##:##;'
|
||||
|
||||
build_rsyncd_conf
|
||||
|
||||
makepath "$fromdir/foo" "$fromdir/bar/baz"
|
||||
makepath "$todir"
|
||||
echo one >"$fromdir/foo/one"
|
||||
echo two >"$fromdir/bar/two"
|
||||
echo three >"$fromdir/bar/baz/three"
|
||||
|
||||
cd "$scratchdir"
|
||||
|
||||
ln -s test-rsyncd.conf rsyncd.conf
|
||||
|
||||
confopt=''
|
||||
case `id -u` in
|
||||
0)
|
||||
# Root needs to specify the config file, or it uses /etc/rsyncd.conf.
|
||||
echo "Forcing --config=$conf"
|
||||
confopt=" --config=$conf"
|
||||
;;
|
||||
esac
|
||||
|
||||
$RSYNC -ve "$SSH" --rsync-path="$RSYNC$confopt" localhost::
|
||||
|
||||
RSYNC_CONNECT_PROG="$RSYNC --config=$conf --daemon"
|
||||
export RSYNC_CONNECT_PROG
|
||||
|
||||
$RSYNC -v localhost::
|
||||
$RSYNC -v localhost:: \
|
||||
| tee "$outfile"
|
||||
# These have a space-padded 15-char name, then a tab, then a comment.
|
||||
sed 's/NOCOMMENT//' <<EOT >"$chkfile"
|
||||
test-from r/o
|
||||
test-to r/w
|
||||
test-scratch NOCOMMENT
|
||||
EOT
|
||||
diff $diffopt "$chkfile" "$outfile" || test_fail "test 1 failed"
|
||||
|
||||
$RSYNC -r localhost::test-hidden \
|
||||
| sed "$FILE_REPL" | sed "$DIR_REPL" | sed "$LS_REPL" \
|
||||
| tee "$outfile"
|
||||
cat <<EOT >"$chkfile"
|
||||
drwxr-xr-x DIR ####/##/## ##:##:## .
|
||||
drwxr-xr-x DIR ####/##/## ##:##:## bar
|
||||
-rw-r--r-- 4 ####/##/## ##:##:## bar/two
|
||||
drwxr-xr-x DIR ####/##/## ##:##:## bar/baz
|
||||
-rw-r--r-- 6 ####/##/## ##:##:## bar/baz/three
|
||||
drwxr-xr-x DIR ####/##/## ##:##:## foo
|
||||
-rw-r--r-- 4 ####/##/## ##:##:## foo/one
|
||||
EOT
|
||||
diff $diffopt "$chkfile" "$outfile" || test_fail "test 2 failed"
|
||||
|
||||
$RSYNC -r localhost::test-from/f* \
|
||||
| sed "$FILE_REPL" | sed "$DIR_REPL" | sed "$LS_REPL" \
|
||||
| tee "$outfile"
|
||||
cat <<EOT >"$chkfile"
|
||||
drwxr-xr-x DIR ####/##/## ##:##:## foo
|
||||
-rw-r--r-- 4 ####/##/## ##:##:## foo/one
|
||||
EOT
|
||||
diff $diffopt "$chkfile" "$outfile" || test_fail "test 3 failed"
|
||||
|
||||
|
||||
@@ -18,7 +18,7 @@ case $0 in
|
||||
*fake*)
|
||||
$RSYNC --version | grep ", xattrs" >/dev/null || test_skipped "Rsync needs xattrs for fake device tests"
|
||||
RSYNC="$RSYNC --fake-super"
|
||||
TLS_ARGS=--fake-super
|
||||
TLS_ARGS="$TLS_ARGS --fake-super"
|
||||
case "`xattr 2>&1`" in
|
||||
*--list:*)
|
||||
mknod() {
|
||||
@@ -76,19 +76,20 @@ mknod "$fromdir/block2" b 42 73 || test_skipped "Can't create block device node"
|
||||
mknod "$fromdir/block3" b 105 73 || test_skipped "Can't create block device node"
|
||||
ln "$fromdir/block3" "$fromdir/block2.5" || echo "Skipping hard-linked device test..."
|
||||
mkfifo "$fromdir/fifo" || mknod "$fromdir/fifo" p || test_skipped "Can't run mkfifo"
|
||||
touch -r "$fromdir/block" "$fromdir/block2"
|
||||
# Work around time rounding/truncating issue by touching both files.
|
||||
touch -r "$fromdir/block" "$fromdir/block" "$fromdir/block2"
|
||||
|
||||
$RSYNC -ai "$fromdir/block" "$todir/block2" \
|
||||
| tee "$outfile"
|
||||
cat <<EOT >"$chkfile"
|
||||
cD+++++++++ block
|
||||
cD$all_plus block
|
||||
EOT
|
||||
diff $diffopt "$chkfile" "$outfile" || test_fail "test 1 failed"
|
||||
|
||||
$RSYNC -ai "$fromdir/block2" "$todir/block" \
|
||||
| tee "$outfile"
|
||||
cat <<EOT >"$chkfile"
|
||||
cD+++++++++ block2
|
||||
cD$all_plus block2
|
||||
EOT
|
||||
diff $diffopt "$chkfile" "$outfile" || test_fail "test 2 failed"
|
||||
|
||||
@@ -97,7 +98,7 @@ sleep 1
|
||||
$RSYNC -Di "$fromdir/block3" "$todir/block" \
|
||||
| tee "$outfile"
|
||||
cat <<EOT >"$chkfile"
|
||||
cD..T...... block3
|
||||
cDc.T.$dots block3
|
||||
EOT
|
||||
diff $diffopt "$chkfile" "$outfile" || test_fail "test 3 failed"
|
||||
|
||||
@@ -105,15 +106,15 @@ $RSYNC -aiHvv "$fromdir/" "$todir/" \
|
||||
| tee "$outfile"
|
||||
filter_outfile
|
||||
cat <<EOT >"$chkfile"
|
||||
.d..t...... ./
|
||||
cD..t...... block
|
||||
cD block2
|
||||
cD+++++++++ block3
|
||||
hD+++++++++ block2.5 => block3
|
||||
cD+++++++++ char
|
||||
cD+++++++++ char2
|
||||
cD+++++++++ char3
|
||||
cS+++++++++ fifo
|
||||
.d..t.$dots ./
|
||||
cDc.t.$dots block
|
||||
cDc...$dots block2
|
||||
cD$all_plus block3
|
||||
hD$all_plus block2.5 => block3
|
||||
cD$all_plus char
|
||||
cD$all_plus char2
|
||||
cD$all_plus char3
|
||||
cS$all_plus fifo
|
||||
EOT
|
||||
if test ! -r "$fromdir/block2.5"; then
|
||||
sed -e '/block2\.5/d' <"$chkfile" >"$chkfile.new"
|
||||
@@ -132,15 +133,15 @@ if test -b "$fromdir/block2.5"; then
|
||||
$RSYNC -aii --link-dest="$todir" "$fromdir/" "$chkdir/" \
|
||||
| tee "$outfile"
|
||||
cat <<EOT >"$chkfile"
|
||||
cd ./
|
||||
hD block
|
||||
hD block2
|
||||
hD block2.5
|
||||
hD block3
|
||||
hD char
|
||||
hD char2
|
||||
hD char3
|
||||
hS fifo
|
||||
cd$allspace ./
|
||||
hD$allspace block
|
||||
hD$allspace block2
|
||||
hD$allspace block2.5
|
||||
hD$allspace block3
|
||||
hD$allspace char
|
||||
hD$allspace char2
|
||||
hD$allspace char3
|
||||
hS$allspace fifo
|
||||
EOT
|
||||
diff $diffopt "$chkfile" "$outfile" || test_fail "test 4 failed"
|
||||
fi
|
||||
|
||||
@@ -153,13 +153,13 @@ checkit "$RSYNC -avvC --filter='merge $excl' --delete-excluded \
|
||||
|
||||
rm "$chkdir"/foo/file1
|
||||
rm "$chkdir"/bar/down/to/bar/baz/*.deep
|
||||
cp -p "$fromdir"/bar/down/to/foo/*.junk "$chkdir"/bar/down/to/foo
|
||||
cp -p "$fromdir"/bar/down/to/foo/to "$chkdir"/bar/down/to/foo
|
||||
cp_touch "$fromdir"/bar/down/to/foo/*.junk "$chkdir"/bar/down/to/foo
|
||||
cp_touch "$fromdir"/bar/down/to/foo/to "$chkdir"/bar/down/to/foo
|
||||
|
||||
$RSYNC -av --existing -f 'show .filt*' -f 'hide,! */' --del "$fromdir/" "$todir/"
|
||||
|
||||
echo retained >"$todir"/bar/down/to/bar/baz/nodel.deep
|
||||
cp -p "$todir"/bar/down/to/bar/baz/nodel.deep "$chkdir"/bar/down/to/bar/baz
|
||||
cp_touch "$todir"/bar/down/to/bar/baz/nodel.deep "$chkdir"/bar/down/to/bar/baz
|
||||
|
||||
$RSYNC -av --existing --filter='-! */' "$fromdir/" "$chkdir/"
|
||||
|
||||
|
||||
30
testsuite/files-from.test
Normal file
30
testsuite/files-from.test
Normal file
@@ -0,0 +1,30 @@
|
||||
#!/bin/sh
|
||||
|
||||
# Copyright (C) 2008 by Wayne Davison <wayned@samba.org>
|
||||
|
||||
# This program is distributable under the terms of the GNU GPL (see
|
||||
# COPYING).
|
||||
|
||||
# Test that --files-from=FILE works right.
|
||||
|
||||
. "$suitedir/rsync.fns"
|
||||
|
||||
hands_setup
|
||||
|
||||
# This list of files skips the contents of "subsubdir" but includes
|
||||
# the contents of "subsubdir2" due to its trailing slash.
|
||||
cat >"$scratchdir/filelist" <<EOT
|
||||
from/./
|
||||
from/./dir/subdir
|
||||
from/./dir/subdir/subsubdir
|
||||
from/./dir/subdir/subsubdir2/
|
||||
from/./dir/subdir/foobar.baz
|
||||
EOT
|
||||
|
||||
# Create a chkdir without the content that we expect to be omitted.
|
||||
$RSYNC -a --exclude=dir/text --exclude='subsubdir/**' "$fromdir/" "$chkdir/"
|
||||
|
||||
checkit "$RSYNC -av --files-from='$scratchdir/filelist' '$scratchdir' '$todir/'" "$chkdir" "$todir"
|
||||
|
||||
# The script would have aborted on error, so getting here means we've won.
|
||||
exit 0
|
||||
@@ -13,7 +13,7 @@ mkdir "$fromdir"
|
||||
mkdir "$todir"
|
||||
|
||||
cp -p "$srcdir"/rsync.c "$fromdir"/rsync.c
|
||||
cp -p "$fromdir"/rsync.c "$todir"/rsync2.c
|
||||
cp_touch "$fromdir"/rsync.c "$todir"/rsync2.c
|
||||
sleep 1
|
||||
|
||||
# Let's do it!
|
||||
|
||||
@@ -11,6 +11,8 @@
|
||||
|
||||
. "$suitedir/rsync.fns"
|
||||
|
||||
SSH="$scratchdir/src/support/lsh"
|
||||
|
||||
outfile="$scratchdir/rsync.out"
|
||||
|
||||
# Build some hardlinks
|
||||
@@ -38,12 +40,23 @@ echo "extra extra" >>"$todir/name1"
|
||||
checkit "$RSYNC -aHivv --no-whole-file '$fromdir/' '$todir/'" "$fromdir" "$todir"
|
||||
|
||||
# Add a new link in a new subdirectory to test that we don't try to link
|
||||
# the files before the directory gets created.
|
||||
mkdir "$fromdir/subdir"
|
||||
ln "$name1" "$fromdir/subdir/new-file"
|
||||
# the files before the directory gets created. We also create a bunch of
|
||||
# extra files to ensure that an incremental-recursion transfer works across
|
||||
# distant files.
|
||||
makepath "$fromdir/subdir/down/deep"
|
||||
|
||||
files=''
|
||||
for x in a b c d e f g h i j k l m n o p q r s t u v w x y z 0 1 2 3 4 5 6 7 8 9; do
|
||||
for y in a b c d e f g h i j k l m n o p q r s t u v w x y z 0 1 2 3 4 5 6 7 8 9; do
|
||||
files="$files $x$y"
|
||||
done
|
||||
done
|
||||
(cd "$fromdir/subdir"; touch $files)
|
||||
|
||||
ln "$name1" "$fromdir/subdir/down/deep/new-file"
|
||||
rm "$todir/text"
|
||||
|
||||
checkit "$RSYNC -aHivv '$fromdir/' '$todir/'" "$fromdir" "$todir"
|
||||
checkit "$RSYNC -aHivve '$SSH' --rsync-path='$RSYNC' '$fromdir/' localhost:'$todir/'" "$fromdir" "$todir"
|
||||
|
||||
# Do some duplicate copies using --link-dest and --copy-dest to test that
|
||||
# we hard-link all locally-inherited items.
|
||||
|
||||
@@ -25,16 +25,14 @@ umask 0
|
||||
ln -s ../bar/baz/rsync "$fromdir/foo/sym"
|
||||
umask 022
|
||||
ln "$fromdir/foo/config1" "$fromdir/foo/extra"
|
||||
rm -f "$to2dir"
|
||||
|
||||
# Check if the OS can hard-link symlinks or not.
|
||||
# (Note: the link we check MUST NOT point to a valid file!)
|
||||
ln -s no-such-dir "$to2dir"
|
||||
if ln "$to2dir" "$to2dir.test" 2>/dev/null; then
|
||||
# Check if rsync is set to hard-link symlinks.
|
||||
if egrep '^#define CAN_HARDLINK_SYMLINK 1' config.h >/dev/null; then
|
||||
L=hL
|
||||
else
|
||||
L=cL
|
||||
fi
|
||||
rm -f "$to2dir" "$to2dir.test"
|
||||
|
||||
# Check if rsync can preserve time on symlinks
|
||||
case "$RSYNC" in
|
||||
@@ -53,15 +51,15 @@ esac
|
||||
$RSYNC -iplr "$fromdir/" "$todir/" \
|
||||
| tee "$outfile"
|
||||
cat <<EOT >"$chkfile"
|
||||
cd+++++++++ ./
|
||||
cd+++++++++ bar/
|
||||
cd+++++++++ bar/baz/
|
||||
>f+++++++++ bar/baz/rsync
|
||||
cd+++++++++ foo/
|
||||
>f+++++++++ foo/config1
|
||||
>f+++++++++ foo/config2
|
||||
>f+++++++++ foo/extra
|
||||
cL+++++++++ foo/sym -> ../bar/baz/rsync
|
||||
cd$all_plus ./
|
||||
cd$all_plus bar/
|
||||
cd$all_plus bar/baz/
|
||||
>f$all_plus bar/baz/rsync
|
||||
cd$all_plus foo/
|
||||
>f$all_plus foo/config1
|
||||
>f$all_plus foo/config2
|
||||
>f$all_plus foo/extra
|
||||
cL$all_plus foo/sym -> ../bar/baz/rsync
|
||||
EOT
|
||||
diff $diffopt "$chkfile" "$outfile" || test_fail "test 1 failed"
|
||||
|
||||
@@ -73,10 +71,10 @@ chmod 601 "$fromdir/foo/config2"
|
||||
$RSYNC -iplrH "$fromdir/" "$todir/" \
|
||||
| tee "$outfile"
|
||||
cat <<EOT >"$chkfile"
|
||||
>f..T...... bar/baz/rsync
|
||||
>f..T...... foo/config1
|
||||
>f.sTp..... foo/config2
|
||||
hf..T...... foo/extra => foo/config1
|
||||
>f..T.$dots bar/baz/rsync
|
||||
>f..T.$dots foo/config1
|
||||
>f.sTp$dots foo/config2
|
||||
hf..T.$dots foo/extra => foo/config1
|
||||
EOT
|
||||
diff $diffopt "$chkfile" "$outfile" || test_fail "test 2 failed"
|
||||
|
||||
@@ -93,11 +91,11 @@ chmod 777 "$todir/bar/baz/rsync"
|
||||
$RSYNC -iplrtc "$fromdir/" "$todir/" \
|
||||
| tee "$outfile"
|
||||
cat <<EOT >"$chkfile"
|
||||
.f..tp..... bar/baz/rsync
|
||||
.d..t...... foo/
|
||||
.f..t...... foo/config1
|
||||
>fcstp..... foo/config2
|
||||
cL.$T...... foo/sym -> ../bar/baz/rsync
|
||||
.f..tp$dots bar/baz/rsync
|
||||
.d..t.$dots foo/
|
||||
.f..t.$dots foo/config1
|
||||
>fcstp$dots foo/config2
|
||||
cLc$T.$dots foo/sym -> ../bar/baz/rsync
|
||||
EOT
|
||||
diff $diffopt "$chkfile" "$outfile" || test_fail "test 3 failed"
|
||||
|
||||
@@ -122,15 +120,15 @@ $RSYNC -ivvplrtH "$fromdir/" "$todir/" \
|
||||
| tee "$outfile"
|
||||
filter_outfile
|
||||
cat <<EOT >"$chkfile"
|
||||
.d ./
|
||||
.d bar/
|
||||
.d bar/baz/
|
||||
.f...p..... bar/baz/rsync
|
||||
.d foo/
|
||||
.f foo/config1
|
||||
>f..t...... foo/config2
|
||||
hf foo/extra
|
||||
.L foo/sym -> ../bar/baz/rsync
|
||||
.d$allspace ./
|
||||
.d$allspace bar/
|
||||
.d$allspace bar/baz/
|
||||
.f...p$dots bar/baz/rsync
|
||||
.d$allspace foo/
|
||||
.f$allspace foo/config1
|
||||
>f..t.$dots foo/config2
|
||||
hf$allspace foo/extra
|
||||
.L$allspace foo/sym -> ../bar/baz/rsync
|
||||
EOT
|
||||
diff $diffopt "$chkfile" "$outfile" || test_fail "test 5 failed"
|
||||
|
||||
@@ -149,8 +147,8 @@ touch "$todir/foo/config2"
|
||||
$RSYNC -iplrtH "$fromdir/" "$todir/" \
|
||||
| tee "$outfile"
|
||||
cat <<EOT >"$chkfile"
|
||||
.f...p..... foo/config1
|
||||
>f..t...... foo/config2
|
||||
.f...p$dots foo/config1
|
||||
>f..t.$dots foo/config2
|
||||
EOT
|
||||
diff $diffopt "$chkfile" "$outfile" || test_fail "test 7 failed"
|
||||
|
||||
@@ -158,29 +156,29 @@ $RSYNC -ivvplrtH --copy-dest=../to "$fromdir/" "$to2dir/" \
|
||||
| tee "$outfile"
|
||||
filter_outfile
|
||||
case `tail -1 "$outfile"` in
|
||||
cL..t*)
|
||||
sym_dots='..t......'
|
||||
L_sym_dots='cL..t......'
|
||||
cLc.t*)
|
||||
sym_dots="c.t.$dots"
|
||||
L_sym_dots="cL$sym_dots"
|
||||
is_uptodate='-> ../bar/baz/rsync'
|
||||
echo "cL$sym_dots foo/sym $is_uptodate" >"$chkfile.extra"
|
||||
L=cL
|
||||
;;
|
||||
*)
|
||||
sym_dots=' '
|
||||
L_sym_dots='.L '
|
||||
sym_dots="$allspace"
|
||||
L_sym_dots=".L$allspace"
|
||||
is_uptodate='is uptodate'
|
||||
touch "$chkfile.extra"
|
||||
;;
|
||||
esac
|
||||
cat <<EOT >"$chkfile"
|
||||
cd ./
|
||||
cd bar/
|
||||
cd bar/baz/
|
||||
cf bar/baz/rsync
|
||||
cd foo/
|
||||
cf foo/config1
|
||||
cf foo/config2
|
||||
hf foo/extra => foo/config1
|
||||
cd$allspace ./
|
||||
cd$allspace bar/
|
||||
cd$allspace bar/baz/
|
||||
cf$allspace bar/baz/rsync
|
||||
cd$allspace foo/
|
||||
cf$allspace foo/config1
|
||||
cf$allspace foo/config2
|
||||
hf$allspace foo/extra => foo/config1
|
||||
cL$sym_dots foo/sym -> ../bar/baz/rsync
|
||||
EOT
|
||||
diff $diffopt "$chkfile" "$outfile" || test_fail "test 8 failed"
|
||||
@@ -189,7 +187,7 @@ rm -rf "$to2dir"
|
||||
$RSYNC -iplrtH --copy-dest=../to "$fromdir/" "$to2dir/" \
|
||||
| tee "$outfile"
|
||||
cat - "$chkfile.extra" <<EOT >"$chkfile"
|
||||
hf foo/extra => foo/config1
|
||||
hf$allspace foo/extra => foo/config1
|
||||
EOT
|
||||
diff $diffopt "$chkfile" "$outfile" || test_fail "test 9 failed"
|
||||
|
||||
@@ -215,14 +213,14 @@ $RSYNC -ivvplrtH --link-dest="$todir" "$fromdir/" "$to2dir/" \
|
||||
| tee "$outfile"
|
||||
filter_outfile
|
||||
cat <<EOT >"$chkfile"
|
||||
cd ./
|
||||
cd bar/
|
||||
cd bar/baz/
|
||||
hf bar/baz/rsync
|
||||
cd foo/
|
||||
hf foo/config1
|
||||
hf foo/config2
|
||||
hf foo/extra => foo/config1
|
||||
cd$allspace ./
|
||||
cd$allspace bar/
|
||||
cd$allspace bar/baz/
|
||||
hf$allspace bar/baz/rsync
|
||||
cd$allspace foo/
|
||||
hf$allspace foo/config1
|
||||
hf$allspace foo/config2
|
||||
hf$allspace foo/extra => foo/config1
|
||||
$L$sym_dots foo/sym -> ../bar/baz/rsync
|
||||
EOT
|
||||
diff $diffopt "$chkfile" "$outfile" || test_fail "test 11 failed"
|
||||
@@ -263,14 +261,14 @@ $RSYNC -ivvplrtH --compare-dest="$todir" "$fromdir/" "$to2dir/" \
|
||||
| tee "$outfile"
|
||||
filter_outfile
|
||||
cat <<EOT >"$chkfile"
|
||||
cd ./
|
||||
cd bar/
|
||||
cd bar/baz/
|
||||
.f bar/baz/rsync
|
||||
cd foo/
|
||||
.f foo/config1
|
||||
.f foo/config2
|
||||
.f foo/extra
|
||||
cd$allspace ./
|
||||
cd$allspace bar/
|
||||
cd$allspace bar/baz/
|
||||
.f$allspace bar/baz/rsync
|
||||
cd$allspace foo/
|
||||
.f$allspace foo/config1
|
||||
.f$allspace foo/config2
|
||||
.f$allspace foo/extra
|
||||
$L_sym_dots foo/sym -> ../bar/baz/rsync
|
||||
EOT
|
||||
diff $diffopt "$chkfile" "$outfile" || test_fail "test 15 failed"
|
||||
|
||||
@@ -19,15 +19,15 @@ mkdir from2/sub1 from3/sub1
|
||||
mkdir from3/sub2 from1/dir-and-not-dir
|
||||
mkdir chk chk/sub1 chk/sub2 chk/dir-and-not-dir
|
||||
echo "one" >from1/one
|
||||
cp -p from1/one from2/one
|
||||
cp -p from1/one from3/one
|
||||
cp_touch from1/one from2/one
|
||||
cp_touch from1/one from3/one
|
||||
echo "two" >from1/two
|
||||
echo "three" >from2/three
|
||||
echo "four" >from3/four
|
||||
echo "five" >from1/five
|
||||
echo "six" >from3/six
|
||||
echo "sub1" >from2/sub1/uno
|
||||
cp -p from2/sub1/uno from3/sub1/uno
|
||||
cp_touch from2/sub1/uno from3/sub1/uno
|
||||
echo "sub2" >from3/sub1/dos
|
||||
echo "sub3" >from2/sub1/tres
|
||||
echo "subby" >from3/sub2/subby
|
||||
@@ -36,11 +36,11 @@ echo "not-dir" >from3/dir-and-not-dir
|
||||
echo "arg-test" >deep/arg-test
|
||||
echo "shallow" >shallow
|
||||
|
||||
cp -p from1/one from1/two from2/three from3/four from1/five from3/six chk
|
||||
cp -p deep/arg-test shallow chk
|
||||
cp -p from1/dir-and-not-dir/inside chk/dir-and-not-dir
|
||||
cp -p from2/sub1/uno from3/sub1/dos from2/sub1/tres chk/sub1
|
||||
cp -p from3/sub2/subby chk/sub2
|
||||
cp_touch from1/one from1/two from2/three from3/four from1/five from3/six chk
|
||||
cp_touch deep/arg-test shallow chk
|
||||
cp_touch from1/dir-and-not-dir/inside chk/dir-and-not-dir
|
||||
cp_touch from2/sub1/uno from3/sub1/dos from2/sub1/tres chk/sub1
|
||||
cp_touch from3/sub2/subby chk/sub2
|
||||
|
||||
# Make sure that time has moved on.
|
||||
sleep 1
|
||||
@@ -51,7 +51,7 @@ $RSYNC -av --existing -f 'exclude,! */' from2/ from3/
|
||||
$RSYNC -av --existing -f 'exclude,! */' from1/ chk/
|
||||
$RSYNC -av --existing -f 'exclude,! */' from3/ chk/
|
||||
|
||||
checkit "$RSYNC -avv deep/arg-test shallow from1/ from2/ from3/ to/" chk to
|
||||
checkit "$RSYNC -avv deep/arg-test shallow from1/ from2/ from3/ to/" "$chkdir" "$todir"
|
||||
|
||||
# The script would have aborted on error, so getting here means we've won.
|
||||
exit 0
|
||||
|
||||
27
testsuite/missing.test
Normal file
27
testsuite/missing.test
Normal file
@@ -0,0 +1,27 @@
|
||||
#! /bin/sh
|
||||
|
||||
# This program is distributable under the terms of the GNU GPL (see
|
||||
# COPYING).
|
||||
|
||||
# Test three bugs fixed by my redoing of the missing_below logic.
|
||||
|
||||
. $srcdir/testsuite/rsync.fns
|
||||
|
||||
makepath "$fromdir/subdir" "$todir"
|
||||
echo data >"$fromdir/subdir/file"
|
||||
echo data >"$todir/other"
|
||||
|
||||
# Test 1: Too much "not creating new..." output on a dry run
|
||||
$RSYNC -n -r --ignore-non-existing -vv "$fromdir/" "$todir/" | tee "$scratchdir/out"
|
||||
if grep 'not creating new.*subdir/file' "$scratchdir/out" >/dev/null; then
|
||||
test_fail 'test 1 failed'
|
||||
fi
|
||||
|
||||
# Test 2: Attempt to make a fuzzy dirlist for a dir not created on a dry run
|
||||
$RSYNC -n -r -R --no-implied-dirs -y "$fromdir/./subdir/file" "$todir/" \
|
||||
|| test_fail 'test 2 failed'
|
||||
|
||||
# Test 3: --delete-after pass skipped when last dir is dry-missing
|
||||
$RSYNC -n -r --delete-after -i "$fromdir/" "$todir/" | tee "$scratchdir/out"
|
||||
grep '^\*deleting * other' "$scratchdir/out" >/dev/null \
|
||||
|| test_fail 'test 3 failed'
|
||||
@@ -23,6 +23,11 @@ fromdir="$tmpdir/from"
|
||||
todir="$tmpdir/to"
|
||||
chkdir="$tmpdir/chk"
|
||||
|
||||
# For itemized output:
|
||||
all_plus='+++++++++'
|
||||
allspace=' '
|
||||
dots='.....' # trailing dots after changes
|
||||
|
||||
# Berkley's nice.
|
||||
PATH="$PATH:/usr/ucb"
|
||||
|
||||
@@ -47,6 +52,29 @@ runtest() {
|
||||
fi
|
||||
}
|
||||
|
||||
set_cp_destdir() {
|
||||
while test $# -gt 1; do
|
||||
shift
|
||||
done
|
||||
destdir="$1"
|
||||
}
|
||||
|
||||
# Perform a "cp -p", making sure that timestamps are really the same,
|
||||
# even if the copy rounded microsecond times on the destination file.
|
||||
cp_touch() {
|
||||
cp -p "${@}" || test_fail "cp -p failed"
|
||||
if test $# -gt 2 -o -d "$2"; then
|
||||
set_cp_destdir "${@}" # sets destdir var
|
||||
while test $# -gt 1; do
|
||||
destname="$destdir/`basename $1`"
|
||||
touch -r "$destname" "$1" "$destname"
|
||||
shift
|
||||
done
|
||||
else
|
||||
touch -r "$2" "$1" "$2"
|
||||
fi
|
||||
}
|
||||
|
||||
# Call this if you want to filter out verbose messages (-v or -vv) from
|
||||
# the output of an rsync run (whittling the output down to just the file
|
||||
# messages). This isn't needed if you use -i without -v.
|
||||
@@ -239,7 +267,7 @@ hosts allow = localhost 127.0.0.0/24 192.168.0.0/16 10.0.0.0/8 $hostname
|
||||
log file = $logfile
|
||||
log format = %i %h [%a] %m (%u) %l %f%L
|
||||
transfer logging = yes
|
||||
exclude = foobar.baz
|
||||
exclude = ? foobar.baz
|
||||
max verbosity = 9
|
||||
uid = 0
|
||||
gid = 0
|
||||
@@ -247,14 +275,20 @@ gid = 0
|
||||
[test-from]
|
||||
path = $fromdir
|
||||
read only = yes
|
||||
comment = r/o
|
||||
|
||||
[test-to]
|
||||
path = $todir
|
||||
read only = no
|
||||
comment = r/w
|
||||
|
||||
[test-scratch]
|
||||
path = $scratchdir
|
||||
read only = no
|
||||
|
||||
[test-hidden]
|
||||
path = $fromdir
|
||||
list = no
|
||||
EOF
|
||||
|
||||
# Build a helper script to ignore exit code 23
|
||||
|
||||
@@ -10,20 +10,7 @@
|
||||
|
||||
. "$suitedir/rsync.fns"
|
||||
|
||||
SSH="$scratchdir/pretend-ssh"
|
||||
|
||||
cat >"$SSH" <<'EOT'
|
||||
while : ; do
|
||||
case "$1" in
|
||||
-*) shift ;;
|
||||
localhost) shift; break ;;
|
||||
*) exit 1 ;;
|
||||
esac
|
||||
done
|
||||
|
||||
eval "${@}"
|
||||
EOT
|
||||
chmod +x "$SSH"
|
||||
SSH="$scratchdir/src/support/lsh"
|
||||
|
||||
if test x"$rsync_enable_ssh_tests" = xyes; then
|
||||
if type ssh >/dev/null ; then
|
||||
@@ -31,7 +18,7 @@ if test x"$rsync_enable_ssh_tests" = xyes; then
|
||||
fi
|
||||
fi
|
||||
|
||||
if ! [ "`"$SSH" -o'BatchMode yes' localhost echo yes`" = "yes" ]; then
|
||||
if ! [ "`$SSH -o'BatchMode yes' localhost echo yes`" = "yes" ]; then
|
||||
test_skipped "Skipping SSH tests because ssh conection to localhost not authorised"
|
||||
fi
|
||||
|
||||
|
||||
@@ -20,6 +20,7 @@ case "`xattr 2>&1`" in
|
||||
xls() {
|
||||
xattr -l "${@}"
|
||||
}
|
||||
RUSR='rsync.nonuser'
|
||||
;;
|
||||
*)
|
||||
xset() {
|
||||
@@ -31,6 +32,7 @@ case "`xattr 2>&1`" in
|
||||
xls() {
|
||||
getfattr -d "${@}"
|
||||
}
|
||||
RUSR='user.rsync'
|
||||
;;
|
||||
esac
|
||||
|
||||
@@ -44,7 +46,7 @@ echo deeper >"$fromdir/foo/bar/file5"
|
||||
|
||||
makepath "$chkdir/foo"
|
||||
echo wow >"$chkdir/file1"
|
||||
cp -p "$fromdir/foo/file3" "$chkdir/foo"
|
||||
cp_touch "$fromdir/foo/file3" "$chkdir/foo"
|
||||
|
||||
files='foo file0 file1 file2 foo/file3 file4 foo/bar/file5'
|
||||
|
||||
@@ -62,43 +64,84 @@ xset user.foo foo file2
|
||||
xset user.bar bar file2
|
||||
xset user.long 'a long attribute for our new file that tests to ensure that this works' file2
|
||||
|
||||
xset user.dir1 'need to test directory xattrs too' foo
|
||||
xset user.dir2 'another xattr' foo
|
||||
xset user.dir3 'this is one last one for the moment' foo
|
||||
|
||||
xset user.foo 'new foo' foo/file3 foo/bar/file5
|
||||
xset user.bar 'new bar' foo/file3 foo/bar/file5
|
||||
xset user.long 'this is also a long attribute that will be truncated in the initial data send' foo/file3 foo/bar/file5
|
||||
xset user.equal 'this long attribute should remain the same and not need to be transferred' foo/file3 foo/bar/file5
|
||||
xset $RUSR.equal 'this long attribute should remain the same and not need to be transferred' foo/file3 foo/bar/file5
|
||||
|
||||
xset user.short 'old short' "$chkdir/file1"
|
||||
xset user.extra 'remove me' "$chkdir/file1"
|
||||
|
||||
xset user.foo 'old foo' "$chkdir/foo/file3"
|
||||
xset user.equal 'this long attribute should remain the same and not need to be transferred' "$chkdir/foo/file3"
|
||||
xset $RUSR.equal 'this long attribute should remain the same and not need to be transferred' "$chkdir/foo/file3"
|
||||
|
||||
xls $files >"$scratchdir/xattrs.txt"
|
||||
|
||||
# OK, let's try a simple xattr copy.
|
||||
checkit "$RSYNC -avX . '$chkdir/'" "$fromdir" "$chkdir"
|
||||
checkit "$RSYNC -avX --super . '$chkdir/'" "$fromdir" "$chkdir"
|
||||
|
||||
cd "$chkdir"
|
||||
xls $files | diff $diffopt "$scratchdir/xattrs.txt" -
|
||||
|
||||
cd "$fromdir"
|
||||
|
||||
checkit "$RSYNC -aiX --copy-dest=../chk . ../to" "$fromdir" "$todir"
|
||||
checkit "$RSYNC -aiX --super --copy-dest=../chk . ../to" "$fromdir" "$todir"
|
||||
|
||||
cd "$todir"
|
||||
xls $files | diff $diffopt "$scratchdir/xattrs.txt" -
|
||||
|
||||
cd "$fromdir"
|
||||
xset user.nice 'this is nice, but different' file1
|
||||
|
||||
xls $files >"$scratchdir/xattrs.txt"
|
||||
|
||||
rm -rf "$todir"
|
||||
|
||||
checkit "$RSYNC -aiX --link-dest=../chk . ../to" "$chkdir" "$todir"
|
||||
xset user.nice 'this is nice, but different' file1
|
||||
|
||||
checkit "$RSYNC -aiX --fake-super . ../chk" "$fromdir" "$chkdir"
|
||||
|
||||
cd "$chkdir"
|
||||
xls $files >"$scratchdir/xattrs.txt"
|
||||
|
||||
cd "$fromdir"
|
||||
checkit "$RSYNC -aiX --fake-super --link-dest=../chk . ../to" "$chkdir" "$todir"
|
||||
|
||||
cd "$todir"
|
||||
xls $files | diff $diffopt "$scratchdir/xattrs.txt" -
|
||||
|
||||
sed -n -e '/\.\/file1$/d' -e '/^[^ ][^ ]* *[^ ][^ ]* *[^ ][^ ]* *1 /p' "$scratchdir/ls-to" >"$scratchdir/ls-diff"
|
||||
if [ -s "$scratchdir/ls-diff" ]; then
|
||||
echo "Missing hard links on:"
|
||||
cat "$scratchdir/ls-diff"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
cd "$fromdir"
|
||||
rm -rf "$todir" "$chkdir"
|
||||
|
||||
$RSYNC -aX file1 file2
|
||||
$RSYNC -aX file1 file2 ../chk/
|
||||
$RSYNC -aX --del ../chk/ .
|
||||
$RSYNC -aX file1 ../lnk/
|
||||
|
||||
xls file1 file2 >"$scratchdir/xattrs.txt"
|
||||
|
||||
checkit "$RSYNC -aiiX --copy-dest=../lnk . ../to" "$chkdir" "$todir"
|
||||
|
||||
cd "$todir"
|
||||
xls file1 file2 | diff $diffopt "$scratchdir/xattrs.txt" -
|
||||
|
||||
cd "$fromdir"
|
||||
rm "$todir/file2"
|
||||
|
||||
echo extra >file1
|
||||
$RSYNC -aX . ../chk/
|
||||
|
||||
checkit "$RSYNC -aiiX . ../to" "$chkdir" "$todir"
|
||||
|
||||
cd "$todir"
|
||||
xls file1 file2 | diff $diffopt "$scratchdir/xattrs.txt" -
|
||||
|
||||
# The script would have aborted on error, so getting here means we've won.
|
||||
exit 0
|
||||
|
||||
18
tls.c
18
tls.c
@@ -2,7 +2,7 @@
|
||||
* Trivial ls for comparing two directories after running an rsync.
|
||||
*
|
||||
* Copyright (C) 2001, 2002 Martin Pool <mbp@samba.org>
|
||||
* Copyright (C) 2003-2007 Wayne Davison
|
||||
* Copyright (C) 2003-2008 Wayne Davison
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
@@ -35,7 +35,7 @@
|
||||
* change. */
|
||||
|
||||
#include "rsync.h"
|
||||
#include "popt.h"
|
||||
#include <popt.h>
|
||||
#include "lib/sysxattrs.h"
|
||||
|
||||
#define PROGRAM "tls"
|
||||
@@ -45,6 +45,8 @@ int dry_run = 0;
|
||||
int am_root = 0;
|
||||
int read_only = 1;
|
||||
int list_only = 0;
|
||||
int link_times = 0;
|
||||
int link_owner = 0;
|
||||
int preserve_perms = 0;
|
||||
int preserve_executability = 0;
|
||||
|
||||
@@ -134,12 +136,14 @@ static void list_file(const char *fname)
|
||||
|
||||
/* On some BSD platforms the mode bits of a symlink are
|
||||
* undefined. Also it tends not to be possible to reset a
|
||||
* symlink's mtime, so we have to ignore it too. */
|
||||
* symlink's mtime, so we default to ignoring it too. */
|
||||
if (S_ISLNK(buf.st_mode)) {
|
||||
int len;
|
||||
buf.st_mode &= ~0777;
|
||||
buf.st_mtime = (time_t)0;
|
||||
buf.st_uid = buf.st_gid = 0;
|
||||
if (!link_times)
|
||||
buf.st_mtime = (time_t)0;
|
||||
if (!link_owner)
|
||||
buf.st_uid = buf.st_gid = 0;
|
||||
strlcpy(linkbuf, " -> ", sizeof linkbuf);
|
||||
/* const-cast required for silly UNICOS headers */
|
||||
len = readlink((char *) fname, linkbuf+4, sizeof(linkbuf) - 4);
|
||||
@@ -184,6 +188,8 @@ static void list_file(const char *fname)
|
||||
|
||||
static struct poptOption long_options[] = {
|
||||
/* longName, shortName, argInfo, argPtr, value, descrip, argDesc */
|
||||
{"link-times", 'l', POPT_ARG_NONE, &link_times, 0, 0, 0 },
|
||||
{"link-owner", 'L', POPT_ARG_NONE, &link_owner, 0, 0, 0 },
|
||||
#ifdef SUPPORT_XATTRS
|
||||
{"fake-super", 'f', POPT_ARG_VAL, &am_root, -1, 0, 0 },
|
||||
#endif
|
||||
@@ -197,6 +203,8 @@ static void tls_usage(int ret)
|
||||
fprintf(F,"usage: " PROGRAM " [OPTIONS] FILE ...\n");
|
||||
fprintf(F,"Trivial file listing program for portably checking rsync\n");
|
||||
fprintf(F,"\nOptions:\n");
|
||||
fprintf(F," -l, --link-times display the time on a symlink\n");
|
||||
fprintf(F," -L, --link-owner display the owner+group on a symlink\n");
|
||||
#ifdef SUPPORT_XATTRS
|
||||
fprintf(F," -f, --fake-super display attributes including fake-super xattrs\n");
|
||||
#endif
|
||||
|
||||
2
token.c
2
token.c
@@ -3,7 +3,7 @@
|
||||
*
|
||||
* Copyright (C) 1996 Andrew Tridgell
|
||||
* Copyright (C) 1996 Paul Mackerras
|
||||
* Copyright (C) 2003-2007 Wayne Davison
|
||||
* Copyright (C) 2003-2008 Wayne Davison
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
*
|
||||
* Copyright (C) 1996 Andrew Tridgell
|
||||
* Copyright (C) 1996 Paul Mackerras
|
||||
* Copyright (C) 2004-2007 Wayne Davison
|
||||
* Copyright (C) 2004-2008 Wayne Davison
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
|
||||
509
util.c
509
util.c
@@ -4,7 +4,7 @@
|
||||
* Copyright (C) 1996-2000 Andrew Tridgell
|
||||
* Copyright (C) 1996 Paul Mackerras
|
||||
* Copyright (C) 2001, 2002 Martin Pool <mbp@samba.org>
|
||||
* Copyright (C) 2003-2007 Wayne Davison
|
||||
* Copyright (C) 2003-2008 Wayne Davison
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
@@ -29,11 +29,12 @@ extern int module_id;
|
||||
extern int modify_window;
|
||||
extern int relative_paths;
|
||||
extern int human_readable;
|
||||
extern int preserve_xattrs;
|
||||
extern char *module_dir;
|
||||
extern unsigned int module_dirlen;
|
||||
extern mode_t orig_umask;
|
||||
extern char *partial_dir;
|
||||
extern struct filter_list_struct server_filter_list;
|
||||
extern struct filter_list_struct daemon_filter_list;
|
||||
|
||||
int sanitize_paths = 0;
|
||||
|
||||
@@ -264,6 +265,8 @@ static int safe_read(int desc, char *ptr, size_t len)
|
||||
|
||||
/* Copy a file. If ofd < 0, copy_file unlinks and opens the "dest" file.
|
||||
* Otherwise, it just writes to and closes the provided file descriptor.
|
||||
* In either case, if --xattrs are being preserved, the dest file will
|
||||
* have its xattrs set from the source file.
|
||||
*
|
||||
* This is used in conjunction with the --temp-dir, --backup, and
|
||||
* --copy-dest options. */
|
||||
@@ -275,38 +278,54 @@ int copy_file(const char *source, const char *dest, int ofd,
|
||||
int len; /* Number of bytes read into `buf'. */
|
||||
|
||||
if ((ifd = do_open(source, O_RDONLY, 0)) < 0) {
|
||||
int save_errno = errno;
|
||||
rsyserr(FERROR_XFER, errno, "open %s", full_fname(source));
|
||||
errno = save_errno;
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (ofd < 0) {
|
||||
if (robust_unlink(dest) && errno != ENOENT) {
|
||||
int save_errno = errno;
|
||||
rsyserr(FERROR_XFER, errno, "unlink %s", full_fname(dest));
|
||||
errno = save_errno;
|
||||
return -1;
|
||||
}
|
||||
|
||||
if ((ofd = do_open(dest, O_WRONLY | O_CREAT | O_TRUNC | O_EXCL, mode)) < 0
|
||||
&& (!create_bak_dir || errno != ENOENT || make_bak_dir(dest) < 0
|
||||
|| (ofd = do_open(dest, O_WRONLY | O_CREAT | O_TRUNC | O_EXCL, mode)) < 0)) {
|
||||
rsyserr(FERROR_XFER, errno, "open %s", full_fname(dest));
|
||||
close(ifd);
|
||||
return -1;
|
||||
if ((ofd = do_open(dest, O_WRONLY | O_CREAT | O_TRUNC | O_EXCL, mode)) < 0) {
|
||||
int save_errno = errno ? errno : EINVAL; /* 0 paranoia */
|
||||
if (create_bak_dir && errno == ENOENT && make_bak_dir(dest) == 0) {
|
||||
if ((ofd = do_open(dest, O_WRONLY | O_CREAT | O_TRUNC | O_EXCL, mode)) < 0)
|
||||
save_errno = errno ? errno : save_errno;
|
||||
else
|
||||
save_errno = 0;
|
||||
}
|
||||
if (save_errno) {
|
||||
rsyserr(FERROR_XFER, save_errno, "open %s", full_fname(dest));
|
||||
close(ifd);
|
||||
errno = save_errno;
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
while ((len = safe_read(ifd, buf, sizeof buf)) > 0) {
|
||||
if (full_write(ofd, buf, len) < 0) {
|
||||
int save_errno = errno;
|
||||
rsyserr(FERROR_XFER, errno, "write %s", full_fname(dest));
|
||||
close(ifd);
|
||||
close(ofd);
|
||||
errno = save_errno;
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
if (len < 0) {
|
||||
int save_errno = errno;
|
||||
rsyserr(FERROR_XFER, errno, "read %s", full_fname(source));
|
||||
close(ifd);
|
||||
close(ofd);
|
||||
errno = save_errno;
|
||||
return -1;
|
||||
}
|
||||
|
||||
@@ -316,11 +335,18 @@ int copy_file(const char *source, const char *dest, int ofd,
|
||||
}
|
||||
|
||||
if (close(ofd) < 0) {
|
||||
int save_errno = errno;
|
||||
rsyserr(FERROR_XFER, errno, "close failed on %s",
|
||||
full_fname(dest));
|
||||
errno = save_errno;
|
||||
return -1;
|
||||
}
|
||||
|
||||
#ifdef SUPPORT_XATTRS
|
||||
if (preserve_xattrs)
|
||||
copy_xattrs(source, dest);
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -401,14 +427,17 @@ int robust_rename(const char *from, const char *to, const char *partialptr,
|
||||
switch (errno) {
|
||||
#ifdef ETXTBSY
|
||||
case ETXTBSY:
|
||||
if (robust_unlink(to) != 0)
|
||||
if (robust_unlink(to) != 0) {
|
||||
errno = ETXTBSY;
|
||||
return -1;
|
||||
}
|
||||
errno = ETXTBSY;
|
||||
break;
|
||||
#endif
|
||||
case EXDEV:
|
||||
if (partialptr) {
|
||||
if (!handle_partial_dir(partialptr,PDIR_CREATE))
|
||||
return -1;
|
||||
return -2;
|
||||
to = partialptr;
|
||||
}
|
||||
if (copy_file(from, to, -1, mode, 0) != 0)
|
||||
@@ -503,82 +532,172 @@ int lock_range(int fd, int offset, int len)
|
||||
return fcntl(fd,F_SETLK,&lock) == 0;
|
||||
}
|
||||
|
||||
static int filter_server_path(char *arg)
|
||||
{
|
||||
char *s;
|
||||
#define ENSURE_MEMSPACE(buf, type, sz, req) \
|
||||
if ((req) > sz && !(buf = realloc_array(buf, type, sz = MAX(sz * 2, req)))) \
|
||||
out_of_memory("glob_expand")
|
||||
|
||||
if (server_filter_list.head) {
|
||||
for (s = arg; (s = strchr(s, '/')) != NULL; ) {
|
||||
*s = '\0';
|
||||
if (check_filter(&server_filter_list, arg, 1) < 0) {
|
||||
/* We must leave arg truncated! */
|
||||
return 1;
|
||||
}
|
||||
*s++ = '/';
|
||||
static inline void call_glob_match(const char *name, int len, int from_glob,
|
||||
char *arg, int abpos, int fbpos);
|
||||
|
||||
static struct glob_data {
|
||||
char *arg_buf, *filt_buf, **argv;
|
||||
int absize, fbsize, maxargs, argc;
|
||||
} glob;
|
||||
|
||||
static void glob_match(char *arg, int abpos, int fbpos)
|
||||
{
|
||||
int len;
|
||||
char *slash;
|
||||
|
||||
while (*arg == '.' && arg[1] == '/') {
|
||||
if (fbpos < 0) {
|
||||
ENSURE_MEMSPACE(glob.filt_buf, char, glob.fbsize, glob.absize);
|
||||
memcpy(glob.filt_buf, glob.arg_buf, abpos + 1);
|
||||
fbpos = abpos;
|
||||
}
|
||||
ENSURE_MEMSPACE(glob.arg_buf, char, glob.absize, abpos + 3);
|
||||
glob.arg_buf[abpos++] = *arg++;
|
||||
glob.arg_buf[abpos++] = *arg++;
|
||||
glob.arg_buf[abpos] = '\0';
|
||||
}
|
||||
return 0;
|
||||
if ((slash = strchr(arg, '/')) != NULL) {
|
||||
*slash = '\0';
|
||||
len = slash - arg;
|
||||
} else
|
||||
len = strlen(arg);
|
||||
if (strpbrk(arg, "*?[")) {
|
||||
struct dirent *di;
|
||||
DIR *d;
|
||||
|
||||
if (!(d = opendir(abpos ? glob.arg_buf : ".")))
|
||||
return;
|
||||
while ((di = readdir(d)) != NULL) {
|
||||
char *dname = d_name(di);
|
||||
if (dname[0] == '.' && (dname[1] == '\0'
|
||||
|| (dname[1] == '.' && dname[2] == '\0')))
|
||||
continue;
|
||||
if (!wildmatch(arg, dname))
|
||||
continue;
|
||||
call_glob_match(dname, strlen(dname), 1,
|
||||
slash ? arg + len + 1 : NULL,
|
||||
abpos, fbpos);
|
||||
}
|
||||
closedir(d);
|
||||
} else {
|
||||
call_glob_match(arg, len, 0,
|
||||
slash ? arg + len + 1 : NULL,
|
||||
abpos, fbpos);
|
||||
}
|
||||
if (slash)
|
||||
*slash = '/';
|
||||
}
|
||||
|
||||
void glob_expand(char *s, char ***argv_ptr, int *argc_ptr, int *maxargs_ptr)
|
||||
static inline void call_glob_match(const char *name, int len, int from_glob,
|
||||
char *arg, int abpos, int fbpos)
|
||||
{
|
||||
char **argv = *argv_ptr;
|
||||
int argc = *argc_ptr;
|
||||
int maxargs = *maxargs_ptr;
|
||||
#if !defined HAVE_GLOB || !defined HAVE_GLOB_H
|
||||
if (argc == maxargs) {
|
||||
maxargs += MAX_ARGS;
|
||||
if (!(argv = realloc_array(argv, char *, maxargs)))
|
||||
out_of_memory("glob_expand");
|
||||
*argv_ptr = argv;
|
||||
*maxargs_ptr = maxargs;
|
||||
}
|
||||
if (!*s)
|
||||
s = ".";
|
||||
s = argv[argc++] = strdup(s);
|
||||
filter_server_path(s);
|
||||
#else
|
||||
glob_t globbuf;
|
||||
char *use_buf;
|
||||
|
||||
if (maxargs <= argc)
|
||||
return;
|
||||
if (!*s)
|
||||
s = ".";
|
||||
ENSURE_MEMSPACE(glob.arg_buf, char, glob.absize, abpos + len + 2);
|
||||
memcpy(glob.arg_buf + abpos, name, len);
|
||||
abpos += len;
|
||||
glob.arg_buf[abpos] = '\0';
|
||||
|
||||
if (fbpos >= 0) {
|
||||
ENSURE_MEMSPACE(glob.filt_buf, char, glob.fbsize, fbpos + len + 2);
|
||||
memcpy(glob.filt_buf + fbpos, name, len);
|
||||
fbpos += len;
|
||||
glob.filt_buf[fbpos] = '\0';
|
||||
use_buf = glob.filt_buf;
|
||||
} else
|
||||
use_buf = glob.arg_buf;
|
||||
|
||||
if (from_glob || (arg && len)) {
|
||||
STRUCT_STAT st;
|
||||
int is_dir;
|
||||
|
||||
if (do_stat(glob.arg_buf, &st) != 0)
|
||||
return;
|
||||
is_dir = S_ISDIR(st.st_mode) != 0;
|
||||
if (arg && !is_dir)
|
||||
return;
|
||||
|
||||
if (daemon_filter_list.head
|
||||
&& check_filter(&daemon_filter_list, FLOG, use_buf, is_dir) < 0)
|
||||
return;
|
||||
}
|
||||
|
||||
if (arg) {
|
||||
glob.arg_buf[abpos++] = '/';
|
||||
glob.arg_buf[abpos] = '\0';
|
||||
if (fbpos >= 0) {
|
||||
glob.filt_buf[fbpos++] = '/';
|
||||
glob.filt_buf[fbpos] = '\0';
|
||||
}
|
||||
glob_match(arg, abpos, fbpos);
|
||||
} else {
|
||||
ENSURE_MEMSPACE(glob.argv, char *, glob.maxargs, glob.argc + 1);
|
||||
if (!(glob.argv[glob.argc++] = strdup(glob.arg_buf)))
|
||||
out_of_memory("glob_match");
|
||||
}
|
||||
}
|
||||
|
||||
/* This routine performs wild-card expansion of the pathname in "arg". Any
|
||||
* daemon-excluded files/dirs will not be matched by the wildcards. Returns 0
|
||||
* if a wild-card string is the only returned item (due to matching nothing). */
|
||||
int glob_expand(const char *arg, char ***argv_p, int *argc_p, int *maxargs_p)
|
||||
{
|
||||
int ret, save_argc;
|
||||
char *s;
|
||||
|
||||
if (!arg) {
|
||||
if (glob.filt_buf)
|
||||
free(glob.filt_buf);
|
||||
free(glob.arg_buf);
|
||||
memset(&glob, 0, sizeof glob);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (sanitize_paths)
|
||||
s = sanitize_path(NULL, s, "", 0);
|
||||
else
|
||||
s = strdup(s);
|
||||
if (!s)
|
||||
out_of_memory("glob_expand");
|
||||
|
||||
memset(&globbuf, 0, sizeof globbuf);
|
||||
if (!filter_server_path(s))
|
||||
glob(s, 0, NULL, &globbuf);
|
||||
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");
|
||||
*argv_ptr = argv;
|
||||
*maxargs_ptr = maxargs;
|
||||
}
|
||||
if (globbuf.gl_pathc == 0)
|
||||
argv[argc++] = s;
|
||||
s = sanitize_path(NULL, arg, "", 0, SP_KEEP_DOT_DIRS);
|
||||
else {
|
||||
int i;
|
||||
free(s);
|
||||
for (i = 0; i < (int)globbuf.gl_pathc; i++) {
|
||||
if (!(argv[argc++] = strdup(globbuf.gl_pathv[i])))
|
||||
out_of_memory("glob_expand");
|
||||
}
|
||||
s = strdup(arg);
|
||||
if (!s)
|
||||
out_of_memory("glob_expand");
|
||||
clean_fname(s, CFN_KEEP_DOT_DIRS
|
||||
| CFN_KEEP_TRAILING_SLASH
|
||||
| CFN_COLLAPSE_DOT_DOT_DIRS);
|
||||
}
|
||||
globfree(&globbuf);
|
||||
#endif
|
||||
*argc_ptr = argc;
|
||||
|
||||
ENSURE_MEMSPACE(glob.arg_buf, char, glob.absize, MAXPATHLEN);
|
||||
*glob.arg_buf = '\0';
|
||||
|
||||
glob.argc = save_argc = *argc_p;
|
||||
glob.argv = *argv_p;
|
||||
glob.maxargs = *maxargs_p;
|
||||
|
||||
ENSURE_MEMSPACE(glob.argv, char *, glob.maxargs, 100);
|
||||
|
||||
glob_match(s, 0, -1);
|
||||
|
||||
/* The arg didn't match anything, so add the failed arg to the list. */
|
||||
if (glob.argc == save_argc) {
|
||||
ENSURE_MEMSPACE(glob.argv, char *, glob.maxargs, glob.argc + 1);
|
||||
glob.argv[glob.argc++] = s;
|
||||
ret = 0;
|
||||
} else {
|
||||
free(s);
|
||||
ret = 1;
|
||||
}
|
||||
|
||||
*maxargs_p = glob.maxargs;
|
||||
*argv_p = glob.argv;
|
||||
*argc_p = glob.argc;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* This routine is only used in daemon mode. */
|
||||
void glob_expand_module(char *base1, char *arg, char ***argv_ptr, int *argc_ptr, int *maxargs_ptr)
|
||||
void glob_expand_module(char *base1, char *arg, char ***argv_p, int *argc_p, int *maxargs_p)
|
||||
{
|
||||
char *p, *s;
|
||||
char *base = base1;
|
||||
@@ -600,7 +719,7 @@ void glob_expand_module(char *base1, char *arg, char ***argv_ptr, int *argc_ptr,
|
||||
for (s = arg; *s; s = p + base_len) {
|
||||
if ((p = strstr(s, base)) != NULL)
|
||||
*p = '\0'; /* split it at this point */
|
||||
glob_expand(s, argv_ptr, argc_ptr, maxargs_ptr);
|
||||
glob_expand(s, argv_p, argc_p, maxargs_p);
|
||||
if (!p)
|
||||
break;
|
||||
}
|
||||
@@ -687,13 +806,14 @@ int count_dir_elements(const char *p)
|
||||
return cnt;
|
||||
}
|
||||
|
||||
/* Turns multiple adjacent slashes into a single slash, drops interior "."
|
||||
* elements, drops an intial "./" unless CFN_KEEP_LEADING_DOT_DIR is flagged,
|
||||
* will even drop a trailing '.' after a '/' if CFN_DROP_TRAILING_DOT_DIR is
|
||||
* flagged, removes a trailing slash (perhaps after removing the aforementioned
|
||||
* dot) unless CFN_KEEP_TRAILING_SLASH is flagged, will even collapse ".."
|
||||
* elements (except at the start of the string) if CFN_COLLAPSE_DOT_DOT_DIRS
|
||||
* is flagged. If the resulting name would be empty, we return ".". */
|
||||
/* Turns multiple adjacent slashes into a single slash (possible exception:
|
||||
* the preserving of two leading slashes at the start), drops all leading or
|
||||
* interior "." elements unless CFN_KEEP_DOT_DIRS is flagged. Will also drop
|
||||
* a trailing '.' after a '/' if CFN_DROP_TRAILING_DOT_DIR is flagged, removes
|
||||
* a trailing slash (perhaps after removing the aforementioned dot) unless
|
||||
* CFN_KEEP_TRAILING_SLASH is flagged, and will also collapse ".." elements
|
||||
* (except at the start) if CFN_COLLAPSE_DOT_DOT_DIRS is flagged. If the
|
||||
* resulting name would be empty, returns ".". */
|
||||
unsigned int clean_fname(char *name, int flags)
|
||||
{
|
||||
char *limit = name - 1, *t = name, *f = name;
|
||||
@@ -702,9 +822,16 @@ unsigned int clean_fname(char *name, int flags)
|
||||
if (!name)
|
||||
return 0;
|
||||
|
||||
if ((anchored = *f == '/') != 0)
|
||||
if ((anchored = *f == '/') != 0) {
|
||||
*t++ = *f++;
|
||||
else if (flags & CFN_KEEP_LEADING_DOT_DIR && *f == '.' && f[1] == '/') {
|
||||
#ifdef __CYGWIN__
|
||||
/* If there are exactly 2 slashes at the start, preserve
|
||||
* them. Would break daemon excludes unless the paths are
|
||||
* really treated differently, so used this sparingly. */
|
||||
if (*f == '/' && f[1] != '/')
|
||||
*t++ = *f++;
|
||||
#endif
|
||||
} else if (flags & CFN_KEEP_DOT_DIRS && *f == '.' && f[1] == '/') {
|
||||
*t++ = *f++;
|
||||
*t++ = *f++;
|
||||
}
|
||||
@@ -716,7 +843,7 @@ unsigned int clean_fname(char *name, int flags)
|
||||
}
|
||||
if (*f == '.') {
|
||||
/* discard interior "." dirs */
|
||||
if (f[1] == '/') {
|
||||
if (f[1] == '/' && !(flags & CFN_KEEP_DOT_DIRS)) {
|
||||
f += 2;
|
||||
continue;
|
||||
}
|
||||
@@ -773,10 +900,11 @@ unsigned int clean_fname(char *name, int flags)
|
||||
* 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 *sanitize_path(char *dest, const char *p, const char *rootdir, int depth,
|
||||
int flags)
|
||||
{
|
||||
char *start, *sanp;
|
||||
int rlen = 0, leave_one_dotdir = relative_paths;
|
||||
int rlen = 0, drop_dot_dirs = !relative_paths || !(flags & SP_KEEP_DOT_DIRS);
|
||||
|
||||
if (dest != p) {
|
||||
int plen = strlen(p);
|
||||
@@ -799,21 +927,22 @@ char *sanitize_path(char *dest, const char *p, const char *rootdir, int depth)
|
||||
}
|
||||
}
|
||||
|
||||
if (drop_dot_dirs) {
|
||||
while (*p == '.' && p[1] == '/')
|
||||
p += 2;
|
||||
}
|
||||
|
||||
start = sanp = dest + rlen;
|
||||
/* This loop iterates once per filename component in p, pointing at
|
||||
* the start of the name (past any prior slash) for each iteration. */
|
||||
while (*p) {
|
||||
/* 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')) {
|
||||
if (leave_one_dotdir && p[1])
|
||||
leave_one_dotdir = 0;
|
||||
else {
|
||||
if (drop_dot_dirs) {
|
||||
if (*p == '.' && (p[1] == '/' || p[1] == '\0')) {
|
||||
/* skip "." component */
|
||||
p++;
|
||||
continue;
|
||||
@@ -826,10 +955,8 @@ char *sanitize_path(char *dest, const char *p, const char *rootdir, int depth)
|
||||
if (sanp != start) {
|
||||
/* back up sanp one level */
|
||||
--sanp; /* now pointing at slash */
|
||||
while (sanp > start && sanp[-1] != '/') {
|
||||
/* skip back up to slash */
|
||||
while (sanp > start && sanp[-1] != '/')
|
||||
sanp--;
|
||||
}
|
||||
}
|
||||
continue;
|
||||
}
|
||||
@@ -853,14 +980,17 @@ char *sanitize_path(char *dest, const char *p, const char *rootdir, int depth)
|
||||
/* Like chdir(), but it keeps track of the current directory (in the
|
||||
* global "curr_dir"), and ensures that the path size doesn't overflow.
|
||||
* Also cleans the path using the clean_fname() function. */
|
||||
int push_dir(const char *dir, int set_path_only)
|
||||
int change_dir(const char *dir, int set_path_only)
|
||||
{
|
||||
static int initialised;
|
||||
unsigned int len;
|
||||
|
||||
if (!initialised) {
|
||||
initialised = 1;
|
||||
getcwd(curr_dir, sizeof curr_dir - 1);
|
||||
if (getcwd(curr_dir, sizeof curr_dir - 1) == NULL) {
|
||||
rsyserr(FERROR, errno, "getcwd()");
|
||||
exit_cleanup(RERR_FILESELECT);
|
||||
}
|
||||
curr_dir_len = strlen(curr_dir);
|
||||
}
|
||||
|
||||
@@ -871,21 +1001,26 @@ int push_dir(const char *dir, int set_path_only)
|
||||
if (len == 1 && *dir == '.')
|
||||
return 1;
|
||||
|
||||
if ((*dir == '/' ? len : curr_dir_len + 1 + len) >= sizeof curr_dir) {
|
||||
errno = ENAMETOOLONG;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!set_path_only && chdir(dir))
|
||||
return 0;
|
||||
|
||||
if (*dir == '/') {
|
||||
if (len >= sizeof curr_dir) {
|
||||
errno = ENAMETOOLONG;
|
||||
return 0;
|
||||
}
|
||||
if (!set_path_only && chdir(dir))
|
||||
return 0;
|
||||
memcpy(curr_dir, dir, len + 1);
|
||||
curr_dir_len = len;
|
||||
} else {
|
||||
curr_dir[curr_dir_len++] = '/';
|
||||
memcpy(curr_dir + curr_dir_len, dir, len + 1);
|
||||
curr_dir_len += len;
|
||||
if (curr_dir_len + 1 + len >= sizeof curr_dir) {
|
||||
errno = ENAMETOOLONG;
|
||||
return 0;
|
||||
}
|
||||
curr_dir[curr_dir_len] = '/';
|
||||
memcpy(curr_dir + curr_dir_len + 1, dir, len + 1);
|
||||
|
||||
if (!set_path_only && chdir(curr_dir)) {
|
||||
curr_dir[curr_dir_len] = '\0';
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
curr_dir_len = clean_fname(curr_dir, CFN_COLLAPSE_DOT_DOT_DIRS);
|
||||
@@ -896,30 +1031,37 @@ int push_dir(const char *dir, int set_path_only)
|
||||
}
|
||||
|
||||
if (verbose >= 5 && !set_path_only)
|
||||
rprintf(FINFO, "[%s] push_dir(%s)\n", who_am_i(), curr_dir);
|
||||
rprintf(FINFO, "[%s] change_dir(%s)\n", who_am_i(), curr_dir);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse a push_dir() call. You must pass in an absolute path
|
||||
* that was copied from a prior value of "curr_dir".
|
||||
**/
|
||||
int pop_dir(const char *dir)
|
||||
/* This will make a relative path absolute and clean it up via clean_fname().
|
||||
* Returns the string, which might be newly allocated, or NULL on error. */
|
||||
char *normalize_path(char *path, BOOL force_newbuf, unsigned int *len_ptr)
|
||||
{
|
||||
if (chdir(dir))
|
||||
return 0;
|
||||
unsigned int len;
|
||||
|
||||
curr_dir_len = strlcpy(curr_dir, dir, sizeof curr_dir);
|
||||
if (curr_dir_len >= sizeof curr_dir)
|
||||
curr_dir_len = sizeof curr_dir - 1;
|
||||
if (sanitize_paths)
|
||||
curr_dir_depth = count_dir_elements(curr_dir + module_dirlen);
|
||||
if (*path != '/') { /* Make path absolute. */
|
||||
int len = strlen(path);
|
||||
if (curr_dir_len + 1 + len >= sizeof curr_dir)
|
||||
return NULL;
|
||||
curr_dir[curr_dir_len] = '/';
|
||||
memcpy(curr_dir + curr_dir_len + 1, path, len + 1);
|
||||
if (!(path = strdup(curr_dir)))
|
||||
out_of_memory("normalize_path");
|
||||
curr_dir[curr_dir_len] = '\0';
|
||||
} else if (force_newbuf) {
|
||||
if (!(path = strdup(path)))
|
||||
out_of_memory("normalize_path");
|
||||
}
|
||||
|
||||
if (verbose >= 5)
|
||||
rprintf(FINFO, "[%s] pop_dir(%s)\n", who_am_i(), curr_dir);
|
||||
len = clean_fname(path, CFN_COLLAPSE_DOT_DOT_DIRS | CFN_DROP_TRAILING_DOT_DIR);
|
||||
|
||||
return 1;
|
||||
if (len_ptr)
|
||||
*len_ptr = len;
|
||||
|
||||
return path;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -977,13 +1119,13 @@ char *partial_dir_fname(const char *fname)
|
||||
fn = fname;
|
||||
if ((int)pathjoin(t, sz, partial_dir, fn) >= sz)
|
||||
return NULL;
|
||||
if (server_filter_list.head) {
|
||||
if (daemon_filter_list.head) {
|
||||
t = strrchr(partial_fname, '/');
|
||||
*t = '\0';
|
||||
if (check_filter(&server_filter_list, partial_fname, 1) < 0)
|
||||
if (check_filter(&daemon_filter_list, FLOG, partial_fname, 1) < 0)
|
||||
return NULL;
|
||||
*t = '/';
|
||||
if (check_filter(&server_filter_list, partial_fname, 0) < 0)
|
||||
if (check_filter(&daemon_filter_list, FLOG, partial_fname, 0) < 0)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@@ -1009,12 +1151,16 @@ int handle_partial_dir(const char *fname, int create)
|
||||
STRUCT_STAT st;
|
||||
int statret = do_lstat(dir, &st);
|
||||
if (statret == 0 && !S_ISDIR(st.st_mode)) {
|
||||
if (do_unlink(dir) < 0)
|
||||
if (do_unlink(dir) < 0) {
|
||||
*fn = '/';
|
||||
return 0;
|
||||
}
|
||||
statret = -1;
|
||||
}
|
||||
if (statret < 0 && do_mkdir(dir, 0700) < 0)
|
||||
if (statret < 0 && do_mkdir(dir, 0700) < 0) {
|
||||
*fn = '/';
|
||||
return 0;
|
||||
}
|
||||
} else
|
||||
do_rmdir(dir);
|
||||
*fn = '/';
|
||||
@@ -1086,6 +1232,28 @@ int unsafe_symlink(const char *dest, const char *src)
|
||||
return (depth < 0);
|
||||
}
|
||||
|
||||
#define HUMANIFY(mult) \
|
||||
do { \
|
||||
if (num >= mult || num <= -mult) { \
|
||||
double dnum = (double)num / mult; \
|
||||
char units; \
|
||||
if (num < 0) \
|
||||
dnum = -dnum; \
|
||||
if (dnum < mult) \
|
||||
units = 'K'; \
|
||||
else if ((dnum /= mult) < mult) \
|
||||
units = 'M'; \
|
||||
else { \
|
||||
dnum /= mult; \
|
||||
units = 'G'; \
|
||||
} \
|
||||
if (num < 0) \
|
||||
dnum = -dnum; \
|
||||
snprintf(bufs[n], sizeof bufs[0], "%.2f%c", dnum, units); \
|
||||
return bufs[n]; \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
/* Return the int64 number as a string. If the --human-readable option was
|
||||
* specified, we may output the number in K, M, or G units. We can return
|
||||
* up to 4 buffers at a time. */
|
||||
@@ -1094,27 +1262,15 @@ char *human_num(int64 num)
|
||||
static char bufs[4][128]; /* more than enough room */
|
||||
static unsigned int n;
|
||||
char *s;
|
||||
int negated;
|
||||
|
||||
n = (n + 1) % (sizeof bufs / sizeof bufs[0]);
|
||||
|
||||
if (human_readable) {
|
||||
char units = '\0';
|
||||
int mult = human_readable == 1 ? 1000 : 1024;
|
||||
double dnum = 0;
|
||||
if (num > mult*mult*mult) {
|
||||
dnum = (double)num / (mult*mult*mult);
|
||||
units = 'G';
|
||||
} else if (num > mult*mult) {
|
||||
dnum = (double)num / (mult*mult);
|
||||
units = 'M';
|
||||
} else if (num > mult) {
|
||||
dnum = (double)num / mult;
|
||||
units = 'K';
|
||||
}
|
||||
if (units) {
|
||||
snprintf(bufs[n], sizeof bufs[0], "%.2f%c", dnum, units);
|
||||
return bufs[n];
|
||||
}
|
||||
if (human_readable == 1)
|
||||
HUMANIFY(1000);
|
||||
else
|
||||
HUMANIFY(1024);
|
||||
}
|
||||
|
||||
s = bufs[n] + sizeof bufs[0] - 1;
|
||||
@@ -1122,10 +1278,23 @@ char *human_num(int64 num)
|
||||
|
||||
if (!num)
|
||||
*--s = '0';
|
||||
if (num < 0) {
|
||||
/* A maximum-size negated number can't fit as a positive,
|
||||
* so do one digit in negated form to start us off. */
|
||||
*--s = (char)(-(num % 10)) + '0';
|
||||
num = -(num / 10);
|
||||
negated = 1;
|
||||
} else
|
||||
negated = 0;
|
||||
|
||||
while (num) {
|
||||
*--s = (char)(num % 10) + '0';
|
||||
num /= 10;
|
||||
}
|
||||
|
||||
if (negated)
|
||||
*--s = '-';
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
@@ -1138,8 +1307,8 @@ char *human_dnum(double dnum, int decimal_digits)
|
||||
int len = strlen(buf);
|
||||
if (isDigit(buf + len - 1)) {
|
||||
/* There's extra room in buf prior to the start of the num. */
|
||||
buf -= decimal_digits + 1;
|
||||
snprintf(buf, len + decimal_digits + 2, "%.*f", decimal_digits, dnum);
|
||||
buf -= decimal_digits + 2;
|
||||
snprintf(buf, len + decimal_digits + 3, "%.*f", decimal_digits, dnum);
|
||||
}
|
||||
return buf;
|
||||
}
|
||||
@@ -1255,7 +1424,7 @@ void *_new_array(unsigned long num, unsigned int size, int use_calloc)
|
||||
return use_calloc ? calloc(num, size) : malloc(num * size);
|
||||
}
|
||||
|
||||
void *_realloc_array(void *ptr, unsigned int size, unsigned long num)
|
||||
void *_realloc_array(void *ptr, unsigned int size, size_t num)
|
||||
{
|
||||
if (num >= MALLOC_MAX/size)
|
||||
return NULL;
|
||||
@@ -1463,6 +1632,39 @@ int bitbag_next_bit(struct bitbag *bb, int after)
|
||||
return -1;
|
||||
}
|
||||
|
||||
void flist_ndx_push(flist_ndx_list *lp, int ndx)
|
||||
{
|
||||
struct flist_ndx_item *item;
|
||||
|
||||
if (!(item = new(struct flist_ndx_item)))
|
||||
out_of_memory("flist_ndx_push");
|
||||
item->next = NULL;
|
||||
item->ndx = ndx;
|
||||
if (lp->tail)
|
||||
lp->tail->next = item;
|
||||
else
|
||||
lp->head = item;
|
||||
lp->tail = item;
|
||||
}
|
||||
|
||||
int flist_ndx_pop(flist_ndx_list *lp)
|
||||
{
|
||||
struct flist_ndx_item *next;
|
||||
int ndx;
|
||||
|
||||
if (!lp->head)
|
||||
return -1;
|
||||
|
||||
ndx = lp->head->ndx;
|
||||
next = lp->head->next;
|
||||
free(lp->head);
|
||||
lp->head = next;
|
||||
if (!next)
|
||||
lp->tail = NULL;
|
||||
|
||||
return ndx;
|
||||
}
|
||||
|
||||
void *expand_item_list(item_list *lp, size_t item_size,
|
||||
const char *desc, int incr)
|
||||
{
|
||||
@@ -1476,7 +1678,10 @@ void *expand_item_list(item_list *lp, size_t item_size,
|
||||
new_size += incr;
|
||||
else
|
||||
new_size *= 2;
|
||||
new_ptr = realloc_array(lp->items, char, new_size * item_size);
|
||||
if (new_size < lp->malloced)
|
||||
overflow_exit("expand_item_list");
|
||||
/* Using _realloc_array() lets us pass the size, not a type. */
|
||||
new_ptr = _realloc_array(lp->items, item_size, new_size);
|
||||
if (verbose >= 4) {
|
||||
rprintf(FINFO, "[%s] expand %s to %.0f bytes, did%s move\n",
|
||||
who_am_i(), desc, (double)new_size * item_size,
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* Test suite for the wildmatch code.
|
||||
*
|
||||
* Copyright (C) 2003-2007 Wayne Davison
|
||||
* Copyright (C) 2003-2008 Wayne Davison
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
|
||||
163
xattrs.c
163
xattrs.c
@@ -3,7 +3,7 @@
|
||||
* Written by Jay Fenlason, vaguely based on the ACLs patch.
|
||||
*
|
||||
* Copyright (C) 2004 Red Hat, Inc.
|
||||
* Copyright (C) 2006, 2007 Wayne Davison
|
||||
* Copyright (C) 2006-2008 Wayne Davison
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
@@ -44,9 +44,9 @@ extern int checksum_seed;
|
||||
|
||||
#define XATTR_ABBREV(x) ((size_t)((x).name - (x).datum) < (x).datum_len)
|
||||
|
||||
#define XSTATE_ABBREV 0
|
||||
#define XSTATE_DONE 1
|
||||
#define XSTATE_TODO 2
|
||||
#define XSTATE_ABBREV 1
|
||||
#define XSTATE_DONE 2
|
||||
#define XSTATE_TODO 3
|
||||
|
||||
#define USER_PREFIX "user."
|
||||
#define UPRE_LEN ((int)sizeof USER_PREFIX - 1)
|
||||
@@ -62,9 +62,12 @@ extern int checksum_seed;
|
||||
#endif
|
||||
#define RPRE_LEN ((int)sizeof RSYNC_PREFIX - 1)
|
||||
|
||||
#define XSTAT_ATTR RSYNC_PREFIX "%stat"
|
||||
#define XACC_ACL_ATTR RSYNC_PREFIX "%aacl"
|
||||
#define XDEF_ACL_ATTR RSYNC_PREFIX "%dacl"
|
||||
#define XSTAT_SUFFIX "stat"
|
||||
#define XSTAT_ATTR RSYNC_PREFIX "%" XSTAT_SUFFIX
|
||||
#define XACC_ACL_SUFFIX "aacl"
|
||||
#define XACC_ACL_ATTR RSYNC_PREFIX "%" XACC_ACL_SUFFIX
|
||||
#define XDEF_ACL_SUFFIX "dacl"
|
||||
#define XDEF_ACL_ATTR RSYNC_PREFIX "%" XDEF_ACL_SUFFIX
|
||||
|
||||
typedef struct {
|
||||
char *datum, *name;
|
||||
@@ -175,8 +178,9 @@ static char *get_xattr_data(const char *fname, const char *name, size_t *len_ptr
|
||||
|
||||
if (!datum_len && !extra_len)
|
||||
extra_len = 1; /* request non-zero amount of memory */
|
||||
if (datum_len + extra_len < datum_len /* checks for overflow */
|
||||
|| !(ptr = new_array(char, datum_len + extra_len)))
|
||||
if (datum_len + extra_len < datum_len)
|
||||
overflow_exit("get_xattr_data");
|
||||
if (!(ptr = new_array(char, datum_len + extra_len)))
|
||||
out_of_memory("get_xattr_data");
|
||||
|
||||
if (datum_len) {
|
||||
@@ -206,7 +210,7 @@ static int rsync_xal_get(const char *fname, item_list *xalp)
|
||||
size_t datum_len, name_offset;
|
||||
char *name, *ptr;
|
||||
#ifdef HAVE_LINUX_XATTRS
|
||||
int user_only = am_sender ? 0 : !am_root;
|
||||
int user_only = am_sender ? 0 : am_root <= 0;
|
||||
#endif
|
||||
rsync_xa *rxa;
|
||||
int count;
|
||||
@@ -231,7 +235,10 @@ static int rsync_xal_get(const char *fname, item_list *xalp)
|
||||
if (name_len > RPRE_LEN && name[RPRE_LEN] == '%'
|
||||
&& HAS_PREFIX(name, RSYNC_PREFIX)) {
|
||||
if ((am_sender && preserve_xattrs < 2)
|
||||
|| (am_root < 0 && strcmp(name, XSTAT_ATTR) == 0))
|
||||
|| (am_root < 0
|
||||
&& (strcmp(name+RPRE_LEN+1, XSTAT_SUFFIX) == 0
|
||||
|| strcmp(name+RPRE_LEN+1, XACC_ACL_SUFFIX) == 0
|
||||
|| strcmp(name+RPRE_LEN+1, XDEF_ACL_SUFFIX) == 0)))
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -253,14 +260,6 @@ static int rsync_xal_get(const char *fname, item_list *xalp)
|
||||
} else
|
||||
name_offset = datum_len;
|
||||
|
||||
#ifdef HAVE_LINUX_XATTRS
|
||||
if (am_root < 0 && name_len > RPRE_LEN && name[RPRE_LEN] != '%'
|
||||
&& HAS_PREFIX(name, RSYNC_PREFIX)) {
|
||||
name += RPRE_LEN;
|
||||
name_len -= RPRE_LEN;
|
||||
}
|
||||
#endif
|
||||
|
||||
rxa = EXPAND_ITEM_LIST(xalp, rsync_xa, RSYNC_XAL_INITIAL);
|
||||
rxa->name = ptr + name_offset;
|
||||
memcpy(rxa->name, name, name_len);
|
||||
@@ -289,6 +288,48 @@ int get_xattr(const char *fname, stat_x *sxp)
|
||||
return 0;
|
||||
}
|
||||
|
||||
int copy_xattrs(const char *source, const char *dest)
|
||||
{
|
||||
ssize_t list_len, name_len;
|
||||
size_t datum_len;
|
||||
char *name, *ptr;
|
||||
#ifdef HAVE_LINUX_XATTRS
|
||||
int user_only = am_root <= 0;
|
||||
#endif
|
||||
|
||||
/* This puts the name list into the "namebuf" buffer. */
|
||||
if ((list_len = get_xattr_names(source)) < 0)
|
||||
return -1;
|
||||
|
||||
for (name = namebuf; list_len > 0; name += name_len) {
|
||||
name_len = strlen(name) + 1;
|
||||
list_len -= name_len;
|
||||
|
||||
#ifdef HAVE_LINUX_XATTRS
|
||||
/* We always ignore the system namespace, and non-root
|
||||
* ignores everything but the user namespace. */
|
||||
if (user_only ? !HAS_PREFIX(name, USER_PREFIX)
|
||||
: HAS_PREFIX(name, SYSTEM_PREFIX))
|
||||
continue;
|
||||
#endif
|
||||
|
||||
datum_len = 0;
|
||||
if (!(ptr = get_xattr_data(source, name, &datum_len, 0)))
|
||||
return -1;
|
||||
if (sys_lsetxattr(dest, name, ptr, datum_len) < 0) {
|
||||
int save_errno = errno ? errno : EINVAL;
|
||||
rsyserr(FERROR_XFER, errno,
|
||||
"rsync_xal_set: lsetxattr(\"%s\",\"%s\") failed",
|
||||
dest, name);
|
||||
errno = save_errno;
|
||||
return -1;
|
||||
}
|
||||
free(ptr);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int find_matching_xattr(item_list *xalp)
|
||||
{
|
||||
size_t i, j;
|
||||
@@ -352,25 +393,32 @@ int send_xattr(stat_x *sxp, int f)
|
||||
int count = sxp->xattr->count;
|
||||
write_varint(f, count);
|
||||
for (rxa = sxp->xattr->items; count--; rxa++) {
|
||||
size_t name_len = rxa->name_len;
|
||||
const char *name = rxa->name;
|
||||
/* Strip the rsync prefix from disguised namespaces. */
|
||||
if (name_len > RPRE_LEN
|
||||
#ifdef HAVE_LINUX_XATTRS
|
||||
write_varint(f, rxa->name_len);
|
||||
write_varint(f, rxa->datum_len);
|
||||
write_buf(f, rxa->name, rxa->name_len);
|
||||
#else
|
||||
/* We strip the rsync prefix from disguised namespaces
|
||||
* and put everything else in the user namespace. */
|
||||
if (HAS_PREFIX(rxa->name, RSYNC_PREFIX)
|
||||
&& rxa->name[RPRE_LEN] != '%') {
|
||||
write_varint(f, rxa->name_len - RPRE_LEN);
|
||||
write_varint(f, rxa->datum_len);
|
||||
write_buf(f, rxa->name + RPRE_LEN, rxa->name_len - RPRE_LEN);
|
||||
} else {
|
||||
write_varint(f, rxa->name_len + UPRE_LEN);
|
||||
write_varint(f, rxa->datum_len);
|
||||
write_buf(f, USER_PREFIX, UPRE_LEN);
|
||||
write_buf(f, rxa->name, rxa->name_len);
|
||||
&& am_root < 0
|
||||
#endif
|
||||
&& name[RPRE_LEN] != '%' && HAS_PREFIX(name, RSYNC_PREFIX)) {
|
||||
name += RPRE_LEN;
|
||||
name_len -= RPRE_LEN;
|
||||
}
|
||||
#ifndef HAVE_LINUX_XATTRS
|
||||
else {
|
||||
/* Put everything else in the user namespace. */
|
||||
name_len += UPRE_LEN;
|
||||
}
|
||||
#endif
|
||||
write_varint(f, name_len);
|
||||
write_varint(f, rxa->datum_len);
|
||||
#ifndef HAVE_LINUX_XATTRS
|
||||
if (name_len > rxa->name_len) {
|
||||
write_buf(f, USER_PREFIX, UPRE_LEN);
|
||||
name_len -= UPRE_LEN;
|
||||
}
|
||||
#endif
|
||||
write_buf(f, name, name_len);
|
||||
if (rxa->datum_len > MAX_FULL_DATUM)
|
||||
write_buf(f, rxa->datum + 1, MAX_DIGEST_LEN);
|
||||
else
|
||||
@@ -455,9 +503,11 @@ int xattr_diff(struct file_struct *file, stat_x *sxp, int find_all)
|
||||
return !xattrs_equal;
|
||||
}
|
||||
|
||||
/* When called by the generator with a NULL fname, this tells the sender
|
||||
* which abbreviated xattr values we need. When called by the sender
|
||||
* (with a non-NULL fname), we send all the extra xattr data it needs. */
|
||||
/* When called by the generator (with a NULL fname), this tells the sender
|
||||
* all the abbreviated xattr values we need. When called by the sender
|
||||
* (with a non-NULL fname), we send all the extra xattr data it needs.
|
||||
* The generator may also call with f_out < 0 to just change all the
|
||||
* XSTATE_ABBREV states into XSTATE_DONE. */
|
||||
void send_xattr_request(const char *fname, struct file_struct *file, int f_out)
|
||||
{
|
||||
item_list *lst = rsync_xal_l.items;
|
||||
@@ -476,6 +526,7 @@ void send_xattr_request(const char *fname, struct file_struct *file, int f_out)
|
||||
rxa->datum[0] = XSTATE_DONE;
|
||||
continue;
|
||||
case XSTATE_TODO:
|
||||
assert(f_out >= 0);
|
||||
break;
|
||||
default:
|
||||
continue;
|
||||
@@ -504,7 +555,8 @@ void send_xattr_request(const char *fname, struct file_struct *file, int f_out)
|
||||
}
|
||||
}
|
||||
|
||||
write_byte(f_out, 0); /* end the list */
|
||||
if (f_out >= 0)
|
||||
write_byte(f_out, 0); /* end the list */
|
||||
}
|
||||
|
||||
/* When called by the sender, read the request from the generator and mark
|
||||
@@ -538,8 +590,9 @@ int recv_xattr_request(struct file_struct *file, int f_in)
|
||||
who_am_i(), num, f_name(file, NULL));
|
||||
exit_cleanup(RERR_STREAMIO);
|
||||
}
|
||||
if (rxa->datum_len <= MAX_FULL_DATUM || rxa->datum[0] != XSTATE_ABBREV) {
|
||||
rprintf(FERROR, "[%s] internal abbrev error!\n", who_am_i());
|
||||
if (!XATTR_ABBREV(*rxa) || rxa->datum[0] != XSTATE_ABBREV) {
|
||||
rprintf(FERROR, "[%s] internal abbrev error on %s (%s, len=%ld)!\n",
|
||||
who_am_i(), f_name(file, NULL), rxa->name, (long)rxa->datum_len);
|
||||
exit_cleanup(RERR_STREAMIO);
|
||||
}
|
||||
|
||||
@@ -552,7 +605,7 @@ int recv_xattr_request(struct file_struct *file, int f_in)
|
||||
rxa->datum_len = read_varint(f_in);
|
||||
|
||||
if (rxa->name_len + rxa->datum_len < rxa->name_len)
|
||||
out_of_memory("recv_xattr_request"); /* overflow */
|
||||
overflow_exit("recv_xattr_request");
|
||||
rxa->datum = new_array(char, rxa->datum_len + rxa->name_len);
|
||||
if (!rxa->datum)
|
||||
out_of_memory("recv_xattr_request");
|
||||
@@ -574,6 +627,11 @@ void receive_xattr(struct file_struct *file, int f)
|
||||
{
|
||||
static item_list temp_xattr = EMPTY_ITEM_LIST;
|
||||
int count, num;
|
||||
#ifdef HAVE_LINUX_XATTRS
|
||||
int need_sort = 0;
|
||||
#else
|
||||
int need_sort = 1;
|
||||
#endif
|
||||
int ndx = read_varint(f);
|
||||
|
||||
if (ndx < 0 || (size_t)ndx > rsync_xal_l.count) {
|
||||
@@ -599,10 +657,9 @@ void receive_xattr(struct file_struct *file, int f)
|
||||
size_t datum_len = read_varint(f);
|
||||
size_t dget_len = datum_len > MAX_FULL_DATUM ? 1 + MAX_DIGEST_LEN : datum_len;
|
||||
size_t extra_len = MIGHT_NEED_RPRE ? RPRE_LEN : 0;
|
||||
if (dget_len + extra_len < dget_len)
|
||||
out_of_memory("receive_xattr"); /* overflow */
|
||||
if (dget_len + extra_len + name_len < dget_len)
|
||||
out_of_memory("receive_xattr"); /* overflow */
|
||||
if ((dget_len + extra_len < dget_len)
|
||||
|| (dget_len + extra_len + name_len < dget_len))
|
||||
overflow_exit("receive_xattr");
|
||||
ptr = new_array(char, dget_len + extra_len + name_len);
|
||||
if (!ptr)
|
||||
out_of_memory("receive_xattr");
|
||||
@@ -624,6 +681,7 @@ void receive_xattr(struct file_struct *file, int f)
|
||||
name -= RPRE_LEN;
|
||||
name_len += RPRE_LEN;
|
||||
memcpy(name, RSYNC_PREFIX, RPRE_LEN);
|
||||
need_sort = 1;
|
||||
}
|
||||
#else
|
||||
/* This OS only has a user namespace, so we either
|
||||
@@ -655,6 +713,9 @@ void receive_xattr(struct file_struct *file, int f)
|
||||
rxa->num = num;
|
||||
}
|
||||
|
||||
if (need_sort && count > 1)
|
||||
qsort(temp_xattr.items, count, sizeof (rsync_xa), rsync_xal_compare_names);
|
||||
|
||||
ndx = rsync_xal_l.count; /* pre-incremented count */
|
||||
rsync_xal_store(&temp_xattr); /* adds item to rsync_xal_l */
|
||||
|
||||
@@ -684,7 +745,11 @@ static int rsync_xal_set(const char *fname, item_list *xalp,
|
||||
ssize_t list_len;
|
||||
size_t i, len;
|
||||
char *name, *ptr, sum[MAX_DIGEST_LEN];
|
||||
int name_len, ret = 0;
|
||||
#ifdef HAVE_LINUX_XATTRS
|
||||
int user_only = am_root <= 0;
|
||||
#endif
|
||||
size_t name_len;
|
||||
int ret = 0;
|
||||
|
||||
/* This puts the current name list into the "namebuf" buffer. */
|
||||
if ((list_len = get_xattr_names(fname)) < 0)
|
||||
@@ -758,8 +823,8 @@ static int rsync_xal_set(const char *fname, item_list *xalp,
|
||||
#ifdef HAVE_LINUX_XATTRS
|
||||
/* We always ignore the system namespace, and non-root
|
||||
* ignores everything but the user namespace. */
|
||||
if (am_root ? HAS_PREFIX(name, SYSTEM_PREFIX)
|
||||
: !HAS_PREFIX(name, USER_PREFIX))
|
||||
if (user_only ? !HAS_PREFIX(name, USER_PREFIX)
|
||||
: HAS_PREFIX(name, SYSTEM_PREFIX))
|
||||
continue;
|
||||
#endif
|
||||
if (am_root < 0 && name_len > RPRE_LEN
|
||||
|
||||
Reference in New Issue
Block a user