mirror of
https://github.com/RsyncProject/rsync.git
synced 2026-05-24 23:05:52 -04:00
Compare commits
262 Commits
v3.4.1-sec
...
v3.0.9pre1
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
93bdc6478e | ||
|
|
2d07fa6350 | ||
|
|
33e37a49ba | ||
|
|
5782ac04d7 | ||
|
|
fc41c32159 | ||
|
|
365124a214 | ||
|
|
dbf68ca4c1 | ||
|
|
ba35ba06c9 | ||
|
|
0b519262c6 | ||
|
|
3ef38b0d1b | ||
|
|
5a1d092ae1 | ||
|
|
1ddcdaf3f6 | ||
|
|
93562b1941 | ||
|
|
959bd70820 | ||
|
|
a7271fb30f | ||
|
|
277036153a | ||
|
|
bc6363f9ab | ||
|
|
e71130fd77 | ||
|
|
38c9f1becf | ||
|
|
779663fc6c | ||
|
|
9562cc8925 | ||
|
|
a945aa19d9 | ||
|
|
2a1d251750 | ||
|
|
8750f64ec7 | ||
|
|
922895d9a3 | ||
|
|
72193c82a6 | ||
|
|
b178eb04d3 | ||
|
|
3158b8df6c | ||
|
|
aa3640c09b | ||
|
|
07b5c770db | ||
|
|
8b7f20b6d3 | ||
|
|
1dabd5dc9a | ||
|
|
58d657c98f | ||
|
|
e46262f36d | ||
|
|
4d92246a54 | ||
|
|
8f48ba03b5 | ||
|
|
eb8058577d | ||
|
|
3c624bba85 | ||
|
|
24e76f840e | ||
|
|
b62ea517f6 | ||
|
|
a6b3c2b512 | ||
|
|
4e95f91f27 | ||
|
|
fad4ab9d0b | ||
|
|
f91b15fbd6 | ||
|
|
83b94efa6b | ||
|
|
2064c28d6d | ||
|
|
c499002e51 | ||
|
|
c8255147b0 | ||
|
|
eee85e3c36 | ||
|
|
0c0219fe84 | ||
|
|
a92edcbf5c | ||
|
|
17549c95de | ||
|
|
9d6fe1a6f0 | ||
|
|
c43624c575 | ||
|
|
4baef8d663 | ||
|
|
c3ee6ac369 | ||
|
|
63c5ac38a2 | ||
|
|
ce41e68995 | ||
|
|
8538db7829 | ||
|
|
559bd2ff31 | ||
|
|
485a40318c | ||
|
|
ede8cae34b | ||
|
|
58ab32037d | ||
|
|
00cde6582c | ||
|
|
e6ba6e1107 | ||
|
|
efad2e85ea | ||
|
|
c463617443 | ||
|
|
6abb59adf6 | ||
|
|
d79bc5c791 | ||
|
|
10cd07c225 | ||
|
|
62e9eb7bc2 | ||
|
|
de20d72541 | ||
|
|
f8cd1c4730 | ||
|
|
5de3fe19b6 | ||
|
|
0ac2d243bf | ||
|
|
14556a30b3 | ||
|
|
8c1f2d53ec | ||
|
|
f532cede11 | ||
|
|
05022e00a2 | ||
|
|
24a743b565 | ||
|
|
e36f5c9f6c | ||
|
|
c9c3215698 | ||
|
|
dbfde9e50a | ||
|
|
1cdb5e1c86 | ||
|
|
24afdc500a | ||
|
|
303759b803 | ||
|
|
a699f7c6af | ||
|
|
a250fa251b | ||
|
|
e44aa644c2 | ||
|
|
ef67c238b5 | ||
|
|
111599be2b | ||
|
|
8e918e1861 | ||
|
|
0874fc4872 | ||
|
|
55dbbdeafe | ||
|
|
cbd27d5e18 | ||
|
|
178ccdde7d | ||
|
|
e51bb8f330 | ||
|
|
6d9207bd38 | ||
|
|
6b87566744 | ||
|
|
b384d71e53 | ||
|
|
11f4f34ed9 | ||
|
|
fe2c582af8 | ||
|
|
2ecd8b7cd2 | ||
|
|
54f00c3f89 | ||
|
|
1fc8c51705 | ||
|
|
b04604945d | ||
|
|
808b1d61c0 | ||
|
|
2f01fb1152 | ||
|
|
ae358c1960 | ||
|
|
212dfdb960 | ||
|
|
c11a77894b | ||
|
|
96cce18ce6 | ||
|
|
a21264a8b9 | ||
|
|
96486cc534 | ||
|
|
e0b1b82d84 | ||
|
|
d94b958400 | ||
|
|
79731940bb | ||
|
|
bdc038fce0 | ||
|
|
2eacba9c41 | ||
|
|
0c5853c32e | ||
|
|
3baa4d2b31 | ||
|
|
018dc6f998 | ||
|
|
523dad4bb3 | ||
|
|
e0c17aa3b7 | ||
|
|
79870bd269 | ||
|
|
e4368e37fe | ||
|
|
eee529f571 | ||
|
|
ff4715a7c2 | ||
|
|
855983b434 | ||
|
|
2455140b04 | ||
|
|
ae4d4205e3 | ||
|
|
9523670032 | ||
|
|
01e57e926c | ||
|
|
ebbab3788f | ||
|
|
d041c17c40 | ||
|
|
b2b1af40c2 | ||
|
|
c5759a2817 | ||
|
|
5ef08b8c39 | ||
|
|
03f907e386 | ||
|
|
573e24346c | ||
|
|
a415379037 | ||
|
|
cc4edc2d78 | ||
|
|
07bd6618b9 | ||
|
|
2daed024b1 | ||
|
|
6622816eff | ||
|
|
3f137ce0e2 | ||
|
|
d616bff57f | ||
|
|
40b3a59fc8 | ||
|
|
4640ae85fe | ||
|
|
24f739c118 | ||
|
|
996824825f | ||
|
|
bbef6566cd | ||
|
|
9be5093726 | ||
|
|
feb8dacc14 | ||
|
|
ff908116ef | ||
|
|
ea53d161be | ||
|
|
7875e6fe63 | ||
|
|
8e2771aa6e | ||
|
|
386f22cec6 | ||
|
|
272adea36b | ||
|
|
a69b165524 | ||
|
|
bf350d7b31 | ||
|
|
70a9cd5752 | ||
|
|
42560e2e53 | ||
|
|
d058d0aecd | ||
|
|
af00666a40 | ||
|
|
2517f5440d | ||
|
|
f2522e3f53 | ||
|
|
8fba76d5c3 | ||
|
|
782b96d3e2 | ||
|
|
1f6b697f28 | ||
|
|
919491948e | ||
|
|
0ea6f486d9 | ||
|
|
9493048c10 | ||
|
|
4dea1a9492 | ||
|
|
650bca3770 | ||
|
|
794f38099a | ||
|
|
8250d8a1c6 | ||
|
|
1fb6163c51 | ||
|
|
7f51d0e849 | ||
|
|
ece2d0e415 | ||
|
|
445640e803 | ||
|
|
5ea7c8aae3 | ||
|
|
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 |
5
.gitignore
vendored
5
.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,8 @@ config.status
|
||||
/rounding.h
|
||||
/doc/rsync.pdf
|
||||
/doc/rsync.ps
|
||||
/support/savetransfer
|
||||
/testsuite/chown-fake.test
|
||||
/testsuite/devices-fake.test
|
||||
/testsuite/xattrs-hlink.test
|
||||
/patches
|
||||
|
||||
13
INSTALL
13
INSTALL
@@ -17,7 +17,7 @@ for the daemon by editing the NOBODY_USER and NOBODY_GROUP defines in
|
||||
config.h, or just override them in your /etc/rsyncd.conf file.
|
||||
|
||||
As of 2.4.7, rsync uses Eric Troan's popt option-parsing library. A
|
||||
cut-down copy of release 1.6.4 is included in the rsync distribution,
|
||||
cut-down copy of a recent release is included in the rsync distribution,
|
||||
and will be used if there is no popt library on your build host, or if
|
||||
the --with-included-popt option is passed to ./configure.
|
||||
|
||||
@@ -25,6 +25,17 @@ If you configure using --enable-maintainer-mode, then rsync will try
|
||||
to pop up an xterm on DISPLAY=:0 if it crashes. You might find this
|
||||
useful, but it should be turned off for production builds.
|
||||
|
||||
MAKE COMPATIBILITY
|
||||
------------------
|
||||
|
||||
Note that Makefile.in has a rule that uses a wildcard in a prerequisite. If
|
||||
your make has a problem with this rule, you will see an error like this:
|
||||
|
||||
Don't know how to make ./*.c
|
||||
|
||||
You can change the "proto.h-tstamp" target in Makefile.in to list all the *.c
|
||||
filenames explicitly in order to avoid this issue.
|
||||
|
||||
RPM NOTES
|
||||
---------
|
||||
|
||||
|
||||
59
Makefile.in
59
Makefile.in
@@ -48,7 +48,7 @@ TLS_OBJ = tls.o syscall.o lib/compat.o lib/snprintf.o lib/permstring.o lib/sysxa
|
||||
CHECK_PROGS = rsync$(EXEEXT) tls$(EXEEXT) getgroups$(EXEEXT) getfsdev$(EXEEXT) \
|
||||
trimslash$(EXEEXT) t_unsafe$(EXEEXT) wildtest$(EXEEXT)
|
||||
|
||||
CHECK_SYMLINKS = testsuite/chown-fake.test testsuite/devices-fake.test
|
||||
CHECK_SYMLINKS = testsuite/chown-fake.test testsuite/devices-fake.test testsuite/xattrs-hlink.test
|
||||
|
||||
# Objects for CHECK_PROGS to clean
|
||||
CHECK_OBJS=tls.o getgroups.o getfsdev.o t_stub.o t_unsafe.o trimslash.o wildtest.o
|
||||
@@ -59,7 +59,7 @@ CHECK_OBJS=tls.o getgroups.o getfsdev.o t_stub.o t_unsafe.o trimslash.o wildtest
|
||||
$(CC) -I. -I$(srcdir) $(CFLAGS) $(CPPFLAGS) -c $< @CC_SHOBJ_FLAG@
|
||||
@OBJ_RESTORE@
|
||||
|
||||
all: conf_stop make_stop rsync$(EXEEXT) @MAKE_MAN@
|
||||
all: Makefile rsync$(EXEEXT) @MAKE_MAN@
|
||||
|
||||
install: all
|
||||
-mkdir -p ${DESTDIR}${bindir}
|
||||
@@ -123,32 +123,58 @@ gensend: gen
|
||||
conf:
|
||||
cd $(srcdir) && $(MAKE) -f prepare-source.mak conf
|
||||
|
||||
conf_stop: configure.sh config.h.in
|
||||
|
||||
configure.sh config.h.in: configure.in aclocal.m4
|
||||
configure.sh config.h.in: configure.ac aclocal.m4
|
||||
@if test -f configure.sh; then cp -p configure.sh configure.sh.old; else touch configure.sh.old; fi
|
||||
@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
|
||||
./config.status
|
||||
|
||||
make_stop: Makefile
|
||||
|
||||
Makefile: Makefile.in config.status
|
||||
Makefile: Makefile.in config.status configure.sh config.h.in
|
||||
@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 \
|
||||
if test "$(MAKECMDGOALS)" = reconfigure; then \
|
||||
echo 'Continuing with "make reconfigure".'; \
|
||||
else \
|
||||
echo "Makefile updated -- rerun your make command."; \
|
||||
exit 1; \
|
||||
fi \
|
||||
fi
|
||||
|
||||
proto: proto.h-tstamp
|
||||
|
||||
proto.h: proto.h-tstamp
|
||||
@if test -f proto.h; then :; else cp -p $(srcdir)/proto.h .; fi
|
||||
|
||||
proto.h-tstamp: $(srcdir)/*.c $(srcdir)/lib/compat.c
|
||||
proto.h-tstamp: $(srcdir)/*.c $(srcdir)/lib/compat.c config.h
|
||||
perl $(srcdir)/mkproto.pl $(srcdir)/*.c $(srcdir)/lib/compat.c
|
||||
|
||||
man: rsync.1 rsyncd.conf.5
|
||||
@@ -165,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*
|
||||
@@ -223,6 +249,9 @@ testsuite/chown-fake.test:
|
||||
testsuite/devices-fake.test:
|
||||
ln -s devices.test $(srcdir)/testsuite/devices-fake.test
|
||||
|
||||
testsuite/xattrs-hlink.test:
|
||||
ln -s xattrs.test $(srcdir)/testsuite/xattrs-hlink.test
|
||||
|
||||
# This does *not* depend on building or installing: you can use it to
|
||||
# check a version installed from a binary or some other source tree,
|
||||
# if you want.
|
||||
|
||||
88
NEWS
88
NEWS
@@ -1,89 +1,19 @@
|
||||
NEWS for rsync 3.0.3 (29 Jun 2008)
|
||||
NEWS for rsync 3.0.9 (UNRELEASED)
|
||||
Protocol: 30 (unchanged)
|
||||
Changes since 3.0.2:
|
||||
Changes since 3.0.8:
|
||||
|
||||
BUG FIXES:
|
||||
|
||||
- Fixed a wildcard matching problem in the daemon when a module has
|
||||
"use chroot" enabled.
|
||||
- Fix a crash bug in checksum scanning when --inplace is used.
|
||||
|
||||
- Fixed a crash bug in the hard-link code.
|
||||
- Fix preservation of a symlink's system xattrs (e.g. selinux) on Linux.
|
||||
|
||||
- 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.
|
||||
- Fix a bug with the modifying of unwritable directories.
|
||||
|
||||
- Fixed an xattr-sending glitch that could cause an "Internal abbrev"
|
||||
error.
|
||||
- Fix --fake-super's interaction with --link-dest same-file comparisons.
|
||||
|
||||
- Fixed the combination of --xattrs and --backup.
|
||||
- Fix the updating of the curr_dir buffer to avoid a duplicate slash.
|
||||
|
||||
- The generator no longer allows a '.' dir to be excluded by a daemon-
|
||||
exclude rule.
|
||||
- Make daemon-excluded file errors more error-like.
|
||||
|
||||
- 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.
|
||||
- Fix some issues with the post-processing of the man pages.
|
||||
|
||||
496
OLDNEWS
496
OLDNEWS
@@ -1,3 +1,487 @@
|
||||
NEWS for rsync 3.0.8 (26 Mar 2011)
|
||||
Protocol: 30 (unchanged)
|
||||
Changes since 3.0.7:
|
||||
|
||||
BUG FIXES:
|
||||
|
||||
- Fixed two buffer-overflow issues: one where a directory path that is
|
||||
exactly MAXPATHLEN was not handled correctly, and one handling a
|
||||
--backup-dir that is extra extra large.
|
||||
|
||||
- Fixed a data-corruption issue when preserving hard-links without
|
||||
preserving file ownership, and doing deletions either before or during
|
||||
the transfer (CVE-2011-1097). This fixes some assert errors in the
|
||||
hard-linking code, and some potential failed checksums (via -c) that
|
||||
should have matched.
|
||||
|
||||
- Fixed a potential crash when an rsync daemon has a filter/exclude list
|
||||
and the transfer is using ACLs or xattrs.
|
||||
|
||||
- Fixed a hang if a really large file is being processed by an rsync that
|
||||
can't handle 64-bit numbers. Rsync will now complain about the file
|
||||
being too big and skip it.
|
||||
|
||||
- For devices and special files, we now avoid gathering useless ACL and/or
|
||||
xattr information for files that aren't being copied. (The un-copied
|
||||
files are still put into the file list, but there's no need to gather
|
||||
data that is not going to be used.) This ensures that if the user uses
|
||||
--no-D, that rsync can't possibly complain about being unable to gather
|
||||
extended information from special files that are in the file list (but
|
||||
not in the transfer).
|
||||
|
||||
- Properly handle requesting remote filenames that start with a dash. This
|
||||
avoids a potential error where a filename could be interpreted as a
|
||||
(usually invalid) option.
|
||||
|
||||
- Fixed a bug in the comparing of upper-case letters in file suffixes for
|
||||
--skip-compress.
|
||||
|
||||
- If an rsync daemon has a module configured without a path setting, rsync
|
||||
will now disallow access to that module.
|
||||
|
||||
- If the destination arg is an empty string, it will be treated as a
|
||||
reference to the current directory (as 2.x used to do).
|
||||
|
||||
- If rsync was compiled with a newer time-setting function (such as
|
||||
lutimes), rsync will fall-back to an older function (such as utimes) on a
|
||||
system where the newer function is not around. This helps to make the
|
||||
rsync binary more portable in mixed-OS-release situations.
|
||||
|
||||
- Fixed a batch-file writing bug that would not write out the full set of
|
||||
compatibility flags that the transfer was using. This fixes a potential
|
||||
protocol problem for a batch file that contains a sender-side I/O error:
|
||||
it would have been sent in a way that the batch-reader wasn't expecting.
|
||||
|
||||
- Some improvements to the hard-linking code to ensure that device-number
|
||||
hashing is working right, and to supply more information if the hard-link
|
||||
code fails.
|
||||
|
||||
- The --inplace code was improved to not search for an impossible checksum
|
||||
position. The quadruple-verbose chunk[N] message will now mention when
|
||||
an inplace chunk was handled by a seek rather than a read+write.
|
||||
|
||||
- Improved ACL mask handling, e.g. for Solaris.
|
||||
|
||||
- Fixed a bug that prevented --numeric-ids from disabling the translation
|
||||
of user/group IDs for ACLs.
|
||||
|
||||
- Fixed an issue where an xattr and/or ACL transfer that used an alt-dest
|
||||
option (e.g. --link-dest) could output an error trying to itemize the
|
||||
changes against the alt-dest directory's xattr/ACL info but was instead
|
||||
trying to access the not-yet-existing new destination directory.
|
||||
|
||||
- Improved xattr system-error messages to mention the full path to the
|
||||
file.
|
||||
|
||||
- The --link-dest checking for identical symlinks now avoids considering
|
||||
attribute differences that cannot be changed on the receiver.
|
||||
|
||||
- Avoid trying to read/write xattrs on certain file types for certain OSes.
|
||||
Improved configure to set NO_SYMLINK_XATTRS, NO_DEVICE_XATTRS, and/or
|
||||
NO_SPECIAL_XATTRS defines in config.h.
|
||||
|
||||
- Improved the unsafe-symlink errors messages.
|
||||
|
||||
- Fixed a bug setting xattrs on new files that aren't user writable.
|
||||
|
||||
- Avoid re-setting xattrs on a hard-linked file w/the same xattrs.
|
||||
|
||||
- Fixed a bug with --fake-super when copying files and dirs that aren't
|
||||
user writable.
|
||||
|
||||
- Fixed a bug where a sparse file could have its last sparse block turned
|
||||
into a real block when rsync sets the file size (requires ftruncate).
|
||||
|
||||
- If a temp-file name is too long, rsync now avoids truncating the name in
|
||||
the middle of adjacent high-bit characters. This prevents a potential
|
||||
filename error if the filesystem doesn't allow a name to contain an
|
||||
invalid multi-byte sequence.
|
||||
|
||||
- If a muli-protocol socket connection fails (i.e., when contacting a
|
||||
daemon), we now report all the failures, not just the last one. This
|
||||
avoids losing a relevant error (e.g. an IPv4 connection-refused error)
|
||||
that happened before the final error (e.g. an IPv6 protocol-not-supported
|
||||
error).
|
||||
|
||||
- Generate a transfer error if we try to call chown with a -1 for a uid or
|
||||
a gid (which is not settable).
|
||||
|
||||
- Fixed the working of --force when used with --one-file-system.
|
||||
|
||||
- Fix the popt arg parsing so that an option that doesn't take an arg will
|
||||
reject an attempt to supply one (can configure --with-included-popt if
|
||||
your system's popt library doesn't yet have this fix).
|
||||
|
||||
- A couple minor option tweaks to the support/rrsync script, and also some
|
||||
regex changes that make vim highlighting happier.
|
||||
|
||||
- Fixed some issues in the support/mnt-excl script.
|
||||
|
||||
- Various manpage improvements.
|
||||
|
||||
ENHANCEMENTS:
|
||||
|
||||
- Added ".hg/" to the default cvs excludes (see -C & --cvs-exclude).
|
||||
|
||||
DEVELOPER RELATED:
|
||||
|
||||
- Use lchmod() whenever it is available (not just on symlinks).
|
||||
|
||||
- A couple fixes to the socketpair_tcp() routine.
|
||||
|
||||
- Updated the helper scripts in the packaging subdirectory.
|
||||
|
||||
- Renamed configure.in to configure.ac.
|
||||
|
||||
- Fixed configure's checking for iconv routines for newer OS X versions.
|
||||
|
||||
- Fixed the testsuite/xattrs.test script on OS X.
|
||||
|
||||
|
||||
NEWS for rsync 3.0.7 (31 Dec 2009)
|
||||
Protocol: 30 (unchanged)
|
||||
Changes since 3.0.6:
|
||||
|
||||
BUG FIXES:
|
||||
|
||||
- Fixed a bogus free when using --xattrs with --backup.
|
||||
|
||||
- Avoid an error when --dry-run was trying to stat a prior hard-link file
|
||||
that hasn't really been created.
|
||||
|
||||
- Fixed a problem with --compress (-z) where the receiving side could
|
||||
return the error "inflate (token) returned -5".
|
||||
|
||||
- Fixed a bug where --delete-during could delete in a directory before it
|
||||
noticed that the sending side sent an I/O error for that directory (both
|
||||
sides of the transfer must be at least 3.0.7).
|
||||
|
||||
- Improved --skip-compress's error handling of bad character-sets and got
|
||||
rid of a lingering debug fprintf().
|
||||
|
||||
- Fixed the daemon's conveyance of io_error value from the sender.
|
||||
|
||||
- An rsync daemon use seteuid() (when available) if it used setuid().
|
||||
|
||||
- Get the permissions right on a --fake-super transferred directory that
|
||||
needs more owner permissions to emulate root behavior.
|
||||
|
||||
- An absolute-path filter rule (i.e. with a '/' modifier) no longer loses
|
||||
its modifier when sending the filter rules to the remote rsync.
|
||||
|
||||
- Improved the "--delete does not work without -r or -d" message.
|
||||
|
||||
- Improved rsync's handling of --timeout to avoid a weird timeout case
|
||||
where the sender could timeout even though it has recently written data
|
||||
to the socket (but hasn't read data recently, due to the writing).
|
||||
|
||||
- Some misc manpage improvements.
|
||||
|
||||
- Fixed the chmod-temp-dir testsuite on a system without /var/tmp.
|
||||
|
||||
- Make sure that a timeout specified in the daemon's config is used as a
|
||||
maximum timeout value when the user also specifies a timeout.
|
||||
|
||||
- Improved the error-exit reporting when rsync gets an error trying to
|
||||
cleanup after an error: the initial error is reported.
|
||||
|
||||
- Improved configure's detection of IPv6 for solaris and cygwin.
|
||||
|
||||
- The AIX sysacls routines will now return ENOSYS if ENOTSUP is missing.
|
||||
|
||||
- Made our (only used if missing) getaddrinfo() routine use inet_pton()
|
||||
(which we also provide) instead of inet_aton().
|
||||
|
||||
- The exit-related debug messages now mention the program's role so it is
|
||||
clear who output what message.
|
||||
|
||||
DEVELOPER RELATED:
|
||||
|
||||
- Got rid of type-punned compiler warnings output by newer gcc versions.
|
||||
|
||||
- The Makefile now ensures that proto.h will be rebuilt if config.h changes.
|
||||
|
||||
- The testsuite no longer uses "id -u", so it works better on solaris.
|
||||
|
||||
|
||||
NEWS for rsync 3.0.6 (8 May 2009)
|
||||
Protocol: 30 (unchanged)
|
||||
Changes since 3.0.5:
|
||||
|
||||
BUG FIXES:
|
||||
|
||||
- Fixed a --read-batch hang when rsync is reading a batch file that was
|
||||
created from an incremental-recursion transfer.
|
||||
|
||||
- Fixed the daemon's socket code to handle the simultaneous arrival of
|
||||
multiple connections.
|
||||
|
||||
- Fix --safe-links/--copy-unsafe-links to properly handle symlinks that
|
||||
have consecutive slashes in the value.
|
||||
|
||||
- Fixed the parsing of an [IPv6_LITERAL_ADDR] when a USER@ is prefixed.
|
||||
|
||||
- The sender now skips a (bogus) symlink that has a 0-length value, which
|
||||
avoids a transfer error in the receiver.
|
||||
|
||||
- Fixed a case where the sender could die with a tag-0 error if there was
|
||||
an I/O during the sending of the file list.
|
||||
|
||||
- Fixed the rrsync script to avoid a server-side problem when -e is at the
|
||||
start of the short options.
|
||||
|
||||
- Fixed a problem where a vanished directory could turn into an exit code
|
||||
23 instead of the proper exit code 24.
|
||||
|
||||
- Fixed the --iconv conversion of symlinks when doing a local copy.
|
||||
|
||||
- Fixed a problem where --one-file-system was not stopping deletions on the
|
||||
receiving side when a mount-point directory did not match a directory in
|
||||
the transfer.
|
||||
|
||||
- Fixed the dropping of an ACL mask when no named ACL values were present.
|
||||
|
||||
- Fixed an ACL/xattr corruption issue where the --backup option could cause
|
||||
rsync to associate the wrong ACL/xattr information with received files.
|
||||
|
||||
- Fixed the use of --xattrs with --only-write-batch.
|
||||
|
||||
- Fixed the use of --dry-run with --read-batch.
|
||||
|
||||
- Fixed configure's erroneous use of target.
|
||||
|
||||
- Fixed configure's --disable-debug option.
|
||||
|
||||
- Fixed a run-time issue for systems that can't find iconv_open() by adding
|
||||
the --disable-iconv-open configure option.
|
||||
|
||||
- Complain and die if the user tries to combine --remove-source-files (or
|
||||
the deprecated --remove-sent-files) with --read-batch.
|
||||
|
||||
- Fixed an failure transferring special files from Solaris to Linux.
|
||||
|
||||
|
||||
NEWS for rsync 3.0.5 (28 Dec 2008)
|
||||
Protocol: 30 (unchanged)
|
||||
Changes since 3.0.4:
|
||||
|
||||
BUG FIXES:
|
||||
|
||||
- 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.
|
||||
|
||||
- Don't send a bogus "-" option to an older server if there were no short
|
||||
options specified.
|
||||
|
||||
- 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).
|
||||
|
||||
- Fix the %P logfile escape when the daemon logs from inside a chroot.
|
||||
|
||||
- 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.
|
||||
|
||||
- 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.
|
||||
|
||||
- Fixed a bug with "-K --delete" removing symlinks to directories when
|
||||
incremental recursion is active.
|
||||
|
||||
- Fixed a hard to trigger hang when using --remove-source-files.
|
||||
|
||||
- Got rid of an annoying delay when accessing a daemon via a remote-shell.
|
||||
|
||||
- Properly ignore (superfluous) source args on a --read-batch command.
|
||||
|
||||
- Improved the manpage's description of the '*' wildcard to remove the
|
||||
confusing "non-empty" qualifier.
|
||||
|
||||
- Fixed reverse lookups in the compatibility-library version of
|
||||
getnameinfo().
|
||||
|
||||
- Fixed a bug when using --sparse on a sparse file that has over 2GB of
|
||||
consecutive sparse data.
|
||||
|
||||
- Avoid a hang when using at least 3 --verbose options on a transfer with a
|
||||
client sender (which includes local copying).
|
||||
|
||||
- Fixed a problem with --delete-delay reporting an error when it was ready
|
||||
to remove a directory that was now gone.
|
||||
|
||||
- Got rid of a bunch of "warn_unused_result" compiler warnings.
|
||||
|
||||
- If an ftruncate() on a received file fails, it now causes a partial-
|
||||
transfer warning.
|
||||
|
||||
- Allow a path with a leading "//" to be preserved (CYGWIN only).
|
||||
|
||||
ENHANCEMENTS:
|
||||
|
||||
- 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.
|
||||
|
||||
|
||||
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:
|
||||
@@ -290,6 +774,11 @@ Changes since 2.6.9:
|
||||
- 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
|
||||
@@ -2742,9 +3231,16 @@ Changes since 2.4.6:
|
||||
* The existing test.sh script by Phil Hands has been merged into a
|
||||
test framework that works from both "make check" and the Samba
|
||||
build farm.
|
||||
|
||||
|
||||
Partial Protocol History
|
||||
RELEASE DATE VER. DATE OF COMMIT* PROTOCOL
|
||||
?? Jun 2011 3.0.9 30
|
||||
26 Mar 2011 3.0.8 30
|
||||
31 Dec 2009 3.0.7 30
|
||||
08 May 2009 3.0.6 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
|
||||
|
||||
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-2008 Wayne Davison
|
||||
* Copyright (C) 2004-2009 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
|
||||
|
||||
200
acls.c
200
acls.c
@@ -3,7 +3,7 @@
|
||||
*
|
||||
* Copyright (C) 1996 Andrew Tridgell
|
||||
* Copyright (C) 1996 Paul Mackerras
|
||||
* Copyright (C) 2006-2008 Wayne Davison
|
||||
* Copyright (C) 2006-2009 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,8 @@ extern int list_only;
|
||||
extern int orig_umask;
|
||||
extern int numeric_ids;
|
||||
extern int inc_recurse;
|
||||
extern int preserve_devices;
|
||||
extern int preserve_specials;
|
||||
|
||||
/* Flags used to indicate what items are being transmitted for an entry. */
|
||||
#define XMIT_USER_OBJ (1<<0)
|
||||
@@ -88,6 +90,9 @@ static const rsync_acl empty_rsync_acl = {
|
||||
static item_list access_acl_list = EMPTY_ITEM_LIST;
|
||||
static item_list default_acl_list = EMPTY_ITEM_LIST;
|
||||
|
||||
static size_t prior_access_count = (size_t)-1;
|
||||
static size_t prior_default_count = (size_t)-1;
|
||||
|
||||
/* === Calculations on ACL types === */
|
||||
|
||||
static const char *str_acl_type(SMB_ACL_TYPE_T type)
|
||||
@@ -112,10 +117,11 @@ static int calc_sacl_entries(const rsync_acl *racl)
|
||||
/* A System ACL always gets user/group/other permission entries. */
|
||||
return racl->names.count
|
||||
#ifdef ACLS_NEED_MASK
|
||||
+ 4;
|
||||
+ 1
|
||||
#else
|
||||
+ (racl->mask_obj != NO_ENTRY) + 3;
|
||||
+ (racl->mask_obj != NO_ENTRY)
|
||||
#endif
|
||||
+ 3;
|
||||
}
|
||||
|
||||
/* Extracts and returns the permission bits from the ACL. This cannot be
|
||||
@@ -129,15 +135,21 @@ static int rsync_acl_get_perms(const rsync_acl *racl)
|
||||
|
||||
/* Removes the permission-bit entries from the ACL because these
|
||||
* can be reconstructed from the file's mode. */
|
||||
static void rsync_acl_strip_perms(rsync_acl *racl)
|
||||
static void rsync_acl_strip_perms(stat_x *sxp)
|
||||
{
|
||||
rsync_acl *racl = sxp->acc_acl;
|
||||
|
||||
racl->user_obj = NO_ENTRY;
|
||||
if (racl->mask_obj == NO_ENTRY)
|
||||
racl->group_obj = NO_ENTRY;
|
||||
else {
|
||||
if (racl->group_obj == racl->mask_obj)
|
||||
int group_perms = (sxp->st.st_mode >> 3) & 7;
|
||||
if (racl->group_obj == group_perms)
|
||||
racl->group_obj = NO_ENTRY;
|
||||
racl->mask_obj = NO_ENTRY;
|
||||
#ifndef HAVE_SOLARIS_ACLS
|
||||
if (racl->names.count != 0 && racl->mask_obj == group_perms)
|
||||
racl->mask_obj = NO_ENTRY;
|
||||
#endif
|
||||
}
|
||||
racl->other_obj = NO_ENTRY;
|
||||
}
|
||||
@@ -336,15 +348,6 @@ static BOOL unpack_smb_acl(SMB_ACL_T sacl, rsync_acl *racl)
|
||||
/* Truncate the temporary list now that its idas have been saved. */
|
||||
temp_ida_list.count = 0;
|
||||
|
||||
#ifdef ACLS_NEED_MASK
|
||||
if (!racl->names.count && racl->mask_obj != NO_ENTRY) {
|
||||
/* Throw away a superfluous mask, but mask off the
|
||||
* group perms with it first. */
|
||||
racl->group_obj &= racl->mask_obj;
|
||||
racl->mask_obj = NO_ENTRY;
|
||||
}
|
||||
#endif
|
||||
|
||||
return True;
|
||||
}
|
||||
|
||||
@@ -492,9 +495,15 @@ static int get_rsync_acl(const char *fname, rsync_acl *racl,
|
||||
}
|
||||
|
||||
racl->user_obj = IVAL(buf, 0);
|
||||
if (racl->user_obj == NO_ENTRY)
|
||||
racl->user_obj = (mode >> 6) & 7;
|
||||
racl->group_obj = IVAL(buf, 4);
|
||||
if (racl->group_obj == NO_ENTRY)
|
||||
racl->group_obj = (mode >> 3) & 7;
|
||||
racl->mask_obj = IVAL(buf, 8);
|
||||
racl->other_obj = IVAL(buf, 12);
|
||||
if (racl->other_obj == NO_ENTRY)
|
||||
racl->other_obj = mode & 7;
|
||||
|
||||
if (cnt) {
|
||||
char *bp = buf + 4*4;
|
||||
@@ -536,6 +545,23 @@ static int get_rsync_acl(const char *fname, rsync_acl *racl,
|
||||
int get_acl(const char *fname, stat_x *sxp)
|
||||
{
|
||||
sxp->acc_acl = create_racl();
|
||||
|
||||
if (S_ISREG(sxp->st.st_mode) || S_ISDIR(sxp->st.st_mode)) {
|
||||
/* Everyone supports this. */
|
||||
} else if (S_ISLNK(sxp->st.st_mode)) {
|
||||
return 0;
|
||||
} else if (IS_SPECIAL(sxp->st.st_mode)) {
|
||||
#ifndef NO_SPECIAL_ACLS
|
||||
if (!preserve_specials)
|
||||
#endif
|
||||
return 0;
|
||||
} else if (IS_DEVICE(sxp->st.st_mode)) {
|
||||
#ifndef NO_DEVICE_ACLS
|
||||
if (!preserve_devices)
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (get_rsync_acl(fname, sxp->acc_acl, SMB_ACL_TYPE_ACCESS,
|
||||
sxp->st.st_mode) < 0) {
|
||||
free_acl(sxp);
|
||||
@@ -557,7 +583,7 @@ int get_acl(const char *fname, stat_x *sxp)
|
||||
/* === Send functions === */
|
||||
|
||||
/* Send the ida list over the file descriptor. */
|
||||
static void send_ida_entries(const ida_entries *idal, int f)
|
||||
static void send_ida_entries(int f, const ida_entries *idal)
|
||||
{
|
||||
id_access *ida;
|
||||
size_t count = idal->count;
|
||||
@@ -569,9 +595,9 @@ static void send_ida_entries(const ida_entries *idal, int f)
|
||||
const char *name;
|
||||
if (ida->access & NAME_IS_USER) {
|
||||
xbits |= XFLAG_NAME_IS_USER;
|
||||
name = add_uid(ida->id);
|
||||
name = numeric_ids ? NULL : add_uid(ida->id);
|
||||
} else
|
||||
name = add_gid(ida->id);
|
||||
name = numeric_ids ? NULL : add_gid(ida->id);
|
||||
write_varint(f, ida->id);
|
||||
if (inc_recurse && name) {
|
||||
int len = strlen(name);
|
||||
@@ -583,8 +609,8 @@ static void send_ida_entries(const ida_entries *idal, int f)
|
||||
}
|
||||
}
|
||||
|
||||
static void send_rsync_acl(rsync_acl *racl, SMB_ACL_TYPE_T type,
|
||||
item_list *racl_list, int f)
|
||||
static void send_rsync_acl(int f, rsync_acl *racl, SMB_ACL_TYPE_T type,
|
||||
item_list *racl_list)
|
||||
{
|
||||
int ndx = find_matching_rsync_acl(racl, type, racl_list);
|
||||
|
||||
@@ -617,7 +643,7 @@ static void send_rsync_acl(rsync_acl *racl, SMB_ACL_TYPE_T type,
|
||||
if (flags & XMIT_OTHER_OBJ)
|
||||
write_varint(f, racl->other_obj);
|
||||
if (flags & XMIT_NAME_LIST)
|
||||
send_ida_entries(&racl->names, f);
|
||||
send_ida_entries(f, &racl->names);
|
||||
|
||||
/* Give the allocated data to the new list object. */
|
||||
*new_racl = *racl;
|
||||
@@ -627,28 +653,28 @@ static void send_rsync_acl(rsync_acl *racl, SMB_ACL_TYPE_T type,
|
||||
|
||||
/* Send the ACL from the stat_x structure down the indicated file descriptor.
|
||||
* This also frees the ACL data. */
|
||||
void send_acl(stat_x *sxp, int f)
|
||||
void send_acl(int f, stat_x *sxp)
|
||||
{
|
||||
if (!sxp->acc_acl) {
|
||||
sxp->acc_acl = create_racl();
|
||||
rsync_acl_fake_perms(sxp->acc_acl, sxp->st.st_mode);
|
||||
}
|
||||
/* Avoid sending values that can be inferred from other data. */
|
||||
rsync_acl_strip_perms(sxp->acc_acl);
|
||||
rsync_acl_strip_perms(sxp);
|
||||
|
||||
send_rsync_acl(sxp->acc_acl, SMB_ACL_TYPE_ACCESS, &access_acl_list, f);
|
||||
send_rsync_acl(f, sxp->acc_acl, SMB_ACL_TYPE_ACCESS, &access_acl_list);
|
||||
|
||||
if (S_ISDIR(sxp->st.st_mode)) {
|
||||
if (!sxp->def_acl)
|
||||
sxp->def_acl = create_racl();
|
||||
|
||||
send_rsync_acl(sxp->def_acl, SMB_ACL_TYPE_DEFAULT, &default_acl_list, f);
|
||||
send_rsync_acl(f, sxp->def_acl, SMB_ACL_TYPE_DEFAULT, &default_acl_list);
|
||||
}
|
||||
}
|
||||
|
||||
/* === Receive functions === */
|
||||
|
||||
static uint32 recv_acl_access(uchar *name_follows_ptr, int f)
|
||||
static uint32 recv_acl_access(int f, uchar *name_follows_ptr)
|
||||
{
|
||||
uint32 access = read_varint(f);
|
||||
|
||||
@@ -673,7 +699,7 @@ static uint32 recv_acl_access(uchar *name_follows_ptr, int f)
|
||||
return access;
|
||||
}
|
||||
|
||||
static uchar recv_ida_entries(ida_entries *ent, int f)
|
||||
static uchar recv_ida_entries(int f, ida_entries *ent)
|
||||
{
|
||||
uchar computed_mask_bits = 0;
|
||||
int i, count = read_varint(f);
|
||||
@@ -689,7 +715,7 @@ static uchar recv_ida_entries(ida_entries *ent, int f)
|
||||
for (i = 0; i < count; i++) {
|
||||
uchar has_name;
|
||||
id_t id = read_varint(f);
|
||||
uint32 access = recv_acl_access(&has_name, f);
|
||||
uint32 access = recv_acl_access(f, &has_name);
|
||||
|
||||
if (has_name) {
|
||||
if (access & NAME_IS_USER)
|
||||
@@ -712,7 +738,7 @@ static uchar recv_ida_entries(ida_entries *ent, int f)
|
||||
return computed_mask_bits & ~NO_ENTRY;
|
||||
}
|
||||
|
||||
static int recv_rsync_acl(item_list *racl_list, SMB_ACL_TYPE_T type, int f)
|
||||
static int recv_rsync_acl(int f, item_list *racl_list, SMB_ACL_TYPE_T type, mode_t mode)
|
||||
{
|
||||
uchar computed_mask_bits = 0;
|
||||
acl_duo *duo_item;
|
||||
@@ -727,7 +753,7 @@ static int recv_rsync_acl(item_list *racl_list, SMB_ACL_TYPE_T type, int f)
|
||||
|
||||
if (ndx != 0)
|
||||
return ndx - 1;
|
||||
|
||||
|
||||
ndx = racl_list->count;
|
||||
duo_item = EXPAND_ITEM_LIST(racl_list, acl_duo, 1000);
|
||||
duo_item->racl = empty_rsync_acl;
|
||||
@@ -735,29 +761,28 @@ static int recv_rsync_acl(item_list *racl_list, SMB_ACL_TYPE_T type, int f)
|
||||
flags = read_byte(f);
|
||||
|
||||
if (flags & XMIT_USER_OBJ)
|
||||
duo_item->racl.user_obj = recv_acl_access(NULL, f);
|
||||
duo_item->racl.user_obj = recv_acl_access(f, NULL);
|
||||
if (flags & XMIT_GROUP_OBJ)
|
||||
duo_item->racl.group_obj = recv_acl_access(NULL, f);
|
||||
duo_item->racl.group_obj = recv_acl_access(f, NULL);
|
||||
if (flags & XMIT_MASK_OBJ)
|
||||
duo_item->racl.mask_obj = recv_acl_access(NULL, f);
|
||||
duo_item->racl.mask_obj = recv_acl_access(f, NULL);
|
||||
if (flags & XMIT_OTHER_OBJ)
|
||||
duo_item->racl.other_obj = recv_acl_access(NULL, f);
|
||||
duo_item->racl.other_obj = recv_acl_access(f, NULL);
|
||||
if (flags & XMIT_NAME_LIST)
|
||||
computed_mask_bits |= recv_ida_entries(&duo_item->racl.names, f);
|
||||
computed_mask_bits |= recv_ida_entries(f, &duo_item->racl.names);
|
||||
|
||||
#ifdef HAVE_OSX_ACLS
|
||||
/* If we received a superfluous mask, throw it away. */
|
||||
duo_item->racl.mask_obj = NO_ENTRY;
|
||||
#else
|
||||
if (!duo_item->racl.names.count) {
|
||||
/* If we received a superfluous mask, throw it away. */
|
||||
if (duo_item->racl.mask_obj != NO_ENTRY) {
|
||||
/* Mask off the group perms with it first. */
|
||||
duo_item->racl.group_obj &= duo_item->racl.mask_obj | NO_ENTRY;
|
||||
duo_item->racl.mask_obj = NO_ENTRY;
|
||||
}
|
||||
} else if (duo_item->racl.mask_obj == NO_ENTRY) /* Must be non-empty with lists. */
|
||||
duo_item->racl.mask_obj = (computed_mask_bits | duo_item->racl.group_obj) & ~NO_ENTRY;
|
||||
if (duo_item->racl.names.count && duo_item->racl.mask_obj == NO_ENTRY) {
|
||||
/* Mask must be non-empty with lists. */
|
||||
if (type == SMB_ACL_TYPE_ACCESS)
|
||||
computed_mask_bits = (mode >> 3) & 7;
|
||||
else
|
||||
computed_mask_bits |= duo_item->racl.group_obj & ~NO_ENTRY;
|
||||
duo_item->racl.mask_obj = computed_mask_bits;
|
||||
}
|
||||
#endif
|
||||
|
||||
duo_item->sacl = NULL;
|
||||
@@ -766,12 +791,12 @@ static int recv_rsync_acl(item_list *racl_list, SMB_ACL_TYPE_T type, int f)
|
||||
}
|
||||
|
||||
/* Receive the ACL info the sender has included for this file-list entry. */
|
||||
void receive_acl(struct file_struct *file, int f)
|
||||
void receive_acl(int f, struct file_struct *file)
|
||||
{
|
||||
F_ACL(file) = recv_rsync_acl(&access_acl_list, SMB_ACL_TYPE_ACCESS, f);
|
||||
F_ACL(file) = recv_rsync_acl(f, &access_acl_list, SMB_ACL_TYPE_ACCESS, file->mode);
|
||||
|
||||
if (S_ISDIR(file->mode))
|
||||
F_DIR_DEFACL(file) = recv_rsync_acl(&default_acl_list, SMB_ACL_TYPE_DEFAULT, f);
|
||||
F_DIR_DEFACL(file) = recv_rsync_acl(f, &default_acl_list, SMB_ACL_TYPE_DEFAULT, 0);
|
||||
}
|
||||
|
||||
static int cache_rsync_acl(rsync_acl *racl, SMB_ACL_TYPE_T type, item_list *racl_list)
|
||||
@@ -794,17 +819,50 @@ static int cache_rsync_acl(rsync_acl *racl, SMB_ACL_TYPE_T type, item_list *racl
|
||||
|
||||
/* Turn the ACL data in stat_x into cached ACL data, setting the index
|
||||
* values in the file struct. */
|
||||
void cache_acl(struct file_struct *file, stat_x *sxp)
|
||||
void cache_tmp_acl(struct file_struct *file, stat_x *sxp)
|
||||
{
|
||||
if (prior_access_count == (size_t)-1)
|
||||
prior_access_count = access_acl_list.count;
|
||||
|
||||
F_ACL(file) = cache_rsync_acl(sxp->acc_acl,
|
||||
SMB_ACL_TYPE_ACCESS, &access_acl_list);
|
||||
|
||||
if (S_ISDIR(sxp->st.st_mode)) {
|
||||
if (prior_default_count == (size_t)-1)
|
||||
prior_default_count = default_acl_list.count;
|
||||
F_DIR_DEFACL(file) = cache_rsync_acl(sxp->def_acl,
|
||||
SMB_ACL_TYPE_DEFAULT, &default_acl_list);
|
||||
}
|
||||
}
|
||||
|
||||
static void uncache_duo_acls(item_list *duo_list, size_t start)
|
||||
{
|
||||
acl_duo *duo_item = duo_list->items;
|
||||
acl_duo *duo_start = duo_item + start;
|
||||
|
||||
duo_item += duo_list->count;
|
||||
duo_list->count = start;
|
||||
|
||||
while (duo_item-- > duo_start) {
|
||||
rsync_acl_free(&duo_item->racl);
|
||||
if (duo_item->sacl)
|
||||
sys_acl_free_acl(duo_item->sacl);
|
||||
}
|
||||
}
|
||||
|
||||
void uncache_tmp_acls(void)
|
||||
{
|
||||
if (prior_access_count != (size_t)-1) {
|
||||
uncache_duo_acls(&access_acl_list, prior_access_count);
|
||||
prior_access_count = (size_t)-1;
|
||||
}
|
||||
|
||||
if (prior_default_count != (size_t)-1) {
|
||||
uncache_duo_acls(&default_acl_list, prior_default_count);
|
||||
prior_default_count = (size_t)-1;
|
||||
}
|
||||
}
|
||||
|
||||
#ifndef HAVE_OSX_ACLS
|
||||
static mode_t change_sacl_perms(SMB_ACL_T sacl, rsync_acl *racl, mode_t old_mode, mode_t mode)
|
||||
{
|
||||
@@ -850,12 +908,14 @@ static mode_t change_sacl_perms(SMB_ACL_T sacl, rsync_acl *racl, mode_t old_mode
|
||||
COE2( store_access_in_entry,((mode >> 3) & 7, entry) );
|
||||
break;
|
||||
case SMB_ACL_MASK:
|
||||
#ifndef HAVE_SOLARIS_ACLS
|
||||
#ifndef ACLS_NEED_MASK
|
||||
/* mask is only empty when we don't need it. */
|
||||
if (racl->mask_obj == NO_ENTRY)
|
||||
break;
|
||||
#endif
|
||||
COE2( store_access_in_entry,((mode >> 3) & 7, entry) );
|
||||
#endif
|
||||
break;
|
||||
case SMB_ACL_OTHER:
|
||||
COE2( store_access_in_entry,(mode & 7, entry) );
|
||||
@@ -868,7 +928,7 @@ static mode_t change_sacl_perms(SMB_ACL_T sacl, rsync_acl *racl, mode_t old_mode
|
||||
rsyserr(FERROR_XFER, errno, "change_sacl_perms: %s()",
|
||||
errfun);
|
||||
}
|
||||
return (mode_t)~0;
|
||||
return (mode_t)-1;
|
||||
}
|
||||
|
||||
#ifdef SMB_ACL_LOSES_SPECIAL_MODE_BITS
|
||||
@@ -937,7 +997,7 @@ static int set_rsync_acl(const char *fname, acl_duo *duo_item,
|
||||
if (type == SMB_ACL_TYPE_ACCESS) {
|
||||
cur_mode = change_sacl_perms(duo_item->sacl, &duo_item->racl,
|
||||
cur_mode, mode);
|
||||
if (cur_mode == (mode_t)~0)
|
||||
if (cur_mode == (mode_t)-1)
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
@@ -953,17 +1013,17 @@ static int set_rsync_acl(const char *fname, acl_duo *duo_item,
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Set ACL on indicated filename.
|
||||
/* Given a fname, this sets extended access ACL entries, the default ACL (for a
|
||||
* dir), and the regular mode bits on the file. Call this with fname set to
|
||||
* NULL to just check if the ACL is different.
|
||||
*
|
||||
* This sets extended access ACL entries and default ACL. If convenient,
|
||||
* it sets permission bits along with the access ACL and signals having
|
||||
* done so by modifying sxp->st.st_mode.
|
||||
* If the ACL operation has a side-effect of changing the file's mode, the
|
||||
* sxp->st.st_mode value will be changed to match.
|
||||
*
|
||||
* Returns 1 for unchanged, 0 for changed, -1 for failed. Call this
|
||||
* with fname set to NULL to just check if the ACL is unchanged. */
|
||||
int set_acl(const char *fname, const struct file_struct *file, stat_x *sxp)
|
||||
* Returns 0 for an unchanged ACL, 1 for changed, -1 for failed. */
|
||||
int set_acl(const char *fname, const struct file_struct *file, stat_x *sxp, mode_t new_mode)
|
||||
{
|
||||
int unchanged = 1;
|
||||
int changed = 0;
|
||||
int32 ndx;
|
||||
BOOL eq;
|
||||
|
||||
@@ -977,18 +1037,18 @@ int set_acl(const char *fname, const struct file_struct *file, stat_x *sxp)
|
||||
acl_duo *duo_item = access_acl_list.items;
|
||||
duo_item += ndx;
|
||||
eq = sxp->acc_acl
|
||||
&& rsync_acl_equal_enough(sxp->acc_acl, &duo_item->racl, file->mode);
|
||||
&& rsync_acl_equal_enough(sxp->acc_acl, &duo_item->racl, new_mode);
|
||||
if (!eq) {
|
||||
unchanged = 0;
|
||||
changed = 1;
|
||||
if (!dry_run && fname
|
||||
&& set_rsync_acl(fname, duo_item, SMB_ACL_TYPE_ACCESS,
|
||||
sxp, file->mode) < 0)
|
||||
unchanged = -1;
|
||||
sxp, new_mode) < 0)
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
if (!S_ISDIR(sxp->st.st_mode))
|
||||
return unchanged;
|
||||
if (!S_ISDIR(new_mode))
|
||||
return changed;
|
||||
|
||||
ndx = F_DIR_DEFACL(file);
|
||||
if (ndx >= 0 && (size_t)ndx < default_acl_list.count) {
|
||||
@@ -996,16 +1056,15 @@ int set_acl(const char *fname, const struct file_struct *file, stat_x *sxp)
|
||||
duo_item += ndx;
|
||||
eq = sxp->def_acl && rsync_acl_equal(sxp->def_acl, &duo_item->racl);
|
||||
if (!eq) {
|
||||
if (unchanged > 0)
|
||||
unchanged = 0;
|
||||
changed = 1;
|
||||
if (!dry_run && fname
|
||||
&& set_rsync_acl(fname, duo_item, SMB_ACL_TYPE_DEFAULT,
|
||||
sxp, file->mode) < 0)
|
||||
unchanged = -1;
|
||||
sxp, new_mode) < 0)
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
return unchanged;
|
||||
return changed;
|
||||
}
|
||||
|
||||
/* Non-incremental recursion needs to convert all the received IDs.
|
||||
@@ -1048,6 +1107,9 @@ int default_perms_for_dir(const char *dir)
|
||||
if (sacl == NULL) {
|
||||
/* Couldn't get an ACL. Darn. */
|
||||
switch (errno) {
|
||||
case EINVAL:
|
||||
/* If SMB_ACL_TYPE_DEFAULT isn't valid, then the ACLs must be non-POSIX. */
|
||||
break;
|
||||
#ifdef ENOTSUP
|
||||
case ENOTSUP:
|
||||
#endif
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
* Support rsync daemon authentication.
|
||||
*
|
||||
* Copyright (C) 1998-2000 Andrew Tridgell
|
||||
* Copyright (C) 2002-2008 Wayne Davison
|
||||
* Copyright (C) 2002-2009 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
backup.c
40
backup.c
@@ -2,7 +2,7 @@
|
||||
* Backup handling code.
|
||||
*
|
||||
* Copyright (C) 1999 Andrew Tridgell
|
||||
* Copyright (C) 2003-2008 Wayne Davison
|
||||
* Copyright (C) 2003-2009 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
|
||||
@@ -148,19 +148,25 @@ int make_bak_dir(const char *fullpath)
|
||||
#ifdef SUPPORT_ACLS
|
||||
if (preserve_acls && !S_ISLNK(file->mode)) {
|
||||
get_acl(rel, &sx);
|
||||
cache_acl(file, &sx);
|
||||
cache_tmp_acl(file, &sx);
|
||||
free_acl(&sx);
|
||||
}
|
||||
#endif
|
||||
#ifdef SUPPORT_XATTRS
|
||||
if (preserve_xattrs) {
|
||||
get_xattr(rel, &sx);
|
||||
cache_xattr(file, &sx);
|
||||
cache_tmp_xattr(file, &sx);
|
||||
free_xattr(&sx);
|
||||
}
|
||||
#endif
|
||||
set_file_attrs(fbuf, file, NULL, NULL, 0);
|
||||
unmake_file(file);
|
||||
#ifdef SUPPORT_ACLS
|
||||
uncache_tmp_acls();
|
||||
#endif
|
||||
#ifdef SUPPORT_XATTRS
|
||||
uncache_tmp_xattrs();
|
||||
#endif
|
||||
}
|
||||
}
|
||||
*p = '/';
|
||||
@@ -223,20 +229,26 @@ static int keep_backup(const char *fname)
|
||||
|
||||
if (!(buf = get_backup_name(fname))) {
|
||||
unmake_file(file);
|
||||
#ifdef SUPPORT_ACLS
|
||||
uncache_tmp_acls();
|
||||
#endif
|
||||
#ifdef SUPPORT_XATTRS
|
||||
uncache_tmp_xattrs();
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef SUPPORT_ACLS
|
||||
if (preserve_acls && !S_ISLNK(file->mode)) {
|
||||
get_acl(fname, &sx);
|
||||
cache_acl(file, &sx);
|
||||
cache_tmp_acl(file, &sx);
|
||||
free_acl(&sx);
|
||||
}
|
||||
#endif
|
||||
#ifdef SUPPORT_XATTRS
|
||||
if (preserve_xattrs) {
|
||||
get_xattr(fname, &sx);
|
||||
cache_xattr(file, &sx);
|
||||
cache_tmp_xattr(file, &sx);
|
||||
free_xattr(&sx);
|
||||
}
|
||||
#endif
|
||||
@@ -295,10 +307,10 @@ static int keep_backup(const char *fname)
|
||||
#ifdef SUPPORT_LINKS
|
||||
if (!kept && preserve_links && S_ISLNK(file->mode)) {
|
||||
const char *sl = F_SYMLINK(file);
|
||||
if (safe_symlinks && unsafe_symlink(sl, buf)) {
|
||||
if (safe_symlinks && unsafe_symlink(sl, fname)) {
|
||||
if (verbose) {
|
||||
rprintf(FINFO, "ignoring unsafe symlink %s -> %s\n",
|
||||
full_fname(buf), sl);
|
||||
rprintf(FINFO, "not backing up unsafe symlink \"%s\" -> \"%s\"\n",
|
||||
fname, sl);
|
||||
}
|
||||
kept = 1;
|
||||
} else {
|
||||
@@ -326,6 +338,12 @@ static int keep_backup(const char *fname)
|
||||
rprintf(FINFO, "make_bak: skipping non-regular file %s\n",
|
||||
fname);
|
||||
unmake_file(file);
|
||||
#ifdef SUPPORT_ACLS
|
||||
uncache_tmp_acls();
|
||||
#endif
|
||||
#ifdef SUPPORT_XATTRS
|
||||
uncache_tmp_xattrs();
|
||||
#endif
|
||||
return 1;
|
||||
}
|
||||
|
||||
@@ -344,6 +362,12 @@ static int keep_backup(const char *fname)
|
||||
set_file_attrs(buf, file, NULL, fname, 0);
|
||||
preserve_xattrs = save_preserve_xattrs;
|
||||
unmake_file(file);
|
||||
#ifdef SUPPORT_ACLS
|
||||
uncache_tmp_acls();
|
||||
#endif
|
||||
#ifdef SUPPORT_XATTRS
|
||||
uncache_tmp_xattrs();
|
||||
#endif
|
||||
|
||||
if (verbose > 1) {
|
||||
rprintf(FINFO, "backed up %s to %s\n",
|
||||
|
||||
59
batch.c
59
batch.c
@@ -3,7 +3,7 @@
|
||||
*
|
||||
* Copyright (C) 1999 Weiss
|
||||
* Copyright (C) 2004 Chris Shoemaker
|
||||
* Copyright (C) 2004-2008 Wayne Davison
|
||||
* Copyright (C) 2004-2009 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);
|
||||
|
||||
66
byteorder.h
66
byteorder.h
@@ -19,6 +19,7 @@
|
||||
*/
|
||||
|
||||
#undef CAREFUL_ALIGNMENT
|
||||
#undef AVOID_BYTEORDER_INLINE
|
||||
|
||||
/* We know that the x86 can handle misalignment and has the same
|
||||
* byte order (LSB-first) as the 32-bit numbers we transmit. */
|
||||
@@ -32,21 +33,68 @@
|
||||
|
||||
#define CVAL(buf,pos) (((unsigned char *)(buf))[pos])
|
||||
#define UVAL(buf,pos) ((uint32)CVAL(buf,pos))
|
||||
#define SCVAL(buf,pos,val) (CVAL(buf,pos) = (val))
|
||||
|
||||
#if CAREFUL_ALIGNMENT
|
||||
|
||||
#define PVAL(buf,pos) (UVAL(buf,pos)|UVAL(buf,(pos)+1)<<8)
|
||||
#define IVAL(buf,pos) (PVAL(buf,pos)|PVAL(buf,(pos)+2)<<16)
|
||||
#define SSVALX(buf,pos,val) (CVAL(buf,pos)=(val)&0xFF,CVAL(buf,pos+1)=(val)>>8)
|
||||
#define SIVALX(buf,pos,val) (SSVALX(buf,pos,val&0xFFFF),SSVALX(buf,pos+2,val>>16))
|
||||
#define SIVAL(buf,pos,val) SIVALX((buf),(pos),((uint32)(val)))
|
||||
#else
|
||||
/* this handles things for architectures like the 386 that can handle
|
||||
alignment errors */
|
||||
/*
|
||||
WARNING: This section is dependent on the length of int32
|
||||
being correct. set CAREFUL_ALIGNMENT if it is not.
|
||||
*/
|
||||
|
||||
#define IVALu(buf,pos) IVAL(buf,pos)
|
||||
#define SIVALu(buf,pos,val) SIVAL(buf,pos,val)
|
||||
|
||||
#else /* !CAREFUL_ALIGNMENT */
|
||||
|
||||
/* This handles things for architectures like the 386 that can handle alignment errors.
|
||||
* WARNING: This section is dependent on the length of an int32 (and thus a uint32)
|
||||
* being correct (4 bytes)! Set CAREFUL_ALIGNMENT if it is not. */
|
||||
|
||||
# ifdef AVOID_BYTEORDER_INLINE
|
||||
|
||||
#define IVAL(buf,pos) (*(uint32 *)((char *)(buf) + (pos)))
|
||||
#define SIVAL(buf,pos,val) IVAL(buf,pos)=((uint32)(val))
|
||||
#endif
|
||||
|
||||
#define IVALu(buf,pos) IVAL(buf,pos)
|
||||
#define SIVALu(buf,pos,val) SIVAL(buf,pos,val)
|
||||
|
||||
# else /* !AVOID_BYTEORDER_INLINE */
|
||||
|
||||
static inline uint32
|
||||
IVALu(const uchar *buf, int pos)
|
||||
{
|
||||
union {
|
||||
const uchar *b;
|
||||
const uint32 *num;
|
||||
} u;
|
||||
u.b = buf + pos;
|
||||
return *u.num;
|
||||
}
|
||||
|
||||
static inline void
|
||||
SIVALu(uchar *buf, int pos, uint32 val)
|
||||
{
|
||||
union {
|
||||
uchar *b;
|
||||
uint32 *num;
|
||||
} u;
|
||||
u.b = buf + pos;
|
||||
*u.num = val;
|
||||
}
|
||||
|
||||
static inline uint32
|
||||
IVAL(const char *buf, int pos)
|
||||
{
|
||||
return IVALu((uchar*)buf, pos);
|
||||
}
|
||||
|
||||
static inline void
|
||||
SIVAL(char *buf, int pos, uint32 val)
|
||||
{
|
||||
SIVALu((uchar*)buf, pos, val);
|
||||
}
|
||||
|
||||
# endif /* !AVOID_BYTEORDER_INLINE */
|
||||
|
||||
#endif /* !CAREFUL_ALIGNMENT */
|
||||
|
||||
79
case_N.h
79
case_N.h
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* End-of-run cleanup helper code used by cleanup.c.
|
||||
* Allow an arbitrary sequence of case labels.
|
||||
*
|
||||
* Copyright (C) 2006-2008 Wayne Davison
|
||||
* Copyright (C) 2006-2010 Wayne Davison
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
@@ -17,63 +17,60 @@
|
||||
* with this program; if not, visit the http://fsf.org website.
|
||||
*/
|
||||
|
||||
/* This is included by cleanup.c multiple times, once for every segement in
|
||||
* the _exit_cleanup() code. This produces the next "case N:" statement in
|
||||
* sequence and increments the cleanup_step variable by 1. This ensures that
|
||||
* our case statements never get out of whack due to added/removed steps. */
|
||||
/* This is included multiple times, once for every segement in a switch statement.
|
||||
* This produces the next "case N:" statement in sequence. */
|
||||
|
||||
#if !defined EXIT_CLEANUP_CASE_0
|
||||
#define EXIT_CLEANUP_CASE_0
|
||||
#if !defined CASE_N_STATE_0
|
||||
#define CASE_N_STATE_0
|
||||
case 0:
|
||||
#elif !defined EXIT_CLEANUP_CASE_1
|
||||
#define EXIT_CLEANUP_CASE_1
|
||||
#elif !defined CASE_N_STATE_1
|
||||
#define CASE_N_STATE_1
|
||||
case 1:
|
||||
#elif !defined EXIT_CLEANUP_CASE_2
|
||||
#define EXIT_CLEANUP_CASE_2
|
||||
#elif !defined CASE_N_STATE_2
|
||||
#define CASE_N_STATE_2
|
||||
case 2:
|
||||
#elif !defined EXIT_CLEANUP_CASE_3
|
||||
#define EXIT_CLEANUP_CASE_3
|
||||
#elif !defined CASE_N_STATE_3
|
||||
#define CASE_N_STATE_3
|
||||
case 3:
|
||||
#elif !defined EXIT_CLEANUP_CASE_4
|
||||
#define EXIT_CLEANUP_CASE_4
|
||||
#elif !defined CASE_N_STATE_4
|
||||
#define CASE_N_STATE_4
|
||||
case 4:
|
||||
#elif !defined EXIT_CLEANUP_CASE_5
|
||||
#define EXIT_CLEANUP_CASE_5
|
||||
#elif !defined CASE_N_STATE_5
|
||||
#define CASE_N_STATE_5
|
||||
case 5:
|
||||
#elif !defined EXIT_CLEANUP_CASE_6
|
||||
#define EXIT_CLEANUP_CASE_6
|
||||
#elif !defined CASE_N_STATE_6
|
||||
#define CASE_N_STATE_6
|
||||
case 6:
|
||||
#elif !defined EXIT_CLEANUP_CASE_7
|
||||
#define EXIT_CLEANUP_CASE_7
|
||||
#elif !defined CASE_N_STATE_7
|
||||
#define CASE_N_STATE_7
|
||||
case 7:
|
||||
#elif !defined EXIT_CLEANUP_CASE_8
|
||||
#define EXIT_CLEANUP_CASE_8
|
||||
#elif !defined CASE_N_STATE_8
|
||||
#define CASE_N_STATE_8
|
||||
case 8:
|
||||
#elif !defined EXIT_CLEANUP_CASE_9
|
||||
#define EXIT_CLEANUP_CASE_9
|
||||
#elif !defined CASE_N_STATE_9
|
||||
#define CASE_N_STATE_9
|
||||
case 9:
|
||||
#elif !defined EXIT_CLEANUP_CASE_10
|
||||
#define EXIT_CLEANUP_CASE_10
|
||||
#elif !defined CASE_N_STATE_10
|
||||
#define CASE_N_STATE_10
|
||||
case 10:
|
||||
#elif !defined EXIT_CLEANUP_CASE_11
|
||||
#define EXIT_CLEANUP_CASE_11
|
||||
#elif !defined CASE_N_STATE_11
|
||||
#define CASE_N_STATE_11
|
||||
case 11:
|
||||
#elif !defined EXIT_CLEANUP_CASE_12
|
||||
#define EXIT_CLEANUP_CASE_12
|
||||
#elif !defined CASE_N_STATE_12
|
||||
#define CASE_N_STATE_12
|
||||
case 12:
|
||||
#elif !defined EXIT_CLEANUP_CASE_13
|
||||
#define EXIT_CLEANUP_CASE_13
|
||||
#elif !defined CASE_N_STATE_13
|
||||
#define CASE_N_STATE_13
|
||||
case 13:
|
||||
#elif !defined EXIT_CLEANUP_CASE_14
|
||||
#define EXIT_CLEANUP_CASE_14
|
||||
#elif !defined CASE_N_STATE_14
|
||||
#define CASE_N_STATE_14
|
||||
case 14:
|
||||
#elif !defined EXIT_CLEANUP_CASE_15
|
||||
#define EXIT_CLEANUP_CASE_15
|
||||
#elif !defined CASE_N_STATE_15
|
||||
#define CASE_N_STATE_15
|
||||
case 15:
|
||||
#elif !defined EXIT_CLEANUP_CASE_16
|
||||
#define EXIT_CLEANUP_CASE_16
|
||||
#elif !defined CASE_N_STATE_16
|
||||
#define CASE_N_STATE_16
|
||||
case 16:
|
||||
#else
|
||||
#error Need to add more case statements!
|
||||
#endif
|
||||
cleanup_step++;
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
*
|
||||
* Copyright (C) 1996 Andrew Tridgell
|
||||
* Copyright (C) 1996 Paul Mackerras
|
||||
* Copyright (C) 2004-2008 Wayne Davison
|
||||
* Copyright (C) 2004-2009 Wayne Davison
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
@@ -24,8 +24,6 @@
|
||||
extern int checksum_seed;
|
||||
extern int protocol_version;
|
||||
|
||||
int csum_length = SHORT_SUM_LENGTH; /* initial value */
|
||||
|
||||
/*
|
||||
a simple 32 bit checksum that can be upadted from either end
|
||||
(inspired by Mark Adler's Adler-32 checksum)
|
||||
@@ -58,7 +56,7 @@ void get_checksum2(char *buf, int32 len, char *sum)
|
||||
md5_begin(&m);
|
||||
md5_update(&m, (uchar *)buf, len);
|
||||
if (checksum_seed) {
|
||||
SIVAL(seedbuf, 0, checksum_seed);
|
||||
SIVALu(seedbuf, 0, checksum_seed);
|
||||
md5_update(&m, seedbuf, 4);
|
||||
}
|
||||
md5_result(&m, (uchar *)sum);
|
||||
|
||||
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-2008 Wayne Davison
|
||||
* Copyright (C) 2005-2009 Wayne Davison
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
|
||||
39
cleanup.c
39
cleanup.c
@@ -4,7 +4,7 @@
|
||||
* Copyright (C) 1996-2000 Andrew Tridgell
|
||||
* Copyright (C) 1996 Paul Mackerras
|
||||
* Copyright (C) 2002 Martin Pool
|
||||
* Copyright (C) 2003-2008 Wayne Davison
|
||||
* Copyright (C) 2003-2009 Wayne Davison
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
@@ -24,6 +24,7 @@
|
||||
|
||||
extern int am_server;
|
||||
extern int am_daemon;
|
||||
extern int am_receiver;
|
||||
extern int io_error;
|
||||
extern int keep_partial;
|
||||
extern int got_xfer_error;
|
||||
@@ -93,36 +94,44 @@ pid_t cleanup_child_pid = -1;
|
||||
**/
|
||||
NORETURN void _exit_cleanup(int code, const char *file, int line)
|
||||
{
|
||||
static int cleanup_step = 0;
|
||||
static int exit_code = 0;
|
||||
static int switch_step = 0;
|
||||
static int exit_code = 0, exit_line = 0;
|
||||
static const char *exit_file = NULL;
|
||||
static int unmodified_code = 0;
|
||||
|
||||
SIGACTION(SIGUSR1, SIG_IGN);
|
||||
SIGACTION(SIGUSR2, SIG_IGN);
|
||||
|
||||
if (exit_code) /* Preserve first error code when recursing. */
|
||||
if (exit_code) { /* Preserve first exit info when recursing. */
|
||||
code = exit_code;
|
||||
file = exit_file;
|
||||
line = exit_line;
|
||||
}
|
||||
|
||||
/* If this is the exit at the end of the run, the server side
|
||||
* should not attempt to output a message (see log.c). */
|
||||
* should not attempt to output a message (see log_exit()). */
|
||||
if (am_server && code == 0)
|
||||
am_server = 2;
|
||||
|
||||
/* Some of our actions might cause a recursive call back here, so we
|
||||
* keep track of where we are in the cleanup and never repeat a step. */
|
||||
switch (cleanup_step) {
|
||||
#include "case_N.h" /* case 0: cleanup_step++; */
|
||||
switch (switch_step) {
|
||||
#include "case_N.h" /* case 0: */
|
||||
switch_step++;
|
||||
|
||||
exit_code = unmodified_code = code;
|
||||
exit_file = file;
|
||||
exit_line = line;
|
||||
|
||||
if (verbose > 3) {
|
||||
rprintf(FINFO,
|
||||
"_exit_cleanup(code=%d, file=%s, line=%d): entered\n",
|
||||
code, file, line);
|
||||
"[%s] _exit_cleanup(code=%d, file=%s, line=%d): entered\n",
|
||||
who_am_i(), code, file, line);
|
||||
}
|
||||
|
||||
/* FALLTHROUGH */
|
||||
#include "case_N.h"
|
||||
switch_step++;
|
||||
|
||||
if (cleanup_child_pid != -1) {
|
||||
int status;
|
||||
@@ -136,6 +145,7 @@ NORETURN void _exit_cleanup(int code, const char *file, int line)
|
||||
|
||||
/* FALLTHROUGH */
|
||||
#include "case_N.h"
|
||||
switch_step++;
|
||||
|
||||
if (cleanup_got_literal && cleanup_fname && cleanup_new_fname
|
||||
&& keep_partial && handle_partial_dir(cleanup_new_fname, PDIR_CREATE)) {
|
||||
@@ -153,11 +163,14 @@ NORETURN void _exit_cleanup(int code, const char *file, int line)
|
||||
|
||||
/* FALLTHROUGH */
|
||||
#include "case_N.h"
|
||||
switch_step++;
|
||||
|
||||
io_flush(FULL_FLUSH);
|
||||
if (!code || am_server || am_receiver)
|
||||
io_flush(FULL_FLUSH);
|
||||
|
||||
/* FALLTHROUGH */
|
||||
#include "case_N.h"
|
||||
switch_step++;
|
||||
|
||||
if (cleanup_fname)
|
||||
do_unlink(cleanup_fname);
|
||||
@@ -183,16 +196,18 @@ NORETURN void _exit_cleanup(int code, const char *file, int line)
|
||||
|
||||
/* FALLTHROUGH */
|
||||
#include "case_N.h"
|
||||
switch_step++;
|
||||
|
||||
if (verbose > 2) {
|
||||
rprintf(FINFO,
|
||||
"_exit_cleanup(code=%d, file=%s, line=%d): "
|
||||
"[%s] _exit_cleanup(code=%d, file=%s, line=%d): "
|
||||
"about to call exit(%d)\n",
|
||||
unmodified_code, file, line, code);
|
||||
who_am_i(), unmodified_code, file, line, code);
|
||||
}
|
||||
|
||||
/* FALLTHROUGH */
|
||||
#include "case_N.h"
|
||||
switch_step++;
|
||||
|
||||
if (am_server && code)
|
||||
msleep(100);
|
||||
|
||||
@@ -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-2008 Wayne Davison
|
||||
* Copyright (C) 2002-2009 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
|
||||
|
||||
118
clientserver.c
118
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-2008 Wayne Davison
|
||||
* Copyright (C) 2002-2009 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
|
||||
@@ -50,14 +50,12 @@ extern int logfile_format_has_i;
|
||||
extern int logfile_format_has_o_or_i;
|
||||
extern mode_t orig_umask;
|
||||
extern char *bind_address;
|
||||
extern char *sockopts;
|
||||
extern char *config_file;
|
||||
extern char *logfile_format;
|
||||
extern char *files_from;
|
||||
extern char *tmpdir;
|
||||
extern struct chmod_mode_struct *chmod_modes;
|
||||
extern struct filter_list_struct daemon_filter_list;
|
||||
extern char curr_dir[];
|
||||
#ifdef ICONV_OPTION
|
||||
extern char *iconv_opt;
|
||||
extern iconv_t ic_send, ic_recv;
|
||||
@@ -75,6 +73,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
|
||||
@@ -259,7 +259,10 @@ int start_inband_exchange(int f_in, int f_out, const char *user, int argc, char
|
||||
if (strncmp(*argv, modname, modlen) == 0
|
||||
&& argv[0][modlen] == '\0')
|
||||
sargs[sargc++] = modname; /* we send "modname/" */
|
||||
else
|
||||
else if (**argv == '-') {
|
||||
if (asprintf(sargs + sargc++, "./%s", *argv) < 0)
|
||||
out_of_memory("start_inband_exchange");
|
||||
} else
|
||||
sargs[sargc++] = *argv;
|
||||
argv++;
|
||||
argc--;
|
||||
@@ -395,10 +398,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;
|
||||
char **argv, **orig_argv, **orig_early_argv, *chroot_path = NULL;
|
||||
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;
|
||||
@@ -499,30 +512,35 @@ static int rsync_module(int f_in, int f_out, int i, char *addr, char *host)
|
||||
* supplementary groups. */
|
||||
|
||||
module_dir = lp_path(i);
|
||||
if (*module_dir == '\0') {
|
||||
rprintf(FLOG, "No path specified for module %s\n", name);
|
||||
io_printf(f_out, "@ERROR: no path setting.\n");
|
||||
return -1;
|
||||
}
|
||||
if (use_chroot) {
|
||||
if ((p = strstr(module_dir, "/./")) != NULL) {
|
||||
*p = '\0';
|
||||
p += 2;
|
||||
} else if ((p = strdup("/")) == NULL) /* MEMORY LEAK */
|
||||
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 change_dir() that doesn't actually call chdir()
|
||||
* just to make a relative path absolute. */
|
||||
strlcpy(line, curr_dir, sizeof line);
|
||||
if (!change_dir(module_dir, CD_SKIP_CHDIR))
|
||||
goto chdir_failed;
|
||||
if (strcmp(curr_dir, module_dir) != 0
|
||||
&& (module_dir = strdup(curr_dir)) == NULL)
|
||||
out_of_memory("rsync_module");
|
||||
change_dir(line, CD_SKIP_CHDIR); /* 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);
|
||||
@@ -557,16 +575,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)
|
||||
@@ -600,7 +610,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);
|
||||
}
|
||||
}
|
||||
@@ -666,25 +677,19 @@ 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 (!change_dir(module_dir, CD_NORMAL))
|
||||
goto chdir_failed;
|
||||
if (module_dirlen)
|
||||
sanitize_paths = 1;
|
||||
} else {
|
||||
if (!change_dir(module_dir, CD_NORMAL)) {
|
||||
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) {
|
||||
@@ -723,7 +728,11 @@ static int rsync_module(int f_in, int f_out, int i, char *addr, char *host)
|
||||
}
|
||||
#endif
|
||||
|
||||
if (setuid(uid)) {
|
||||
if (setuid(uid) < 0
|
||||
#ifdef HAVE_SETEUID
|
||||
|| seteuid(uid) < 0
|
||||
#endif
|
||||
) {
|
||||
rsyserr(FLOG, errno, "setuid %d failed", (int)uid);
|
||||
io_printf(f_out, "@ERROR: setuid failed\n");
|
||||
return -1;
|
||||
@@ -857,7 +866,7 @@ static int rsync_module(int f_in, int f_out, int i, char *addr, char *host)
|
||||
&& (use_chroot ? lp_numeric_ids(i) != False : lp_numeric_ids(i) == True))
|
||||
numeric_ids = -1; /* Set --numeric-ids w/o breaking protocol. */
|
||||
|
||||
if (lp_timeout(i) && lp_timeout(i) > io_timeout)
|
||||
if (lp_timeout(i) && (!io_timeout || lp_timeout(i) < io_timeout))
|
||||
set_io_timeout(lp_timeout(i));
|
||||
|
||||
/* If we have some incoming/outgoing chmod changes, append them to
|
||||
@@ -972,20 +981,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);
|
||||
}
|
||||
|
||||
|
||||
26
compat.c
26
compat.c
@@ -3,7 +3,7 @@
|
||||
*
|
||||
* Copyright (C) Andrew Tridgell 1996
|
||||
* Copyright (C) Paul Mackerras 1996
|
||||
* Copyright (C) 2004-2008 Wayne Davison
|
||||
* Copyright (C) 2004-2009 Wayne Davison
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
@@ -24,6 +24,8 @@
|
||||
int remote_protocol = 0;
|
||||
int file_extra_cnt = 0; /* count of file-list extras that everyone gets */
|
||||
int inc_recurse = 0;
|
||||
int compat_flags = 0;
|
||||
int use_safe_inc_flist = 0;
|
||||
|
||||
extern int verbose;
|
||||
extern int am_server;
|
||||
@@ -57,12 +59,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 +74,8 @@ int filesfrom_convert = 0;
|
||||
|
||||
#define CF_INC_RECURSE (1<<0)
|
||||
#define CF_SYMLINK_TIMES (1<<1)
|
||||
#define CF_SYMLINK_ICONV (1<<2)
|
||||
#define CF_SAFE_FLIST (1<<3)
|
||||
|
||||
static const char *client_info;
|
||||
|
||||
@@ -243,12 +249,16 @@ void setup_protocol(int f_out,int f_in)
|
||||
exit_cleanup(RERR_PROTOCOL);
|
||||
}
|
||||
} else if (protocol_version >= 30) {
|
||||
int compat_flags;
|
||||
if (am_server) {
|
||||
compat_flags = allow_inc_recurse ? CF_INC_RECURSE : 0;
|
||||
#if defined HAVE_LUTIMES && defined HAVE_UTIMES
|
||||
#ifdef CAN_SET_SYMLINK_TIMES
|
||||
compat_flags |= CF_SYMLINK_TIMES;
|
||||
#endif
|
||||
#ifdef ICONV_OPTION
|
||||
compat_flags |= CF_SYMLINK_ICONV;
|
||||
#endif
|
||||
if (local_server || strchr(client_info, 'f') != NULL)
|
||||
compat_flags |= CF_SAFE_FLIST;
|
||||
write_byte(f_out, compat_flags);
|
||||
} else
|
||||
compat_flags = read_byte(f_in);
|
||||
@@ -259,9 +269,14 @@ void setup_protocol(int f_out,int f_in)
|
||||
? strchr(client_info, 'L') != NULL
|
||||
: !!(compat_flags & CF_SYMLINK_TIMES);
|
||||
}
|
||||
#if defined HAVE_LUTIMES && defined HAVE_UTIMES
|
||||
#ifdef CAN_SET_SYMLINK_TIMES
|
||||
else
|
||||
receiver_symlink_times = 1;
|
||||
#endif
|
||||
#ifdef ICONV_OPTION
|
||||
sender_symlink_iconv = iconv_opt && (am_server
|
||||
? local_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. */
|
||||
@@ -270,8 +285,9 @@ void setup_protocol(int f_out,int f_in)
|
||||
read_batch ? "batch file" : "connection");
|
||||
exit_cleanup(RERR_SYNTAX);
|
||||
}
|
||||
use_safe_inc_flist = !!(compat_flags & CF_SAFE_FLIST);
|
||||
need_messages_from_generator = 1;
|
||||
#if defined HAVE_LUTIMES && defined HAVE_UTIMES
|
||||
#ifdef CAN_SET_SYMLINK_TIMES
|
||||
} else if (!am_sender) {
|
||||
receiver_symlink_times = 1;
|
||||
#endif
|
||||
|
||||
@@ -5,7 +5,7 @@ AC_CONFIG_SRCDIR([byteorder.h])
|
||||
AC_CONFIG_HEADER(config.h)
|
||||
AC_PREREQ(2.59)
|
||||
|
||||
RSYNC_VERSION=3.0.3
|
||||
RSYNC_VERSION=3.0.9pre1
|
||||
AC_SUBST(RSYNC_VERSION)
|
||||
AC_MSG_NOTICE([Configuring rsync $RSYNC_VERSION])
|
||||
|
||||
@@ -13,22 +13,7 @@ AC_DEFINE_UNQUOTED(RSYNC_VERSION, ["$RSYNC_VERSION"], [rsync release version])
|
||||
|
||||
LDFLAGS=${LDFLAGS-""}
|
||||
|
||||
AC_CANONICAL_TARGET([])
|
||||
|
||||
dnl Checks for programs.
|
||||
AC_PROG_CC
|
||||
AC_PROG_CPP
|
||||
AC_PROG_EGREP
|
||||
AC_PROG_INSTALL
|
||||
AC_PROG_CC_STDC
|
||||
AC_SUBST(SHELL)
|
||||
|
||||
AC_DEFINE([_GNU_SOURCE], 1,
|
||||
[Define _GNU_SOURCE so that we get all necessary prototypes])
|
||||
|
||||
if test x"$ac_cv_prog_cc_stdc" = x"no"; then
|
||||
AC_MSG_WARN([rsync requires an ANSI C compiler and you don't seem to have one])
|
||||
fi
|
||||
AC_CANONICAL_HOST
|
||||
|
||||
# We must decide this before testing the compiler.
|
||||
|
||||
@@ -42,14 +27,27 @@ AC_ARG_ENABLE(debug,
|
||||
|
||||
if test x"$enable_debug" = x"no"; then
|
||||
AC_MSG_RESULT(no)
|
||||
CFLAGS=${CFLAGS-"-O"}
|
||||
ac_cv_prog_cc_g=no
|
||||
else
|
||||
AC_MSG_RESULT([yes])
|
||||
# leave CFLAGS alone; AC_PROG_CC will try to include -g if it can
|
||||
dnl AC_DEFINE(DEBUG, 1, [Define to turn on debugging code that may slow normal operation])
|
||||
dnl CFLAGS=${CFLAGS-"-g"}
|
||||
# leave ac_cv_prog_cc_g alone; AC_PROG_CC will try to include -g if it can
|
||||
fi
|
||||
|
||||
dnl Checks for programs.
|
||||
AC_PROG_CC
|
||||
AC_PROG_CPP
|
||||
AC_PROG_EGREP
|
||||
AC_PROG_INSTALL
|
||||
AC_PROG_CC_STDC
|
||||
AC_SUBST(SHELL)
|
||||
|
||||
AC_DEFINE([_GNU_SOURCE], 1,
|
||||
[Define _GNU_SOURCE so that we get all necessary prototypes])
|
||||
|
||||
if test x"$ac_cv_prog_cc_stdc" = x"no"; then
|
||||
AC_MSG_WARN([rsync requires an ANSI C compiler and you do not seem to have one])
|
||||
fi
|
||||
|
||||
AC_ARG_ENABLE(profile,
|
||||
AC_HELP_STRING([--enable-profile],
|
||||
@@ -195,10 +193,10 @@ ipv6trylibc=yes
|
||||
|
||||
AC_ARG_ENABLE(ipv6,
|
||||
AC_HELP_STRING([--disable-ipv6],
|
||||
[don't even try to use IPv6]))
|
||||
[do not even try to use IPv6]))
|
||||
if test x"$enable_ipv6" != x"no"; then
|
||||
AC_MSG_CHECKING([ipv6 stack type])
|
||||
for i in inria kame linux-glibc linux-inet6 toshiba v6d zeta; do
|
||||
for i in inria kame linux-glibc linux-inet6 solaris toshiba v6d zeta cygwin; do
|
||||
case $i in
|
||||
inria)
|
||||
# http://www.kame.net/
|
||||
@@ -242,6 +240,16 @@ AC_DEFINE(INET6, 1, [true if you have IPv6])])
|
||||
CFLAGS="-I/usr/inet6/include $CFLAGS"
|
||||
fi
|
||||
;;
|
||||
solaris)
|
||||
# http://www.sun.com
|
||||
AC_EGREP_CPP(yes, [
|
||||
#include <netinet/ip6.h>
|
||||
#ifdef __sun
|
||||
yes
|
||||
#endif],
|
||||
[ipv6type=$i;
|
||||
AC_DEFINE(INET6, 1, [true if you have IPv6])])
|
||||
;;
|
||||
toshiba)
|
||||
AC_EGREP_CPP(yes, [
|
||||
#include <sys/param.h>
|
||||
@@ -275,6 +283,15 @@ yes
|
||||
ipv6libdir=/usr/local/v6/lib;
|
||||
AC_DEFINE(INET6, 1, [true if you have IPv6])])
|
||||
;;
|
||||
cygwin)
|
||||
AC_EGREP_CPP(yes, [
|
||||
#include <netinet/in.h>
|
||||
#ifdef _CYGWIN_IN6_H
|
||||
yes
|
||||
#endif],
|
||||
[ipv6type=$i;
|
||||
AC_DEFINE(INET6, 1, [true if you have IPv6])])
|
||||
;;
|
||||
esac
|
||||
if test "$ipv6type" != "unknown"; then
|
||||
break
|
||||
@@ -290,7 +307,7 @@ AC_ARG_ENABLE([locale],
|
||||
AC_HELP_STRING([--disable-locale],
|
||||
[disable locale features]))
|
||||
AH_TEMPLATE([CONFIG_LOCALE],
|
||||
[Undefine if you don't want locale features. By default this is defined.])
|
||||
[Undefine if you do not want locale features. By default this is defined.])
|
||||
if test x"$enable_locale" != x"no"; then
|
||||
AC_DEFINE(CONFIG_LOCALE)
|
||||
fi
|
||||
@@ -411,8 +428,10 @@ fi
|
||||
|
||||
AC_SEARCH_LIBS(inet_ntop, resolv)
|
||||
|
||||
# Solaris and HP-UX weirdness:
|
||||
# Search for libiconv_open (not iconv_open) to discover if -liconv is needed!
|
||||
# For OS X, Solaris, HP-UX, etc.: figure out if -liconv is needed. We'll
|
||||
# accept either iconv_open or libiconv_open, since some include files map
|
||||
# the former to the latter.
|
||||
AC_SEARCH_LIBS(iconv_open, iconv)
|
||||
AC_SEARCH_LIBS(libiconv_open, iconv)
|
||||
|
||||
AC_MSG_CHECKING([for iconv declaration])
|
||||
@@ -553,8 +572,9 @@ AC_CHECK_FUNCS(waitpid wait4 getcwd strdup chown chmod lchmod mknod mkfifo \
|
||||
memmove lchown vsnprintf snprintf vasprintf asprintf setsid strpbrk \
|
||||
strlcat strlcpy strtol mallinfo getgroups setgroups geteuid getegid \
|
||||
setlocale setmode open64 lseek64 mkstemp64 mtrace va_copy __va_copy \
|
||||
strerror putenv iconv_open locale_charset nl_langinfo getxattr \
|
||||
extattr_get_link sigaction sigprocmask setattrlist)
|
||||
seteuid strerror putenv iconv_open locale_charset nl_langinfo getxattr \
|
||||
extattr_get_link sigaction sigprocmask setattrlist \
|
||||
utimensat)
|
||||
|
||||
dnl cygwin iconv.h defines iconv_open as libiconv_open
|
||||
if test x"$ac_cv_func_iconv_open" != x"yes"; then
|
||||
@@ -566,10 +586,19 @@ if test $ac_cv_func_getpgrp = yes; then
|
||||
AC_FUNC_GETPGRP
|
||||
fi
|
||||
|
||||
AC_ARG_ENABLE(iconv-open,
|
||||
AC_HELP_STRING([--disable-iconv-open],
|
||||
[disable all use of iconv_open() function]),
|
||||
[], [enable_iconv_open=$ac_cv_func_iconv_open])
|
||||
|
||||
if test x"$enable_iconv_open" != x"no"; then
|
||||
AC_DEFINE(USE_ICONV_OPEN, 1, [Define to 1 if you want rsync to make use of iconv_open()])
|
||||
fi
|
||||
|
||||
AC_ARG_ENABLE(iconv,
|
||||
AC_HELP_STRING([--disable-iconv],
|
||||
[disable rsync's --iconv option]),
|
||||
[], [enable_iconv=$ac_cv_func_iconv_open])
|
||||
[], [enable_iconv=$enable_iconv_open])
|
||||
AH_TEMPLATE([ICONV_OPTION],
|
||||
[Define if you want the --iconv option. Specifing a value will set the
|
||||
default iconv setting (a NULL means no --iconv processing by default).])
|
||||
@@ -762,7 +791,7 @@ rsync_cv_HAVE_SECURE_MKSTEMP=yes,
|
||||
rsync_cv_HAVE_SECURE_MKSTEMP=no,
|
||||
rsync_cv_HAVE_SECURE_MKSTEMP=cross)])
|
||||
if test x"$rsync_cv_HAVE_SECURE_MKSTEMP" = x"yes"; then
|
||||
case $target_os in
|
||||
case $host_os in
|
||||
hpux*)
|
||||
dnl HP-UX has a broken mkstemp() implementation they refuse to fix,
|
||||
dnl so we noisily skip using it. See HP change request JAGaf34426
|
||||
@@ -942,12 +971,18 @@ else
|
||||
AC_MSG_RESULT(Using OS X xattrs)
|
||||
AC_DEFINE(HAVE_OSX_XATTRS, 1, [True if you have Mac OS X xattrs])
|
||||
AC_DEFINE(SUPPORT_XATTRS, 1)
|
||||
AC_DEFINE(NO_DEVICE_XATTRS, 1, [True if device files do not support xattrs])
|
||||
AC_DEFINE(NO_SPECIAL_XATTRS, 1, [True if special files do not support xattrs])
|
||||
;;
|
||||
freebsd*)
|
||||
AC_MSG_RESULT(Using FreeBSD extattrs)
|
||||
AC_DEFINE(HAVE_FREEBSD_XATTRS, 1, [True if you have FreeBSD xattrs])
|
||||
AC_DEFINE(SUPPORT_XATTRS, 1)
|
||||
;;
|
||||
solaris*)
|
||||
# Better Solaris support coming in 3.1.0...
|
||||
AC_DEFINE(NO_SYMLINK_XATTRS, 1, [True if symlinks do not support xattrs])
|
||||
;;
|
||||
*)
|
||||
if test x"$enable_xattr_support" = x"yes"; then
|
||||
AC_MSG_ERROR(Failed to find extended attribute support)
|
||||
@@ -962,7 +997,7 @@ if test x"$enable_acl_support" = x"no" -o x"$enable_xattr_support" = x"no" -o x"
|
||||
AC_MSG_CHECKING([whether $CC supports -Wno-unused-parameter])
|
||||
OLD_CFLAGS="$CFLAGS"
|
||||
CFLAGS="$CFLAGS -Wno-unused-parameter"
|
||||
AC_COMPILE_IFELSE([ ], [rsync_warn_flag=yes], [rsync_warn_flag=no])
|
||||
AC_TRY_LINK([#include <stdio.h>], [printf("hello\n");], [rsync_warn_flag=yes], [rsync_warn_flag=no])
|
||||
AC_MSG_RESULT([$rsync_warn_flag])
|
||||
if test x"$rsync_warn_flag" = x"no"; then
|
||||
CFLAGS="$OLD_CFLAGS"
|
||||
10
exclude.c
10
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-2008 Wayne Davison
|
||||
* Copyright (C) 2003-2009 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,7 +37,7 @@ extern int sanitize_paths;
|
||||
extern int protocol_version;
|
||||
extern int module_id;
|
||||
|
||||
extern char curr_dir[];
|
||||
extern char curr_dir[MAXPATHLEN];
|
||||
extern unsigned int curr_dir_len;
|
||||
extern unsigned int module_dirlen;
|
||||
|
||||
@@ -476,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));
|
||||
}
|
||||
@@ -924,7 +924,7 @@ static char default_cvsignore[] =
|
||||
" *.a *.olb *.o *.obj *.so *.exe"
|
||||
" *.Z *.elc *.ln core"
|
||||
/* The rest we added to suit ourself. */
|
||||
" .svn/ .git/ .bzr/";
|
||||
" .svn/ .git/ .hg/ .bzr/";
|
||||
|
||||
static void get_cvs_excludes(uint32 mflags)
|
||||
{
|
||||
@@ -1121,6 +1121,8 @@ char *get_rule_prefix(int match_flags, const char *pat, int for_xfer,
|
||||
else
|
||||
legal_len = 0;
|
||||
|
||||
if (match_flags & MATCHFLG_ABS_PATH)
|
||||
*op++ = '/';
|
||||
if (match_flags & MATCHFLG_NEGATE)
|
||||
*op++ = '!';
|
||||
if (match_flags & MATCHFLG_CVS_IGNORE)
|
||||
|
||||
40
fileio.c
40
fileio.c
@@ -3,7 +3,7 @@
|
||||
*
|
||||
* Copyright (C) 1998 Andrew Tridgell
|
||||
* Copyright (C) 2002 Martin Pool
|
||||
* Copyright (C) 2004-2008 Wayne Davison
|
||||
* Copyright (C) 2004-2009 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,39 +27,43 @@
|
||||
|
||||
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)
|
||||
int sparse_end(int f, OFF_T size)
|
||||
{
|
||||
int ret;
|
||||
|
||||
if (!sparse_seek)
|
||||
return 0;
|
||||
|
||||
do_lseek(f, sparse_seek-1, SEEK_CUR);
|
||||
#ifdef HAVE_FTRUNCATE
|
||||
ret = do_ftruncate(f, size);
|
||||
#else
|
||||
if (do_lseek(f, sparse_seek-1, SEEK_CUR) != size-1)
|
||||
ret = -1;
|
||||
else {
|
||||
do {
|
||||
ret = write(f, "", 1);
|
||||
} while (ret < 0 && errno == EINTR);
|
||||
|
||||
ret = ret <= 0 ? -1 : 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
sparse_seek = 0;
|
||||
|
||||
do {
|
||||
ret = write(f, "", 1);
|
||||
} while (ret < 0 && errno == EINTR);
|
||||
|
||||
return ret <= 0 ? -1 : 0;
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
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++) {}
|
||||
for (l2 = 0; l2 < len-l1 && buf[len-(l2+1)] == 0; l2++) {}
|
||||
|
||||
/* XXX Riddle me this: why does this function SLOW DOWN when I
|
||||
* remove the following (unneeded) line?? Core Duo weirdness? */
|
||||
last_byte = buf[len-1];
|
||||
|
||||
sparse_seek += l1;
|
||||
|
||||
if (l1 == len)
|
||||
@@ -108,7 +112,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 +129,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;
|
||||
|
||||
375
flist.c
375
flist.c
@@ -4,7 +4,7 @@
|
||||
* Copyright (C) 1996 Andrew Tridgell
|
||||
* Copyright (C) 1996 Paul Mackerras
|
||||
* Copyright (C) 2001, 2002 Martin Pool <mbp@samba.org>
|
||||
* Copyright (C) 2002-2008 Wayne Davison
|
||||
* Copyright (C) 2002-2009 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,6 @@ extern int xfer_dirs;
|
||||
extern int filesfrom_fd;
|
||||
extern int one_file_system;
|
||||
extern int copy_dirlinks;
|
||||
extern int keep_dirlinks;
|
||||
extern int preserve_uid;
|
||||
extern int preserve_gid;
|
||||
extern int preserve_acls;
|
||||
@@ -52,12 +51,10 @@ extern int preserve_links;
|
||||
extern int preserve_hard_links;
|
||||
extern int preserve_devices;
|
||||
extern int preserve_specials;
|
||||
extern int uid_ndx;
|
||||
extern int gid_ndx;
|
||||
extern int delete_during;
|
||||
extern int eol_nulls;
|
||||
extern int relative_paths;
|
||||
extern int implied_dirs;
|
||||
extern int file_extra_cnt;
|
||||
extern int ignore_perishable;
|
||||
extern int non_perishable_cnt;
|
||||
extern int prune_empty_dirs;
|
||||
@@ -66,8 +63,11 @@ extern int copy_unsafe_links;
|
||||
extern int protocol_version;
|
||||
extern int sanitize_paths;
|
||||
extern int munge_symlinks;
|
||||
extern int use_safe_inc_flist;
|
||||
extern int need_unsorted_flist;
|
||||
extern int sender_symlink_iconv;
|
||||
extern int unsort_ndx;
|
||||
extern uid_t our_uid;
|
||||
extern struct stats stats;
|
||||
extern char *filesfrom_host;
|
||||
|
||||
@@ -116,7 +116,7 @@ int flist_eof = 0; /* all the file-lists are now known */
|
||||
* will survive just long enough to be used by send_file_entry(). */
|
||||
static dev_t tmp_rdev;
|
||||
#ifdef SUPPORT_HARD_LINKS
|
||||
static int64 tmp_dev, tmp_ino;
|
||||
static int64 tmp_dev = -1, tmp_ino;
|
||||
#endif
|
||||
static char tmp_sum[MAX_DIGEST_LEN];
|
||||
|
||||
@@ -375,7 +375,7 @@ int change_pathname(struct file_struct *file, const char *dir, int dirlen)
|
||||
if (!change_dir(dir, CD_NORMAL)) {
|
||||
chdir_error:
|
||||
io_error |= IOERR_GENERAL;
|
||||
rsyserr(FERROR, errno, "change_dir %s failed", full_fname(dir));
|
||||
rsyserr(FERROR_XFER, errno, "change_dir %s failed", full_fname(dir));
|
||||
if (dir != orig_dir)
|
||||
change_dir(orig_dir, CD_NORMAL);
|
||||
pathname = NULL;
|
||||
@@ -386,7 +386,11 @@ int change_pathname(struct file_struct *file, const char *dir, int dirlen)
|
||||
return 1;
|
||||
}
|
||||
|
||||
static void send_file_entry(int f, const char *fname, struct file_struct *file, int ndx, int first_ndx)
|
||||
static void send_file_entry(int f, const char *fname, struct file_struct *file,
|
||||
#ifdef SUPPORT_LINKS
|
||||
const char *symlink_name, int symlink_len,
|
||||
#endif
|
||||
int ndx, int first_ndx)
|
||||
{
|
||||
static time_t modtime;
|
||||
static mode_t mode;
|
||||
@@ -420,8 +424,7 @@ static void send_file_entry(int f, const char *fname, struct file_struct *file,
|
||||
else
|
||||
mode = file->mode;
|
||||
|
||||
if ((preserve_devices && IS_DEVICE(mode))
|
||||
|| (preserve_specials && IS_SPECIAL(mode))) {
|
||||
if (preserve_devices && IS_DEVICE(mode)) {
|
||||
if (protocol_version < 28) {
|
||||
if (tmp_rdev == rdev)
|
||||
xflags |= XMIT_SAME_RDEV_pre28;
|
||||
@@ -436,6 +439,17 @@ static void send_file_entry(int f, const char *fname, struct file_struct *file,
|
||||
if (protocol_version < 30 && (uint32)minor(rdev) <= 0xFFu)
|
||||
xflags |= XMIT_RDEV_MINOR_8_pre30;
|
||||
}
|
||||
} else if (preserve_specials && IS_SPECIAL(mode)) {
|
||||
/* Special files don't need an rdev number, so just make
|
||||
* the historical transmission of the value efficient. */
|
||||
if (protocol_version < 28)
|
||||
xflags |= XMIT_SAME_RDEV_pre28;
|
||||
else {
|
||||
rdev = MAKEDEV(major(rdev), 0);
|
||||
xflags |= XMIT_SAME_RDEV_MAJOR;
|
||||
if (protocol_version < 30)
|
||||
xflags |= XMIT_RDEV_MINOR_8_pre30;
|
||||
}
|
||||
} else if (protocol_version < 28)
|
||||
rdev = MAKEDEV(0, 0);
|
||||
if (!preserve_uid || ((uid_t)F_OWNER(file) == uid && *lastname))
|
||||
@@ -464,7 +478,7 @@ static void send_file_entry(int f, const char *fname, struct file_struct *file,
|
||||
modtime = file->modtime;
|
||||
|
||||
#ifdef SUPPORT_HARD_LINKS
|
||||
if (tmp_dev != 0) {
|
||||
if (tmp_dev != -1) {
|
||||
if (protocol_version >= 30) {
|
||||
struct ht_int64_node *np = idev_find(tmp_dev, tmp_ino);
|
||||
first_hlink_ndx = (int32)(long)np->data - 1;
|
||||
@@ -575,24 +589,24 @@ static void send_file_entry(int f, const char *fname, struct file_struct *file,
|
||||
}
|
||||
|
||||
#ifdef SUPPORT_LINKS
|
||||
if (preserve_links && S_ISLNK(mode)) {
|
||||
const char *sl = F_SYMLINK(file);
|
||||
int len = strlen(sl);
|
||||
write_varint30(f, len);
|
||||
write_buf(f, sl, len);
|
||||
if (symlink_len) {
|
||||
write_varint30(f, symlink_len);
|
||||
write_buf(f, symlink_name, symlink_len);
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef SUPPORT_HARD_LINKS
|
||||
if (tmp_dev != 0 && protocol_version < 30) {
|
||||
if (tmp_dev != -1 && protocol_version < 30) {
|
||||
/* Older protocols expect the dev number to be transmitted
|
||||
* 1-incremented so that it is never zero. */
|
||||
if (protocol_version < 26) {
|
||||
/* 32-bit dev_t and ino_t */
|
||||
write_int(f, (int32)dev);
|
||||
write_int(f, (int32)(dev+1));
|
||||
write_int(f, (int32)tmp_ino);
|
||||
} else {
|
||||
/* 64-bit dev_t and ino_t */
|
||||
if (!(xflags & XMIT_SAME_DEV_pre30))
|
||||
write_longint(f, dev);
|
||||
write_longint(f, dev+1);
|
||||
write_longint(f, tmp_ino);
|
||||
}
|
||||
}
|
||||
@@ -616,8 +630,7 @@ static void send_file_entry(int f, const char *fname, struct file_struct *file,
|
||||
stats.total_size += F_LENGTH(file);
|
||||
}
|
||||
|
||||
static struct file_struct *recv_file_entry(struct file_list *flist,
|
||||
int xflags, int f)
|
||||
static struct file_struct *recv_file_entry(int f, struct file_list *flist, int xflags)
|
||||
{
|
||||
static int64 modtime;
|
||||
static mode_t mode;
|
||||
@@ -675,12 +688,12 @@ static struct file_struct *recv_file_entry(struct file_list *flist,
|
||||
|
||||
if (iconvbufs(ic_recv, &inbuf, &outbuf, 0) < 0) {
|
||||
io_error |= IOERR_GENERAL;
|
||||
rprintf(FINFO,
|
||||
rprintf(FERROR_UTF8,
|
||||
"[%s] cannot convert filename: %s (%s)\n",
|
||||
who_am_i(), lastname, strerror(errno));
|
||||
outbuf.len = 0;
|
||||
}
|
||||
outbuf.buf[outbuf.len] = '\0';
|
||||
thisname[outbuf.len] = '\0';
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -722,8 +735,7 @@ static struct file_struct *recv_file_entry(struct file_list *flist,
|
||||
uid = F_OWNER(first);
|
||||
if (preserve_gid)
|
||||
gid = F_GROUP(first);
|
||||
if ((preserve_devices && IS_DEVICE(mode))
|
||||
|| (preserve_specials && IS_SPECIAL(mode))) {
|
||||
if (preserve_devices && IS_DEVICE(mode)) {
|
||||
uint32 *devp = F_RDEV_P(first);
|
||||
rdev = MAKEDEV(DEV_MAJOR(devp), DEV_MINOR(devp));
|
||||
extra_len += DEV_EXTRA_CNT * EXTRA_LEN;
|
||||
@@ -798,7 +810,8 @@ static struct file_struct *recv_file_entry(struct file_list *flist,
|
||||
rdev_minor = read_int(f);
|
||||
rdev = MAKEDEV(rdev_major, rdev_minor);
|
||||
}
|
||||
extra_len += DEV_EXTRA_CNT * EXTRA_LEN;
|
||||
if (IS_DEVICE(mode))
|
||||
extra_len += DEV_EXTRA_CNT * EXTRA_LEN;
|
||||
file_length = 0;
|
||||
} else if (protocol_version < 28)
|
||||
rdev = MAKEDEV(0, 0);
|
||||
@@ -811,6 +824,13 @@ static struct file_struct *recv_file_entry(struct file_list *flist,
|
||||
linkname_len - 1);
|
||||
overflow_exit("recv_file_entry");
|
||||
}
|
||||
#ifdef ICONV_OPTION
|
||||
/* We don't know how much extra room we need to convert
|
||||
* the as-yet-unread symlink data, so let's hope that a
|
||||
* double-size buffer is plenty. */
|
||||
if (sender_symlink_iconv)
|
||||
linkname_len *= 2;
|
||||
#endif
|
||||
if (munge_symlinks)
|
||||
linkname_len += SYMLINK_PREFIX_LEN;
|
||||
}
|
||||
@@ -932,8 +952,7 @@ static struct file_struct *recv_file_entry(struct file_list *flist,
|
||||
}
|
||||
}
|
||||
|
||||
if ((preserve_devices && IS_DEVICE(mode))
|
||||
|| (preserve_specials && IS_SPECIAL(mode))) {
|
||||
if (preserve_devices && IS_DEVICE(mode)) {
|
||||
uint32 *devp = F_RDEV_P(file);
|
||||
DEV_MAJOR(devp) = major(rdev);
|
||||
DEV_MINOR(devp) = minor(rdev);
|
||||
@@ -945,14 +964,40 @@ static struct file_struct *recv_file_entry(struct file_list *flist,
|
||||
if (first_hlink_ndx >= flist->ndx_start) {
|
||||
struct file_struct *first = flist->files[first_hlink_ndx - flist->ndx_start];
|
||||
memcpy(bp, F_SYMLINK(first), linkname_len);
|
||||
} else if (munge_symlinks) {
|
||||
strlcpy(bp, SYMLINK_PREFIX, linkname_len);
|
||||
bp += SYMLINK_PREFIX_LEN;
|
||||
linkname_len -= SYMLINK_PREFIX_LEN;
|
||||
read_sbuf(f, bp, linkname_len - 1);
|
||||
} else {
|
||||
read_sbuf(f, bp, linkname_len - 1);
|
||||
if (sanitize_paths)
|
||||
if (munge_symlinks) {
|
||||
strlcpy(bp, SYMLINK_PREFIX, linkname_len);
|
||||
bp += SYMLINK_PREFIX_LEN;
|
||||
linkname_len -= SYMLINK_PREFIX_LEN;
|
||||
}
|
||||
#ifdef ICONV_OPTION
|
||||
if (sender_symlink_iconv) {
|
||||
xbuf outbuf, inbuf;
|
||||
|
||||
alloc_len = linkname_len;
|
||||
linkname_len /= 2;
|
||||
|
||||
/* Read the symlink data into the end of our double-sized
|
||||
* buffer and then convert it into the right spot. */
|
||||
INIT_XBUF(inbuf, bp + alloc_len - linkname_len,
|
||||
linkname_len - 1, (size_t)-1);
|
||||
read_sbuf(f, inbuf.buf, inbuf.len);
|
||||
INIT_XBUF(outbuf, bp, 0, alloc_len);
|
||||
|
||||
if (iconvbufs(ic_recv, &inbuf, &outbuf, 0) < 0) {
|
||||
io_error |= IOERR_GENERAL;
|
||||
rprintf(FERROR_XFER,
|
||||
"[%s] cannot convert symlink data for: %s (%s)\n",
|
||||
who_am_i(), full_fname(thisname), strerror(errno));
|
||||
bp = (char*)file->basename;
|
||||
*bp++ = '\0';
|
||||
outbuf.len = 0;
|
||||
}
|
||||
bp[outbuf.len] = '\0';
|
||||
} else
|
||||
#endif
|
||||
read_sbuf(f, bp, linkname_len - 1);
|
||||
if (sanitize_paths && !munge_symlinks && *bp)
|
||||
sanitize_path(bp, bp, "", lastdir_depth, SP_DEFAULT);
|
||||
}
|
||||
}
|
||||
@@ -1005,11 +1050,11 @@ static struct file_struct *recv_file_entry(struct file_list *flist,
|
||||
|
||||
#ifdef SUPPORT_ACLS
|
||||
if (preserve_acls && !S_ISLNK(mode))
|
||||
receive_acl(file, f);
|
||||
receive_acl(f, file);
|
||||
#endif
|
||||
#ifdef SUPPORT_XATTRS
|
||||
if (preserve_xattrs)
|
||||
receive_xattr(file, f );
|
||||
receive_xattr(f, file);
|
||||
#endif
|
||||
|
||||
if (S_ISREG(mode) || S_ISLNK(mode))
|
||||
@@ -1045,7 +1090,7 @@ struct file_struct *make_file(const char *fname, struct file_list *flist,
|
||||
|
||||
if (strlcpy(thisname, fname, sizeof thisname) >= sizeof thisname) {
|
||||
io_error |= IOERR_GENERAL;
|
||||
rprintf(FINFO, "skipping overly long name: %s\n", fname);
|
||||
rprintf(FERROR_XFER, "skipping overly long name: %s\n", fname);
|
||||
return NULL;
|
||||
}
|
||||
clean_fname(thisname, 0);
|
||||
@@ -1090,7 +1135,7 @@ struct file_struct *make_file(const char *fname, struct file_list *flist,
|
||||
}
|
||||
} else {
|
||||
io_error |= IOERR_GENERAL;
|
||||
rsyserr(FERROR_XFER, save_errno, "readlink %s failed",
|
||||
rsyserr(FERROR_XFER, save_errno, "readlink_stat(%s) failed",
|
||||
full_fname(thisname));
|
||||
}
|
||||
return NULL;
|
||||
@@ -1213,18 +1258,19 @@ struct file_struct *make_file(const char *fname, struct file_list *flist,
|
||||
if (protocol_version >= 28
|
||||
? (!S_ISDIR(st.st_mode) && st.st_nlink > 1)
|
||||
: S_ISREG(st.st_mode)) {
|
||||
tmp_dev = st.st_dev;
|
||||
tmp_ino = st.st_ino;
|
||||
tmp_dev = (int64)st.st_dev;
|
||||
tmp_ino = (int64)st.st_ino;
|
||||
} else
|
||||
tmp_dev = 0;
|
||||
tmp_dev = -1;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_STRUCT_STAT_ST_RDEV
|
||||
if (IS_DEVICE(st.st_mode) || IS_SPECIAL(st.st_mode)) {
|
||||
if (IS_DEVICE(st.st_mode)) {
|
||||
tmp_rdev = st.st_rdev;
|
||||
st.st_size = 0;
|
||||
}
|
||||
} else if (IS_SPECIAL(st.st_mode))
|
||||
st.st_size = 0;
|
||||
#endif
|
||||
|
||||
file->flags = flags;
|
||||
@@ -1237,10 +1283,12 @@ struct file_struct *make_file(const char *fname, struct file_list *flist,
|
||||
}
|
||||
#endif
|
||||
file->mode = st.st_mode;
|
||||
if (uid_ndx) /* Check uid_ndx instead of preserve_uid for del support */
|
||||
if (preserve_uid)
|
||||
F_OWNER(file) = st.st_uid;
|
||||
if (gid_ndx) /* Check gid_ndx instead of preserve_gid for del support */
|
||||
if (preserve_gid)
|
||||
F_GROUP(file) = st.st_gid;
|
||||
if (am_generator && st.st_uid == our_uid)
|
||||
file->flags |= FLAG_OWNED_BY_US;
|
||||
|
||||
if (basename != thisname)
|
||||
file->dirname = lastdir;
|
||||
@@ -1258,25 +1306,6 @@ struct file_struct *make_file(const char *fname, struct file_list *flist,
|
||||
else if (!pool)
|
||||
F_DEPTH(file) = extra_len / EXTRA_LEN;
|
||||
|
||||
/* This code is only used by the receiver when it is building
|
||||
* a list of files for a delete pass. */
|
||||
if (keep_dirlinks && linkname_len && flist) {
|
||||
STRUCT_STAT st2;
|
||||
int save_mode = file->mode;
|
||||
file->mode = S_IFDIR; /* Find a directory with our name. */
|
||||
if (flist_find(dir_flist, file) >= 0
|
||||
&& x_stat(thisname, &st2, NULL) == 0 && S_ISDIR(st2.st_mode)) {
|
||||
file->modtime = st2.st_mtime;
|
||||
file->len32 = 0;
|
||||
file->mode = st2.st_mode;
|
||||
if (uid_ndx)
|
||||
F_OWNER(file) = st2.st_uid;
|
||||
if (gid_ndx)
|
||||
F_GROUP(file) = st2.st_gid;
|
||||
} else
|
||||
file->mode = save_mode;
|
||||
}
|
||||
|
||||
if (basename_len == 0+1) {
|
||||
if (!pool)
|
||||
unmake_file(file);
|
||||
@@ -1310,10 +1339,35 @@ static struct file_struct *send_file_name(int f, struct file_list *flist,
|
||||
|
||||
if (f >= 0) {
|
||||
char fbuf[MAXPATHLEN];
|
||||
#ifdef SUPPORT_LINKS
|
||||
const char *symlink_name;
|
||||
int symlink_len;
|
||||
#ifdef ICONV_OPTION
|
||||
char symlink_buf[MAXPATHLEN];
|
||||
#endif
|
||||
#endif
|
||||
#if defined SUPPORT_ACLS || defined SUPPORT_XATTRS
|
||||
stat_x sx;
|
||||
#endif
|
||||
|
||||
#ifdef SUPPORT_LINKS
|
||||
if (preserve_links && S_ISLNK(file->mode)) {
|
||||
symlink_name = F_SYMLINK(file);
|
||||
symlink_len = strlen(symlink_name);
|
||||
if (symlink_len == 0) {
|
||||
io_error |= IOERR_GENERAL;
|
||||
f_name(file, fbuf);
|
||||
rprintf(FERROR_XFER,
|
||||
"skipping symlink with 0-length value: %s\n",
|
||||
full_fname(fbuf));
|
||||
return NULL;
|
||||
}
|
||||
} else {
|
||||
symlink_name = NULL;
|
||||
symlink_len = 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef ICONV_OPTION
|
||||
if (ic_send != (iconv_t)-1) {
|
||||
xbuf outbuf, inbuf;
|
||||
@@ -1326,19 +1380,38 @@ static struct file_struct *send_file_name(int f, struct file_list *flist,
|
||||
if (iconvbufs(ic_send, &inbuf, &outbuf, 0) < 0)
|
||||
goto convert_error;
|
||||
outbuf.size += 2;
|
||||
outbuf.buf[outbuf.len++] = '/';
|
||||
fbuf[outbuf.len++] = '/';
|
||||
}
|
||||
|
||||
INIT_XBUF_STRLEN(inbuf, (char*)file->basename);
|
||||
if (iconvbufs(ic_send, &inbuf, &outbuf, 0) < 0) {
|
||||
convert_error:
|
||||
io_error |= IOERR_GENERAL;
|
||||
rprintf(FINFO,
|
||||
rprintf(FERROR_XFER,
|
||||
"[%s] cannot convert filename: %s (%s)\n",
|
||||
who_am_i(), f_name(file, fbuf), strerror(errno));
|
||||
return NULL;
|
||||
}
|
||||
outbuf.buf[outbuf.len] = '\0';
|
||||
fbuf[outbuf.len] = '\0';
|
||||
|
||||
#ifdef SUPPORT_LINKS
|
||||
if (symlink_len && sender_symlink_iconv) {
|
||||
INIT_XBUF(inbuf, (char*)symlink_name, symlink_len, (size_t)-1);
|
||||
INIT_CONST_XBUF(outbuf, symlink_buf);
|
||||
if (iconvbufs(ic_send, &inbuf, &outbuf, 0) < 0) {
|
||||
io_error |= IOERR_GENERAL;
|
||||
f_name(file, fbuf);
|
||||
rprintf(FERROR_XFER,
|
||||
"[%s] cannot convert symlink data for: %s (%s)\n",
|
||||
who_am_i(), full_fname(fbuf), strerror(errno));
|
||||
return NULL;
|
||||
}
|
||||
symlink_buf[outbuf.len] = '\0';
|
||||
|
||||
symlink_name = symlink_buf;
|
||||
symlink_len = outbuf.len;
|
||||
}
|
||||
#endif
|
||||
} else
|
||||
#endif
|
||||
f_name(file, fbuf);
|
||||
@@ -1355,6 +1428,7 @@ static struct file_struct *send_file_name(int f, struct file_list *flist,
|
||||
#endif
|
||||
#ifdef SUPPORT_XATTRS
|
||||
if (preserve_xattrs) {
|
||||
sx.st.st_mode = file->mode;
|
||||
sx.xattr = NULL;
|
||||
if (get_xattr(fname, &sx) < 0) {
|
||||
io_error |= IOERR_GENERAL;
|
||||
@@ -1363,17 +1437,21 @@ static struct file_struct *send_file_name(int f, struct file_list *flist,
|
||||
}
|
||||
#endif
|
||||
|
||||
send_file_entry(f, fbuf, file, flist->used, flist->ndx_start);
|
||||
send_file_entry(f, fbuf, file,
|
||||
#ifdef SUPPORT_LINKS
|
||||
symlink_name, symlink_len,
|
||||
#endif
|
||||
flist->used, flist->ndx_start);
|
||||
|
||||
#ifdef SUPPORT_ACLS
|
||||
if (preserve_acls && !S_ISLNK(file->mode)) {
|
||||
send_acl(&sx, f);
|
||||
send_acl(f, &sx);
|
||||
free_acl(&sx);
|
||||
}
|
||||
#endif
|
||||
#ifdef SUPPORT_XATTRS
|
||||
if (preserve_xattrs) {
|
||||
F_XATTR(file) = send_xattr(&sx, f);
|
||||
F_XATTR(file) = send_xattr(f, &sx);
|
||||
free_xattr(&sx);
|
||||
}
|
||||
#endif
|
||||
@@ -1400,12 +1478,6 @@ static void send_if_directory(int f, struct file_list *flist,
|
||||
unsigned int len = strlen(fbuf);
|
||||
if (len > 1 && fbuf[len-1] == '/')
|
||||
fbuf[--len] = '\0';
|
||||
if (len >= MAXPATHLEN - 1) {
|
||||
io_error |= IOERR_GENERAL;
|
||||
rprintf(FERROR_XFER, "skipping long-named directory: %s\n",
|
||||
full_fname(fbuf));
|
||||
return;
|
||||
}
|
||||
save_filters = push_local_filters(fbuf, len);
|
||||
send_directory(f, flist, fbuf, len, flags);
|
||||
pop_local_filters(save_filters);
|
||||
@@ -1521,6 +1593,19 @@ static void add_dirs_to_tree(int parent_ndx, struct file_list *from_flist,
|
||||
DIR_NEXT_SIBLING(dp) = -1;
|
||||
}
|
||||
|
||||
static void interpret_stat_error(const char *fname, int is_dir)
|
||||
{
|
||||
if (errno == ENOENT) {
|
||||
io_error |= IOERR_VANISHED;
|
||||
rprintf(FWARNING, "%s has vanished: %s\n",
|
||||
is_dir ? "directory" : "file", full_fname(fname));
|
||||
} else {
|
||||
io_error |= IOERR_GENERAL;
|
||||
rsyserr(FERROR_XFER, errno, "link_stat %s failed",
|
||||
full_fname(fname));
|
||||
}
|
||||
}
|
||||
|
||||
/* This function is normally called by the sender, but the receiving side also
|
||||
* calls it from get_dirlist() with f set to -1 so that we just construct the
|
||||
* file list in memory without sending it over the wire. Also, get_dirlist()
|
||||
@@ -1540,32 +1625,45 @@ static void send_directory(int f, struct file_list *flist, char *fbuf, int len,
|
||||
assert(flist != NULL);
|
||||
|
||||
if (!(d = opendir(fbuf))) {
|
||||
if (errno == ENOENT) {
|
||||
if (am_sender) /* Can abuse this for vanished error w/ENOENT: */
|
||||
interpret_stat_error(fbuf, True);
|
||||
return;
|
||||
}
|
||||
io_error |= IOERR_GENERAL;
|
||||
rsyserr(FERROR_XFER, errno, "opendir %s failed", full_fname(fbuf));
|
||||
return;
|
||||
}
|
||||
|
||||
p = fbuf + len;
|
||||
if (len != 1 || *fbuf != '/')
|
||||
if (len == 1 && *fbuf == '/')
|
||||
remainder = MAXPATHLEN - 1;
|
||||
else if (len < MAXPATHLEN-1) {
|
||||
*p++ = '/';
|
||||
*p = '\0';
|
||||
remainder = MAXPATHLEN - (p - fbuf);
|
||||
*p = '\0';
|
||||
remainder = MAXPATHLEN - (len + 1);
|
||||
} else
|
||||
remainder = 0;
|
||||
|
||||
for (errno = 0, di = readdir(d); di; errno = 0, di = readdir(d)) {
|
||||
char *dname = d_name(di);
|
||||
if (dname[0] == '.' && (dname[1] == '\0'
|
||||
|| (dname[1] == '.' && dname[2] == '\0')))
|
||||
continue;
|
||||
if (strlcpy(p, dname, remainder) >= remainder) {
|
||||
unsigned name_len = strlcpy(p, dname, remainder);
|
||||
if (name_len >= remainder) {
|
||||
char save = fbuf[len];
|
||||
fbuf[len] = '\0';
|
||||
io_error |= IOERR_GENERAL;
|
||||
rprintf(FINFO,
|
||||
"cannot send long-named file %s\n",
|
||||
full_fname(fbuf));
|
||||
rprintf(FERROR_XFER,
|
||||
"filename overflows max-path len by %u: %s/%s\n",
|
||||
name_len - remainder + 1, fbuf, dname);
|
||||
fbuf[len] = save;
|
||||
continue;
|
||||
}
|
||||
if (dname[0] == '\0') {
|
||||
io_error |= IOERR_GENERAL;
|
||||
rprintf(FINFO,
|
||||
rprintf(FERROR_XFER,
|
||||
"cannot send file with empty name in %s\n",
|
||||
full_fname(fbuf));
|
||||
continue;
|
||||
@@ -1692,6 +1790,15 @@ done:
|
||||
filter_list = save_filter_list;
|
||||
}
|
||||
|
||||
static NORETURN void fatal_unsafe_io_error(void)
|
||||
{
|
||||
/* This (sadly) can only happen when pushing data because
|
||||
* the sender does not know about what kind of delete
|
||||
* is in effect on the receiving side when pulling. */
|
||||
rprintf(FERROR_XFER, "FATAL I/O ERROR: dying to avoid a --delete-during issue with a pre-3.0.7 receiver.\n");
|
||||
exit_cleanup(RERR_UNSUPPORTED);
|
||||
}
|
||||
|
||||
static void send1extra(int f, struct file_struct *file, struct file_list *flist)
|
||||
{
|
||||
char fbuf[MAXPATHLEN];
|
||||
@@ -1711,9 +1818,7 @@ static void send1extra(int f, struct file_struct *file, struct file_list *flist)
|
||||
if (one_file_system) {
|
||||
STRUCT_STAT st;
|
||||
if (link_stat(fbuf, &st, copy_dirlinks) != 0) {
|
||||
io_error |= IOERR_GENERAL;
|
||||
rsyserr(FERROR_XFER, errno, "link_stat %s failed",
|
||||
full_fname(fbuf));
|
||||
interpret_stat_error(fbuf, True);
|
||||
return;
|
||||
}
|
||||
filesystem_dev = st.st_dev;
|
||||
@@ -1748,9 +1853,7 @@ static void send1extra(int f, struct file_struct *file, struct file_list *flist)
|
||||
if (name_type != NORMAL_NAME) {
|
||||
STRUCT_STAT st;
|
||||
if (link_stat(fbuf, &st, 1) != 0) {
|
||||
io_error |= IOERR_GENERAL;
|
||||
rsyserr(FERROR_XFER, errno, "link_stat %s failed",
|
||||
full_fname(fbuf));
|
||||
interpret_stat_error(fbuf, True);
|
||||
continue;
|
||||
}
|
||||
send_file_name(f, flist, fbuf, &st, FLAG_TOP_DIR | flags, ALL_FILTERS);
|
||||
@@ -1811,7 +1914,16 @@ void send_extra_file_list(int f, int at_least)
|
||||
dp = F_DIR_NODE_P(file);
|
||||
}
|
||||
|
||||
write_byte(f, 0);
|
||||
if (io_error == save_io_error || ignore_errors)
|
||||
write_byte(f, 0);
|
||||
else if (use_safe_inc_flist) {
|
||||
write_shortint(f, XMIT_EXTENDED_FLAGS|XMIT_IO_ERROR_ENDLIST);
|
||||
write_varint(f, io_error);
|
||||
} else {
|
||||
if (delete_during)
|
||||
fatal_unsafe_io_error();
|
||||
write_byte(f, 0);
|
||||
}
|
||||
|
||||
if (need_unsorted_flist) {
|
||||
if (!(flist->sorted = new_array(struct file_struct *, flist->used)))
|
||||
@@ -1886,9 +1998,6 @@ struct file_list *send_file_list(int f, int argc, char *argv[])
|
||||
start_write = stats.total_written;
|
||||
gettimeofday(&start_tv, NULL);
|
||||
|
||||
if (!orig_dir)
|
||||
orig_dir = strdup(curr_dir);
|
||||
|
||||
if (relative_paths && protocol_version >= 30)
|
||||
implied_dirs = 1; /* We send flagged implied dirs */
|
||||
|
||||
@@ -1914,6 +2023,9 @@ struct file_list *send_file_list(int f, int argc, char *argv[])
|
||||
use_ff_fd = 1;
|
||||
}
|
||||
|
||||
if (!orig_dir)
|
||||
orig_dir = strdup(curr_dir);
|
||||
|
||||
while (1) {
|
||||
char fbuf[MAXPATHLEN], *fn, name_type;
|
||||
|
||||
@@ -2108,7 +2220,17 @@ struct file_list *send_file_list(int f, int argc, char *argv[])
|
||||
stats.flist_buildtime = 1;
|
||||
start_tv = end_tv;
|
||||
|
||||
write_byte(f, 0); /* Indicate end of file list */
|
||||
/* Indicate end of file list */
|
||||
if (io_error == 0 || ignore_errors)
|
||||
write_byte(f, 0);
|
||||
else if (use_safe_inc_flist) {
|
||||
write_shortint(f, XMIT_EXTENDED_FLAGS|XMIT_IO_ERROR_ENDLIST);
|
||||
write_varint(f, io_error);
|
||||
} else {
|
||||
if (delete_during && inc_recurse)
|
||||
fatal_unsafe_io_error();
|
||||
write_byte(f, 0);
|
||||
}
|
||||
|
||||
#ifdef SUPPORT_HARD_LINKS
|
||||
if (preserve_hard_links && protocol_version >= 30 && !inc_recurse)
|
||||
@@ -2143,10 +2265,12 @@ struct file_list *send_file_list(int f, int argc, char *argv[])
|
||||
if (numeric_ids <= 0 && !inc_recurse)
|
||||
send_id_list(f);
|
||||
|
||||
set_msg_fd_in(-1);
|
||||
|
||||
/* send the io_error flag */
|
||||
if (protocol_version < 30)
|
||||
write_int(f, ignore_errors ? 0 : io_error);
|
||||
else if (io_error && !ignore_errors)
|
||||
else if (!use_safe_inc_flist && io_error && !ignore_errors)
|
||||
send_msg_int(MSG_IO_ERROR, io_error);
|
||||
|
||||
if (disable_buffering)
|
||||
@@ -2164,7 +2288,7 @@ struct file_list *send_file_list(int f, int argc, char *argv[])
|
||||
if (inc_recurse) {
|
||||
send_dir_depth = 1;
|
||||
add_dirs_to_tree(-1, flist, dir_count);
|
||||
if (!file_total || strcmp(flist->sorted[0]->basename, ".") != 0)
|
||||
if (!file_total || strcmp(flist->sorted[flist->low]->basename, ".") != 0)
|
||||
flist->parent_ndx = -1;
|
||||
flist_done_allocating(flist);
|
||||
if (send_dir_ndx < 0) {
|
||||
@@ -2187,6 +2311,7 @@ struct file_list *recv_file_list(int f)
|
||||
struct file_list *flist;
|
||||
int dstart, flags;
|
||||
int64 start_read;
|
||||
int save_verbose = verbose;
|
||||
|
||||
if (!first_flist)
|
||||
rprintf(FLOG, "receiving file list\n");
|
||||
@@ -2213,14 +2338,28 @@ struct file_list *recv_file_list(int f)
|
||||
dstart = 0;
|
||||
}
|
||||
|
||||
if (am_server && verbose > 2)
|
||||
verbose = 2;
|
||||
while ((flags = read_byte(f)) != 0) {
|
||||
struct file_struct *file;
|
||||
|
||||
flist_expand(flist, 1);
|
||||
|
||||
if (protocol_version >= 28 && (flags & XMIT_EXTENDED_FLAGS))
|
||||
flags |= read_byte(f) << 8;
|
||||
file = recv_file_entry(flist, flags, f);
|
||||
|
||||
if (flags == (XMIT_EXTENDED_FLAGS|XMIT_IO_ERROR_ENDLIST)) {
|
||||
int err;
|
||||
if (!use_safe_inc_flist) {
|
||||
rprintf(FERROR, "Invalid flist flag: %x\n", flags);
|
||||
exit_cleanup(RERR_PROTOCOL);
|
||||
}
|
||||
err = read_varint(f);
|
||||
if (!ignore_errors)
|
||||
io_error |= err;
|
||||
break;
|
||||
}
|
||||
|
||||
flist_expand(flist, 1);
|
||||
file = recv_file_entry(f, flist, flags);
|
||||
|
||||
if (inc_recurse && S_ISDIR(file->mode)) {
|
||||
flist_expand(dir_flist, 1);
|
||||
@@ -2232,11 +2371,12 @@ struct file_list *recv_file_list(int f)
|
||||
maybe_emit_filelist_progress(flist->used);
|
||||
|
||||
if (verbose > 2) {
|
||||
rprintf(FINFO, "recv_file_name(%s)\n",
|
||||
f_name(file, NULL));
|
||||
char *name = f_name(file, NULL);
|
||||
rprintf(FINFO, "recv_file_name(%s)\n", NS(name));
|
||||
}
|
||||
}
|
||||
file_total += flist->used;
|
||||
verbose = save_verbose;
|
||||
|
||||
if (verbose > 2)
|
||||
rprintf(FINFO, "received %d names\n", flist->used);
|
||||
@@ -2288,7 +2428,7 @@ struct file_list *recv_file_list(int f)
|
||||
else
|
||||
io_error |= read_int(f);
|
||||
} else if (inc_recurse && flist->ndx_start == 1) {
|
||||
if (!file_total || strcmp(flist->sorted[0]->basename, ".") != 0)
|
||||
if (!file_total || strcmp(flist->sorted[flist->low]->basename, ".") != 0)
|
||||
flist->parent_ndx = -1;
|
||||
}
|
||||
|
||||
@@ -2383,6 +2523,28 @@ int flist_find(struct file_list *flist, struct file_struct *f)
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Search for an identically-named item in the file list. Differs from
|
||||
* flist_find in that an item that agrees with "f" in directory-ness is
|
||||
* preferred but one that does not is still found. */
|
||||
int flist_find_ignore_dirness(struct file_list *flist, struct file_struct *f)
|
||||
{
|
||||
mode_t save_mode;
|
||||
int ndx;
|
||||
|
||||
/* First look for an item that agrees in directory-ness. */
|
||||
ndx = flist_find(flist, f);
|
||||
if (ndx >= 0)
|
||||
return ndx;
|
||||
|
||||
/* Temporarily flip f->mode to look for an item of opposite
|
||||
* directory-ness. */
|
||||
save_mode = f->mode;
|
||||
f->mode = S_ISDIR(f->mode) ? S_IFREG : S_IFDIR;
|
||||
ndx = flist_find(flist, f);
|
||||
f->mode = save_mode;
|
||||
return ndx;
|
||||
}
|
||||
|
||||
/*
|
||||
* Free up any resources a file_struct has allocated
|
||||
* and clear the file.
|
||||
@@ -2881,13 +3043,14 @@ char *f_name(const struct file_struct *f, char *fbuf)
|
||||
* of the dirname string, and also indicates that "dirname" is a MAXPATHLEN
|
||||
* buffer (the functions we call will append names onto the end, but the old
|
||||
* dir value will be restored on exit). */
|
||||
struct file_list *get_dirlist(char *dirname, int dlen, int ignore_filter_rules)
|
||||
struct file_list *get_dirlist(char *dirname, int dlen, int flags)
|
||||
{
|
||||
struct file_list *dirlist;
|
||||
char dirbuf[MAXPATHLEN];
|
||||
int save_recurse = recurse;
|
||||
int save_xfer_dirs = xfer_dirs;
|
||||
int save_prune_empty_dirs = prune_empty_dirs;
|
||||
int senddir_fd = flags & GDL_IGNORE_FILTER_RULES ? -2 : -1;
|
||||
|
||||
if (dlen < 0) {
|
||||
dlen = strlcpy(dirbuf, dirname, MAXPATHLEN);
|
||||
@@ -2900,7 +3063,7 @@ struct file_list *get_dirlist(char *dirname, int dlen, int ignore_filter_rules)
|
||||
|
||||
recurse = 0;
|
||||
xfer_dirs = 1;
|
||||
send_directory(ignore_filter_rules ? -2 : -1, dirlist, dirname, dlen, 0);
|
||||
send_directory(senddir_fd, dirlist, dirname, dlen, FLAG_CONTENT_DIR);
|
||||
xfer_dirs = save_xfer_dirs;
|
||||
recurse = save_recurse;
|
||||
if (do_progress)
|
||||
|
||||
259
generator.c
259
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-2008 Wayne Davison
|
||||
* Copyright (C) 2003-2009 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,8 +44,6 @@ extern int preserve_hard_links;
|
||||
extern int preserve_executability;
|
||||
extern int preserve_perms;
|
||||
extern int preserve_times;
|
||||
extern int uid_ndx;
|
||||
extern int gid_ndx;
|
||||
extern int delete_mode;
|
||||
extern int delete_before;
|
||||
extern int delete_during;
|
||||
@@ -76,7 +74,7 @@ extern int fuzzy_basis;
|
||||
extern int always_checksum;
|
||||
extern int checksum_len;
|
||||
extern char *partial_dir;
|
||||
extern char *basis_dir[];
|
||||
extern char *basis_dir[MAX_BASIS_DIRS+1];
|
||||
extern int compare_dest;
|
||||
extern int copy_dest;
|
||||
extern int link_dest;
|
||||
@@ -108,7 +106,7 @@ 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;
|
||||
@@ -169,19 +167,12 @@ static enum delret delete_item(char *fbuf, uint16 mode, uint16 flags)
|
||||
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. */
|
||||
@@ -294,7 +285,7 @@ static enum delret delete_dir_contents(char *fname, uint16 flags)
|
||||
}
|
||||
|
||||
strlcpy(p, fp->basename, remainder);
|
||||
if (!(fp->mode & S_IWUSR) && !am_root && (uid_t)F_OWNER(fp) == our_uid)
|
||||
if (!(fp->mode & S_IWUSR) && !am_root && fp->flags & FLAG_OWNED_BY_US)
|
||||
do_chmod(fname, fp->mode | S_IWUSR);
|
||||
/* Save stack by recursing to ourself directly. */
|
||||
if (S_ISDIR(fp->mode)) {
|
||||
@@ -472,7 +463,6 @@ 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);
|
||||
@@ -504,9 +494,6 @@ 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
|
||||
@@ -521,9 +508,12 @@ static void delete_in_dir(char *fbuf, struct file_struct *file, dev_t *fs_dev)
|
||||
f_name(fp, NULL));
|
||||
continue;
|
||||
}
|
||||
if (flist_find(cur_flist, fp) < 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)
|
||||
if (!(fp->mode & S_IWUSR) && !am_root && fp->flags & FLAG_OWNED_BY_US)
|
||||
flags |= DEL_NO_UID_WRITE;
|
||||
f_name(fp, delbuf);
|
||||
if (delete_during == 2) {
|
||||
@@ -535,11 +525,6 @@ 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
|
||||
@@ -579,46 +564,101 @@ static void do_delete_pass(void)
|
||||
rprintf(FINFO, " \r");
|
||||
}
|
||||
|
||||
int unchanged_attrs(const char *fname, struct file_struct *file, stat_x *sxp)
|
||||
static inline int time_differs(struct file_struct *file, stat_x *sxp)
|
||||
{
|
||||
#if !defined HAVE_LUTIMES || !defined HAVE_UTIMES
|
||||
if (S_ISLNK(file->mode)) {
|
||||
;
|
||||
} else
|
||||
#endif
|
||||
if (preserve_times && cmp_time(sxp->st.st_mtime, file->modtime) != 0)
|
||||
return 0;
|
||||
return cmp_time(sxp->st.st_mtime, file->modtime);
|
||||
}
|
||||
|
||||
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;
|
||||
static inline int perms_differ(struct file_struct *file, stat_x *sxp)
|
||||
{
|
||||
if (preserve_perms)
|
||||
return !BITS_EQUAL(sxp->st.st_mode, file->mode, CHMOD_BITS);
|
||||
|
||||
if (preserve_executability)
|
||||
return (sxp->st.st_mode & 0111 ? 1 : 0) ^ (file->mode & 0111 ? 1 : 0);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline int ownership_differs(struct file_struct *file, stat_x *sxp)
|
||||
{
|
||||
if (am_root && uid_ndx && sxp->st.st_uid != (uid_t)F_OWNER(file))
|
||||
return 0;
|
||||
return 1;
|
||||
|
||||
if (gid_ndx && !(file->flags & FLAG_SKIP_GROUP) && sxp->st.st_gid != (gid_t)F_GROUP(file))
|
||||
return 0;
|
||||
return 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef SUPPORT_ACLS
|
||||
if (preserve_acls && !S_ISLNK(file->mode)) {
|
||||
static inline int acls_differ(const char *fname, struct file_struct *file, stat_x *sxp)
|
||||
{
|
||||
if (preserve_acls) {
|
||||
if (!ACL_READY(*sxp))
|
||||
get_acl(fname, sxp);
|
||||
if (set_acl(NULL, file, sxp) == 0)
|
||||
return 0;
|
||||
if (set_acl(NULL, file, sxp, file->mode))
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef SUPPORT_XATTRS
|
||||
static inline int xattrs_differ(const char *fname, struct file_struct *file, stat_x *sxp)
|
||||
{
|
||||
if (preserve_xattrs) {
|
||||
if (!XATTR_READY(*sxp))
|
||||
get_xattr(fname, sxp);
|
||||
if (xattr_diff(file, sxp, 0))
|
||||
return 0;
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
int unchanged_attrs(const char *fname, struct file_struct *file, stat_x *sxp)
|
||||
{
|
||||
if (S_ISLNK(file->mode)) {
|
||||
#ifdef CAN_SET_SYMLINK_TIMES
|
||||
if (preserve_times & PRESERVE_LINK_TIMES && time_differs(file, sxp))
|
||||
return 0;
|
||||
#endif
|
||||
#ifdef CAN_CHMOD_SYMLINK
|
||||
if (perms_differ(file, sxp))
|
||||
return 0;
|
||||
#endif
|
||||
#ifndef CAN_CHOWN_SYMLINK
|
||||
if (ownership_differs(file, sxp))
|
||||
return 0;
|
||||
#endif
|
||||
#if defined SUPPORT_ACLS && 0 /* no current symlink-ACL support */
|
||||
if (acls_differ(fname, file, sxp))
|
||||
return 0;
|
||||
#endif
|
||||
#if defined SUPPORT_XATTRS && !defined NO_SYMLINK_XATTRS
|
||||
if (xattrs_differ(fname, file, sxp))
|
||||
return 0;
|
||||
#endif
|
||||
} else {
|
||||
if (preserve_times && time_differs(file, sxp))
|
||||
return 0;
|
||||
if (perms_differ(file, sxp))
|
||||
return 0;
|
||||
if (ownership_differs(file, sxp))
|
||||
return 0;
|
||||
#ifdef SUPPORT_ACLS
|
||||
if (acls_differ(fname, file, sxp))
|
||||
return 0;
|
||||
#endif
|
||||
#ifdef SUPPORT_XATTRS
|
||||
if (xattrs_differ(fname, file, sxp))
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
@@ -628,12 +668,9 @@ void itemize(const char *fnamecmp, struct file_struct *file, int ndx, int statre
|
||||
{
|
||||
if (statret >= 0) { /* A from-dest-dir statret can == 1! */
|
||||
int keep_time = !preserve_times ? 0
|
||||
: S_ISDIR(file->mode) ? preserve_times > 1 :
|
||||
#if defined HAVE_LUTIMES && defined HAVE_UTIMES
|
||||
1;
|
||||
#else
|
||||
!S_ISLNK(file->mode);
|
||||
#endif
|
||||
: S_ISDIR(file->mode) ? preserve_times & PRESERVE_DIR_TIMES
|
||||
: S_ISLNK(file->mode) ? preserve_times & PRESERVE_LINK_TIMES
|
||||
: 1;
|
||||
|
||||
if (S_ISREG(file->mode) && F_LENGTH(file) != sxp->st.st_size)
|
||||
iflags |= ITEM_REPORT_SIZE;
|
||||
@@ -665,7 +702,7 @@ void itemize(const char *fnamecmp, struct file_struct *file, int ndx, int statre
|
||||
if (preserve_acls && !S_ISLNK(file->mode)) {
|
||||
if (!ACL_READY(*sxp))
|
||||
get_acl(fnamecmp, sxp);
|
||||
if (set_acl(NULL, file, sxp) == 0)
|
||||
if (set_acl(NULL, file, sxp, file->mode))
|
||||
iflags |= ITEM_REPORT_ACL;
|
||||
}
|
||||
#endif
|
||||
@@ -697,7 +734,7 @@ 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 (preserve_xattrs && !dry_run
|
||||
if (preserve_xattrs && do_xfers
|
||||
&& iflags & (ITEM_REPORT_XATTR|ITEM_TRANSFER)) {
|
||||
send_xattr_request(NULL, file,
|
||||
iflags & ITEM_REPORT_XATTR ? sock_f_out : -1);
|
||||
@@ -758,6 +795,12 @@ static void sum_sizes_sqroot(struct sum_struct *sum, int64 len)
|
||||
int s2length;
|
||||
int64 l;
|
||||
|
||||
if (len < 0) {
|
||||
/* The file length overflowed our int64 var, so we can't process this file. */
|
||||
sum->count = -1; /* indicate overflow error */
|
||||
return;
|
||||
}
|
||||
|
||||
if (block_size)
|
||||
blength = block_size;
|
||||
else if (len <= BLOCK_SIZE * BLOCK_SIZE)
|
||||
@@ -1121,8 +1164,8 @@ static int try_dests_non(struct file_struct *file, char *fname, int ndx,
|
||||
}
|
||||
switch (type) {
|
||||
case TYPE_DIR:
|
||||
break;
|
||||
case TYPE_SPECIAL:
|
||||
break;
|
||||
case TYPE_DEVICE:
|
||||
devp = F_RDEV_P(file);
|
||||
if (sxp->st.st_rdev != MAKEDEV(DEV_MAJOR(devp), DEV_MINOR(devp)))
|
||||
@@ -1297,6 +1340,12 @@ static void recv_generator(char *fname, struct file_struct *file, int ndx,
|
||||
skip_dir = NULL;
|
||||
}
|
||||
|
||||
#ifdef SUPPORT_ACLS
|
||||
sx.acc_acl = sx.def_acl = NULL;
|
||||
#endif
|
||||
#ifdef SUPPORT_XATTRS
|
||||
sx.xattr = NULL;
|
||||
#endif
|
||||
if (daemon_filter_list.head && (*fname != '.' || fname[1])) {
|
||||
if (check_filter(&daemon_filter_list, FLOG, fname, is_dir) < 0) {
|
||||
if (is_dir < 0)
|
||||
@@ -1306,7 +1355,7 @@ static void recv_generator(char *fname, struct file_struct *file, int ndx,
|
||||
handle_skipped_hlink(file, itemizing, code, f_out);
|
||||
#endif
|
||||
rprintf(FERROR_XFER,
|
||||
"skipping daemon-excluded %s \"%s\"\n",
|
||||
"ERROR: daemon refused to receive %s \"%s\"\n",
|
||||
is_dir ? "directory" : "file", fname);
|
||||
if (is_dir)
|
||||
goto skipping_dir_contents;
|
||||
@@ -1314,12 +1363,6 @@ static void recv_generator(char *fname, struct file_struct *file, int ndx,
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef SUPPORT_ACLS
|
||||
sx.acc_acl = sx.def_acl = NULL;
|
||||
#endif
|
||||
#ifdef SUPPORT_XATTRS
|
||||
sx.xattr = NULL;
|
||||
#endif
|
||||
if (dry_run > 1 || (dry_missing_dir && is_below(file, dry_missing_dir))) {
|
||||
parent_is_dry_missing:
|
||||
if (fuzzy_dirlist) {
|
||||
@@ -1358,7 +1401,7 @@ static void recv_generator(char *fname, struct file_struct *file, int ndx,
|
||||
|
||||
if (need_fuzzy_dirlist && S_ISREG(file->mode)) {
|
||||
strlcpy(fnamecmpbuf, dn, sizeof fnamecmpbuf);
|
||||
fuzzy_dirlist = get_dirlist(fnamecmpbuf, -1, 1);
|
||||
fuzzy_dirlist = get_dirlist(fnamecmpbuf, -1, GDL_IGNORE_FILTER_RULES);
|
||||
need_fuzzy_dirlist = 0;
|
||||
}
|
||||
|
||||
@@ -1399,9 +1442,18 @@ static void recv_generator(char *fname, struct file_struct *file, int ndx,
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
fnamecmp = fname;
|
||||
|
||||
if (is_dir) {
|
||||
mode_t added_perms;
|
||||
if (!implied_dirs && file->flags & FLAG_IMPLIED_DIR)
|
||||
goto cleanup;
|
||||
if (am_root < 0) {
|
||||
/* For --fake-super, the dir must be useable by the copying
|
||||
* user, just like it would be for root. */
|
||||
added_perms = S_IRUSR|S_IWUSR|S_IXUSR;
|
||||
} else
|
||||
added_perms = 0;
|
||||
if (is_dir < 0) {
|
||||
/* In inc_recurse mode we want to make sure any missing
|
||||
* directories get created while we're still processing
|
||||
@@ -1412,7 +1464,7 @@ static void recv_generator(char *fname, struct file_struct *file, int ndx,
|
||||
&& (S_ISDIR(sx.st.st_mode)
|
||||
|| delete_item(fname, sx.st.st_mode, del_opts | DEL_FOR_DIR) != 0))
|
||||
goto cleanup; /* Any errors get reported later. */
|
||||
if (do_mkdir(fname, file->mode & 0700) == 0)
|
||||
if (do_mkdir(fname, (file->mode|added_perms) & 0700) == 0)
|
||||
file->flags |= FLAG_DIR_CREATED;
|
||||
goto cleanup;
|
||||
}
|
||||
@@ -1446,17 +1498,19 @@ static void recv_generator(char *fname, struct file_struct *file, int ndx,
|
||||
itemizing = 0;
|
||||
code = FNONE;
|
||||
statret = 1;
|
||||
} else if (j >= 0)
|
||||
} else if (j >= 0) {
|
||||
statret = 1;
|
||||
fnamecmp = fnamecmpbuf;
|
||||
}
|
||||
}
|
||||
if (itemizing && f_out != -1) {
|
||||
itemize(fname, file, ndx, statret, &sx,
|
||||
itemize(fnamecmp, file, ndx, statret, &sx,
|
||||
statret ? ITEM_LOCAL_CHANGE : 0, 0, NULL);
|
||||
}
|
||||
if (real_ret != 0 && do_mkdir(fname,file->mode) < 0 && errno != EEXIST) {
|
||||
if (real_ret != 0 && do_mkdir(fname,file->mode|added_perms) < 0 && errno != EEXIST) {
|
||||
if (!relative_paths || errno != ENOENT
|
||||
|| create_directory_path(fname) < 0
|
||||
|| (do_mkdir(fname, file->mode) < 0 && errno != EEXIST)) {
|
||||
|| create_directory_path(fname) < 0
|
||||
|| (do_mkdir(fname, file->mode|added_perms) < 0 && errno != EEXIST)) {
|
||||
rsyserr(FERROR_XFER, errno,
|
||||
"recv_generator: mkdir %s failed",
|
||||
full_fname(fname));
|
||||
@@ -1468,6 +1522,7 @@ static void recv_generator(char *fname, struct file_struct *file, int ndx,
|
||||
goto cleanup;
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef SUPPORT_XATTRS
|
||||
if (preserve_xattrs && statret == 1)
|
||||
copy_xattrs(fnamecmpbuf, fname);
|
||||
@@ -1529,11 +1584,14 @@ static void recv_generator(char *fname, struct file_struct *file, int ndx,
|
||||
const char *sl = F_SYMLINK(file);
|
||||
if (safe_symlinks && unsafe_symlink(sl, fname)) {
|
||||
if (verbose) {
|
||||
if (solo_file)
|
||||
if (solo_file) {
|
||||
/* fname contains the destination path, but we
|
||||
* want to report the source path. */
|
||||
fname = f_name(file, NULL);
|
||||
}
|
||||
rprintf(FINFO,
|
||||
"ignoring unsafe symlink %s -> \"%s\"\n",
|
||||
full_fname(fname), sl);
|
||||
"ignoring unsafe symlink \"%s\" -> \"%s\"\n",
|
||||
fname, sl);
|
||||
}
|
||||
return;
|
||||
}
|
||||
@@ -1610,8 +1668,12 @@ static void recv_generator(char *fname, struct file_struct *file, int ndx,
|
||||
|
||||
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));
|
||||
dev_t rdev;
|
||||
if (IS_DEVICE(file->mode)) {
|
||||
uint32 *devp = F_RDEV_P(file);
|
||||
rdev = MAKEDEV(DEV_MAJOR(devp), DEV_MINOR(devp));
|
||||
} else
|
||||
rdev = 0;
|
||||
if (statret == 0) {
|
||||
int del_for_flag;
|
||||
if (IS_DEVICE(file->mode)) {
|
||||
@@ -1625,7 +1687,7 @@ static void recv_generator(char *fname, struct file_struct *file, int ndx,
|
||||
}
|
||||
if (statret == 0
|
||||
&& BITS_EQUAL(sx.st.st_mode, file->mode, _S_IFMT)
|
||||
&& sx.st.st_rdev == rdev) {
|
||||
&& (IS_SPECIAL(sx.st.st_mode) || sx.st.st_rdev == rdev)) {
|
||||
/* The device or special file is identical. */
|
||||
set_file_attrs(fname, file, &sx, NULL, maybe_ATTRS_REPORT);
|
||||
if (itemizing)
|
||||
@@ -1723,7 +1785,6 @@ static void recv_generator(char *fname, struct file_struct *file, int ndx,
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
fnamecmp = fname;
|
||||
fnamecmp_type = FNAMECMP_FNAME;
|
||||
|
||||
if (statret == 0 && !S_ISREG(sx.st.st_mode)) {
|
||||
@@ -2026,6 +2087,7 @@ static void touch_up_dirs(struct file_list *flist, int ndx)
|
||||
static int counter = 0;
|
||||
struct file_struct *file;
|
||||
char *fname;
|
||||
BOOL fix_dir_perms;
|
||||
int i, start, end;
|
||||
|
||||
if (ndx < 0) {
|
||||
@@ -2046,11 +2108,13 @@ static void touch_up_dirs(struct file_list *flist, int ndx)
|
||||
rprintf(FINFO, "touch_up_dirs: %s (%d)\n",
|
||||
NS(fname), i);
|
||||
}
|
||||
/* Be sure not to retouch permissions with --fake-super. */
|
||||
fix_dir_perms = !am_root && !(file->mode & S_IWUSR);
|
||||
if (!F_IS_ACTIVE(file) || file->flags & FLAG_MISSING_DIR
|
||||
|| (!need_retouch_dir_times && file->mode & S_IWUSR))
|
||||
|| !(need_retouch_dir_times || fix_dir_perms))
|
||||
continue;
|
||||
fname = f_name(file, NULL);
|
||||
if (!(file->mode & S_IWUSR))
|
||||
if (fix_dir_perms)
|
||||
do_chmod(fname, file->mode);
|
||||
if (need_retouch_dir_times) {
|
||||
STRUCT_STAT st;
|
||||
@@ -2058,10 +2122,13 @@ static void touch_up_dirs(struct file_list *flist, int ndx)
|
||||
&& cmp_time(st.st_mtime, file->modtime) != 0)
|
||||
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 (counter >= loopchk_limit) {
|
||||
if (allowed_lull)
|
||||
maybe_send_keepalive();
|
||||
else
|
||||
maybe_flush_socket(0);
|
||||
counter = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2075,8 +2142,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);
|
||||
@@ -2099,7 +2165,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)
|
||||
@@ -2132,10 +2198,9 @@ void check_for_finished_files(int itemizing, enum logcode code, int check_redo)
|
||||
if (first_flist->in_progress || first_flist->to_redo)
|
||||
break;
|
||||
|
||||
if (!read_batch) {
|
||||
write_ndx(sock_f_out, NDX_DONE);
|
||||
write_ndx(sock_f_out, NDX_DONE);
|
||||
if (!read_batch)
|
||||
maybe_flush_socket(1);
|
||||
}
|
||||
|
||||
if (delete_during == 2 || !dir_tweaking) {
|
||||
/* Skip directory touch-up. */
|
||||
@@ -2148,7 +2213,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;
|
||||
@@ -2173,8 +2238,8 @@ 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;
|
||||
need_retouch_dir_times = preserve_times & PRESERVE_DIR_TIMES;
|
||||
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;
|
||||
@@ -2204,7 +2269,7 @@ void generate_files(int f_out, const char *local_name)
|
||||
/* Since we often fill up the outgoing socket and then just sit around
|
||||
* waiting for the other 2 processes to do their thing, we don't want
|
||||
* to exit on a timeout. If the data stops flowing, the receiver will
|
||||
* notice that and let us know via the redo pipe (or its closing). */
|
||||
* notice that and let us know via the message pipe (or its closing). */
|
||||
ignore_timeout = 1;
|
||||
|
||||
dflt_perms = (ACCESSPERMS & ~orig_umask);
|
||||
@@ -2258,10 +2323,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) {
|
||||
@@ -2295,6 +2363,7 @@ void generate_files(int f_out, const char *local_name)
|
||||
rprintf(FINFO, "generate_files phase=%d\n", phase);
|
||||
|
||||
write_ndx(f_out, NDX_DONE);
|
||||
|
||||
/* Reduce round-trip lag-time for a useless delay-updates phase. */
|
||||
if (protocol_version >= 29 && !delay_updates)
|
||||
write_ndx(f_out, NDX_DONE);
|
||||
@@ -2329,7 +2398,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;
|
||||
|
||||
13
hashtable.c
13
hashtable.c
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* Routines to provide a memory-efficient hashtable.
|
||||
*
|
||||
* Copyright (C) 2007-2008 Wayne Davison
|
||||
* Copyright (C) 2007-2009 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,7 @@ struct hashtable *hashtable_create(int size, int key64)
|
||||
tbl->size = size;
|
||||
tbl->entries = 0;
|
||||
tbl->node_size = node_size;
|
||||
tbl->key64 = key64;
|
||||
tbl->key64 = key64 ? 1 : 0;
|
||||
|
||||
return tbl;
|
||||
}
|
||||
@@ -60,6 +60,11 @@ void *hashtable_find(struct hashtable *tbl, int64 key, int allocate_if_missing)
|
||||
struct ht_int32_node *node;
|
||||
uint32 ndx;
|
||||
|
||||
if (key64 ? key == 0 : (int32)key == 0) {
|
||||
rprintf(FERROR, "Internal hashtable error: illegal key supplied!\n");
|
||||
exit_cleanup(RERR_MESSAGEIO);
|
||||
}
|
||||
|
||||
if (allocate_if_missing && tbl->entries > HASH_LOAD_LIMIT(tbl->size)) {
|
||||
void *old_nodes = tbl->nodes;
|
||||
int size = tbl->size * 2;
|
||||
@@ -87,7 +92,7 @@ void *hashtable_find(struct hashtable *tbl, int64 key, int allocate_if_missing)
|
||||
uchar buf[4], *keyp = buf;
|
||||
int i;
|
||||
|
||||
SIVAL(buf, 0, key);
|
||||
SIVALu(buf, 0, key);
|
||||
for (ndx = 0, i = 0; i < 4; i++) {
|
||||
ndx += keyp[i];
|
||||
ndx += (ndx << 10);
|
||||
@@ -142,7 +147,7 @@ void *hashtable_find(struct hashtable *tbl, int64 key, int allocate_if_missing)
|
||||
if (key64)
|
||||
((struct ht_int64_node*)node)->key = key;
|
||||
else
|
||||
node->key = key;
|
||||
node->key = (int32)key;
|
||||
tbl->entries++;
|
||||
return node;
|
||||
}
|
||||
|
||||
99
hlink.c
99
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-2008 Wayne Davison
|
||||
* Copyright (C) 2004-2009 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,14 +30,15 @@ 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;
|
||||
extern int stdout_format_has_i;
|
||||
extern int maybe_ATTRS_REPORT;
|
||||
extern int unsort_ndx;
|
||||
extern char *basis_dir[];
|
||||
extern struct file_list *cur_flist, *first_flist;
|
||||
extern char *basis_dir[MAX_BASIS_DIRS+1];
|
||||
extern struct file_list *cur_flist;
|
||||
|
||||
#ifdef SUPPORT_HARD_LINKS
|
||||
|
||||
@@ -56,7 +57,7 @@ static struct file_list *hlink_flist;
|
||||
void init_hard_links(void)
|
||||
{
|
||||
if (am_sender || protocol_version < 30)
|
||||
dev_tbl = hashtable_create(16, SIZEOF_INT64 == 8);
|
||||
dev_tbl = hashtable_create(16, 1);
|
||||
else if (inc_recurse)
|
||||
prior_hlinks = hashtable_create(1024, 0);
|
||||
}
|
||||
@@ -66,11 +67,12 @@ struct ht_int64_node *idev_find(int64 dev, int64 ino)
|
||||
static struct ht_int64_node *dev_node = NULL;
|
||||
struct hashtable *tbl;
|
||||
|
||||
if (!dev_node || dev_node->key != dev) {
|
||||
/* Note that some OSes have a dev == 0, so increment to avoid storing a 0. */
|
||||
if (!dev_node || dev_node->key != dev+1) {
|
||||
/* We keep a separate hash table of inodes for every device. */
|
||||
dev_node = hashtable_find(dev_tbl, dev, 1);
|
||||
dev_node = hashtable_find(dev_tbl, dev+1, 1);
|
||||
if (!(tbl = dev_node->data))
|
||||
tbl = dev_node->data = hashtable_create(512, SIZEOF_INT64 == 8);
|
||||
tbl = dev_node->data = hashtable_create(512, 1);
|
||||
} else
|
||||
tbl = dev_node->data;
|
||||
|
||||
@@ -119,14 +121,15 @@ 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;
|
||||
prev = IVAL(node->data, 1);
|
||||
flist = flist_for_ndx(prev);
|
||||
flist = flist_for_ndx(prev, NULL);
|
||||
if (flist)
|
||||
flist->files[prev - flist->ndx_start]->flags &= ~FLAG_HLINK_LAST;
|
||||
else {
|
||||
@@ -179,7 +182,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;
|
||||
|
||||
@@ -255,7 +258,7 @@ static char *check_prior(struct file_struct *file, int gnum,
|
||||
while (1) {
|
||||
struct file_list *flist;
|
||||
if (prev_ndx < 0
|
||||
|| (flist = flist_for_ndx(prev_ndx)) == NULL)
|
||||
|| (flist = flist_for_ndx(prev_ndx, NULL)) == NULL)
|
||||
break;
|
||||
fp = flist->files[prev_ndx - flist->ndx_start];
|
||||
if (!(fp->flags & FLAG_SKIP_HLINK)) {
|
||||
@@ -354,9 +357,13 @@ int hard_link_check(struct file_struct *file, int ndx, const char *fname,
|
||||
}
|
||||
|
||||
if (link_stat(prev_name, &prev_st, 0) < 0) {
|
||||
rsyserr(FERROR_XFER, errno, "stat %s failed",
|
||||
full_fname(prev_name));
|
||||
return -1;
|
||||
if (!dry_run || errno != ENOENT) {
|
||||
rsyserr(FERROR_XFER, errno, "stat %s failed", full_fname(prev_name));
|
||||
return -1;
|
||||
}
|
||||
/* A new hard-link will get a new dev & inode, so approximate
|
||||
* those values in dry-run mode by zeroing them. */
|
||||
memset(&prev_st, 0, sizeof prev_st);
|
||||
}
|
||||
|
||||
if (statret < 0 && basis_dir[0] != NULL) {
|
||||
@@ -366,6 +373,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);
|
||||
@@ -395,19 +405,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,
|
||||
@@ -474,19 +502,13 @@ 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);
|
||||
if (flist == NULL) {
|
||||
int start1 = first_flist ? first_flist->ndx_start : 0;
|
||||
int start2 = first_flist ? first_flist->prev->ndx_start : 0;
|
||||
int used = first_flist ? first_flist->prev->used : 0;
|
||||
rprintf(FERROR,
|
||||
"File index not found: %d (%d - %d)\n",
|
||||
ndx, start1 - 1, start2 + used - 1);
|
||||
exit_cleanup(RERR_PROTOCOL);
|
||||
}
|
||||
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);
|
||||
@@ -498,6 +520,10 @@ void finish_hard_link(struct file_struct *file, const char *fname, int fin_ndx,
|
||||
#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;
|
||||
@@ -508,8 +534,19 @@ void finish_hard_link(struct file_struct *file, const char *fname, int fin_ndx,
|
||||
if (inc_recurse) {
|
||||
int gnum = F_HL_GNUM(file);
|
||||
struct ht_int32_node *node = hashtable_find(prior_hlinks, gnum, 0);
|
||||
assert(node != NULL && node->data != NULL);
|
||||
assert(CVAL(node->data, 0) == 0);
|
||||
if (node == NULL) {
|
||||
rprintf(FERROR, "Unable to find a hlink node for %d (%s)\n", gnum, f_name(file, prev_name));
|
||||
exit_cleanup(RERR_MESSAGEIO);
|
||||
}
|
||||
if (node->data == NULL) {
|
||||
rprintf(FERROR, "Hlink node data for %d is NULL (%s)\n", gnum, f_name(file, prev_name));
|
||||
exit_cleanup(RERR_MESSAGEIO);
|
||||
}
|
||||
if (CVAL(node->data, 0) != 0) {
|
||||
rprintf(FERROR, "Hlink node data for %d already has path=%s (%s)\n",
|
||||
gnum, (char*)node->data, f_name(file, prev_name));
|
||||
exit_cleanup(RERR_MESSAGEIO);
|
||||
}
|
||||
free(node->data);
|
||||
if (!(node->data = strdup(our_name)))
|
||||
out_of_memory("finish_hard_link");
|
||||
|
||||
250
io.c
250
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-2008 Wayne Davison
|
||||
* Copyright (C) 2003-2009 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,6 @@
|
||||
extern int bwlimit;
|
||||
extern size_t bwlimit_writemax;
|
||||
extern int io_timeout;
|
||||
extern int allowed_lull;
|
||||
extern int am_server;
|
||||
extern int am_daemon;
|
||||
extern int am_sender;
|
||||
@@ -47,7 +46,7 @@ extern int eol_nulls;
|
||||
extern int flist_eof;
|
||||
extern int list_only;
|
||||
extern int read_batch;
|
||||
extern int csum_length;
|
||||
extern int compat_flags;
|
||||
extern int protect_args;
|
||||
extern int checksum_seed;
|
||||
extern int protocol_version;
|
||||
@@ -60,7 +59,8 @@ extern int filesfrom_convert;
|
||||
extern iconv_t ic_send, ic_recv;
|
||||
#endif
|
||||
|
||||
const char phase_unknown[] = "unknown";
|
||||
int csum_length = SHORT_SUM_LENGTH; /* initial value */
|
||||
int allowed_lull = 0;
|
||||
int ignore_timeout = 0;
|
||||
int batch_fd = -1;
|
||||
int msgdone_cnt = 0;
|
||||
@@ -101,7 +101,7 @@ 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;
|
||||
@@ -119,21 +119,34 @@ static char int_byte_extra[64] = {
|
||||
|
||||
enum festatus { FES_SUCCESS, FES_REDO, FES_NO_SEND };
|
||||
|
||||
static void check_timeout(void)
|
||||
{
|
||||
time_t t, chk;
|
||||
|
||||
if (!io_timeout || ignore_timeout)
|
||||
return;
|
||||
|
||||
t = time(NULL);
|
||||
|
||||
if (!last_io_in)
|
||||
last_io_in = t;
|
||||
|
||||
chk = MAX(last_io_out, last_io_in);
|
||||
if (t - chk >= io_timeout) {
|
||||
if (am_server || am_daemon)
|
||||
exit_cleanup(RERR_TIMEOUT);
|
||||
rprintf(FERROR, "[%s] io timeout after %d seconds -- exiting\n",
|
||||
who_am_i(), (int)(t-chk));
|
||||
exit_cleanup(RERR_TIMEOUT);
|
||||
}
|
||||
}
|
||||
|
||||
static void readfd(int fd, char *buffer, size_t N);
|
||||
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;
|
||||
@@ -147,45 +160,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--;
|
||||
@@ -208,6 +186,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);
|
||||
@@ -217,29 +200,6 @@ static void got_flist_entry_status(enum festatus status, const char *buf)
|
||||
}
|
||||
}
|
||||
|
||||
static void check_timeout(void)
|
||||
{
|
||||
time_t t;
|
||||
|
||||
if (!io_timeout || ignore_timeout)
|
||||
return;
|
||||
|
||||
if (!last_io_in) {
|
||||
last_io_in = time(NULL);
|
||||
return;
|
||||
}
|
||||
|
||||
t = time(NULL);
|
||||
|
||||
if (t - last_io_in >= io_timeout) {
|
||||
if (!am_server && !am_daemon) {
|
||||
rprintf(FERROR, "io timeout after %d seconds -- exiting\n",
|
||||
(int)(t-last_io_in));
|
||||
}
|
||||
exit_cleanup(RERR_TIMEOUT);
|
||||
}
|
||||
}
|
||||
|
||||
/* Note the fds used for the main socket (which might really be a pipe
|
||||
* for a local transfer, but we can ignore that). */
|
||||
void io_set_sock_fds(int f_in, int f_out)
|
||||
@@ -251,13 +211,15 @@ void io_set_sock_fds(int f_in, int f_out)
|
||||
void set_io_timeout(int secs)
|
||||
{
|
||||
io_timeout = secs;
|
||||
allowed_lull = (io_timeout + 1) / 2;
|
||||
|
||||
if (!io_timeout || io_timeout > SELECT_TIMEOUT)
|
||||
if (!io_timeout || allowed_lull > SELECT_TIMEOUT)
|
||||
select_timeout = SELECT_TIMEOUT;
|
||||
else
|
||||
select_timeout = io_timeout;
|
||||
select_timeout = allowed_lull;
|
||||
|
||||
allowed_lull = read_batch ? 0 : (io_timeout + 1) / 2;
|
||||
if (read_batch)
|
||||
allowed_lull = 0;
|
||||
}
|
||||
|
||||
/* Setup the fd used to receive MSG_* messages. Only needed during the
|
||||
@@ -296,33 +258,32 @@ 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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -449,6 +410,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;
|
||||
@@ -486,9 +448,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
|
||||
@@ -531,9 +498,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);
|
||||
@@ -568,10 +535,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)
|
||||
@@ -985,8 +951,8 @@ void maybe_send_keepalive(void)
|
||||
if (time(NULL) - last_io_out >= allowed_lull) {
|
||||
if (!iobuf_out || !iobuf_out_cnt) {
|
||||
if (protocol_version < 29)
|
||||
return; /* there's nothing we can do */
|
||||
if (protocol_version >= 30)
|
||||
send_msg(MSG_DATA, "", 0, 0);
|
||||
else if (protocol_version >= 30)
|
||||
send_msg(MSG_NOOP, "", 0, 0);
|
||||
else {
|
||||
write_int(sock_f_out, cur_flist->used);
|
||||
@@ -1003,11 +969,13 @@ void start_flist_forward(int f_in)
|
||||
assert(iobuf_out != NULL);
|
||||
assert(iobuf_f_out == msg_fd_out);
|
||||
flist_forward_from = f_in;
|
||||
defer_forwarding_messages++;
|
||||
}
|
||||
|
||||
void stop_flist_forward()
|
||||
void stop_flist_forward(void)
|
||||
{
|
||||
flist_forward_from = -1;
|
||||
defer_forwarding_messages--;
|
||||
io_flush(FULL_FLUSH);
|
||||
}
|
||||
|
||||
@@ -1074,6 +1042,8 @@ static int readfd_unbuffered(int fd, char *buf, size_t len)
|
||||
iobuf_in_ndx = 0;
|
||||
break;
|
||||
case MSG_NOOP:
|
||||
if (msg_bytes != 0)
|
||||
goto invalid_msg;
|
||||
if (am_sender)
|
||||
maybe_send_keepalive();
|
||||
break;
|
||||
@@ -1453,6 +1423,22 @@ static void sleep_for_bwlimit(int bytes_written)
|
||||
total_written = (sleep_usec - elapsed_usec) * bwlimit / (ONE_SEC/1024);
|
||||
}
|
||||
|
||||
static const char *what_fd_is(int fd)
|
||||
{
|
||||
static char buf[20];
|
||||
|
||||
if (fd == sock_f_out)
|
||||
return "socket";
|
||||
else if (fd == msg_fd_out)
|
||||
return "message fd";
|
||||
else if (fd == batch_fd)
|
||||
return "batch file";
|
||||
else {
|
||||
snprintf(buf, sizeof buf, "fd %d", fd);
|
||||
return buf;
|
||||
}
|
||||
}
|
||||
|
||||
/* Write len bytes to the file descriptor fd, looping as necessary to get
|
||||
* the job done and also (in certain circumstances) reading any data on
|
||||
* msg_fd_in to avoid deadlock.
|
||||
@@ -1531,8 +1517,8 @@ static void writefd_unbuffered(int fd, const char *buf, size_t len)
|
||||
if (am_server && fd == msg_fd_out)
|
||||
exit_cleanup(RERR_STREAMIO);
|
||||
rsyserr(FERROR, errno,
|
||||
"writefd_unbuffered failed to write %ld bytes [%s]",
|
||||
(long)len, who_am_i());
|
||||
"writefd_unbuffered failed to write %ld bytes to %s [%s]",
|
||||
(long)len, what_fd_is(fd), who_am_i());
|
||||
/* If the other side is sending us error messages, try
|
||||
* to grab any messages they sent before they died. */
|
||||
while (!am_server && fd == sock_f_out && io_multiplexing_in) {
|
||||
@@ -1555,24 +1541,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)
|
||||
@@ -1580,10 +1576,8 @@ static void writefd(int fd, const char *buf, size_t len)
|
||||
if (fd == sock_f_out)
|
||||
stats.total_written += len;
|
||||
|
||||
if (fd == write_batch_monitor_out) {
|
||||
if ((size_t)write(batch_fd, buf, len) != len)
|
||||
exit_cleanup(RERR_FILEIO);
|
||||
}
|
||||
if (fd == write_batch_monitor_out)
|
||||
writefd_unbuffered(batch_fd, buf, len);
|
||||
|
||||
if (!iobuf_out || fd != iobuf_f_out) {
|
||||
writefd_unbuffered(fd, buf, len);
|
||||
@@ -1907,7 +1901,7 @@ void start_write_batch(int fd)
|
||||
* is involved. */
|
||||
write_int(batch_fd, protocol_version);
|
||||
if (protocol_version >= 30)
|
||||
write_byte(batch_fd, inc_recurse);
|
||||
write_byte(batch_fd, compat_flags);
|
||||
write_int(batch_fd, checksum_seed);
|
||||
|
||||
if (am_sender)
|
||||
|
||||
@@ -295,9 +295,8 @@ int getaddrinfo(const char *node,
|
||||
res);
|
||||
} else if (hints.ai_flags & AI_NUMERICHOST) {
|
||||
struct in_addr ip;
|
||||
if (!inet_aton(node, &ip)) {
|
||||
if (inet_pton(AF_INET, node, &ip) <= 0)
|
||||
return EAI_FAIL;
|
||||
}
|
||||
return getaddr_info_single_addr(service,
|
||||
ntohl(ip.s_addr),
|
||||
&hints,
|
||||
@@ -492,13 +491,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) {
|
||||
|
||||
44
lib/md5.c
44
lib/md5.c
@@ -38,22 +38,22 @@ static void md5_process(md_context *ctx, const uchar data[CSUM_CHUNK])
|
||||
C = ctx->C;
|
||||
D = ctx->D;
|
||||
|
||||
X[0] = IVAL(data, 0);
|
||||
X[1] = IVAL(data, 4);
|
||||
X[2] = IVAL(data, 8);
|
||||
X[3] = IVAL(data, 12);
|
||||
X[4] = IVAL(data, 16);
|
||||
X[5] = IVAL(data, 20);
|
||||
X[6] = IVAL(data, 24);
|
||||
X[7] = IVAL(data, 28);
|
||||
X[8] = IVAL(data, 32);
|
||||
X[9] = IVAL(data, 36);
|
||||
X[10] = IVAL(data, 40);
|
||||
X[11] = IVAL(data, 44);
|
||||
X[12] = IVAL(data, 48);
|
||||
X[13] = IVAL(data, 52);
|
||||
X[14] = IVAL(data, 56);
|
||||
X[15] = IVAL(data, 60);
|
||||
X[0] = IVALu(data, 0);
|
||||
X[1] = IVALu(data, 4);
|
||||
X[2] = IVALu(data, 8);
|
||||
X[3] = IVALu(data, 12);
|
||||
X[4] = IVALu(data, 16);
|
||||
X[5] = IVALu(data, 20);
|
||||
X[6] = IVALu(data, 24);
|
||||
X[7] = IVALu(data, 28);
|
||||
X[8] = IVALu(data, 32);
|
||||
X[9] = IVALu(data, 36);
|
||||
X[10] = IVALu(data, 40);
|
||||
X[11] = IVALu(data, 44);
|
||||
X[12] = IVALu(data, 48);
|
||||
X[13] = IVALu(data, 52);
|
||||
X[14] = IVALu(data, 56);
|
||||
X[15] = IVALu(data, 60);
|
||||
|
||||
#define S(x,n) ((x << n) | ((x & 0xFFFFFFFF) >> (32 - n)))
|
||||
|
||||
@@ -192,8 +192,8 @@ void md5_result(md_context *ctx, uchar digest[MD5_DIGEST_LEN])
|
||||
| (ctx->totalN2 << 3);
|
||||
low = (ctx->totalN << 3);
|
||||
|
||||
SIVAL(msglen, 0, low);
|
||||
SIVAL(msglen, 4, high);
|
||||
SIVALu(msglen, 0, low);
|
||||
SIVALu(msglen, 4, high);
|
||||
|
||||
last = ctx->totalN & 0x3F;
|
||||
padn = last < 56 ? 56 - last : 120 - last;
|
||||
@@ -201,10 +201,10 @@ void md5_result(md_context *ctx, uchar digest[MD5_DIGEST_LEN])
|
||||
md5_update(ctx, md5_padding, padn);
|
||||
md5_update(ctx, msglen, 8);
|
||||
|
||||
SIVAL(digest, 0, ctx->A);
|
||||
SIVAL(digest, 4, ctx->B);
|
||||
SIVAL(digest, 8, ctx->C);
|
||||
SIVAL(digest, 12, ctx->D);
|
||||
SIVALu(digest, 0, ctx->A);
|
||||
SIVALu(digest, 4, ctx->B);
|
||||
SIVALu(digest, 8, ctx->C);
|
||||
SIVALu(digest, 12, ctx->D);
|
||||
}
|
||||
|
||||
void get_md5(uchar *out, const uchar *input, int n)
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -551,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;
|
||||
}
|
||||
@@ -1007,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;
|
||||
}
|
||||
@@ -1638,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;
|
||||
@@ -1815,7 +1815,11 @@ SMB_ACL_T sys_acl_get_file( const char *path_p, SMB_ACL_TYPE_T type)
|
||||
|
||||
/* AIX has no DEFAULT */
|
||||
if ( type == SMB_ACL_TYPE_DEFAULT ) {
|
||||
#ifdef ENOTSUP
|
||||
errno = ENOTSUP;
|
||||
#else
|
||||
errno = ENOSYS;
|
||||
#endif
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@@ -2777,6 +2781,11 @@ int no_acl_syscall_error(int err)
|
||||
return 1;
|
||||
}
|
||||
#endif
|
||||
if (err == EINVAL) {
|
||||
/* If the type of SMB_ACL_TYPE_ACCESS or SMB_ACL_TYPE_DEFAULT
|
||||
* isn't valid, then the ACLs must be non-POSIX. */
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
10
loadparm.c
10
loadparm.c
@@ -1,6 +1,3 @@
|
||||
/* This is based on loadparm.c from Samba, written by Andrew Tridgell
|
||||
and Karl Auer */
|
||||
|
||||
/*
|
||||
* 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
|
||||
@@ -16,13 +13,14 @@
|
||||
* with this program; if not, visit the http://fsf.org website.
|
||||
*/
|
||||
|
||||
/* some fixes
|
||||
/* This is based on loadparm.c from Samba, written by Andrew Tridgell
|
||||
* and Karl Auer. Some of the changes are:
|
||||
*
|
||||
* Copyright (C) 2001, 2002 Martin Pool <mbp@samba.org>
|
||||
* Copyright (C) 2003-2009 Wayne Davison <wayned@samba.org>
|
||||
*/
|
||||
|
||||
/*
|
||||
* Load parameters.
|
||||
/* Load parameters.
|
||||
*
|
||||
* This module provides suitable callback functions for the params
|
||||
* module. It builds the internal table of service details which is
|
||||
|
||||
20
log.c
20
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-2008 Wayne Davison
|
||||
* Copyright (C) 2003-2009 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,8 +35,6 @@ extern int msg_fd_out;
|
||||
extern int allow_8bit_chars;
|
||||
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;
|
||||
@@ -52,10 +50,10 @@ extern char *logfile_name;
|
||||
extern iconv_t ic_chck;
|
||||
#endif
|
||||
#ifdef ICONV_OPTION
|
||||
extern iconv_t ic_send, ic_recv;
|
||||
extern iconv_t ic_recv;
|
||||
#endif
|
||||
extern char curr_dir[];
|
||||
extern char *module_dir;
|
||||
extern char curr_dir[MAXPATHLEN];
|
||||
extern char *full_module_path;
|
||||
extern unsigned int module_dirlen;
|
||||
|
||||
static int log_initialised;
|
||||
@@ -85,7 +83,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" },
|
||||
@@ -257,13 +255,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;
|
||||
@@ -599,7 +601,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;
|
||||
|
||||
30
main.c
30
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-2008 Wayne Davison
|
||||
* Copyright (C) 2003-2009 Wayne Davison
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
@@ -33,7 +33,6 @@ extern int list_only;
|
||||
extern int am_root;
|
||||
extern int am_server;
|
||||
extern int am_sender;
|
||||
extern int am_generator;
|
||||
extern int am_daemon;
|
||||
extern int inc_recurse;
|
||||
extern int blocking_io;
|
||||
@@ -65,13 +64,14 @@ extern int write_batch;
|
||||
extern int batch_fd;
|
||||
extern int filesfrom_fd;
|
||||
extern int connect_timeout;
|
||||
extern dev_t filesystem_dev;
|
||||
extern pid_t cleanup_child_pid;
|
||||
extern unsigned int module_dirlen;
|
||||
extern struct stats stats;
|
||||
extern char *filesfrom_host;
|
||||
extern char *partial_dir;
|
||||
extern char *dest_option;
|
||||
extern char *basis_dir[];
|
||||
extern char *basis_dir[MAX_BASIS_DIRS+1];
|
||||
extern char *rsync_path;
|
||||
extern char *shell_cmd;
|
||||
extern char *batch_name;
|
||||
@@ -81,6 +81,8 @@ extern struct file_list *first_flist;
|
||||
extern struct filter_list_struct daemon_filter_list;
|
||||
|
||||
uid_t our_uid;
|
||||
int am_receiver = 0; /* Only set to 1 after the receiver/generator fork. */
|
||||
int am_generator = 0; /* Only set to 1 after the receiver/generator fork. */
|
||||
int local_server = 0;
|
||||
int daemon_over_rsh = 0;
|
||||
mode_t orig_umask = 0;
|
||||
@@ -427,7 +429,11 @@ static pid_t do_cmd(char *cmd, char *machine, char *user, char **remote_argv, in
|
||||
rprintf(FERROR, "internal: args[] overflowed in do_cmd()\n");
|
||||
exit_cleanup(RERR_SYNTAX);
|
||||
}
|
||||
args[argc++] = *remote_argv++;
|
||||
if (**remote_argv == '-') {
|
||||
if (asprintf(args + argc++, "./%s", *remote_argv++) < 0)
|
||||
out_of_memory("do_cmd");
|
||||
} else
|
||||
args[argc++] = *remote_argv++;
|
||||
remote_argc--;
|
||||
}
|
||||
}
|
||||
@@ -469,7 +475,7 @@ static pid_t do_cmd(char *cmd, char *machine, char *user, char **remote_argv, in
|
||||
#ifdef ICONV_CONST
|
||||
setup_iconv();
|
||||
#endif
|
||||
if (protect_args)
|
||||
if (protect_args && !daemon_over_rsh)
|
||||
send_protected_args(*f_out_p, args);
|
||||
}
|
||||
|
||||
@@ -507,6 +513,10 @@ static char *get_local_name(struct file_list *flist, char *dest_path)
|
||||
if (!dest_path || list_only)
|
||||
return NULL;
|
||||
|
||||
/* Treat an empty string as a copy into the current directory. */
|
||||
if (!*dest_path)
|
||||
dest_path = ".";
|
||||
|
||||
if (daemon_filter_list.head) {
|
||||
char *slash = strrchr(dest_path, '/');
|
||||
if (slash && (slash[1] == '\0' || (slash[1] == '.' && slash[2] == '\0')))
|
||||
@@ -516,7 +526,7 @@ static char *get_local_name(struct file_list *flist, char *dest_path)
|
||||
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",
|
||||
rprintf(FERROR, "ERROR: daemon has excluded destination \"%s\"\n",
|
||||
dest_path);
|
||||
exit_cleanup(RERR_FILESELECT);
|
||||
}
|
||||
@@ -533,6 +543,7 @@ static char *get_local_name(struct file_list *flist, char *dest_path)
|
||||
full_fname(dest_path));
|
||||
exit_cleanup(RERR_FILESELECT);
|
||||
}
|
||||
filesystem_dev = st.st_dev; /* ensures --force works right w/-x */
|
||||
return NULL;
|
||||
}
|
||||
if (file_total > 1) {
|
||||
@@ -760,6 +771,8 @@ static int do_recv(int f_in, int f_out, char *local_name)
|
||||
}
|
||||
|
||||
if (pid == 0) {
|
||||
am_receiver = 1;
|
||||
|
||||
close(error_pipe[0]);
|
||||
if (f_in != f_out)
|
||||
close(f_out);
|
||||
@@ -1016,7 +1029,6 @@ int client_run(int f_in, int f_out, pid_t pid, int argc, char *argv[])
|
||||
if (write_batch && !am_server)
|
||||
start_write_batch(f_out);
|
||||
flist = send_file_list(f_out, argc, argv);
|
||||
set_msg_fd_in(-1);
|
||||
if (verbose > 3)
|
||||
rprintf(FINFO,"file list sent\n");
|
||||
|
||||
@@ -1187,8 +1199,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) {
|
||||
|
||||
49
match.c
49
match.c
@@ -3,7 +3,7 @@
|
||||
*
|
||||
* Copyright (C) 1996 Andrew Tridgell
|
||||
* Copyright (C) 1996 Paul Mackerras
|
||||
* Copyright (C) 2003-2008 Wayne Davison
|
||||
* Copyright (C) 2003-2009 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
|
||||
@@ -90,8 +90,7 @@ static void build_hash_table(struct sum_struct *s)
|
||||
static OFF_T last_match;
|
||||
|
||||
|
||||
/**
|
||||
* Transmit a literal and/or match token.
|
||||
/* Transmit a literal and/or match token.
|
||||
*
|
||||
* This delightfully-named function is called either when we find a
|
||||
* match and need to transmit all the unmatched data leading up to it,
|
||||
@@ -99,9 +98,9 @@ static OFF_T last_match;
|
||||
* transmit it. As a result of this second case, it is called even if
|
||||
* we have not matched at all!
|
||||
*
|
||||
* @param i If >0, the number of a matched token. If 0, indicates we
|
||||
* have only literal data.
|
||||
**/
|
||||
* If i >= 0, the number of a matched token. If < 0, indicates we have
|
||||
* only literal data. A -1 will send a 0-token-int too, and a -2 sends
|
||||
* only literal data, w/o any token-int. */
|
||||
static void matched(int f, struct sum_struct *s, struct map_struct *buf,
|
||||
OFF_T offset, int32 i)
|
||||
{
|
||||
@@ -141,8 +140,8 @@ static void matched(int f, struct sum_struct *s, struct map_struct *buf,
|
||||
static void hash_search(int f,struct sum_struct *s,
|
||||
struct map_struct *buf, OFF_T len)
|
||||
{
|
||||
OFF_T offset, end;
|
||||
int32 k, want_i, backup;
|
||||
OFF_T offset, aligned_offset, end;
|
||||
int32 k, want_i, aligned_i, backup;
|
||||
char sum2[SUM_LENGTH];
|
||||
uint32 s1, s2, sum;
|
||||
int more;
|
||||
@@ -167,7 +166,7 @@ static void hash_search(int f,struct sum_struct *s,
|
||||
if (verbose > 3)
|
||||
rprintf(FINFO, "sum=%.8x k=%ld\n", sum, (long)k);
|
||||
|
||||
offset = 0;
|
||||
offset = aligned_offset = aligned_i = 0;
|
||||
|
||||
end = len + 1 - s->sums[s->count-1].len;
|
||||
|
||||
@@ -232,27 +231,28 @@ static void hash_search(int f,struct sum_struct *s,
|
||||
|
||||
/* When updating in-place, the best possible match is
|
||||
* one with an identical offset, so we prefer that over
|
||||
* the following want_i optimization. */
|
||||
* the adjacent want_i optimization. */
|
||||
if (updating_basis_file) {
|
||||
int32 i2;
|
||||
for (i2 = i; i2 >= 0; i2 = s->sums[i2].chain) {
|
||||
if (s->sums[i2].offset != offset)
|
||||
continue;
|
||||
if (i2 != i) {
|
||||
if (sum != s->sums[i2].sum1)
|
||||
break;
|
||||
if (memcmp(sum2, s->sums[i2].sum2,
|
||||
s->s2length) != 0)
|
||||
break;
|
||||
i = i2;
|
||||
/* All the generator's chunks start at blength boundaries. */
|
||||
while (aligned_offset < offset) {
|
||||
aligned_offset += s->blength;
|
||||
aligned_i++;
|
||||
}
|
||||
if (offset == aligned_offset && aligned_i < s->count) {
|
||||
if (i != aligned_i) {
|
||||
if (sum != s->sums[aligned_i].sum1
|
||||
|| l != s->sums[aligned_i].len
|
||||
|| memcmp(sum2, s->sums[aligned_i].sum2, s->s2length) != 0)
|
||||
goto check_want_i;
|
||||
i = aligned_i;
|
||||
}
|
||||
/* This chunk was at the same offset on
|
||||
* both the sender and the receiver. */
|
||||
/* This identical chunk is in the same spot in the old and new file. */
|
||||
s->sums[i].flags |= SUMFLG_SAME_OFFSET;
|
||||
goto set_want_i;
|
||||
want_i = i;
|
||||
}
|
||||
}
|
||||
|
||||
check_want_i:
|
||||
/* we've found a match, but now check to see
|
||||
* if want_i can hint at a better match. */
|
||||
if (i != want_i && want_i < s->count
|
||||
@@ -264,7 +264,6 @@ static void hash_search(int f,struct sum_struct *s,
|
||||
* will be happy */
|
||||
i = want_i;
|
||||
}
|
||||
set_want_i:
|
||||
want_i = i + 1;
|
||||
|
||||
matched(f,s,buf,offset,i);
|
||||
|
||||
221
options.c
221
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-2008 Wayne Davison
|
||||
* Copyright (C) 2002-2011 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,7 +78,6 @@ int def_compress_level = Z_DEFAULT_COMPRESSION;
|
||||
int am_root = 0; /* 0 = normal, 1 = root, 2 = --super, -1 = --fake-super */
|
||||
int am_server = 0;
|
||||
int am_sender = 0;
|
||||
int am_generator = 0;
|
||||
int am_starting_up = 1;
|
||||
int relative_paths = -1;
|
||||
int implied_dirs = 1;
|
||||
@@ -86,7 +85,6 @@ int numeric_ids = 0;
|
||||
int allow_8bit_chars = 0;
|
||||
int force_delete = 0;
|
||||
int io_timeout = 0;
|
||||
int allowed_lull = 0;
|
||||
int prune_empty_dirs = 0;
|
||||
int use_qsort = 0;
|
||||
char *files_from = NULL;
|
||||
@@ -228,7 +226,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 = "";
|
||||
@@ -254,13 +253,13 @@ static void print_rsync_version(enum logcode f)
|
||||
#ifdef ICONV_OPTION
|
||||
iconv = "";
|
||||
#endif
|
||||
#if defined HAVE_LUTIMES && defined HAVE_UTIMES
|
||||
#ifdef CAN_SET_SYMLINK_TIMES
|
||||
symtimes = "";
|
||||
#endif
|
||||
|
||||
rprintf(f, "%s version %s protocol version %d%s\n",
|
||||
RSYNC_NAME, RSYNC_VERSION, PROTOCOL_VERSION, subprotocol);
|
||||
rprintf(f, "Copyright (C) 1996-2008 by Andrew Tridgell, Wayne Davison, and others.\n");
|
||||
rprintf(f, "Copyright (C) 1996-2011 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",
|
||||
@@ -487,7 +486,7 @@ static struct poptOption long_options[] = {
|
||||
{"xattrs", 'X', POPT_ARG_NONE, 0, 'X', 0, 0 },
|
||||
{"no-xattrs", 0, POPT_ARG_VAL, &preserve_xattrs, 0, 0, 0 },
|
||||
{"no-X", 0, POPT_ARG_VAL, &preserve_xattrs, 0, 0, 0 },
|
||||
{"times", 't', POPT_ARG_VAL, &preserve_times, 2, 0, 0 },
|
||||
{"times", 't', POPT_ARG_VAL, &preserve_times, 1, 0, 0 },
|
||||
{"no-times", 0, POPT_ARG_VAL, &preserve_times, 0, 0, 0 },
|
||||
{"no-t", 0, POPT_ARG_VAL, &preserve_times, 0, 0, 0 },
|
||||
{"omit-dir-times", 'O', POPT_ARG_VAL, &omit_dir_times, 1, 0, 0 },
|
||||
@@ -531,8 +530,8 @@ static struct poptOption long_options[] = {
|
||||
{"ignore-times", 'I', POPT_ARG_NONE, &ignore_times, 0, 0, 0 },
|
||||
{"size-only", 0, POPT_ARG_NONE, &size_only, 0, 0, 0 },
|
||||
{"one-file-system", 'x', POPT_ARG_NONE, 0, 'x', 0, 0 },
|
||||
{"no-one-file-system",'x',POPT_ARG_VAL, &one_file_system, 0, 0, 0 },
|
||||
{"no-x", 'x', POPT_ARG_VAL, &one_file_system, 0, 0, 0 },
|
||||
{"no-one-file-system",0, POPT_ARG_VAL, &one_file_system, 0, 0, 0 },
|
||||
{"no-x", 0, POPT_ARG_VAL, &one_file_system, 0, 0, 0 },
|
||||
{"update", 'u', POPT_ARG_NONE, &update_only, 0, 0, 0 },
|
||||
{"existing", 0, POPT_ARG_NONE, &ignore_non_existing, 0, 0, 0 },
|
||||
{"ignore-non-existing",0,POPT_ARG_NONE, &ignore_non_existing, 0, 0, 0 },
|
||||
@@ -1065,7 +1064,7 @@ int parse_arguments(int *argc_p, const char ***argv_p)
|
||||
preserve_links = 1;
|
||||
#endif
|
||||
preserve_perms = 1;
|
||||
preserve_times = 2;
|
||||
preserve_times = 1;
|
||||
preserve_gid = 1;
|
||||
preserve_uid = 1;
|
||||
preserve_devices = 1;
|
||||
@@ -1356,6 +1355,12 @@ int parse_arguments(int *argc_p, const char ***argv_p)
|
||||
"--read-batch cannot be used with --files-from\n");
|
||||
return 0;
|
||||
}
|
||||
if (read_batch && remove_source_files) {
|
||||
snprintf(err_buf, sizeof err_buf,
|
||||
"--read-batch cannot be used with --remove-%s-files\n",
|
||||
remove_source_files == 1 ? "source" : "sent");
|
||||
return 0;
|
||||
}
|
||||
if (batch_name && strlen(batch_name) > MAX_BATCH_NAME_LEN) {
|
||||
snprintf(err_buf, sizeof err_buf,
|
||||
"the batch-file name must be %d characters or less.\n",
|
||||
@@ -1425,7 +1430,7 @@ int parse_arguments(int *argc_p, const char ***argv_p)
|
||||
}
|
||||
if (!xfer_dirs && delete_mode) {
|
||||
snprintf(err_buf, sizeof err_buf,
|
||||
"--delete does not work without -r or -d.\n");
|
||||
"--delete does not work without --recursive (-r) or --dirs (-d).\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -1486,17 +1491,18 @@ int parse_arguments(int *argc_p, const char ***argv_p)
|
||||
return 0;
|
||||
}
|
||||
if (backup_dir) {
|
||||
backup_dir_len = strlcpy(backup_dir_buf, backup_dir, sizeof backup_dir_buf);
|
||||
backup_dir_remainder = sizeof backup_dir_buf - backup_dir_len;
|
||||
if (backup_dir_remainder < 32) {
|
||||
size_t len = strlcpy(backup_dir_buf, backup_dir, sizeof backup_dir_buf);
|
||||
if (len > sizeof backup_dir_buf - 128) {
|
||||
snprintf(err_buf, sizeof err_buf,
|
||||
"the --backup-dir path is WAY too long.\n");
|
||||
return 0;
|
||||
}
|
||||
backup_dir_len = (int)len;
|
||||
if (backup_dir_buf[backup_dir_len - 1] != '/') {
|
||||
backup_dir_buf[backup_dir_len++] = '/';
|
||||
backup_dir_buf[backup_dir_len] = '\0';
|
||||
}
|
||||
backup_dir_remainder = sizeof backup_dir_buf - backup_dir_len;
|
||||
if (verbose > 1 && !am_sender)
|
||||
rprintf(FINFO, "backup_dir is %s\n", backup_dir_buf);
|
||||
} else if (!backup_suffix_len && (!am_server || !am_sender)) {
|
||||
@@ -1509,13 +1515,18 @@ int parse_arguments(int *argc_p, const char ***argv_p)
|
||||
parse_rule(&filter_list, backup_dir_buf, 0, 0);
|
||||
}
|
||||
|
||||
if (preserve_times) {
|
||||
preserve_times = PRESERVE_FILE_TIMES;
|
||||
if (!omit_dir_times)
|
||||
preserve_times |= PRESERVE_DIR_TIMES;
|
||||
#ifdef CAN_SET_SYMLINK_TIMES
|
||||
preserve_times |= PRESERVE_LINK_TIMES;
|
||||
#endif
|
||||
}
|
||||
|
||||
if (make_backups && !backup_dir) {
|
||||
omit_dir_times = 0; /* Implied, so avoid -O to sender. */
|
||||
if (preserve_times > 1)
|
||||
preserve_times = 1;
|
||||
} else if (omit_dir_times) {
|
||||
if (preserve_times > 1)
|
||||
preserve_times = 1;
|
||||
preserve_times &= ~PRESERVE_DIR_TIMES;
|
||||
}
|
||||
|
||||
if (stdout_format) {
|
||||
@@ -1808,25 +1819,41 @@ 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';
|
||||
#ifdef CAN_SET_SYMLINK_TIMES
|
||||
argstr[x++] = 'L';
|
||||
#endif
|
||||
#ifdef ICONV_OPTION
|
||||
argstr[x++] = 's';
|
||||
#endif
|
||||
argstr[x++] = 'f';
|
||||
}
|
||||
|
||||
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) {
|
||||
@@ -2008,7 +2035,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];
|
||||
@@ -2048,6 +2074,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;
|
||||
|
||||
@@ -2055,6 +2086,62 @@ void server_options(char **args, int *argc_p)
|
||||
out_of_memory("server_options");
|
||||
}
|
||||
|
||||
/* If str points to a valid hostspec, return allocated memory containing the
|
||||
* [USER@]HOST part of the string, and set the path_start_ptr to the part of
|
||||
* the string after the host part. Otherwise, return NULL. If port_ptr is
|
||||
* non-NULL, we must be parsing an rsync:// URL hostname, and we will set
|
||||
* *port_ptr if a port number is found. Note that IPv6 IPs will have their
|
||||
* (required for parsing) [ and ] chars elided from the returned string. */
|
||||
static char *parse_hostspec(char *str, char **path_start_ptr, int *port_ptr)
|
||||
{
|
||||
char *s, *host_start = str;
|
||||
int hostlen = 0, userlen = 0;
|
||||
char *ret;
|
||||
|
||||
for (s = str; ; s++) {
|
||||
if (!*s) {
|
||||
/* It is only OK if we run out of string with rsync:// */
|
||||
if (!port_ptr)
|
||||
return NULL;
|
||||
if (!hostlen)
|
||||
hostlen = s - host_start;
|
||||
break;
|
||||
}
|
||||
if (*s == ':' || *s == '/') {
|
||||
if (!hostlen)
|
||||
hostlen = s - host_start;
|
||||
if (*s++ == '/') {
|
||||
if (!port_ptr)
|
||||
return NULL;
|
||||
} else if (port_ptr) {
|
||||
*port_ptr = atoi(s);
|
||||
while (isDigit(s)) s++;
|
||||
if (*s && *s++ != '/')
|
||||
return NULL;
|
||||
}
|
||||
break;
|
||||
}
|
||||
if (*s == '@') {
|
||||
userlen = s - str + 1;
|
||||
host_start = s + 1;
|
||||
} else if (*s == '[') {
|
||||
if (s != host_start++)
|
||||
return NULL;
|
||||
while (*s && *s != ']' && *s != '/') s++; /*SHARED ITERATOR*/
|
||||
hostlen = s - host_start;
|
||||
if (*s != ']' || (s[1] && s[1] != '/' && s[1] != ':') || !hostlen)
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
*path_start_ptr = s;
|
||||
ret = new_array(char, userlen + hostlen + 1);
|
||||
if (userlen)
|
||||
strlcpy(ret, str, userlen + 1);
|
||||
strlcpy(ret + userlen, host_start, hostlen + 1);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Look for a HOST specfication of the form "HOST:PATH", "HOST::PATH", or
|
||||
* "rsync://HOST:PORT/PATH". If found, *host_ptr will be set to some allocated
|
||||
* memory with the HOST. If a daemon-accessing spec was specified, the value
|
||||
@@ -2064,68 +2151,28 @@ void server_options(char **args, int *argc_p)
|
||||
* "[::ffff:127.0.0.1]") which is returned without the '[' and ']'. */
|
||||
char *check_for_hostspec(char *s, char **host_ptr, int *port_ptr)
|
||||
{
|
||||
char *p;
|
||||
int not_host;
|
||||
int hostlen;
|
||||
char *path;
|
||||
|
||||
if (port_ptr && strncasecmp(URL_PREFIX, s, strlen(URL_PREFIX)) == 0) {
|
||||
char *path;
|
||||
s += strlen(URL_PREFIX);
|
||||
if ((p = strchr(s, '/')) != NULL) {
|
||||
hostlen = p - s;
|
||||
path = p + 1;
|
||||
} else {
|
||||
hostlen = strlen(s);
|
||||
path = "";
|
||||
*host_ptr = parse_hostspec(s + strlen(URL_PREFIX), &path, port_ptr);
|
||||
if (*host_ptr) {
|
||||
if (!*port_ptr)
|
||||
*port_ptr = RSYNC_PORT;
|
||||
return path;
|
||||
}
|
||||
if (*s == '[' && (p = strchr(s, ']')) != NULL) {
|
||||
s++;
|
||||
hostlen = p - s;
|
||||
if (p[1] == ':')
|
||||
*port_ptr = atoi(p+2);
|
||||
} else {
|
||||
if ((p = strchr(s, ':')) != NULL && p < s + hostlen) {
|
||||
hostlen = p - s;
|
||||
*port_ptr = atoi(p+1);
|
||||
}
|
||||
}
|
||||
if (!*port_ptr)
|
||||
*port_ptr = RSYNC_PORT;
|
||||
*host_ptr = new_array(char, hostlen + 1);
|
||||
strlcpy(*host_ptr, s, hostlen + 1);
|
||||
return path;
|
||||
}
|
||||
|
||||
if (*s == '[' && (p = strchr(s, ']')) != NULL && p[1] == ':') {
|
||||
s++;
|
||||
hostlen = p - s;
|
||||
*p = '\0';
|
||||
not_host = strchr(s, '/') || !strchr(s, ':');
|
||||
*p = ']';
|
||||
if (not_host)
|
||||
return NULL;
|
||||
p++;
|
||||
} else {
|
||||
if (!(p = strchr(s, ':')))
|
||||
return NULL;
|
||||
hostlen = p - s;
|
||||
*p = '\0';
|
||||
not_host = strchr(s, '/') != NULL;
|
||||
*p = ':';
|
||||
if (not_host)
|
||||
return NULL;
|
||||
}
|
||||
*host_ptr = parse_hostspec(s, &path, NULL);
|
||||
if (!*host_ptr)
|
||||
return NULL;
|
||||
|
||||
*host_ptr = new_array(char, hostlen + 1);
|
||||
strlcpy(*host_ptr, s, hostlen + 1);
|
||||
|
||||
if (p[1] == ':') {
|
||||
if (*path == ':') {
|
||||
if (port_ptr && !*port_ptr)
|
||||
*port_ptr = RSYNC_PORT;
|
||||
return p + 2;
|
||||
return path + 1;
|
||||
}
|
||||
if (port_ptr)
|
||||
*port_ptr = 0;
|
||||
|
||||
return p + 1;
|
||||
return path;
|
||||
}
|
||||
|
||||
@@ -7,7 +7,7 @@ use strict;
|
||||
our %short_no_arg;
|
||||
our %short_with_num;
|
||||
our %long_opt = (
|
||||
'no-i-r' => 0,
|
||||
'daemon' => -1,
|
||||
'fake-super' => 0,
|
||||
'log-file' => 3,
|
||||
);
|
||||
@@ -24,7 +24,7 @@ while (<IN>) {
|
||||
undef $last_long_opt;
|
||||
} elsif (/\Qargs[ac++]\E = "--([^"=]+)"/) {
|
||||
$last_long_opt = $1;
|
||||
$long_opt{$1} = 0;
|
||||
$long_opt{$1} = 0 unless exists $long_opt{$1};
|
||||
} elsif (defined($last_long_opt)
|
||||
&& /\Qargs[ac++]\E = ([^["\s]+);/ && $1 ne 'dest_option') {
|
||||
$long_opt{$last_long_opt} = 2;
|
||||
|
||||
@@ -1,18 +0,0 @@
|
||||
#!/usr/bin/perl
|
||||
# This script finds extraneous "extern" variables in the *.c files.
|
||||
# Run it from inside the main rsync directory.
|
||||
|
||||
use strict;
|
||||
|
||||
my @files = glob('*.c');
|
||||
|
||||
foreach my $fn (@files) {
|
||||
open(IN, '<', $fn) or die;
|
||||
undef $/; $_ = <IN>; $/ = "\n";
|
||||
close IN;
|
||||
my @externs = /^extern .*?([^[\s(*;&.]+)(?:\[.*?\])?;/mg;
|
||||
foreach my $find (@externs) {
|
||||
my @matches = /(?<!\sstruct )\b(\Q$find\E)\b/g;
|
||||
print $fn, ': ', $find, "\n" if @matches == 1;
|
||||
}
|
||||
}
|
||||
48
packaging/git-status.pl
Normal file
48
packaging/git-status.pl
Normal file
@@ -0,0 +1,48 @@
|
||||
# Do some git-status checking for the current dir and (optionally)
|
||||
# the patches dir.
|
||||
|
||||
sub check_git_state
|
||||
{
|
||||
my($master_branch, $fatal_unless_clean, $check_patches_dir) = @_;
|
||||
|
||||
my($cur_branch) = check_git_status($fatal_unless_clean);
|
||||
if ($cur_branch ne $master_branch) {
|
||||
print "The checkout is not on the $master_branch branch.\n";
|
||||
exit 1 if $master_branch ne 'master';
|
||||
print "Do you want me to continue with --branch=$cur_branch? [n] ";
|
||||
$_ = <STDIN>;
|
||||
exit 1 unless /^y/i;
|
||||
$_[0] = $master_branch = $cur_branch; # Updates caller's $master_branch too.
|
||||
}
|
||||
|
||||
if ($check_patches_dir && -d 'patches/.git') {
|
||||
($cur_branch) = check_git_status($fatal_unless_clean, 'patches');
|
||||
if ($cur_branch ne $master_branch) {
|
||||
print "The *patches* checkout is on branch $cur_branch, not branch $master_branch.\n";
|
||||
print "Do you want to change it to branch $master_branch? [n] ";
|
||||
$_ = <STDIN>;
|
||||
exit 1 unless /^y/i;
|
||||
system "cd patches && git checkout '$master_branch'";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
sub check_git_status
|
||||
{
|
||||
my($fatal_unless_clean, $subdir) = @_;
|
||||
$subdir = '.' unless defined $subdir;
|
||||
my $status = `cd '$subdir' && git status`;
|
||||
my $is_clean = $status =~ /\nnothing to commit \(working directory clean\)/;
|
||||
my($cur_branch) = $status =~ /^# On branch (.+)\n/;
|
||||
if ($fatal_unless_clean && !$is_clean) {
|
||||
if ($subdir eq '.') {
|
||||
$subdir = '';
|
||||
} else {
|
||||
$subdir = " *$subdir*";
|
||||
}
|
||||
die "The$subdir checkout is not clean:\n", $status;
|
||||
}
|
||||
($cur_branch, $is_clean, $status);
|
||||
}
|
||||
|
||||
1;
|
||||
@@ -1,9 +1,9 @@
|
||||
Summary: A fast, versatile, remote (and local) file-copying tool
|
||||
Name: rsync
|
||||
Version: 3.0.3
|
||||
%define fullversion %{version}
|
||||
Release: 1
|
||||
%define srcdir src
|
||||
Version: 3.0.9
|
||||
%define fullversion %{version}pre1
|
||||
Release: 0.1.pre1
|
||||
%define srcdir src-previews
|
||||
Group: Applications/Internet
|
||||
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
|
||||
@@ -66,8 +66,8 @@ rm -rf $RPM_BUILD_ROOT
|
||||
%{_mandir}/man5/rsyncd.conf.5*
|
||||
|
||||
%changelog
|
||||
* Sun Jun 29 2008 Wayne Davison <wayned@samba.org>
|
||||
Released 3.0.3.
|
||||
* Wed Jun 22 2011 Wayne Davison <wayned@samba.org>
|
||||
Released 3.0.9pre1.
|
||||
|
||||
* Fri Mar 21 2008 Wayne Davison <wayned@samba.org>
|
||||
Added installation of /etc/xinetd.d/rsync file and some commented-out
|
||||
|
||||
@@ -3,8 +3,8 @@ use strict;
|
||||
|
||||
# This script expects the directory ~/samba-rsync-ftp to exist and to be a
|
||||
# copy of the /home/ftp/pub/rsync dir on samba.org. It also requires a
|
||||
# pristine CVS checkout of rsync (don't use your normal rsync build dir
|
||||
# unless you're 100% sure that there are not unchecked-in changes).
|
||||
# git checkout of rsync (feel free to use your normal rsync build dir as
|
||||
# long as it doesn't have any uncommitted changes).
|
||||
#
|
||||
# If this is run with -ctu, it will make an updated "nightly" tar file in
|
||||
# the nightly dir. It will also remove any old tar files, regenerate the
|
||||
@@ -56,6 +56,58 @@ if ($make_tar) {
|
||||
}
|
||||
close IN;
|
||||
|
||||
my $confversion;
|
||||
open(IN, '<', 'configure.ac') or die "Unable to open configure.ac: $!\n";
|
||||
while (<IN>) {
|
||||
if (/^RSYNC_VERSION=(.*)/) {
|
||||
$confversion = $1;
|
||||
last;
|
||||
}
|
||||
}
|
||||
close IN;
|
||||
die "Unable to find RSYNC_VERSION in configure.ac\n" unless defined $confversion;
|
||||
|
||||
open(IN, '<', 'OLDNEWS') or die "Unable to open OLDNEWS: $!\n";
|
||||
$_ = <IN>;
|
||||
my($lastversion) = /(\d+\.\d+\.\d+)/;
|
||||
my $last_protocol_version;
|
||||
while (<IN>) {
|
||||
if (my($ver,$pdate,$pver) = /^\s+\S\S\s\S\S\S\s\d\d\d\d\s+(\d+\.\d+\.\d+)\s+(\d\d \w\w\w \d\d\d\d\s+)?(\d+)$/) {
|
||||
$last_protocol_version = $pver if $ver eq $lastversion;
|
||||
}
|
||||
}
|
||||
close IN;
|
||||
die "Unable to determine protocol_version for $lastversion.\n" unless defined $last_protocol_version;
|
||||
|
||||
my($protocol_version,$subprotocol_version);
|
||||
open(IN, '<', 'rsync.h') or die "Unable to open rsync.h: $!\n";
|
||||
while (<IN>) {
|
||||
if (/^#define\s+PROTOCOL_VERSION\s+(\d+)/) {
|
||||
$protocol_version = $1;
|
||||
} elsif (/^#define\s+SUBPROTOCOL_VERSION\s+(\d+)/) {
|
||||
$subprotocol_version = $1;
|
||||
}
|
||||
}
|
||||
close IN;
|
||||
die "Unable to determine the current PROTOCOL_VERSION.\n" unless defined $protocol_version;
|
||||
die "Unable to determine the current SUBPROTOCOL_VERSION.\n" unless defined $subprotocol_version;
|
||||
|
||||
if ($confversion =~ /dev|pre/) {
|
||||
if ($last_protocol_version ne $protocol_version) {
|
||||
if ($subprotocol_version == 0) {
|
||||
die "SUBPROTOCOL_VERSION must not be 0 for a non-final release with a changed PROTOCOL_VERSION.\n";
|
||||
}
|
||||
} else {
|
||||
if ($subprotocol_version != 0) {
|
||||
die "SUBPROTOCOL_VERSION must be 0 when the PROTOCOL_VERSION hasn't changed from the last release.\n";
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if ($subprotocol_version != 0) {
|
||||
die "SUBPROTOCOL_VERSION must be 0 for a final release.\n";
|
||||
}
|
||||
}
|
||||
|
||||
print "Creating $name.tar.gz\n";
|
||||
system "rsync -a @extra_files $name/";
|
||||
system "git archive --format=tar --prefix=$name/ HEAD | tar xf -";
|
||||
|
||||
@@ -1,18 +1,21 @@
|
||||
#!/usr/bin/perl -w
|
||||
# This script is used to turn one or more of the "patch/*" branches
|
||||
#!/usr/bin/perl
|
||||
# This script is used to turn one or more of the "patch/BASE/*" branches
|
||||
# into one or more diffs in the "patches" directory. Pass the option
|
||||
# --gen if you want generated files in the diffs. Pass the name of
|
||||
# one or more diffs if you want to just update a subset of all the
|
||||
# diffs.
|
||||
|
||||
use strict;
|
||||
use warnings;
|
||||
use Getopt::Long;
|
||||
|
||||
my $patches_dir = 'patches';
|
||||
my $tmp_dir = "patches.$$";
|
||||
my $make_gen_cmd = 'make -f prepare-source.mak conf && ./config.status && make gen';
|
||||
|
||||
&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 ),
|
||||
@@ -28,10 +31,19 @@ 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';
|
||||
|
||||
my($status, $is_clean, $starting_branch) = &check_git_status;
|
||||
if (!$skip_branch_check && !$is_clean) {
|
||||
die "The checkout is not clean:\n", $status;
|
||||
require 'packaging/git-status.pl';
|
||||
check_git_state($master_branch, !$skip_branch_check, 1);
|
||||
|
||||
my $master_commit;
|
||||
open PIPE, '-|', "git log -1 --no-color $master_branch" or die $!;
|
||||
while (<PIPE>) {
|
||||
if (/^commit (\S+)/) {
|
||||
$master_commit = $1;
|
||||
last;
|
||||
}
|
||||
}
|
||||
close PIPE;
|
||||
die "Unable to determine commit hash for master branch: $master_branch\n" unless defined $master_commit;
|
||||
|
||||
my @extra_files;
|
||||
open(IN, '<', 'Makefile.in') or die "Couldn't open Makefile.in: $!\n";
|
||||
@@ -49,19 +61,17 @@ close IN;
|
||||
if ($incl_generated_files) {
|
||||
die "'$tmp_dir' must not exist in the current directory.\n" if -e $tmp_dir;
|
||||
mkdir($tmp_dir, 0700) or die "Unable to mkdir($tmp_dir): $!\n";
|
||||
system "./config.status Makefile && make gen && rsync -a @extra_files $tmp_dir/master/" and exit 1;
|
||||
system "$make_gen_cmd && rsync -a @extra_files $tmp_dir/master/" and exit 1;
|
||||
}
|
||||
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/(.*)#) {
|
||||
if (m# patch/\Q$master_branch\E/(.*)#o) {
|
||||
$patches{$1} = 1;
|
||||
} elsif (m# patch/(.*)#) {
|
||||
$patches{$1} = $local_patch{$1} = 1;
|
||||
}
|
||||
}
|
||||
close PIPE;
|
||||
@@ -70,19 +80,23 @@ my @patches = sort keys %patches;
|
||||
|
||||
my(%parent, %description);
|
||||
foreach my $patch (@patches) {
|
||||
my $branch = ($local_patch{$patch} ? '' : 'origin/') . "patch/$patch";
|
||||
my $branch = "patch/$master_branch/$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 +104,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, $_);
|
||||
}
|
||||
}
|
||||
@@ -107,7 +124,7 @@ if ($incl_generated_files) {
|
||||
}
|
||||
|
||||
sleep 1 while $last_touch >= time;
|
||||
system "git checkout $starting_branch" and exit 1;
|
||||
system "git checkout $master_branch" and exit 1;
|
||||
|
||||
exit;
|
||||
|
||||
@@ -117,28 +134,27 @@ sub update_patch
|
||||
my($patch) = @_;
|
||||
|
||||
my $parent = $parent{$patch};
|
||||
my $based_on;
|
||||
if (defined $parent) {
|
||||
unless ($completed{$parent}++) {
|
||||
update_patch($parent);
|
||||
}
|
||||
$parent = "patch/$parent";
|
||||
$based_on = $parent = "patch/$master_branch/$parent";
|
||||
} else {
|
||||
$parent = 'master';
|
||||
$parent = $master_branch;
|
||||
$based_on = $master_commit;
|
||||
}
|
||||
|
||||
print "======== $patch ========\n";
|
||||
|
||||
sleep 1 while $incl_generated_files && $last_touch >= time;
|
||||
if ($local_patch{$patch}) {
|
||||
system "git checkout patch/$patch" and return 0;
|
||||
} else {
|
||||
system "git checkout --track -b patch/$patch origin/patch/$patch" and return 0;
|
||||
}
|
||||
system "git checkout patch/$master_branch/$patch" and return 0;
|
||||
|
||||
my $ok = system("git merge $parent") == 0;
|
||||
my $ok = system("git merge $based_on") == 0;
|
||||
if (!$ok || $launch_shell) {
|
||||
print qq|"git merge $parent" incomplete -- please fix.\n| if !$ok;
|
||||
$ENV{PS1} = "[$parent] patch/$patch: ";
|
||||
my($parent_dir) = $parent =~ m{([^/]+)$};
|
||||
print qq|"git merge $based_on" incomplete -- please fix.\n| if !$ok;
|
||||
$ENV{PS1} = "[$parent_dir] $patch: ";
|
||||
while (1) {
|
||||
if (system($ENV{SHELL}) != 0) {
|
||||
print "Abort? [n/y] ";
|
||||
@@ -146,21 +162,21 @@ sub update_patch
|
||||
next unless /^y/i;
|
||||
return 0;
|
||||
}
|
||||
($status, $is_clean) = &check_git_status;
|
||||
my($cur_branch, $is_clean, $status) = check_git_status(0);
|
||||
last if $is_clean;
|
||||
print $status;
|
||||
}
|
||||
}
|
||||
|
||||
open(OUT, '>', "$patches_dir/$patch.diff") or die $!;
|
||||
print OUT $description{$patch}, "\n";
|
||||
print OUT $description{$patch}, "\nbased-on: $based_on\n";
|
||||
|
||||
if ($incl_generated_files) {
|
||||
system "./config.status Makefile && make gen && rsync -a @extra_files $tmp_dir/$patch/" and exit 1;
|
||||
system "$make_gen_cmd && rsync -a @extra_files $tmp_dir/$patch/" and exit 1;
|
||||
}
|
||||
$last_touch = time;
|
||||
|
||||
open(PIPE, '-|', 'git', 'diff', $parent) or die $!;
|
||||
open(PIPE, '-|', 'git', 'diff', $based_on) or die $!;
|
||||
DIFF: while (<PIPE>) {
|
||||
while (m{^diff --git a/PATCH}) {
|
||||
while (<PIPE>) {
|
||||
@@ -174,8 +190,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;
|
||||
@@ -192,22 +213,18 @@ sub update_patch
|
||||
|
||||
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]
|
||||
Usage: patch-update [OPTIONS] [patches/DIFF...]
|
||||
|
||||
--gen[=DIR] Include generated files. Optional dest DIR overrides "patches".
|
||||
--skip-check Skip the check that ensures starting with a clean branch.
|
||||
Options:
|
||||
-b, --branch=BRANCH The master branch to merge into the patch/BASE/* branches.
|
||||
--gen[=DIR] Include generated files. Optional destination DIR
|
||||
arg overrides the default of using the "patches" dir.
|
||||
--skip-check Skip the check that ensures starting with a clean branch.
|
||||
-s, --shell Launch a shell for every patch/BASE/* branch updated, not
|
||||
just when a conflict occurs.
|
||||
-h, --help Output this help message.
|
||||
EOT
|
||||
}
|
||||
|
||||
@@ -1,18 +1,27 @@
|
||||
#!/usr/bin/perl
|
||||
use strict;
|
||||
|
||||
# This script expects the directory ~/samba-rsync-ftp to exist and to be a
|
||||
# copy of the /home/ftp/pub/rsync dir on samba.org. When the script is done,
|
||||
# the git repository in the current directory will be updated, and the local
|
||||
# ~/samba-rsync-ftp dir will be ready to be rsynced to samba.org.
|
||||
|
||||
use strict;
|
||||
use warnings;
|
||||
use Cwd;
|
||||
use Getopt::Long;
|
||||
use Term::ReadKey;
|
||||
use Date::Format;
|
||||
|
||||
my $dest = $ENV{HOME} . '/samba-rsync-ftp';
|
||||
my $passfile = $ENV{HOME} . '/.rsyncpass';
|
||||
my $path = $ENV{PATH};
|
||||
my $make_gen_cmd = 'make -f prepare-source.mak conf && ./config.status && make gen';
|
||||
|
||||
&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);
|
||||
@@ -52,14 +61,11 @@ die "There is no .git dir in the current directory.\n" unless -d '.git';
|
||||
die "'a' must not exist in the current directory.\n" if -e 'a';
|
||||
die "'b' must not exist in the current directory.\n" if -e 'b';
|
||||
|
||||
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/;
|
||||
require 'packaging/git-status.pl';
|
||||
check_git_state($master_branch, 1, 1);
|
||||
|
||||
my $confversion;
|
||||
open(IN, '<', 'configure.in') or die $!;
|
||||
open(IN, '<', 'configure.ac') or die $!;
|
||||
while (<IN>) {
|
||||
if (/^RSYNC_VERSION=(.*)/) {
|
||||
$confversion = $1;
|
||||
@@ -67,12 +73,31 @@ while (<IN>) {
|
||||
}
|
||||
}
|
||||
close IN;
|
||||
die "Unable to find RSYNC_VERSION in configure.in\n" unless defined $confversion;
|
||||
die "Unable to find RSYNC_VERSION in configure.ac\n" unless defined $confversion;
|
||||
|
||||
open(IN, '<', 'OLDNEWS') or die $!;
|
||||
$_ = <IN>;
|
||||
close IN;
|
||||
my($lastversion) = /(\d+\.\d+\.\d+)/;
|
||||
my($last_protocol_version, %pdate);
|
||||
while (<IN>) {
|
||||
if (my($ver,$pdate,$pver) = /^\s+\S\S\s\S\S\S\s\d\d\d\d\s+(\d+\.\d+\.\d+)\s+(\d\d \w\w\w \d\d\d\d\s+)?(\d+)$/) {
|
||||
$pdate{$ver} = $pdate if defined $pdate;
|
||||
$last_protocol_version = $pver if $ver eq $lastversion;
|
||||
}
|
||||
}
|
||||
close IN;
|
||||
die "Unable to determine protocol_version for $lastversion.\n" unless defined $last_protocol_version;
|
||||
|
||||
my $protocol_version;
|
||||
open(IN, '<', 'rsync.h') or die $!;
|
||||
while (<IN>) {
|
||||
if (/^#define\s+PROTOCOL_VERSION\s+(\d+)/) {
|
||||
$protocol_version = $1;
|
||||
last;
|
||||
}
|
||||
}
|
||||
close IN;
|
||||
die "Unable to determine the current PROTOCOL_VERSION.\n" unless defined $protocol_version;
|
||||
|
||||
my $version = $confversion;
|
||||
$version =~ s/dev/pre1/ || $version =~ s/pre(\d+)/ 'pre' . ($1 + 1) /e;
|
||||
@@ -110,6 +135,23 @@ chomp($_ = <STDIN>);
|
||||
$release = $_ if $_ ne '';
|
||||
$release .= ".$pre" if $pre;
|
||||
|
||||
(my $finalversion = $version) =~ s/pre\d+//;
|
||||
my($proto_changed,$proto_change_date);
|
||||
if ($protocol_version eq $last_protocol_version) {
|
||||
$proto_changed = 'unchanged';
|
||||
$proto_change_date = "\t\t";
|
||||
} else {
|
||||
$proto_changed = 'changed';
|
||||
if (!defined($proto_change_date = $pdate{$finalversion})) {
|
||||
while (1) {
|
||||
print "On what date did the protocol change to $protocol_version get checked in? (dd Mmm yyyy) ";
|
||||
chomp($_ = <STDIN>);
|
||||
last if /^\d\d \w\w\w \d\d\d\d$/;
|
||||
}
|
||||
$proto_change_date = "$_\t";
|
||||
}
|
||||
}
|
||||
|
||||
my($srcdir,$srcdiffdir,$lastsrcdir,$skipping);
|
||||
if ($lastversion =~ /pre/) {
|
||||
if (!$pre) {
|
||||
@@ -138,9 +180,9 @@ print "\n", $break, <<EOT;
|
||||
\$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 SUBPROTOCOL_VERSION in rsync.h, if needed
|
||||
- tweak the version in configure.ac and the spec files
|
||||
- tweak NEWS and OLDNEWS to ensure header values are correct
|
||||
- tweak the date in the *.yo files and generate the manpages
|
||||
- generate configure.sh, config.h.in, and proto.h
|
||||
- page through the differences
|
||||
@@ -149,12 +191,11 @@ EOT
|
||||
print "<Press Enter to continue> ";
|
||||
$_ = <STDIN>;
|
||||
|
||||
(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 ) );
|
||||
qw( configure.ac rsync.h NEWS OLDNEWS options.c ) );
|
||||
|
||||
foreach my $fn (@tweak_files) {
|
||||
open(IN, '<', $fn) or die $!;
|
||||
@@ -176,18 +217,19 @@ foreach my $fn (@tweak_files) {
|
||||
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 . ' ' . get_subprotocol_version($2) }e
|
||||
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;
|
||||
s{^(NEWS for rsync \Q$finalversion\E )(\(UNRELEASED\))\s*(\nProtocol: )(\d+) (\([^)]+\))\n}
|
||||
{ $1 . ($pre ? $2 : "($today)") . "$3$protocol_version ($proto_changed)\n" }ei
|
||||
or die "The first 2 lines of $fn are not in the right format. They must be:\n"
|
||||
. "NEWS for rsync $finalversion (UNRELEASED)\n"
|
||||
. "Protocol: $protocol_version ($proto_changed)\n";
|
||||
} elsif ($fn eq 'OLDNEWS') {
|
||||
s/^\t\S\S\s\S\S\S\s\d\d\d\d(\t\Q$finalversion\E)/\t$ztoday$1/m
|
||||
s{^(\t\S\S\s\S\S\S\s\d\d\d\d)(\t\Q$finalversion\E\t).*}
|
||||
{ ($pre ? $1 : "\t$ztoday") . $2 . $proto_change_date . $protocol_version }em
|
||||
or die "Unable to find \"?? ??? $year\t$finalversion\" line in $fn\n";
|
||||
next if $pre;
|
||||
} elsif ($fn eq 'options.c') {
|
||||
if (s/(Copyright \(C\) 2002-)(\d+)( Wayne Davison)/$1$year$3/
|
||||
&& $2 ne $year) {
|
||||
@@ -221,7 +263,7 @@ print $break, <<EOT;
|
||||
|
||||
About to:
|
||||
- commit all version changes
|
||||
- merge the master branch into the patch/* branches
|
||||
- merge the $master_branch branch into the patch/$master_branch/* branches
|
||||
- update the files in the "patches" dir and OPTIONALLY
|
||||
(if you type 'y') to launch a shell for each patch
|
||||
|
||||
@@ -232,11 +274,15 @@ 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";
|
||||
system "packaging/patch-update --branch=$master_branch";
|
||||
|
||||
if ($ans =~ /^y/i) {
|
||||
print "\nVisiting all \"patch/*\" branches ...\n";
|
||||
system "packaging/patch-update --shell";
|
||||
print "\nVisiting all \"patch/$master_branch/*\" branches ...\n";
|
||||
system "packaging/patch-update --branch=$master_branch --shell";
|
||||
}
|
||||
|
||||
if (-d 'patches/.git') {
|
||||
system "cd patches && git commit -a -m 'The patches for $version.'" and exit 1;
|
||||
}
|
||||
|
||||
print $break, <<EOT;
|
||||
@@ -256,6 +302,9 @@ EOT
|
||||
print "<Press Enter to continue> ";
|
||||
$_ = <STDIN>;
|
||||
|
||||
# We want to use our passphrase-providing "gpg" script, so modify the PATH.
|
||||
$ENV{PATH} = "$curdir/packaging/bin:$path";
|
||||
|
||||
my $passphrase;
|
||||
while (1) {
|
||||
ReadMode('noecho');
|
||||
@@ -273,17 +322,23 @@ while (1) {
|
||||
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;
|
||||
exit 1 if /failed/;
|
||||
|
||||
if (-d 'patches/.git') {
|
||||
$_ = `cd patches && git tag -s -m 'Version $version.' v$version 2>&1`;
|
||||
print $_;
|
||||
exit 1 if /bad passphrase|failed/;
|
||||
}
|
||||
|
||||
unlink($passfile);
|
||||
last;
|
||||
}
|
||||
|
||||
$ENV{PATH} = $path;
|
||||
|
||||
# Extract the generated files from the old tar.
|
||||
@_ = @extra_files;
|
||||
map { s#^#rsync-$lastversion/# } @_;
|
||||
@@ -291,7 +346,7 @@ system "tar xzf $lasttar_file @_";
|
||||
rename("rsync-$lastversion", 'a');
|
||||
|
||||
print "Creating $diff_file ...\n";
|
||||
system "./config.status Makefile; make gen; rsync -a @extra_files b/";
|
||||
system "$make_gen_cmd && rsync -a @extra_files b/" and exit 1;
|
||||
my $sed_script = 's:^((---|\+\+\+) [ab]/[^\t]+)\t.*:\1:';
|
||||
system "(git diff v$lastversion v$version; diff -upN a b | sed -r '$sed_script') | gzip -9 >$diff_file";
|
||||
system "rm -rf a";
|
||||
@@ -305,7 +360,7 @@ 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 "packaging/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";
|
||||
@@ -343,3 +398,24 @@ Local changes are done. When you're satisfied, push the git repository
|
||||
and rsync the release files. Remember to announce the release on *BOTH*
|
||||
rsync-announce@lists.samba.org and rsync@lists.samba.org (and the web)!
|
||||
EOT
|
||||
|
||||
exit;
|
||||
|
||||
sub get_subprotocol_version
|
||||
{
|
||||
my($subver) = @_;
|
||||
if ($pre && $proto_changed eq 'changed') {
|
||||
return $subver == 0 ? 1 : $subver;
|
||||
}
|
||||
0;
|
||||
}
|
||||
|
||||
sub usage
|
||||
{
|
||||
die <<EOT;
|
||||
Usage: release-rsync [OPTIONS]
|
||||
|
||||
-b, --branch=BRANCH The branch to release (default: master)
|
||||
-h, --help Display this help message
|
||||
EOT
|
||||
}
|
||||
|
||||
83
packaging/var-checker
Executable file
83
packaging/var-checker
Executable file
@@ -0,0 +1,83 @@
|
||||
#!/usr/bin/perl
|
||||
# This script checks the *.c files for extraneous "extern" variables,
|
||||
# for vars that are defined but not used, and for inconsistent array
|
||||
# sizes. Run it from inside the main rsync directory.
|
||||
|
||||
use strict;
|
||||
use warnings;
|
||||
|
||||
my %add_syscall_c = map { $_ => 1 } qw( t_stub.c t_unsafe.c tls.c trimslash.c );
|
||||
my %add_compat_c = map { $_ => 1 } qw( t_stub.c tls.c trimslash.c wildtest.c );
|
||||
my %add_util_c = map { $_ => 1 } qw( t_stub.c t_unsafe.c );
|
||||
my %sizes;
|
||||
|
||||
open(IN, '<', 'syscall.c') or die $!;
|
||||
undef $/; my $syscall_c = <IN>; $/ = "\n";
|
||||
close IN;
|
||||
$syscall_c =~ s/^extern\s.*//mg;
|
||||
|
||||
open(IN, '<', 'lib/compat.c') or die $!;
|
||||
undef $/; my $compat_c = <IN>; $/ = "\n";
|
||||
close IN;
|
||||
$compat_c =~ s/^extern\s.*//mg;
|
||||
|
||||
open(IN, '<', 'util.c') or die $!;
|
||||
undef $/; my $util_c = <IN>; $/ = "\n";
|
||||
close IN;
|
||||
$util_c =~ s/^extern\s.*//mg;
|
||||
|
||||
my @files = glob('*.c');
|
||||
|
||||
foreach my $fn (@files) {
|
||||
open(IN, '<', $fn) or die $!;
|
||||
undef $/; $_ = <IN>; $/ = "\n";
|
||||
close IN;
|
||||
|
||||
my @vars = /^(?!(?:extern|enum)\s)([a-zA-Z]\S*\s+.*);/mg;
|
||||
my @externs = /^extern\s+(.*);/mg;
|
||||
|
||||
$_ .= $syscall_c if $add_syscall_c{$fn};
|
||||
$_ .= $compat_c if $add_compat_c{$fn};
|
||||
$_ .= $util_c if $add_util_c{$fn};
|
||||
s/INFO_GTE/info_levels/g;
|
||||
s/DEBUG_GTE/debug_levels/g;
|
||||
|
||||
check_vars($fn, 'var', @vars);
|
||||
check_vars($fn, 'extern', @externs);
|
||||
}
|
||||
|
||||
exit;
|
||||
|
||||
# The file's contents are in $_.
|
||||
sub check_vars
|
||||
{
|
||||
my $fn = shift;
|
||||
my $type = shift;
|
||||
|
||||
foreach my $line (@_) {
|
||||
$line =~ s/\s*\{.*\}//;
|
||||
$line =~ s/\s*\(.*\)//;
|
||||
foreach my $item (split(/\s*,\s*/, $line)) {
|
||||
$item =~ s/\s*=.*//;
|
||||
my $sz = $item =~ s/(\[.*?\])// ? $1 : '';
|
||||
my($var) = $item =~ /([^*\s]+)$/;
|
||||
if (!defined $var) {
|
||||
print "Bogus match? ($item)\n";
|
||||
next;
|
||||
}
|
||||
if ($sz) {
|
||||
if (defined $sizes{$var}) {
|
||||
if ($sizes{$var} ne $sz) {
|
||||
print $fn, ' has inconsistent size for "', $var,
|
||||
"\": $sizes{$var} vs $sz\n";
|
||||
}
|
||||
} else {
|
||||
$sizes{$var} = $sz;
|
||||
}
|
||||
}
|
||||
my @matches = /(?<!\sstruct )\b(\Q$var\E)(?!\w)/g;
|
||||
push(@matches, /(\QSIGACTION(\E)/g) if $var eq 'sigact';
|
||||
print $fn, " has extraneous $type: \"", $var, "\"\n" if @matches == 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
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-2008 Wayne Davison
|
||||
* Copyright (C) 2004-2009 Wayne Davison
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
|
||||
19
popt/popt.c
19
popt/popt.c
@@ -860,20 +860,21 @@ int poptGetNextOpt(poptContext con)
|
||||
|
||||
origOptString++;
|
||||
if (*origOptString != '\0')
|
||||
con->os->nextCharArg = origOptString + (*origOptString == '=');
|
||||
con->os->nextCharArg = origOptString;
|
||||
}
|
||||
/*@=branchstate@*/
|
||||
|
||||
if (opt == NULL) return POPT_ERROR_BADOPT; /* XXX can't happen */
|
||||
if (opt->arg && (opt->argInfo & POPT_ARG_MASK) == POPT_ARG_NONE) {
|
||||
if (poptSaveInt((int *)opt->arg, opt->argInfo, 1L))
|
||||
return POPT_ERROR_BADOPERATION;
|
||||
} else if ((opt->argInfo & POPT_ARG_MASK) == POPT_ARG_VAL) {
|
||||
if ((opt->argInfo & POPT_ARG_MASK) == POPT_ARG_NONE
|
||||
|| (opt->argInfo & POPT_ARG_MASK) == POPT_ARG_VAL) {
|
||||
if (longArg || (con->os->nextCharArg && con->os->nextCharArg[0] == '='))
|
||||
return POPT_ERROR_UNWANTEDARG;
|
||||
if (opt->arg) {
|
||||
if (poptSaveInt((int *)opt->arg, opt->argInfo, (long)opt->val))
|
||||
long val = (opt->argInfo & POPT_ARG_MASK) == POPT_ARG_VAL ? opt->val : 1;
|
||||
if (poptSaveInt((int *)opt->arg, opt->argInfo, val))
|
||||
return POPT_ERROR_BADOPERATION;
|
||||
}
|
||||
} else if ((opt->argInfo & POPT_ARG_MASK) != POPT_ARG_NONE) {
|
||||
} else {
|
||||
con->os->nextArg = _free(con->os->nextArg);
|
||||
/*@-usedef@*/ /* FIX: W2DO? */
|
||||
if (longArg) {
|
||||
@@ -881,7 +882,7 @@ int poptGetNextOpt(poptContext con)
|
||||
longArg = expandNextArg(con, longArg);
|
||||
con->os->nextArg = longArg;
|
||||
} else if (con->os->nextCharArg) {
|
||||
longArg = expandNextArg(con, con->os->nextCharArg);
|
||||
longArg = expandNextArg(con, con->os->nextCharArg + (con->os->nextCharArg[0] == '='));
|
||||
con->os->nextArg = longArg;
|
||||
con->os->nextCharArg = NULL;
|
||||
} else {
|
||||
@@ -1202,6 +1203,8 @@ const char * poptStrerror(const int error)
|
||||
switch (error) {
|
||||
case POPT_ERROR_NOARG:
|
||||
return POPT_("missing argument");
|
||||
case POPT_ERROR_UNWANTEDARG:
|
||||
return POPT_("option does not take an argument");
|
||||
case POPT_ERROR_BADOPT:
|
||||
return POPT_("unknown option");
|
||||
case POPT_ERROR_BADOPERATION:
|
||||
|
||||
@@ -82,6 +82,7 @@
|
||||
/*@{*/
|
||||
#define POPT_ERROR_NOARG -10 /*!< missing argument */
|
||||
#define POPT_ERROR_BADOPT -11 /*!< unknown option */
|
||||
#define POPT_ERROR_UNWANTEDARG -12 /*!< option does not take an argument */
|
||||
#define POPT_ERROR_OPTSTOODEEP -13 /*!< aliases nested too deeply */
|
||||
#define POPT_ERROR_BADQUOTE -15 /*!< error in paramter quoting */
|
||||
#define POPT_ERROR_ERRNO -16 /*!< errno set, use strerror(errno) */
|
||||
|
||||
@@ -85,7 +85,7 @@ char *alloca(size_t size);
|
||||
# endif
|
||||
# endif
|
||||
# endif
|
||||
#elif defined(__GNUC__) && defined(__STRICT_ANSI__)
|
||||
#elif !defined(alloca)
|
||||
#define alloca __builtin_alloca
|
||||
#endif
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
conf: configure.sh config.h.in
|
||||
|
||||
configure.sh: configure.in aclocal.m4
|
||||
configure.sh: configure.ac aclocal.m4
|
||||
autoconf -o configure.sh
|
||||
|
||||
config.h.in: configure.in aclocal.m4
|
||||
config.h.in: configure.ac aclocal.m4
|
||||
autoheader && touch config.h.in
|
||||
|
||||
@@ -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-2008 Wayne Davison
|
||||
* Copyright (C) 2003-2009 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
|
||||
|
||||
238
receiver.c
238
receiver.c
@@ -3,7 +3,7 @@
|
||||
*
|
||||
* Copyright (C) 1996-2000 Andrew Tridgell
|
||||
* Copyright (C) 1996 Paul Mackerras
|
||||
* Copyright (C) 2003-2008 Wayne Davison
|
||||
* Copyright (C) 2003-2009 Wayne Davison
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
@@ -24,6 +24,7 @@
|
||||
extern int verbose;
|
||||
extern int dry_run;
|
||||
extern int do_xfers;
|
||||
extern int am_root;
|
||||
extern int am_server;
|
||||
extern int do_progress;
|
||||
extern int inc_recurse;
|
||||
@@ -53,40 +54,39 @@ extern mode_t orig_umask;
|
||||
extern struct stats stats;
|
||||
extern char *tmpdir;
|
||||
extern char *partial_dir;
|
||||
extern char *basis_dir[];
|
||||
extern char *basis_dir[MAX_BASIS_DIRS+1];
|
||||
extern struct file_list *cur_flist, *first_flist, *dir_flist;
|
||||
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;
|
||||
|
||||
/*
|
||||
* get_tmpname() - create a tmp filename for a given filename
|
||||
*
|
||||
* If a tmpdir is defined, use that as the directory to
|
||||
* put it in. Otherwise, the tmp filename is in the same
|
||||
* directory as the given name. Note that there may be no
|
||||
* directory at all in the given name!
|
||||
*
|
||||
* The tmp filename is basically the given filename with a
|
||||
* dot prepended, and .XXXXXX appended (for mkstemp() to
|
||||
* put its unique gunk in). Take care to not exceed
|
||||
* either the MAXPATHLEN or NAME_MAX, esp. the last, as
|
||||
* the basename basically becomes 8 chars longer. In that
|
||||
* case, the original name is shortened sufficiently to
|
||||
* make it all fit.
|
||||
*
|
||||
* Of course, there's no real reason for the tmp name to
|
||||
* look like the original, except to satisfy us humans.
|
||||
* As long as it's unique, rsync will work.
|
||||
*/
|
||||
#define TMPNAME_SUFFIX ".XXXXXX"
|
||||
#define TMPNAME_SUFFIX_LEN ((int)sizeof TMPNAME_SUFFIX - 1)
|
||||
|
||||
/* get_tmpname() - create a tmp filename for a given filename
|
||||
*
|
||||
* If a tmpdir is defined, use that as the directory to put it in. Otherwise,
|
||||
* the tmp filename is in the same directory as the given name. Note that
|
||||
* there may be no directory at all in the given name!
|
||||
*
|
||||
* The tmp filename is basically the given filename with a dot prepended, and
|
||||
* .XXXXXX appended (for mkstemp() to put its unique gunk in). We take care
|
||||
* to not exceed either the MAXPATHLEN or NAME_MAX, especially the last, as
|
||||
* the basename basically becomes 8 characters longer. In such a case, the
|
||||
* original name is shortened sufficiently to make it all fit.
|
||||
*
|
||||
* Of course, the only reason the file is based on the original name is to
|
||||
* make it easier to figure out what purpose a temp file is serving when a
|
||||
* transfer is in progress. */
|
||||
int get_tmpname(char *fnametmp, const char *fname)
|
||||
{
|
||||
int maxname, added, length = 0;
|
||||
const char *f;
|
||||
char *suf;
|
||||
|
||||
if (tmpdir) {
|
||||
/* Note: this can't overflow, so the return value is safe */
|
||||
@@ -106,8 +106,9 @@ int get_tmpname(char *fnametmp, const char *fname)
|
||||
fnametmp[length++] = '.';
|
||||
|
||||
/* The maxname value is bufsize, and includes space for the '\0'.
|
||||
* (Note that NAME_MAX get -8 for the leading '.' above.) */
|
||||
maxname = MIN(MAXPATHLEN - 7 - length, NAME_MAX - 8);
|
||||
* NAME_MAX needs an extra -1 for the name's leading dot. */
|
||||
maxname = MIN(MAXPATHLEN - length - TMPNAME_SUFFIX_LEN,
|
||||
NAME_MAX - 1 - TMPNAME_SUFFIX_LEN);
|
||||
|
||||
if (maxname < 1) {
|
||||
rprintf(FERROR_XFER, "temporary filename too long: %s\n", fname);
|
||||
@@ -118,7 +119,17 @@ int get_tmpname(char *fnametmp, const char *fname)
|
||||
added = strlcpy(fnametmp + length, f, maxname);
|
||||
if (added >= maxname)
|
||||
added = maxname - 1;
|
||||
memcpy(fnametmp + length + added, ".XXXXXX", 8);
|
||||
suf = fnametmp + length + added;
|
||||
|
||||
/* Trim any dangling high-bit chars if the first-trimmed char (if any) is
|
||||
* also a high-bit char, just in case we cut into a multi-byte sequence.
|
||||
* We are guaranteed to stop because of the leading '.' we added. */
|
||||
if ((int)f[added] & 0x80) {
|
||||
while ((int)suf[-1] & 0x80)
|
||||
suf--;
|
||||
}
|
||||
|
||||
memcpy(suf, TMPNAME_SUFFIX, TMPNAME_SUFFIX_LEN+1);
|
||||
|
||||
return 1;
|
||||
}
|
||||
@@ -130,15 +141,25 @@ int get_tmpname(char *fnametmp, const char *fname)
|
||||
int open_tmpfile(char *fnametmp, const char *fname, struct file_struct *file)
|
||||
{
|
||||
int fd;
|
||||
mode_t added_perms;
|
||||
|
||||
if (!get_tmpname(fnametmp, fname))
|
||||
return -1;
|
||||
|
||||
if (am_root < 0) {
|
||||
/* For --fake-super, the file must be useable by the copying
|
||||
* user, just like it would be for root. */
|
||||
added_perms = S_IRUSR|S_IWUSR;
|
||||
} else {
|
||||
/* For a normal copy, we need to be able to tweak things like xattrs. */
|
||||
added_perms = S_IWUSR;
|
||||
}
|
||||
|
||||
/* We initially set the perms without the setuid/setgid bits or group
|
||||
* access to ensure that there is no race condition. They will be
|
||||
* correctly updated after the right owner and group info is set.
|
||||
* (Thanks to snabb@epipe.fi for pointing this out.) */
|
||||
fd = do_mkstemp(fnametmp, file->mode & INITACCESSPERMS);
|
||||
fd = do_mkstemp(fnametmp, (file->mode|added_perms) & INITACCESSPERMS);
|
||||
|
||||
#if 0
|
||||
/* In most cases parent directories will already exist because their
|
||||
@@ -148,7 +169,7 @@ int open_tmpfile(char *fnametmp, const char *fname, struct file_struct *file)
|
||||
&& create_directory_path(fnametmp) == 0) {
|
||||
/* Get back to name with XXXXXX in it. */
|
||||
get_tmpname(fnametmp, fname);
|
||||
fd = do_mkstemp(fnametmp, file->mode & INITACCESSPERMS);
|
||||
fd = do_mkstemp(fnametmp, (file->mode|added_perms) & INITACCESSPERMS);
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -248,8 +269,9 @@ static int receive_data(int f_in, char *fname_r, int fd_r, OFF_T size_r,
|
||||
|
||||
if (verbose > 3) {
|
||||
rprintf(FINFO,
|
||||
"chunk[%d] of size %ld at %.0f offset=%.0f\n",
|
||||
i, (long)len, (double)offset2, (double)offset);
|
||||
"chunk[%d] of size %ld at %.0f offset=%.0f%s\n",
|
||||
i, (long)len, (double)offset2, (double)offset,
|
||||
updating_basis_or_equiv && offset == offset2 ? " (seek)" : "");
|
||||
}
|
||||
|
||||
if (mapbuf) {
|
||||
@@ -284,14 +306,16 @@ 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 && do_ftruncate(fd, offset) < 0) {
|
||||
rsyserr(FERROR_XFER, errno, "ftruncate failed on %s",
|
||||
full_fname(fname));
|
||||
}
|
||||
#endif
|
||||
|
||||
if (do_progress)
|
||||
end_progress(total_size);
|
||||
|
||||
if (fd != -1 && offset > 0 && sparse_end(fd) != 0) {
|
||||
if (fd != -1 && offset > 0 && sparse_end(fd, offset) != 0) {
|
||||
report_write_error:
|
||||
rsyserr(FERROR_XFER, errno, "write failed on %s",
|
||||
full_fname(fname));
|
||||
@@ -348,25 +372,68 @@ 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 && !dry_run)
|
||||
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 int done_cnt = 0;
|
||||
static BOOL got_eof = False;
|
||||
int flist_num = first_flist->flist_num;
|
||||
|
||||
if (got_eof)
|
||||
return 0;
|
||||
|
||||
while (next_ndx < desired_ndx) {
|
||||
if (inc_recurse && flist_num <= done_cnt)
|
||||
return 0;
|
||||
if (next_ndx >= 0)
|
||||
no_batched_update(next_ndx, False);
|
||||
if ((next_ndx = read_int(batch_gen_fd)) < 0) {
|
||||
if (inc_recurse) {
|
||||
done_cnt++;
|
||||
continue;
|
||||
}
|
||||
got_eof = True;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
return next_gen_ndx;
|
||||
|
||||
if (next_ndx == desired_ndx) {
|
||||
next_ndx = -1;
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -375,7 +442,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 +476,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)
|
||||
@@ -441,14 +503,15 @@ int recv_files(int f_in, char *local_name)
|
||||
rprintf(FINFO, "recv_files(%s)\n", fname);
|
||||
|
||||
#ifdef SUPPORT_XATTRS
|
||||
if (iflags & ITEM_REPORT_XATTR && !dry_run)
|
||||
if (preserve_xattrs && iflags & ITEM_REPORT_XATTR && do_xfers)
|
||||
recv_xattr_request(file, f_in);
|
||||
#endif
|
||||
|
||||
if (!(iflags & ITEM_TRANSFER)) {
|
||||
maybe_log_item(file, iflags, itemizing, xname);
|
||||
#ifdef SUPPORT_XATTRS
|
||||
if (preserve_xattrs && iflags & ITEM_REPORT_XATTR && !dry_run)
|
||||
if (preserve_xattrs && iflags & ITEM_REPORT_XATTR && do_xfers
|
||||
&& !BITS_SET(iflags, ITEM_XNAME_FOLLOWS|ITEM_LOCAL_CHANGE))
|
||||
set_file_attrs(fname, file, NULL, fname, 0);
|
||||
#endif
|
||||
continue;
|
||||
@@ -495,6 +558,21 @@ int recv_files(int f_in, char *local_name)
|
||||
exit_cleanup(RERR_PROTOCOL);
|
||||
}
|
||||
|
||||
if (read_batch) {
|
||||
int wanted = redoing
|
||||
? we_want_redo(ndx)
|
||||
: gen_wants_ndx(ndx);
|
||||
if (!wanted) {
|
||||
rprintf(FINFO,
|
||||
"(Skipping batched update for%s \"%s\")\n",
|
||||
redoing ? " resend of" : "",
|
||||
fname);
|
||||
discard_receive_data(f_in, F_LENGTH(file));
|
||||
file->flags |= FLAG_FILE_SENT;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
if (!do_xfers) { /* log the transfer */
|
||||
log_item(FCLIENT, file, &stats, iflags, NULL);
|
||||
if (read_batch)
|
||||
@@ -508,20 +586,6 @@ int recv_files(int f_in, char *local_name)
|
||||
continue;
|
||||
}
|
||||
|
||||
if (read_batch) {
|
||||
next_gen_ndx = get_next_gen_ndx(batch_gen_fd, next_gen_ndx, ndx);
|
||||
if (ndx < next_gen_ndx) {
|
||||
rprintf(FINFO,
|
||||
"(Skipping batched update for \"%s\")\n",
|
||||
fname);
|
||||
discard_receive_data(f_in, F_LENGTH(file));
|
||||
if (inc_recurse)
|
||||
send_msg_int(MSG_NO_SEND, ndx);
|
||||
continue;
|
||||
}
|
||||
next_gen_ndx = -1;
|
||||
}
|
||||
|
||||
partialptr = partial_dir ? partial_dir_fname(fname) : fname;
|
||||
|
||||
if (protocol_version >= 29) {
|
||||
@@ -698,23 +762,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 +818,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-2008 Wayne Davison
|
||||
* Copyright (C) 2007-2009 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
|
||||
|
||||
102
rsync.c
102
rsync.c
@@ -3,7 +3,7 @@
|
||||
*
|
||||
* Copyright (C) 1996 Andrew Tridgell
|
||||
* Copyright (C) 1996 Paul Mackerras
|
||||
* Copyright (C) 2003-2008 Wayne Davison
|
||||
* Copyright (C) 2003-2009 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,12 +37,11 @@ extern int preserve_times;
|
||||
extern int am_root;
|
||||
extern int am_server;
|
||||
extern int am_sender;
|
||||
extern int am_receiver;
|
||||
extern int am_generator;
|
||||
extern int am_starting_up;
|
||||
extern int allow_8bit_chars;
|
||||
extern int protocol_version;
|
||||
extern int uid_ndx;
|
||||
extern int gid_ndx;
|
||||
extern int inc_recurse;
|
||||
extern int inplace;
|
||||
extern int flist_eof;
|
||||
@@ -80,7 +79,6 @@ void setup_iconv(void)
|
||||
# endif
|
||||
|
||||
if (!am_server && !allow_8bit_chars) {
|
||||
|
||||
/* It's OK if this fails... */
|
||||
ic_chck = iconv_open(defset, defset);
|
||||
|
||||
@@ -221,16 +219,19 @@ void send_protected_args(int fd, char *args[])
|
||||
if (verbose > 1)
|
||||
print_child_argv("protected args:", args + i + 1);
|
||||
do {
|
||||
if (!args[i][0])
|
||||
write_buf(fd, ".", 2);
|
||||
#ifdef ICONV_OPTION
|
||||
if (convert) {
|
||||
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;
|
||||
} else
|
||||
}
|
||||
#endif
|
||||
else
|
||||
write_buf(fd, args[i], strlen(args[i]) + 1);
|
||||
} while (args[++i]);
|
||||
write_byte(fd, 0);
|
||||
@@ -257,8 +258,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);
|
||||
@@ -268,9 +278,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);
|
||||
}
|
||||
|
||||
@@ -291,25 +302,14 @@ int read_ndx_and_attrs(int f_in, int *iflag_ptr, uchar *type_ptr,
|
||||
iflags = protocol_version >= 29 ? read_shortint(f_in)
|
||||
: ITEM_TRANSFER | ITEM_MISSING_DATA;
|
||||
|
||||
/* Honor the old-style keep-alive indicator. */
|
||||
if (protocol_version < 30
|
||||
&& ndx == cur_flist->used && iflags == ITEM_IS_NEW) {
|
||||
/* Support the protocol-29 keep-alive style. */
|
||||
if (protocol_version < 30 && ndx == cur_flist->used && iflags == ITEM_IS_NEW) {
|
||||
if (am_sender)
|
||||
maybe_send_keepalive();
|
||||
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);
|
||||
@@ -423,7 +423,9 @@ int set_file_attrs(const char *fname, struct file_struct *file, stat_x *sxp,
|
||||
set_xattr(fname, file, fnamecmp, sxp);
|
||||
#endif
|
||||
|
||||
if (!preserve_times || (S_ISDIR(sxp->st.st_mode) && preserve_times == 1))
|
||||
if (!preserve_times
|
||||
|| (!(preserve_times & PRESERVE_DIR_TIMES) && S_ISDIR(sxp->st.st_mode))
|
||||
|| (!(preserve_times & PRESERVE_LINK_TIMES) && S_ISLNK(sxp->st.st_mode)))
|
||||
flags |= ATTRS_SKIP_MTIME;
|
||||
if (!(flags & ATTRS_SKIP_MTIME)
|
||||
&& cmp_time(sxp->st.st_mtime, file->modtime) != 0) {
|
||||
@@ -442,7 +444,7 @@ int set_file_attrs(const char *fname, struct file_struct *file, stat_x *sxp,
|
||||
change_uid = am_root && uid_ndx && sxp->st.st_uid != (uid_t)F_OWNER(file);
|
||||
change_gid = gid_ndx && !(file->flags & FLAG_SKIP_GROUP)
|
||||
&& sxp->st.st_gid != (gid_t)F_GROUP(file);
|
||||
#if !defined HAVE_LCHOWN && !defined CHOWN_MODIFIES_SYMLINK
|
||||
#ifndef CAN_CHOWN_SYMLINK
|
||||
if (S_ISLNK(sxp->st.st_mode)) {
|
||||
;
|
||||
} else
|
||||
@@ -461,9 +463,9 @@ int set_file_attrs(const char *fname, struct file_struct *file, stat_x *sxp,
|
||||
}
|
||||
}
|
||||
if (am_root >= 0) {
|
||||
if (do_lchown(fname,
|
||||
change_uid ? (uid_t)F_OWNER(file) : sxp->st.st_uid,
|
||||
change_gid ? (gid_t)F_GROUP(file) : sxp->st.st_gid) != 0) {
|
||||
uid_t uid = change_uid ? (uid_t)F_OWNER(file) : sxp->st.st_uid;
|
||||
gid_t gid = change_gid ? (gid_t)F_GROUP(file) : sxp->st.st_gid;
|
||||
if (do_lchown(fname, uid, gid) != 0) {
|
||||
/* We shouldn't have attempted to change uid
|
||||
* or gid unless have the privilege. */
|
||||
rsyserr(FERROR_XFER, errno, "%s %s failed",
|
||||
@@ -471,6 +473,10 @@ int set_file_attrs(const char *fname, struct file_struct *file, stat_x *sxp,
|
||||
full_fname(fname));
|
||||
goto cleanup;
|
||||
}
|
||||
if (uid == (uid_t)-1 && sxp->st.st_uid != (uid_t)-1)
|
||||
rprintf(FERROR_XFER, "uid 4294967295 (-1) is impossible to set on %s\n", full_fname(fname));
|
||||
if (gid == (gid_t)-1 && sxp->st.st_gid != (gid_t)-1)
|
||||
rprintf(FERROR_XFER, "gid 4294967295 (-1) is impossible to set on %s\n", full_fname(fname));
|
||||
/* A lchown had been done, so we need to re-stat if
|
||||
* the destination had the setuid or setgid bits set
|
||||
* (due to the side effect of the chown call). */
|
||||
@@ -489,8 +495,10 @@ int set_file_attrs(const char *fname, struct file_struct *file, stat_x *sxp,
|
||||
* If set_acl() changes permission bits in the process of setting
|
||||
* an access ACL, it changes sxp->st.st_mode so we know whether we
|
||||
* need to chmod(). */
|
||||
if (preserve_acls && !S_ISLNK(new_mode) && set_acl(fname, file, sxp) == 0)
|
||||
updated = 1;
|
||||
if (preserve_acls && !S_ISLNK(new_mode)) {
|
||||
if (set_acl(fname, file, sxp, new_mode) > 0)
|
||||
updated = 1;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_CHMOD
|
||||
@@ -610,28 +618,48 @@ 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)
|
||||
{
|
||||
if (am_starting_up)
|
||||
return am_server ? "server" : "client";
|
||||
return am_sender ? "sender" : am_generator ? "generator" : "receiver";
|
||||
return am_sender ? "sender"
|
||||
: am_generator ? "generator"
|
||||
: am_receiver ? "receiver"
|
||||
: "Receiver"; /* pre-forked receiver */
|
||||
}
|
||||
|
||||
43
rsync.h
43
rsync.h
@@ -32,7 +32,7 @@
|
||||
#define DEFAULT_LOCK_FILE "/var/run/rsyncd.lock"
|
||||
#define URL_PREFIX "rsync://"
|
||||
|
||||
#define SYMLINK_PREFIX "/rsyncd-munged/"
|
||||
#define SYMLINK_PREFIX "/rsyncd-munged/" /* This MUST have a trailing slash! */
|
||||
#define SYMLINK_PREFIX_LEN ((int)sizeof SYMLINK_PREFIX - 1)
|
||||
|
||||
#define BACKUP_SUFFIX "~"
|
||||
@@ -60,10 +60,12 @@
|
||||
#define XMIT_RDEV_MINOR_8_pre30 (1<<11) /* protocols 28 - 29 */
|
||||
#define XMIT_GROUP_NAME_FOLLOWS (1<<11) /* protocols 30 - now */
|
||||
#define XMIT_HLINK_FIRST (1<<12) /* protocols 30 - now (HLINKED files only) */
|
||||
#define XMIT_IO_ERROR_ENDLIST (1<<12) /* protocols 31*- now (w/XMIT_EXTENDED_FLAGS) (also protocol 30 w/'f' compat flag) */
|
||||
|
||||
/* These flags are used in the live flist data. */
|
||||
|
||||
#define FLAG_TOP_DIR (1<<0) /* sender/receiver/generator */
|
||||
#define FLAG_OWNED_BY_US (1<<0) /* generator: set by make_file() for aux flists only */
|
||||
#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 */
|
||||
@@ -82,8 +84,12 @@
|
||||
|
||||
/* These flags are passed to functions but not stored. */
|
||||
|
||||
#define FLAG_DIVERT_DIRS (1<<16)/* sender */
|
||||
#define FLAG_DIVERT_DIRS (1<<16) /* sender, but must be unique */
|
||||
|
||||
/* These flags are for get_dirlist(). */
|
||||
#define GDL_IGNORE_FILTER_RULES (1<<0)
|
||||
|
||||
/* Some helper macros for matching bits. */
|
||||
#define BITS_SET(val,bits) (((val) & (bits)) == (bits))
|
||||
#define BITS_SETnUNSET(val,onbits,offbits) (((val) & ((onbits)|(offbits))) == (onbits))
|
||||
#define BITS_EQUAL(b1,b2,mask) (((unsigned)(b1) & (unsigned)(mask)) \
|
||||
@@ -94,7 +100,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! */
|
||||
* It must ALWAYS be 0 when the protocol goes final (and NEVER before)! */
|
||||
#define SUBPROTOCOL_VERSION 0
|
||||
|
||||
/* We refuse to interoperate with versions that are not in this range.
|
||||
@@ -211,6 +217,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) */
|
||||
};
|
||||
|
||||
@@ -221,6 +228,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 */
|
||||
@@ -332,6 +340,18 @@ enum msgcode {
|
||||
#include <utime.h>
|
||||
#endif
|
||||
|
||||
#if defined HAVE_LUTIMES || defined HAVE_UTIMENSAT
|
||||
#define CAN_SET_SYMLINK_TIMES 1
|
||||
#endif
|
||||
|
||||
#if defined HAVE_LCHOWN || defined CHOWN_MODIFIES_SYMLINK
|
||||
#define CAN_CHOWN_SYMLINK 1
|
||||
#endif
|
||||
|
||||
#if defined HAVE_LCHMOD || defined HAVE_SETATTRLIST
|
||||
#define CAN_CHMOD_SYMLINK 1
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_SYS_SELECT_H
|
||||
#include <sys/select.h>
|
||||
#endif
|
||||
@@ -394,7 +414,7 @@ enum msgcode {
|
||||
# include <limits.h>
|
||||
#endif
|
||||
|
||||
#if defined HAVE_ICONV_OPEN && defined HAVE_ICONV_H
|
||||
#if defined USE_ICONV_OPEN && defined HAVE_ICONV_H
|
||||
#include <iconv.h>
|
||||
#ifndef ICONV_CONST
|
||||
#define ICONV_CONST
|
||||
@@ -427,6 +447,8 @@ typedef unsigned int mode_t;
|
||||
#endif
|
||||
#ifndef HAVE_OFF_T
|
||||
typedef long off_t;
|
||||
#undef SIZEOF_OFF_T
|
||||
#define SIZEOF_OFF_T SIZEOF_LONG
|
||||
#endif
|
||||
#ifndef HAVE_SIZE_T
|
||||
typedef unsigned int size_t;
|
||||
@@ -830,6 +852,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 {
|
||||
@@ -1055,6 +1086,10 @@ extern int errno;
|
||||
#define IS_SPECIAL(mode) (S_ISSOCK(mode) || S_ISFIFO(mode))
|
||||
#define IS_DEVICE(mode) (S_ISCHR(mode) || S_ISBLK(mode))
|
||||
|
||||
#define PRESERVE_FILE_TIMES (1<<0)
|
||||
#define PRESERVE_DIR_TIMES (1<<1)
|
||||
#define PRESERVE_LINK_TIMES (1<<2)
|
||||
|
||||
/* Initial mask on permissions given to temporary files. Mask off setuid
|
||||
bits and group access because of potential race-condition security
|
||||
holes, and mask other access because mode 707 is bizarre */
|
||||
|
||||
404
rsync.yo
404
rsync.yo
@@ -1,5 +1,5 @@
|
||||
mailto(rsync-bugs@samba.org)
|
||||
manpage(rsync)(1)(29 Jun 2008)()()
|
||||
manpage(rsync)(1)(22 Jun 2011)()()
|
||||
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
|
||||
@@ -514,7 +518,7 @@ dit(bf(-c, --checksum)) This changes the way rsync checks if the files have
|
||||
been changed and are in need of a transfer. Without this option, rsync
|
||||
uses a "quick check" that (by default) checks if each file's size and time
|
||||
of last modification match between the sender and receiver. This option
|
||||
changes this to compare a 128-bit MD4 checksum for each file that has a
|
||||
changes this to compare a 128-bit checksum for each file that has a
|
||||
matching size. Generating the checksums means that both sides will expend
|
||||
a lot of disk I/O reading all the data in the files in the transfer (and
|
||||
this is prior to any reading that will be done to transfer changed files),
|
||||
@@ -532,6 +536,9 @@ checksum that is generated as the file is transferred, but that
|
||||
automatic after-the-transfer verification has nothing to do with this
|
||||
option's before-the-transfer "Does this file need to be updated?" check.
|
||||
|
||||
For protocol 30 and beyond (first supported in 3.0.0), the checksum used is
|
||||
MD5. For older protocols, the checksum used is MD4.
|
||||
|
||||
dit(bf(-a, --archive)) This is equivalent to bf(-rlptgoD). It is a quick
|
||||
way of saying you want recursion and want to preserve almost
|
||||
everything (with -H being a notable omission).
|
||||
@@ -619,7 +626,7 @@ quote(tt( rsync -avR /foo/./bar/baz.c remote:/tmp/))
|
||||
|
||||
That would create /tmp/bar/baz.c on the remote machine. (Note that the
|
||||
dot must be followed by a slash, so "/foo/." would not be abbreviated.)
|
||||
(2) For older rsync versions, you would need to use a chdir to limit the
|
||||
For older rsync versions, you would need to use a chdir to limit the
|
||||
source path. For example, when pushing files:
|
||||
|
||||
quote(tt( (cd /foo; rsync -avR bar/baz.c remote:/tmp/) ))
|
||||
@@ -667,7 +674,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
|
||||
@@ -681,6 +688,12 @@ specify a backup suffix using the bf(--suffix) option
|
||||
(otherwise the files backed up in the specified directory
|
||||
will keep their original filenames).
|
||||
|
||||
Note that if you specify a relative path, the backup directory will be
|
||||
relative to the destination directory, so you probably want to specify
|
||||
either an absolute path or a path that starts with "../". If an rsync
|
||||
daemon is the receiver, the backup dir cannot go outside the module's path
|
||||
hierarchy, so take extra care not to delete it or copy into it.
|
||||
|
||||
dit(bf(--suffix=SUFFIX)) This option allows you to override the default
|
||||
backup suffix used with the bf(--backup) (bf(-b)) option. The default suffix is a ~
|
||||
if no -bf(-backup-dir) was specified, otherwise it is an empty string.
|
||||
@@ -697,29 +710,45 @@ 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 option changes how rsync transfers a file when the
|
||||
file's data needs to be updated: instead of the default method of creating
|
||||
This option is a transfer rule, not an exclude, so it doesn't affect the
|
||||
data that goes into the file-lists, and thus it doesn't affect deletions.
|
||||
It just limits the files that the receiver requests to be transferred.
|
||||
|
||||
dit(bf(--inplace)) This option changes how rsync transfers a file when
|
||||
its 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).
|
||||
This has several effects:
|
||||
|
||||
quote(itemization(
|
||||
it() Hard links are not broken. This means the new data will be visible
|
||||
through other hard links to the destination file. Moreover, attempts to
|
||||
copy differing source files onto a multiply-linked destination file will
|
||||
result in a "tug of war" with the destination data changing back and forth.
|
||||
it() 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).
|
||||
it() The file's data will be in an inconsistent state during the transfer
|
||||
and will be left that way if the transfer is interrupted or if an update
|
||||
fails.
|
||||
it() A file that rsync cannot write to cannot be updated. While a super user
|
||||
can update any file, a normal user needs to be granted write permission for
|
||||
the open of the file for writing to be successful.
|
||||
it() 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. This does not apply if you use 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
|
||||
This option is useful for transferring large files with block-based changes
|
||||
or appended data, and also on systems that are disk bound, not network
|
||||
bound.
|
||||
bound. It can also help keep a copy-on-write filesystem snapshot from
|
||||
diverging the entire contents of a file that only has minor changes.
|
||||
|
||||
The option implies bf(--partial) (since an interrupted transfer does not delete
|
||||
the file), but conflicts with bf(--partial-dir) and bf(--delay-updates).
|
||||
@@ -803,6 +832,17 @@ bf(--force) or bf(--delete) is in effect).
|
||||
See also bf(--keep-dirlinks) for an analogous option for the receiving
|
||||
side.
|
||||
|
||||
bf(--copy-dirlinks) applies to all symlinks to directories in the source. If
|
||||
you want to follow only a few specified symlinks, a trick you can use is to
|
||||
pass them as additional source args with a trailing slash, using bf(--relative)
|
||||
to make the paths match up right. For example:
|
||||
|
||||
quote(tt(rsync -r --relative src/./ src/./follow-me/ dest/))
|
||||
|
||||
This works because rsync calls bf(lstat)(2) on the source arg as given, and the
|
||||
trailing slash makes bf(lstat)(2) follow the symlink, giving rise to a directory
|
||||
in the file-list which overrides the symlink found during the scan of "src/./".
|
||||
|
||||
dit(bf(-K, --keep-dirlinks)) This option causes the receiving side to treat
|
||||
a symlink to a directory as though it were a real directory, but only if it
|
||||
matches a real directory from the sender. Without this option, the
|
||||
@@ -826,17 +866,25 @@ to modify your receiving hierarchy.
|
||||
See also bf(--copy-dirlinks) for an analogous option for the sending side.
|
||||
|
||||
dit(bf(-H, --hard-links)) This tells rsync to look for hard-linked files in
|
||||
the transfer and link together the corresponding files on the receiving
|
||||
side. Without this option, hard-linked files in the transfer are treated
|
||||
the source and link together the corresponding files on the destination.
|
||||
Without this option, hard-linked files in the source are treated
|
||||
as though they were separate files.
|
||||
|
||||
When you are updating a non-empty destination, this option only ensures
|
||||
that files that are hard-linked together on the source are hard-linked
|
||||
together on the destination. It does NOT currently endeavor to break
|
||||
already existing hard links on the destination that do not exist between
|
||||
the source files. Note, however, that if one or more extra-linked files
|
||||
have content changes, they will become unlinked when updated (assuming you
|
||||
are not using the bf(--inplace) option).
|
||||
This option does NOT necessarily ensure that the pattern of hard links on the
|
||||
destination exactly matches that on the source. Cases in which the
|
||||
destination may end up with extra hard links include the following:
|
||||
|
||||
quote(itemization(
|
||||
it() If the destination contains extraneous hard-links (more linking than
|
||||
what is present in the source file list), the copying algorithm will not
|
||||
break them explicitly. However, if one or more of the paths have content
|
||||
differences, the normal file-update process will break those extra links
|
||||
(unless you are using the bf(--inplace) option).
|
||||
it() If you specify a bf(--link-dest) directory that contains hard links,
|
||||
the linking of the destination files against the bf(--link-dest) files can
|
||||
cause some paths in the destination to become linked together due to the
|
||||
bf(--link-dest) associations.
|
||||
))
|
||||
|
||||
Note that rsync can only detect hard links between files that are inside
|
||||
the transfer set. If rsync updates a file that has extra hard-link
|
||||
@@ -849,7 +897,10 @@ see the bf(--inplace) option for more caveats).
|
||||
If incremental recursion is active (see bf(--recursive)), rsync may transfer
|
||||
a missing hard-linked file before it finds that another link for that contents
|
||||
exists elsewhere in the hierarchy. This does not affect the accuracy of
|
||||
the transfer, just its efficiency. One way to avoid this is to disable
|
||||
the transfer (i.e. which files are hard-linked together), just its efficiency
|
||||
(i.e. copying the data for a new, early copy of a hard-linked file that could
|
||||
have been found later in the transfer in another member of the hard-linked
|
||||
set of files). One way to avoid this inefficiency is to disable
|
||||
incremental recursion using the bf(--no-inc-recursive) option.
|
||||
|
||||
dit(bf(-p, --perms)) This option causes the receiving rsync to set the
|
||||
@@ -927,24 +978,31 @@ The source and destination systems must have compatible ACL entries for this
|
||||
option to work properly. See the bf(--fake-super) option for a way to backup
|
||||
and restore ACLs that are not compatible.
|
||||
|
||||
dit(bf(-X, --xattrs)) This option causes rsync to update the remote
|
||||
extended attributes to be the same as the local ones.
|
||||
dit(bf(-X, --xattrs)) This option causes rsync to update the destination
|
||||
extended attributes to be the same as the source ones.
|
||||
|
||||
For systems that support extended-attribute namespaces, a copy being done by a
|
||||
super-user copies all namespaces except system.*. A normal user only copies
|
||||
the user.* namespace. To be able to backup and restore non-user namespaces as
|
||||
a normal user, see the bf(--fake-super) option.
|
||||
|
||||
Note that this option does not copy rsyncs special xattr values (e.g. those
|
||||
used by bf(--fake-super)) unless you repeat the option (e.g. -XX). This
|
||||
"copy all xattrs" mode cannot be used with bf(--fake-super).
|
||||
|
||||
dit(bf(--chmod)) This option tells rsync to apply one or more
|
||||
comma-separated "chmod" strings to the permission of the files in the
|
||||
transfer. The resulting value is treated as though it was the permissions
|
||||
transfer. The resulting value is treated as though it were the permissions
|
||||
that the sending side supplied for the file, which means that this option
|
||||
can seem to have no effect on existing files if bf(--perms) is not enabled.
|
||||
|
||||
In addition to the normal parsing rules specified in the bf(chmod)(1)
|
||||
manpage, you can specify an item that should only apply to a directory by
|
||||
prefixing it with a 'D', or specify an item that should only apply to a
|
||||
file by prefixing it with a 'F'. For example:
|
||||
file by prefixing it with a 'F'. For example, the following will ensure
|
||||
that all directories get marked set-gid, that no files are other-writable,
|
||||
that both are user-writable and group-writable, and that both have
|
||||
consistent executability across all bits:
|
||||
|
||||
quote(--chmod=Dg+s,ug+w,Fo-w,+X)
|
||||
|
||||
@@ -1007,7 +1065,7 @@ all groups (not just the current user's groups) via the bf(--groups)
|
||||
option, and copying devices via the bf(--devices) option. This is useful
|
||||
for systems that allow such activities without being the super-user, and
|
||||
also for ensuring that you will get errors if the receiving side isn't
|
||||
being running as the super-user. To turn off super-user activities, the
|
||||
being run as the super-user. To turn off super-user activities, the
|
||||
super-user can use bf(--no-super).
|
||||
|
||||
dit(bf(--fake-super)) When this option is enabled, rsync simulates
|
||||
@@ -1045,10 +1103,6 @@ dit(bf(-S, --sparse)) Try to handle sparse files efficiently so they take
|
||||
up less space on the destination. Conflicts with bf(--inplace) because it's
|
||||
not possible to overwrite data in a sparse fashion.
|
||||
|
||||
NOTE: Don't use this option when the destination is a Solaris "tmpfs"
|
||||
filesystem. It doesn't seem to handle seeks over null regions
|
||||
correctly and ends up corrupting the files.
|
||||
|
||||
dit(bf(-n, --dry-run)) This makes rsync perform a trial run that doesn't
|
||||
make any changes (and produces mostly the same output as a real run). It
|
||||
is most commonly used in combination with the bf(-v, --verbose) and/or
|
||||
@@ -1057,19 +1111,20 @@ to do before one actually runs it.
|
||||
|
||||
The output of bf(--itemize-changes) is supposed to be exactly the same on a
|
||||
dry run and a subsequent real run (barring intentional trickery and system
|
||||
call failures); if it isn't, that's a bug. Other output is the same to the
|
||||
extent practical, but may differ in some areas. Notably, a dry run does not
|
||||
call failures); if it isn't, that's a bug. Other output should be mostly
|
||||
unchanged, but may differ in some areas. Notably, a dry run does not
|
||||
send the actual data for file transfers, so bf(--progress) has no effect,
|
||||
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.
|
||||
where no file transfers were needed.
|
||||
|
||||
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
|
||||
"disk" is actually a networked filesystem). This is the default when both
|
||||
the source and destination are specified as local paths.
|
||||
the source and destination are specified as local paths, but only if no
|
||||
batch-writing option is in effect.
|
||||
|
||||
dit(bf(-x, --one-file-system)) This tells rsync to avoid crossing a
|
||||
filesystem boundary when recursing. This does not limit the user's ability
|
||||
@@ -1095,10 +1150,18 @@ yet on the destination. If this option is
|
||||
combined with the bf(--ignore-existing) option, no files will be updated
|
||||
(which can be useful if all you want to do is delete extraneous files).
|
||||
|
||||
This option is a transfer rule, not an exclude, so it doesn't affect the
|
||||
data that goes into the file-lists, and thus it doesn't affect deletions.
|
||||
It just limits the files that the receiver requests to be transferred.
|
||||
|
||||
dit(bf(--ignore-existing)) This tells rsync to skip updating files that
|
||||
already exist on the destination (this does em(not) ignore existing
|
||||
directories, or nothing would get done). See also bf(--existing).
|
||||
|
||||
This option is a transfer rule, not an exclude, so it doesn't affect the
|
||||
data that goes into the file-lists, and thus it doesn't affect deletions.
|
||||
It just limits the files that the receiver requests to be transferred.
|
||||
|
||||
This option can be useful for those doing backups using the bf(--link-dest)
|
||||
option when they need to continue a backup run that got interrupted. Since
|
||||
a bf(--link-dest) run is copied into a new directory hierarchy (when it is
|
||||
@@ -1117,7 +1180,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).
|
||||
@@ -1133,13 +1196,13 @@ going to be deleted.
|
||||
If the sending side detects any I/O errors, then the deletion of any
|
||||
files at the destination will be automatically disabled. This is to
|
||||
prevent temporary filesystem failures (such as NFS errors) on the
|
||||
sending side causing a massive deletion of files on the
|
||||
sending side from causing a massive deletion of files on the
|
||||
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).
|
||||
|
||||
@@ -1156,19 +1219,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
|
||||
@@ -1214,6 +1284,10 @@ file that is larger than the specified SIZE. The SIZE value can be
|
||||
suffixed with a string to indicate a size multiplier, and
|
||||
may be a fractional value (e.g. "bf(--max-size=1.5m)").
|
||||
|
||||
This option is a transfer rule, not an exclude, so it doesn't affect the
|
||||
data that goes into the file-lists, and thus it doesn't affect deletions.
|
||||
It just limits the files that the receiver requests to be transferred.
|
||||
|
||||
The suffixes are as follows: "K" (or "KiB") is a kibibyte (1024),
|
||||
"M" (or "MiB") is a mebibyte (1024*1024), and "G" (or "GiB") is a
|
||||
gibibyte (1024*1024*1024).
|
||||
@@ -1228,7 +1302,7 @@ Examples: --max-size=1.5mb-1 is 1499999 bytes, and --max-size=2g+1 is
|
||||
dit(bf(--min-size=SIZE)) This tells rsync to avoid transferring any
|
||||
file that is smaller than the specified SIZE, which can help in not
|
||||
transferring small, junk files.
|
||||
See the bf(--max-size) option for a description of SIZE.
|
||||
See the bf(--max-size) option for a description of SIZE and other information.
|
||||
|
||||
dit(bf(-B, --block-size=BLOCKSIZE)) This forces the block size used in
|
||||
rsync's delta-transfer algorithm to a fixed value. It is normally selected based on
|
||||
@@ -1291,7 +1365,7 @@ initial items are marked as perishable -- see the FILTER RULES section):
|
||||
|
||||
quote(quote(tt(RCS SCCS CVS CVS.adm RCSLOG cvslog.* tags TAGS .make.state
|
||||
.nse_depinfo *~ #* .#* ,* _$* *$ *.old *.bak *.BAK *.orig *.rej .del-*
|
||||
*.a *.olb *.o *.obj *.so *.exe *.Z *.elc *.ln core .svn/ .git/ .bzr/)))
|
||||
*.a *.olb *.o *.obj *.so *.exe *.Z *.elc *.ln core .svn/ .git/ .hg/ .bzr/)))
|
||||
|
||||
then, files listed in a $HOME/.cvsignore are added to the list and any
|
||||
files listed in the CVSIGNORE environment variable (all cvsignore names
|
||||
@@ -1416,6 +1490,17 @@ quote(tt( rsync -a --files-from=:/path/file-list src:/ /tmp/copy))
|
||||
This would copy all the files specified in the /path/file-list file that
|
||||
was located on the remote "src" host.
|
||||
|
||||
If the bf(--iconv) and bf(--protect-args) options are specified and the
|
||||
bf(--files-from) filenames are being sent from one host to another, the
|
||||
filenames will be translated from the sending host's charset to the
|
||||
receiving host's charset.
|
||||
|
||||
NOTE: sorting the list of files in the --files-from input helps rsync to be
|
||||
more efficient, as it will avoid re-visiting the path elements that are shared
|
||||
between adjacent entries. If the input is not sorted, some path elements
|
||||
(implied directories) may end up being scanned multiple times, and rsync will
|
||||
eventually unduplicate them after they get turned into file-list elements.
|
||||
|
||||
dit(bf(-0, --from0)) This tells rsync that the rules/filenames it reads from a
|
||||
file are terminated by a null ('\0') character, not a NL, CR, or CR+LF.
|
||||
This affects bf(--exclude-from), bf(--include-from), bf(--files-from), and any
|
||||
@@ -1423,18 +1508,14 @@ merged files specified in a bf(--filter) rule.
|
||||
It does not affect bf(--cvs-exclude) (since all names read from a .cvsignore
|
||||
file are split on whitespace).
|
||||
|
||||
If the bf(--iconv) and bf(--protect-args) options are specified and the
|
||||
bf(--files-from) filenames are being sent from one host to another, the
|
||||
filenames will be translated from the sending host's charset to the
|
||||
receiving host's charset.
|
||||
|
||||
dit(bf(-s, --protect-args)) This option sends all filenames and some options to
|
||||
dit(bf(-s, --protect-args)) This option sends all filenames and most options to
|
||||
the remote rsync without allowing the remote shell to interpret them. This
|
||||
means that spaces are not split in names, and any non-wildcard special
|
||||
characters are not translated (such as ~, $, ;, &, etc.). Wildcards are
|
||||
expanded on the remote host by rsync (instead of the shell doing it).
|
||||
|
||||
If you use this option with bf(--iconv), the args will also be translated
|
||||
If you use this option with bf(--iconv), the args related to the remote
|
||||
side will also be translated
|
||||
from the local to the remote character-set. The translation happens before
|
||||
wild-cards are expanded. See also the bf(--files-from) option.
|
||||
|
||||
@@ -1522,6 +1603,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.
|
||||
@@ -1573,7 +1659,7 @@ You may specify an empty string to indicate that no file should be skipped.
|
||||
|
||||
Simple character-class matching is supported: each must consist of a list
|
||||
of letters inside the square brackets (e.g. no special classes, such as
|
||||
"[:alpha:]", are supported).
|
||||
"[:alpha:]", are supported, and '-' has no special meaning).
|
||||
|
||||
The characters asterisk (*) and question-mark (?) have no special meaning.
|
||||
|
||||
@@ -1582,10 +1668,26 @@ matches 2 suffixes):
|
||||
|
||||
verb( --skip-compress=gz/jpg/mp[34]/7z/bz2)
|
||||
|
||||
The default list of suffixes that will not be compressed is this (several
|
||||
of these are newly added for 3.0.0):
|
||||
The default list of suffixes that will not be compressed is this (in this
|
||||
version of rsync):
|
||||
|
||||
verb( gz/zip/z/rpm/deb/iso/bz2/t[gb]z/7z/mp[34]/mov/avi/ogg/jpg/jpeg)
|
||||
bf(7z)
|
||||
bf(avi)
|
||||
bf(bz2)
|
||||
bf(deb)
|
||||
bf(gz)
|
||||
bf(iso)
|
||||
bf(jpeg)
|
||||
bf(jpg)
|
||||
bf(mov)
|
||||
bf(mp3)
|
||||
bf(mp4)
|
||||
bf(ogg)
|
||||
bf(rpm)
|
||||
bf(tbz)
|
||||
bf(tgz)
|
||||
bf(z)
|
||||
bf(zip)
|
||||
|
||||
This list will be replaced by your bf(--skip-compress) list in all but one
|
||||
situation: a copy from a daemon rsync will add your skipped suffixes to
|
||||
@@ -1718,22 +1820,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
|
||||
@@ -1764,6 +1866,9 @@ specify an empty string, updated files will not be mentioned in the log file.
|
||||
For a list of the possible escape characters, see the "log format" setting
|
||||
in the rsyncd.conf manpage.
|
||||
|
||||
The default FORMAT used if bf(--log-file) is specified and this option is not
|
||||
is '%i %n%L'.
|
||||
|
||||
dit(bf(--stats)) This tells rsync to print a verbose set of statistics
|
||||
on the file transfer, allowing you to tell how effective rsync's delta-transfer
|
||||
algorithm is for your data.
|
||||
@@ -1913,11 +2018,16 @@ creation of a bunch of useless directories when the sending rsync is
|
||||
recursively scanning a hierarchy of files using include/exclude/filter
|
||||
rules.
|
||||
|
||||
Note that the use of transfer rules, such as the bf(--min-size) option, does
|
||||
not affect what goes into the file list, and thus does not leave directories
|
||||
empty, even if none of the files in a directory match the transfer rule.
|
||||
|
||||
Because the file-list is actually being pruned, this option also affects
|
||||
what directories get deleted when a delete is active. However, keep in
|
||||
mind that excluded files and directories can prevent existing items from
|
||||
being deleted (because an exclude hides source files and protects
|
||||
destination files).
|
||||
being deleted due to an exclude both hiding source files and protecting
|
||||
destination files. See the perishable filter-rule option for how to avoid
|
||||
this.
|
||||
|
||||
You can prevent the pruning of certain empty directories from the file-list
|
||||
by using a global "protect" filter. For instance, this option would ensure
|
||||
@@ -1976,7 +2086,8 @@ transfer that may be interrupted.
|
||||
|
||||
dit(bf(--password-file)) This option allows you to provide a password in a
|
||||
file for accessing an rsync daemon. The file must not be world readable.
|
||||
It should contain just the password as a single line.
|
||||
It should contain just the password as the first line of the file (all
|
||||
other lines are ignored).
|
||||
|
||||
This option does not supply a password to a remote shell transport such as
|
||||
ssh; to learn how to do that, consult the remote shell's documentation.
|
||||
@@ -2086,14 +2197,14 @@ If rsync was complied without support for IPv6, the bf(--ipv6) option
|
||||
will have no effect. The bf(--version) output will tell you if this
|
||||
is the case.
|
||||
|
||||
dit(bf(--checksum-seed=NUM)) Set the MD4 checksum seed to the integer
|
||||
dit(bf(--checksum-seed=NUM)) Set the checksum seed to the integer
|
||||
NUM. This 4 byte checksum seed is included in each block and file
|
||||
MD4 checksum calculation. By default the checksum seed is generated
|
||||
checksum calculation. By default the checksum seed is generated
|
||||
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()
|
||||
|
||||
@@ -2264,7 +2375,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:]].
|
||||
@@ -2337,6 +2448,39 @@ itemization(
|
||||
explicitly included or it would be excluded by the "*")
|
||||
)
|
||||
|
||||
The following modifiers are accepted after a "+" or "-":
|
||||
|
||||
itemization(
|
||||
it() A bf(/) specifies that the include/exclude rule should be matched
|
||||
against the absolute pathname of the current item. For example,
|
||||
"-/ /etc/passwd" would exclude the passwd file any time the transfer
|
||||
was sending files from the "/etc" directory, and "-/ subdir/foo"
|
||||
would always exclude "foo" when it is in a dir named "subdir", even
|
||||
if "foo" is at the root of the current transfer.
|
||||
it() A bf(!) specifies that the include/exclude should take effect if
|
||||
the pattern fails to match. For instance, "-! */" would exclude all
|
||||
non-directories.
|
||||
it() A bf(C) is used to indicate that all the global CVS-exclude rules
|
||||
should be inserted as excludes in place of the "-C". No arg should
|
||||
follow.
|
||||
it() An bf(s) is used to indicate that the rule applies to the sending
|
||||
side. When a rule affects the sending side, it prevents files from
|
||||
being transferred. The default is for a rule to affect both sides
|
||||
unless bf(--delete-excluded) was specified, in which case default rules
|
||||
become sender-side only. See also the hide (H) and show (S) rules,
|
||||
which are an alternate way to specify sending-side includes/excludes.
|
||||
it() An bf(r) is used to indicate that the rule applies to the receiving
|
||||
side. When a rule affects the receiving side, it prevents files from
|
||||
being deleted. See the bf(s) modifier for more info. See also the
|
||||
protect (P) and risk (R) rules, which are an alternate way to
|
||||
specify receiver-side includes/excludes.
|
||||
it() A bf(p) indicates that a rule is perishable, meaning that it is
|
||||
ignored in directories that are being deleted. For instance, the bf(-C)
|
||||
option's default rules that exclude things like "CVS" and "*.o" are
|
||||
marked as perishable, and will not prevent a directory that was removed
|
||||
on the source from being deleted on the destination.
|
||||
)
|
||||
|
||||
manpagesection(MERGE-FILE FILTER RULES)
|
||||
|
||||
You can merge whole files into your filter rules by specifying either a
|
||||
@@ -2385,44 +2529,15 @@ itemization(
|
||||
"- foo + bar" is parsed as two rules (assuming that prefix-parsing wasn't
|
||||
also disabled).
|
||||
it() You may also specify any of the modifiers for the "+" or "-" rules
|
||||
(below) in order to have the rules that are read in from the file
|
||||
default to having that modifier set. For instance, "merge,-/ .excl" would
|
||||
(above) in order to have the rules that are read in from the file
|
||||
default to having that modifier set (except for the bf(!) modifier, which
|
||||
would not be useful). For instance, "merge,-/ .excl" would
|
||||
treat the contents of .excl as absolute-path excludes,
|
||||
while "dir-merge,s .filt" and ":sC" would each make all their
|
||||
per-directory rules apply only on the sending side.
|
||||
)
|
||||
|
||||
The following modifiers are accepted after a "+" or "-":
|
||||
|
||||
itemization(
|
||||
it() A bf(/) specifies that the include/exclude rule should be matched
|
||||
against the absolute pathname of the current item. For example,
|
||||
"-/ /etc/passwd" would exclude the passwd file any time the transfer
|
||||
was sending files from the "/etc" directory, and "-/ subdir/foo"
|
||||
would always exclude "foo" when it is in a dir named "subdir", even
|
||||
if "foo" is at the root of the current transfer.
|
||||
it() A bf(!) specifies that the include/exclude should take effect if
|
||||
the pattern fails to match. For instance, "-! */" would exclude all
|
||||
non-directories.
|
||||
it() A bf(C) is used to indicate that all the global CVS-exclude rules
|
||||
should be inserted as excludes in place of the "-C". No arg should
|
||||
follow.
|
||||
it() An bf(s) is used to indicate that the rule applies to the sending
|
||||
side. When a rule affects the sending side, it prevents files from
|
||||
being transferred. The default is for a rule to affect both sides
|
||||
unless bf(--delete-excluded) was specified, in which case default rules
|
||||
become sender-side only. See also the hide (H) and show (S) rules,
|
||||
which are an alternate way to specify sending-side includes/excludes.
|
||||
it() An bf(r) is used to indicate that the rule applies to the receiving
|
||||
side. When a rule affects the receiving side, it prevents files from
|
||||
being deleted. See the bf(s) modifier for more info. See also the
|
||||
protect (P) and risk (R) rules, which are an alternate way to
|
||||
specify receiver-side includes/excludes.
|
||||
it() A bf(p) indicates that a rule is perishable, meaning that it is
|
||||
ignored in directories that are being deleted. For instance, the bf(-C)
|
||||
option's default rules that exclude things like "CVS" and "*.o" are
|
||||
marked as perishable, and will not prevent a directory that was removed
|
||||
on the source from being deleted on the destination.
|
||||
per-directory rules apply only on the sending side. If the merge rule
|
||||
specifies sides to affect (via the bf(s) or bf(r) modifier or both),
|
||||
then the rules in the file must not specify sides (via a modifier or
|
||||
a rule prefix such as bf(hide)).
|
||||
)
|
||||
|
||||
Per-directory rules are inherited in all subdirectories of the directory
|
||||
@@ -2634,27 +2749,26 @@ of the destination trees. The write-batch option causes the rsync
|
||||
client to store in a "batch file" all the information needed to repeat
|
||||
this operation against other, identical destination trees.
|
||||
|
||||
To apply the recorded changes to another destination tree, run rsync
|
||||
with the read-batch option, specifying the name of the same batch
|
||||
file, and the destination tree. Rsync updates the destination tree
|
||||
using the information stored in the batch file.
|
||||
|
||||
For convenience, one additional file is creating when the write-batch
|
||||
option is used. This file's name is created by appending
|
||||
".sh" to the batch filename. The .sh file contains
|
||||
a command-line suitable for updating a destination tree using that
|
||||
batch file. It can be executed using a Bourne (or Bourne-like) shell,
|
||||
optionally
|
||||
passing in an alternate destination tree pathname which is then used
|
||||
instead of the original path. This is useful when the destination tree
|
||||
path differs from the original destination tree path.
|
||||
|
||||
Generating the batch file once saves having to perform the file
|
||||
status, checksum, and data block generation more than once when
|
||||
updating multiple destination trees. Multicast transport protocols can
|
||||
be used to transfer the batch update files in parallel to many hosts
|
||||
at once, instead of sending the same data to every host individually.
|
||||
|
||||
To apply the recorded changes to another destination tree, run rsync
|
||||
with the read-batch option, specifying the name of the same batch
|
||||
file, and the destination tree. Rsync updates the destination tree
|
||||
using the information stored in the batch file.
|
||||
|
||||
For your convenience, a script file is also created when the write-batch
|
||||
option is used: it will be named the same as the batch file with ".sh"
|
||||
appended. This script file contains a command-line suitable for updating a
|
||||
destination tree using the associated batch file. It can be executed using
|
||||
a Bourne (or Bourne-like) shell, optionally passing in an alternate
|
||||
destination tree pathname which is then used instead of the original
|
||||
destination path. This is useful when the destination tree path on the
|
||||
current host differs from the one used to create the batch file.
|
||||
|
||||
Examples:
|
||||
|
||||
quote(
|
||||
@@ -2746,9 +2860,9 @@ bf(--links).
|
||||
If bf(--copy-links) is specified, then symlinks are "collapsed" by
|
||||
copying their referent, rather than the symlink.
|
||||
|
||||
rsync also distinguishes "safe" and "unsafe" symbolic links. An
|
||||
example where this might be used is a web site mirror that wishes
|
||||
ensure the rsync module they copy does not include symbolic links to
|
||||
Rsync can also distinguish "safe" and "unsafe" symbolic links. An
|
||||
example where this might be used is a web site mirror that wishes to
|
||||
ensure that the rsync module that is copied does not include symbolic links to
|
||||
bf(/etc/passwd) in the public section of the site. Using
|
||||
bf(--copy-unsafe-links) will cause any links to be copied as the file
|
||||
they point to on the destination. Using bf(--safe-links) will cause
|
||||
@@ -2837,7 +2951,7 @@ dit(bf(CVSIGNORE)) The CVSIGNORE environment variable supplements any
|
||||
ignore patterns in .cvsignore files. See the bf(--cvs-exclude) option for
|
||||
more details.
|
||||
dit(bf(RSYNC_ICONV)) Specify a default bf(--iconv) setting using this
|
||||
environment variable.
|
||||
environment variable. (First supported in 3.0.0.)
|
||||
dit(bf(RSYNC_RSH)) The RSYNC_RSH environment variable allows you to
|
||||
override the default shell used as the transport for rsync. Command line
|
||||
options are permitted after the command name, just as in the bf(-e) option.
|
||||
@@ -2882,7 +2996,7 @@ url(http://rsync.samba.org/)(http://rsync.samba.org/)
|
||||
|
||||
manpagesection(VERSION)
|
||||
|
||||
This man page is current for version 3.0.3 of rsync.
|
||||
This man page is current for version 3.0.9pre1 of rsync.
|
||||
|
||||
manpagesection(INTERNAL OPTIONS)
|
||||
|
||||
@@ -2915,7 +3029,7 @@ Jean-loup Gailly and Mark Adler.
|
||||
|
||||
manpagesection(THANKS)
|
||||
|
||||
Especial thanks go out to: John Van Essen, Matt McCutchen, Wesley W. Terpstra,
|
||||
Special thanks go out to: John Van Essen, Matt McCutchen, Wesley W. Terpstra,
|
||||
David Dykstra, Jos Backus, Sebastian Krahmer, Martin Pool, and our
|
||||
gone-but-not-forgotten compadre, J.W. Schultz.
|
||||
|
||||
|
||||
30
rsync3.txt
30
rsync3.txt
@@ -1,6 +1,6 @@
|
||||
-*- indented-text -*-
|
||||
|
||||
Notes towards a new version of rsync
|
||||
Notes towards a new version of rsync
|
||||
Martin Pool <mbp@samba.org>, September 2001.
|
||||
|
||||
|
||||
@@ -13,7 +13,7 @@ Good things about the current implementation:
|
||||
|
||||
- Fairly reliable.
|
||||
|
||||
- The choice of runnning over a plain TCP socket or tunneling over
|
||||
- The choice of running over a plain TCP socket or tunneling over
|
||||
ssh.
|
||||
|
||||
- rsync operations are idempotent: you can always run the same
|
||||
@@ -51,7 +51,7 @@ Bad things about the current implementation:
|
||||
hard to modify/extend
|
||||
|
||||
- Both the program and the protocol assume a single non-interactive
|
||||
one-way transfer
|
||||
one-way transfer
|
||||
|
||||
- A list of all files are held in memory for the entire transfer,
|
||||
which cripples scalability to large file trees
|
||||
@@ -88,7 +88,7 @@ Protocol philosophy:
|
||||
|
||||
Questionable features:
|
||||
|
||||
These are neat, but not necessarily clean or worth preserving.
|
||||
These are neat, but not necessarily clean or worth preserving.
|
||||
|
||||
- The remote rsync can be wrapped by some other program, such as in
|
||||
tridge's rsync-mail scripts. The general feature of sending and
|
||||
@@ -100,7 +100,7 @@ Desirable features:
|
||||
|
||||
These don't really require architectural changes; they're just
|
||||
something to keep in mind.
|
||||
|
||||
|
||||
- Synchronize ACLs and extended attributes
|
||||
|
||||
- Anonymous servers should be efficient
|
||||
@@ -122,7 +122,7 @@ Desirable features:
|
||||
Alternatively, as long as transfers are idempotent, we can just
|
||||
restart the whole thing. [NFSv4]
|
||||
|
||||
- Scripting support.
|
||||
- Scripting support.
|
||||
|
||||
- Propagate atimes and do not modify them. This is very ugly on
|
||||
Unix. It might be better to try to add O_NOATIME to kernels, and
|
||||
@@ -224,7 +224,7 @@ Scripting hooks:
|
||||
- What basis file to use
|
||||
|
||||
- Logging
|
||||
|
||||
|
||||
- Whether to allow transfers (for public servers)
|
||||
|
||||
- Authentication
|
||||
@@ -275,7 +275,7 @@ Pie-in-the-sky features:
|
||||
|
||||
These might have a severe impact on the protocol, and are not
|
||||
clearly in our core requirements. It looks like in many of them
|
||||
having scripting hooks will allow us
|
||||
having scripting hooks will allow us
|
||||
|
||||
- Transport over UDP multicast. The hard part is handling multiple
|
||||
destinations which have different basis files. We can look at
|
||||
@@ -344,7 +344,7 @@ In favour of using a new protocol:
|
||||
|
||||
- If we start from scratch, it can be documented as we go, and we
|
||||
can avoid design decisions that make the protocol complex or
|
||||
implementation-bound.
|
||||
implementation-bound.
|
||||
|
||||
|
||||
Error handling:
|
||||
@@ -365,7 +365,7 @@ Concurrency:
|
||||
- We can do nonblocking network IO, but not so for disk.
|
||||
|
||||
- It makes sense to on the destination be generating signatures and
|
||||
applying patches at the same time.
|
||||
applying patches at the same time.
|
||||
|
||||
- Can structure this with nonblocking, threads, separate processes,
|
||||
etc.
|
||||
@@ -381,7 +381,7 @@ Uses:
|
||||
http://www.ietf.org/proceedings/00jul/00july-133.htm#P24510_1276764
|
||||
|
||||
- Sync with PDA
|
||||
|
||||
|
||||
- Network backup systems
|
||||
|
||||
- CVS filemover
|
||||
@@ -419,7 +419,7 @@ Filesystem migration:
|
||||
Atomic updates:
|
||||
|
||||
The NFSv4 working group wants atomic migration. Most of the
|
||||
responsibility for this lies on the NFS server or OS.
|
||||
responsibility for this lies on the NFS server or OS.
|
||||
|
||||
If migrating a whole tree, then we could do a nearly-atomic rename
|
||||
at the end. This ties in to having separate basis and destination
|
||||
@@ -427,11 +427,11 @@ Atomic updates:
|
||||
|
||||
There's no way in Unix to replace a whole set of files atomically.
|
||||
However, if we get them all onto the destination machine and then do
|
||||
the updates quickly it would greatly reduce the window.
|
||||
the updates quickly it would greatly reduce the window.
|
||||
|
||||
|
||||
Scalability:
|
||||
|
||||
|
||||
We should aim to work well on machines in use in a year or two.
|
||||
That probably means transfers of many millions of files in one
|
||||
batch, and gigabytes or terabytes of data.
|
||||
@@ -466,4 +466,4 @@ Related work:
|
||||
- http://freshmeat.net/search/?site=Freshmeat&q=mirror§ion=projects
|
||||
|
||||
- BitTorrent -- p2p mirroring
|
||||
http://bitconjurer.org/BitTorrent/
|
||||
http://bitconjurer.org/BitTorrent/
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
mailto(rsync-bugs@samba.org)
|
||||
manpage(rsyncd.conf)(5)(29 Jun 2008)()()
|
||||
manpage(rsyncd.conf)(5)(22 Jun 2011)()()
|
||||
manpagename(rsyncd.conf)(configuration file for rsync in daemon mode)
|
||||
manpagesynopsis()
|
||||
|
||||
@@ -101,12 +101,11 @@ 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)
|
||||
|
||||
After the global parameters you should define a number of modules, each
|
||||
@@ -213,7 +212,8 @@ 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
|
||||
@@ -256,7 +256,7 @@ 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.)
|
||||
|
||||
@@ -310,7 +310,7 @@ 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
|
||||
daemon side to behave as if the bf(--fake-user) command-line option had
|
||||
daemon side to behave as if the bf(--fake-super) command-line option had
|
||||
been specified. This allows the full attributes of a file to be stored
|
||||
without having to have the daemon actually running as root.
|
||||
|
||||
@@ -393,8 +393,8 @@ usernames and passwords are stored in the file specified by the
|
||||
"secrets file" parameter. The default is for all users to be able to
|
||||
connect without a password (this is called "anonymous rsync").
|
||||
|
||||
See also the "CONNECTING TO AN RSYNC DAEMON OVER A REMOTE SHELL
|
||||
PROGRAM" section in bf(rsync)(1) for information on how handle an
|
||||
See also the section entitled "USING RSYNC-DAEMON FEATURES VIA A REMOTE
|
||||
SHELL CONNECTION" in bf(rsync)(1) for information on how handle an
|
||||
rsyncd.conf-level username that differs from the remote-shell-level
|
||||
username when using a remote shell to connect to an rsync daemon.
|
||||
|
||||
@@ -509,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
|
||||
@@ -700,7 +700,7 @@ url(http://rsync.samba.org/)(http://rsync.samba.org/)
|
||||
|
||||
manpagesection(VERSION)
|
||||
|
||||
This man page is current for version 3.0.3 of rsync.
|
||||
This man page is current for version 3.0.9pre1 of rsync.
|
||||
|
||||
manpagesection(CREDITS)
|
||||
|
||||
|
||||
23
sender.c
23
sender.c
@@ -3,7 +3,7 @@
|
||||
*
|
||||
* Copyright (C) 1996 Andrew Tridgell
|
||||
* Copyright (C) 1996 Paul Mackerras
|
||||
* Copyright (C) 2003-2008 Wayne Davison
|
||||
* Copyright (C) 2003-2009 Wayne Davison
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
@@ -22,7 +22,6 @@
|
||||
#include "rsync.h"
|
||||
|
||||
extern int verbose;
|
||||
extern int dry_run;
|
||||
extern int do_xfers;
|
||||
extern int am_server;
|
||||
extern int am_daemon;
|
||||
@@ -127,13 +126,7 @@ 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 (!change_pathname(file, NULL, 0))
|
||||
return;
|
||||
@@ -159,7 +152,7 @@ static void write_ndx_and_attrs(int f_out, int ndx, int iflags,
|
||||
if (iflags & ITEM_XNAME_FOLLOWS)
|
||||
write_vstring(f_out, buf, len);
|
||||
#ifdef SUPPORT_XATTRS
|
||||
if (preserve_xattrs && iflags & ITEM_REPORT_XATTR && !dry_run)
|
||||
if (preserve_xattrs && iflags & ITEM_REPORT_XATTR && do_xfers)
|
||||
send_xattr_request(fname, file, f_out);
|
||||
#endif
|
||||
}
|
||||
@@ -180,6 +173,7 @@ void send_files(int f_in, int f_out)
|
||||
int itemizing = am_server ? logfile_format_has_i : stdout_format_has_i;
|
||||
enum logcode log_code = log_before_transfer ? FLOG : FINFO;
|
||||
int f_xfer = write_batch < 0 ? batch_fd : f_out;
|
||||
int save_io_error = io_error;
|
||||
int ndx, j;
|
||||
|
||||
if (verbose > 2)
|
||||
@@ -229,7 +223,7 @@ void send_files(int f_in, int f_out)
|
||||
rprintf(FINFO, "send_files(%d, %s%s%s)\n", ndx, path,slash,fname);
|
||||
|
||||
#ifdef SUPPORT_XATTRS
|
||||
if (preserve_xattrs && iflags & ITEM_REPORT_XATTR && !dry_run)
|
||||
if (preserve_xattrs && iflags & ITEM_REPORT_XATTR && do_xfers)
|
||||
recv_xattr_request(file, f_in);
|
||||
#endif
|
||||
|
||||
@@ -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);
|
||||
@@ -368,6 +362,9 @@ void send_files(int f_in, int f_out)
|
||||
if (make_backups < 0)
|
||||
make_backups = -make_backups;
|
||||
|
||||
if (io_error != save_io_error && protocol_version >= 30)
|
||||
send_msg_int(MSG_IO_ERROR, io_error);
|
||||
|
||||
if (verbose > 2)
|
||||
rprintf(FINFO, "send files finished\n");
|
||||
|
||||
|
||||
162
socket.c
162
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-2008 Wayne Davison
|
||||
* Copyright (C) 2003-2009 Wayne Davison
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
@@ -39,12 +39,11 @@ extern int connect_timeout;
|
||||
static struct sigaction sigact;
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Establish a proxy connection on an open socket to a web proxy by
|
||||
* using the CONNECT method. If proxy_user and proxy_pass are not NULL,
|
||||
* they are used to authenticate to the proxy using the "Basic"
|
||||
* proxy-authorization protocol
|
||||
**/
|
||||
static int sock_exec(const char *prog);
|
||||
|
||||
/* Establish a proxy connection on an open socket to a web proxy by using the
|
||||
* CONNECT method. If proxy_user and proxy_pass are not NULL, they are used to
|
||||
* authenticate to the proxy using the "Basic" proxy-authorization protocol. */
|
||||
static int establish_proxy_connection(int fd, char *host, int port,
|
||||
char *proxy_user, char *proxy_pass)
|
||||
{
|
||||
@@ -125,10 +124,8 @@ static int establish_proxy_connection(int fd, char *host, int port,
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Try to set the local address for a newly-created socket. Return -1
|
||||
* if this fails.
|
||||
**/
|
||||
/* Try to set the local address for a newly-created socket.
|
||||
* Return -1 if this fails. */
|
||||
int try_bind_local(int s, int ai_family, int ai_socktype,
|
||||
const char *bind_addr)
|
||||
{
|
||||
@@ -165,31 +162,27 @@ static RETSIGTYPE contimeout_handler(UNUSED(int val))
|
||||
connect_timeout = -1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Open a socket to a tcp remote host with the specified port .
|
||||
/* Open a socket to a tcp remote host with the specified port.
|
||||
*
|
||||
* Based on code from Warren. Proxy support by Stephen Rothwell.
|
||||
* getaddrinfo() rewrite contributed by KAME.net.
|
||||
*
|
||||
* Now that we support IPv6 we need to look up the remote machine's
|
||||
* address first, using @p af_hint to set a preference for the type
|
||||
* of address. Then depending on whether it has v4 or v6 addresses we
|
||||
* try to open a connection.
|
||||
* Now that we support IPv6 we need to look up the remote machine's address
|
||||
* first, using af_hint to set a preference for the type of address. Then
|
||||
* depending on whether it has v4 or v6 addresses we try to open a connection.
|
||||
*
|
||||
* The loop allows for machines with some addresses which may not be
|
||||
* reachable, perhaps because we can't e.g. route ipv6 to that network
|
||||
* but we can get ip4 packets through.
|
||||
* The loop allows for machines with some addresses which may not be reachable,
|
||||
* perhaps because we can't e.g. route ipv6 to that network but we can get ip4
|
||||
* packets through.
|
||||
*
|
||||
* @param bind_addr Local address to use. Normally NULL to bind
|
||||
* the wildcard address.
|
||||
* bind_addr: local address to use. Normally NULL to bind the wildcard address.
|
||||
*
|
||||
* @param af_hint Address family, e.g. AF_INET or AF_INET6.
|
||||
**/
|
||||
* af_hint: address family, e.g. AF_INET or AF_INET6. */
|
||||
int open_socket_out(char *host, int port, const char *bind_addr,
|
||||
int af_hint)
|
||||
{
|
||||
int type = SOCK_STREAM;
|
||||
int error, s;
|
||||
int error, s, j, addr_cnt, *errnos;
|
||||
struct addrinfo hints, *res0, *res;
|
||||
char portbuf[10];
|
||||
char *h, *cp;
|
||||
@@ -251,12 +244,17 @@ int open_socket_out(char *host, int port, const char *bind_addr,
|
||||
return -1;
|
||||
}
|
||||
|
||||
for (res = res0, addr_cnt = 0; res; res = res->ai_next, addr_cnt++) {}
|
||||
errnos = new_array0(int, addr_cnt);
|
||||
if (!errnos)
|
||||
out_of_memory("open_socket_out");
|
||||
|
||||
s = -1;
|
||||
/* Try to connect to all addresses for this machine until we get
|
||||
* through. It might e.g. be multi-homed, or have both IPv4 and IPv6
|
||||
* addresses. We need to create a socket for each record, since the
|
||||
* address record tells us what protocol to use to try to connect. */
|
||||
for (res = res0; res; res = res->ai_next) {
|
||||
for (res = res0, j = 0; res; res = res->ai_next, j++) {
|
||||
s = socket(res->ai_family, res->ai_socktype, res->ai_protocol);
|
||||
if (s < 0)
|
||||
continue;
|
||||
@@ -287,8 +285,10 @@ int open_socket_out(char *host, int port, const char *bind_addr,
|
||||
if (connect_timeout > 0)
|
||||
alarm(0);
|
||||
|
||||
if (s < 0)
|
||||
if (s < 0) {
|
||||
errnos[j] = errno;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (proxied
|
||||
&& establish_proxy_connection(s, host, port,
|
||||
@@ -300,16 +300,26 @@ int open_socket_out(char *host, int port, const char *bind_addr,
|
||||
break;
|
||||
}
|
||||
freeaddrinfo(res0);
|
||||
|
||||
if (s < 0) {
|
||||
rsyserr(FERROR, errno, "failed to connect to %s", h);
|
||||
return -1;
|
||||
char buf[2048];
|
||||
for (res = res0, j = 0; res; res = res->ai_next, j++) {
|
||||
if (errnos[j] == 0)
|
||||
continue;
|
||||
if (inet_ntop(res->ai_family, res->ai_addr->sa_data + 2, buf, sizeof buf) == NULL)
|
||||
strlcpy(buf, "*inet_ntop failed*", sizeof buf);
|
||||
rsyserr(FERROR, errnos[j], "failed to connect to %s (%s)", h, buf);
|
||||
}
|
||||
s = -1;
|
||||
}
|
||||
|
||||
free(errnos);
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Open an outgoing socket, but allow for it to be intercepted by
|
||||
/* Open an outgoing socket, but allow for it to be intercepted by
|
||||
* $RSYNC_CONNECT_PROG, which will execute a program across a TCP
|
||||
* socketpair rather than really opening a socket.
|
||||
*
|
||||
@@ -318,8 +328,7 @@ int open_socket_out(char *host, int port, const char *bind_addr,
|
||||
*
|
||||
* This is based on the Samba LIBSMB_PROG feature.
|
||||
*
|
||||
* @param bind_addr Local address to use. Normally NULL to get the stack default.
|
||||
**/
|
||||
* bind_addr: local address to use. Normally NULL to get the stack default. */
|
||||
int open_socket_out_wrapped(char *host, int port, const char *bind_addr,
|
||||
int af_hint)
|
||||
{
|
||||
@@ -372,9 +381,7 @@ int open_socket_out_wrapped(char *host, int port, const char *bind_addr,
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Open one or more sockets for incoming data using the specified type,
|
||||
/* Open one or more sockets for incoming data using the specified type,
|
||||
* port, and address.
|
||||
*
|
||||
* The getaddrinfo() call may return several address results, e.g. for
|
||||
@@ -383,9 +390,7 @@ int open_socket_out_wrapped(char *host, int port, const char *bind_addr,
|
||||
* We return an array of file-descriptors to the sockets, with a trailing
|
||||
* -1 value to indicate the end of the list.
|
||||
*
|
||||
* @param bind_addr Local address to bind, or NULL to allow it to
|
||||
* default.
|
||||
**/
|
||||
* bind_addr: local address to bind, or NULL to allow it to default. */
|
||||
static int *open_socket_in(int type, int port, const char *bind_addr,
|
||||
int af_hint)
|
||||
{
|
||||
@@ -490,9 +495,7 @@ static int *open_socket_in(int type, int port, const char *bind_addr,
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Determine if a file descriptor is in fact a socket
|
||||
*/
|
||||
/* Determine if a file descriptor is in fact a socket. */
|
||||
int is_a_socket(int fd)
|
||||
{
|
||||
int v;
|
||||
@@ -578,7 +581,7 @@ void start_accept_loop(int port, int (*fn)(int, int))
|
||||
fds = deffds;
|
||||
#endif
|
||||
|
||||
if (select(maxfd + 1, &fds, NULL, NULL, NULL) != 1)
|
||||
if (select(maxfd + 1, &fds, NULL, NULL, NULL) < 1)
|
||||
continue;
|
||||
|
||||
for (i = 0, fd = -1; sp[i] >= 0; i++) {
|
||||
@@ -660,13 +663,11 @@ struct
|
||||
#ifdef SO_RCVTIMEO
|
||||
{"SO_RCVTIMEO", SOL_SOCKET, SO_RCVTIMEO, 0, OPT_INT},
|
||||
#endif
|
||||
{NULL,0,0,0,0}};
|
||||
{NULL,0,0,0,0}
|
||||
};
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Set user socket options
|
||||
**/
|
||||
/* Set user socket options. */
|
||||
void set_socket_options(int fd, char *options)
|
||||
{
|
||||
char *tok;
|
||||
@@ -732,15 +733,10 @@ void set_socket_options(int fd, char *options)
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* This is like socketpair but uses tcp. It is used by the Samba
|
||||
* regression test code.
|
||||
*
|
||||
* The function guarantees that nobody else can attach to the socket,
|
||||
* or if they do that this function fails and the socket gets closed
|
||||
* returns 0 on success, -1 on failure the resulting file descriptors
|
||||
* are symmetrical.
|
||||
**/
|
||||
/* This is like socketpair but uses tcp. The function guarantees that nobody
|
||||
* else can attach to the socket, or if they do that this function fails and
|
||||
* the socket gets closed. Returns 0 on success, -1 on failure. The resulting
|
||||
* file descriptors are symmetrical. Currently only for RSYNC_CONNECT_PROG. */
|
||||
static int socketpair_tcp(int fd[2])
|
||||
{
|
||||
int listener;
|
||||
@@ -761,16 +757,12 @@ static int socketpair_tcp(int fd[2])
|
||||
sock2.sin_len = sizeof sock2;
|
||||
#endif
|
||||
sock2.sin_family = PF_INET;
|
||||
sock2.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
|
||||
|
||||
bind(listener, (struct sockaddr *)&sock2, sizeof sock2);
|
||||
|
||||
if (listen(listener, 1) != 0)
|
||||
goto failed;
|
||||
|
||||
if (getsockname(listener, (struct sockaddr *)&sock, &socklen) != 0)
|
||||
goto failed;
|
||||
|
||||
if ((fd[1] = socket(PF_INET, SOCK_STREAM, 0)) == -1)
|
||||
if (bind(listener, (struct sockaddr *)&sock2, sizeof sock2) != 0
|
||||
|| listen(listener, 1) != 0
|
||||
|| getsockname(listener, (struct sockaddr *)&sock, &socklen) != 0
|
||||
|| (fd[1] = socket(PF_INET, SOCK_STREAM, 0)) == -1)
|
||||
goto failed;
|
||||
|
||||
set_nonblocking(fd[1]);
|
||||
@@ -783,7 +775,7 @@ static int socketpair_tcp(int fd[2])
|
||||
} else
|
||||
connect_done = 1;
|
||||
|
||||
if ((fd[0] = accept(listener, (struct sockaddr *)&sock, &socklen)) == -1)
|
||||
if ((fd[0] = accept(listener, (struct sockaddr *)&sock2, &socklen)) == -1)
|
||||
goto failed;
|
||||
|
||||
close(listener);
|
||||
@@ -811,18 +803,15 @@ static int socketpair_tcp(int fd[2])
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Run a program on a local tcp socket, so that we can talk to it's
|
||||
* stdin and stdout. This is used to fake a connection to a daemon
|
||||
* for testing -- not for the normal case of running SSH.
|
||||
/* Run a program on a local tcp socket, so that we can talk to it's stdin and
|
||||
* stdout. This is used to fake a connection to a daemon for testing -- not
|
||||
* for the normal case of running SSH.
|
||||
*
|
||||
* @return a socket which is attached to a subprocess running
|
||||
* "prog". stdin and stdout are attached. stderr is left attached to
|
||||
* the original stderr
|
||||
**/
|
||||
int sock_exec(const char *prog)
|
||||
* Retruns a socket which is attached to a subprocess running "prog". stdin and
|
||||
* stdout are attached. stderr is left attached to the original stderr. */
|
||||
static int sock_exec(const char *prog)
|
||||
{
|
||||
pid_t pid;
|
||||
int fd[2];
|
||||
|
||||
if (socketpair_tcp(fd) != 0) {
|
||||
@@ -831,14 +820,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;
|
||||
}
|
||||
|
||||
@@ -13,7 +13,7 @@ do_cd=y # Default path is user's home dir, just like ssh.
|
||||
while : ; do
|
||||
case "$1" in
|
||||
-l) user="$2"; shift; shift ;;
|
||||
-l*) user=`echo $1 | sed 's/^-l//'`; shift ;;
|
||||
-l*) user=`echo "$1" | sed 's/^-l//'`; shift ;;
|
||||
--no-cd) do_cd=n; shift ;;
|
||||
-*) shift ;;
|
||||
localhost) shift; break ;;
|
||||
@@ -22,9 +22,9 @@ while : ; do
|
||||
done
|
||||
|
||||
if [ "$user" ]; then
|
||||
prefix="sudo -H -u $user"
|
||||
prefix="sudo -H -u '$user'"
|
||||
if [ $do_cd = y ]; then
|
||||
home=`perl -e "print((getpwnam("$user"))[7])"`
|
||||
home=`perl -e "print((getpwnam('$user'))[7])"`
|
||||
# Yeah, this may fail, but attempts to get sudo to cd are harder.
|
||||
cd $home
|
||||
fi
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
#!/usr/bin/perl -w
|
||||
#!/usr/bin/perl
|
||||
# This script takes a command-line arg of a source directory
|
||||
# that will be passed to rsync, and generates a set of excludes
|
||||
# that will exclude all mount points from the list. This is
|
||||
@@ -18,19 +18,24 @@
|
||||
# easily adapted to read /etc/mtab or similar.
|
||||
#
|
||||
# ADDENDUM: The addition of the --filter option (which has support for
|
||||
# absolute-anchored excludes) has made this script less useful than it
|
||||
# was. Beginning with 2.6.4, you can achieve the effect of this script
|
||||
# through this command:
|
||||
# absolute-anchored excludes) can make this screen unneeded in some
|
||||
# scenarios. If you don't need delete protection on the receiving side
|
||||
# (or if the destination path is identical to the source path), then you
|
||||
# can exclude some absolute paths from the transfer based on the mount
|
||||
# dirs. For instance:
|
||||
#
|
||||
# awk '{print $2}' /proc/mounts | rsync -f 'merge,/- -' host:/dir /dest/
|
||||
# awk '{print $2}' /proc/mounts | grep -v '^/$' | \
|
||||
# rsync -avf 'merge,/- -' /dir host:/dest/
|
||||
|
||||
use strict;
|
||||
use warnings;
|
||||
use Cwd 'abs_path';
|
||||
|
||||
my $file = '/proc/mounts';
|
||||
my $dir = shift || '/';
|
||||
$dir = abs_path($dir);
|
||||
$dir =~ s#([^/]*)$##;
|
||||
my $trailing_slash = $dir =~ m{./$} ? '/' : '';
|
||||
$dir = abs_path($dir) . $trailing_slash;
|
||||
$dir =~ s{([^/]*)$}{};
|
||||
my $trailing = $1;
|
||||
$trailing = '' if $trailing eq '.' || !-d "$dir$trailing";
|
||||
$trailing .= '/' if $trailing ne '';
|
||||
@@ -38,7 +43,7 @@ $trailing .= '/' if $trailing ne '';
|
||||
open(IN, $file) or die "Unable to open $file: $!\n";
|
||||
while (<IN>) {
|
||||
$_ = (split)[1];
|
||||
next unless s#^\Q$dir$trailing\E##o && $_ ne '';
|
||||
next unless s{^\Q$dir$trailing\E}{}o && $_ ne '';
|
||||
print "- /$trailing$_\n";
|
||||
}
|
||||
close IN;
|
||||
|
||||
@@ -92,7 +92,6 @@ our %long_opt = (
|
||||
'max-size' => 1,
|
||||
'min-size' => 1,
|
||||
'modify-window' => 1,
|
||||
'no-i-r' => 0,
|
||||
'no-implied-dirs' => 0,
|
||||
'no-r' => 0,
|
||||
'no-relative' => 0,
|
||||
@@ -109,6 +108,7 @@ our %long_opt = (
|
||||
'size-only' => 0,
|
||||
'skip-compress' => 1,
|
||||
'specials' => 0,
|
||||
'stats' => 0,
|
||||
'suffix' => 1,
|
||||
'super' => 0,
|
||||
'temp-dir' => 2,
|
||||
@@ -143,7 +143,8 @@ while ($command =~ /((?:[^\s\\]+|\\.[^\s\\]*)+)/g) {
|
||||
if ($_ eq '.') {
|
||||
$in_options = 0;
|
||||
} else {
|
||||
next if /^-$short_no_arg+(e\d*\.\w*)?$/o || /^-$short_with_num\d+$/o;
|
||||
die "$0: invalid option: '-'\n" if $_ eq '-';
|
||||
next if /^-$short_no_arg*(e\d*\.\w*)?$/o || /^-$short_with_num\d+$/o;
|
||||
|
||||
my($opt,$arg) = /^--([^=]+)(?:=(.*))?$/;
|
||||
my $disabled;
|
||||
@@ -174,10 +175,10 @@ while ($command =~ /((?:[^\s\\]+|\\.[^\s\\]*)+)/g) {
|
||||
} else {
|
||||
if ($subdir ne '/') {
|
||||
# Validate args to ensure they don't try to leave our restricted dir.
|
||||
s#//+#/#g;
|
||||
s#^/##;
|
||||
s#^$#.#;
|
||||
die "Do not use .. in any path!\n" if m#(^|/)\\?\.\\?\.(\\?/|$)#;
|
||||
s{//+}{/}g;
|
||||
s{^/}{};
|
||||
s{^$}{.};
|
||||
die "$0: do not use .. in any path!\n" if m{(^|/)\\?\.\\?\.(\\?/|$)};
|
||||
}
|
||||
push(@args, bsd_glob($_, GLOB_LIMIT|GLOB_NOCHECK|GLOB_BRACE|GLOB_QUOTE));
|
||||
}
|
||||
@@ -204,10 +205,10 @@ sub check_arg
|
||||
my($opt, $arg, $type) = @_;
|
||||
$arg =~ s/\\(.)/$1/g;
|
||||
if ($subdir ne '/' && ($type == 3 || ($type == 2 && !$am_sender))) {
|
||||
$arg =~ s#//#/#g;
|
||||
$arg =~ s{//}{/}g;
|
||||
die "Do not use .. in --$opt; anchor the path at the root of your restricted dir.\n"
|
||||
if $arg =~ m#(^|/)\.\.(/|$)#;
|
||||
$arg =~ s#^/#$subdir/#;
|
||||
if $arg =~ m{(^|/)\.\.(/|$)};
|
||||
$arg =~ s{^/}{$subdir/};
|
||||
}
|
||||
$arg;
|
||||
}
|
||||
|
||||
104
syscall.c
104
syscall.c
@@ -4,7 +4,7 @@
|
||||
*
|
||||
* Copyright (C) 1998 Andrew Tridgell
|
||||
* Copyright (C) 2002 Martin Pool
|
||||
* Copyright (C) 2003-2008 Wayne Davison
|
||||
* Copyright (C) 2003-2009 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
|
||||
@@ -152,10 +152,11 @@ int do_chmod(const char *path, mode_t mode)
|
||||
int code;
|
||||
if (dry_run) return 0;
|
||||
RETURN_ERROR_IF_RO_OR_LO;
|
||||
if (S_ISLNK(mode)) {
|
||||
#ifdef HAVE_LCHMOD
|
||||
code = lchmod(path, mode & CHMOD_BITS);
|
||||
#elif defined HAVE_SETATTRLIST
|
||||
code = lchmod(path, mode & CHMOD_BITS);
|
||||
#else
|
||||
if (S_ISLNK(mode)) {
|
||||
# if defined HAVE_SETATTRLIST
|
||||
struct attrlist attrList;
|
||||
uint32_t m = mode & CHMOD_BITS; /* manpage is wrong: not mode_t! */
|
||||
|
||||
@@ -163,11 +164,12 @@ int do_chmod(const char *path, mode_t mode)
|
||||
attrList.bitmapcount = ATTR_BIT_MAP_COUNT;
|
||||
attrList.commonattr = ATTR_CMN_ACCESSMASK;
|
||||
code = setattrlist(path, &attrList, &m, sizeof m, FSOPT_NOFOLLOW);
|
||||
#else
|
||||
# else
|
||||
code = 1;
|
||||
#endif
|
||||
# endif
|
||||
} else
|
||||
code = chmod(path, mode & CHMOD_BITS); /* DISCOURAGED FUNCTION */
|
||||
#endif /* !HAVE_LCHMOD */
|
||||
if (code != 0 && (preserve_perms || preserve_executability))
|
||||
return code;
|
||||
return 0;
|
||||
@@ -181,6 +183,22 @@ int do_rename(const char *fname1, const char *fname2)
|
||||
return rename(fname1, fname2);
|
||||
}
|
||||
|
||||
#ifdef HAVE_FTRUNCATE
|
||||
int do_ftruncate(int fd, OFF_T size)
|
||||
{
|
||||
int ret;
|
||||
|
||||
if (dry_run) return 0;
|
||||
RETURN_ERROR_IF_RO_OR_LO;
|
||||
|
||||
do {
|
||||
ret = ftruncate(fd, size);
|
||||
} while (ret < 0 && errno == EINTR);
|
||||
|
||||
return ret;
|
||||
}
|
||||
#endif
|
||||
|
||||
void trim_trailing_slashes(char *name)
|
||||
{
|
||||
int l;
|
||||
@@ -282,3 +300,77 @@ OFF_T do_lseek(int fd, OFF_T offset, int whence)
|
||||
return lseek(fd, offset, whence);
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifdef HAVE_UTIMENSAT
|
||||
int do_utimensat(const char *fname, time_t modtime, uint32 mod_nsec)
|
||||
{
|
||||
struct timespec t[2];
|
||||
|
||||
if (dry_run) return 0;
|
||||
RETURN_ERROR_IF_RO_OR_LO;
|
||||
|
||||
t[0].tv_sec = 0;
|
||||
t[0].tv_nsec = UTIME_NOW;
|
||||
t[1].tv_sec = modtime;
|
||||
t[1].tv_nsec = mod_nsec;
|
||||
return utimensat(AT_FDCWD, fname, t, AT_SYMLINK_NOFOLLOW);
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_LUTIMES
|
||||
int do_lutimes(const char *fname, time_t modtime, uint32 mod_nsec)
|
||||
{
|
||||
struct timeval t[2];
|
||||
|
||||
if (dry_run) return 0;
|
||||
RETURN_ERROR_IF_RO_OR_LO;
|
||||
|
||||
t[0].tv_sec = time(NULL);
|
||||
t[0].tv_usec = 0;
|
||||
t[1].tv_sec = modtime;
|
||||
t[1].tv_usec = mod_nsec / 1000;
|
||||
return lutimes(fname, t);
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_UTIMES
|
||||
int do_utimes(const char *fname, time_t modtime, uint32 mod_nsec)
|
||||
{
|
||||
struct timeval t[2];
|
||||
|
||||
if (dry_run) return 0;
|
||||
RETURN_ERROR_IF_RO_OR_LO;
|
||||
|
||||
t[0].tv_sec = time(NULL);
|
||||
t[0].tv_usec = 0;
|
||||
t[1].tv_sec = modtime;
|
||||
t[1].tv_usec = mod_nsec / 1000;
|
||||
return utimes(fname, t);
|
||||
}
|
||||
|
||||
#elif defined HAVE_UTIME
|
||||
int do_utime(const char *fname, time_t modtime, UNUSED(uint32 mod_nsec))
|
||||
{
|
||||
#ifdef HAVE_STRUCT_UTIMBUF
|
||||
struct utimbuf tbuf;
|
||||
#else
|
||||
time_t t[2];
|
||||
#endif
|
||||
|
||||
if (dry_run) return 0;
|
||||
RETURN_ERROR_IF_RO_OR_LO;
|
||||
|
||||
# ifdef HAVE_STRUCT_UTIMBUF
|
||||
tbuf.actime = time(NULL);
|
||||
tbuf.modtime = modtime;
|
||||
return utime(fname, &tbuf);
|
||||
# else
|
||||
t[0] = time(NULL);
|
||||
t[1] = modtime;
|
||||
return utime(fname, t);
|
||||
# endif
|
||||
}
|
||||
|
||||
#else
|
||||
#error Need utimes or utime function.
|
||||
#endif
|
||||
|
||||
3
t_stub.c
3
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-2008 Wayne Davison
|
||||
* Copyright (C) 2003-2009 Wayne Davison
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
@@ -26,6 +26,7 @@ int module_id = -1;
|
||||
int relative_paths = 0;
|
||||
int human_readable = 0;
|
||||
int module_dirlen = 0;
|
||||
int preserve_times = 0;
|
||||
int preserve_xattrs = 0;
|
||||
mode_t orig_umask = 002;
|
||||
char *partial_dir;
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
* Test harness for unsafe_symlink(). Not linked into rsync itself.
|
||||
*
|
||||
* Copyright (C) 2002 Martin Pool
|
||||
* Copyright (C) 2003-2008 Wayne Davison
|
||||
* Copyright (C) 2003-2009 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,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"'
|
||||
|
||||
@@ -13,12 +13,19 @@
|
||||
|
||||
hands_setup
|
||||
|
||||
tmpdir2=/tmp
|
||||
tmpdir2=$RSYNC_TEST_TMP
|
||||
if [ x"$tmpdir2" = x ]; then
|
||||
tmpdir2=/tmp
|
||||
fi
|
||||
sdev=`$TOOLDIR/getfsdev $scratchdir`
|
||||
tdev=`$TOOLDIR/getfsdev $tmpdir2`
|
||||
if [ x$sdev = x$tdev ]; then
|
||||
tmpdir2=/var/tmp
|
||||
tdev=`$TOOLDIR/getfsdev $tmpdir2`
|
||||
if [ -d $tmpdir2 ]; then
|
||||
tdev=`$TOOLDIR/getfsdev $tmpdir2`
|
||||
else
|
||||
tdev="$sdev"
|
||||
fi
|
||||
[ x$sdev = x$tdev ] && test_skipped "Can't find a tmp dir on a different file system"
|
||||
fi
|
||||
|
||||
|
||||
@@ -37,7 +37,7 @@ case $0 in
|
||||
;;
|
||||
*)
|
||||
RSYNC="$RSYNC --super"
|
||||
case `id -u` in
|
||||
case `get_testuid` in
|
||||
'') ;; # If "id" failed, try to continue...
|
||||
0) ;;
|
||||
*) if [ -f /usr/bin/fakeroot ]; then
|
||||
|
||||
@@ -25,6 +25,7 @@ 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];####/##/## ##:##:##;'
|
||||
|
||||
@@ -41,7 +42,7 @@ cd "$scratchdir"
|
||||
ln -s test-rsyncd.conf rsyncd.conf
|
||||
|
||||
confopt=''
|
||||
case `id -u` in
|
||||
case `get_testuid` in
|
||||
0)
|
||||
# Root needs to specify the config file, or it uses /etc/rsyncd.conf.
|
||||
echo "Forcing --config=$conf"
|
||||
@@ -65,7 +66,7 @@ EOT
|
||||
diff $diffopt "$chkfile" "$outfile" || test_fail "test 1 failed"
|
||||
|
||||
$RSYNC -r localhost::test-hidden \
|
||||
| sed "$DIR_REPL" | sed "$LS_REPL" \
|
||||
| sed "$FILE_REPL" | sed "$DIR_REPL" | sed "$LS_REPL" \
|
||||
| tee "$outfile"
|
||||
cat <<EOT >"$chkfile"
|
||||
drwxr-xr-x DIR ####/##/## ##:##:## .
|
||||
@@ -79,7 +80,7 @@ EOT
|
||||
diff $diffopt "$chkfile" "$outfile" || test_fail "test 2 failed"
|
||||
|
||||
$RSYNC -r localhost::test-from/f* \
|
||||
| sed "$DIR_REPL" | sed "$LS_REPL" \
|
||||
| sed "$FILE_REPL" | sed "$DIR_REPL" | sed "$LS_REPL" \
|
||||
| tee "$outfile"
|
||||
cat <<EOT >"$chkfile"
|
||||
drwxr-xr-x DIR ####/##/## ##:##:## foo
|
||||
|
||||
@@ -51,7 +51,7 @@ case $0 in
|
||||
esac
|
||||
;;
|
||||
*)
|
||||
case `id -u` in
|
||||
case `get_testuid` in
|
||||
'') ;; # If "id" failed, try to continue...
|
||||
0) ;;
|
||||
*) if [ -f /usr/bin/fakeroot ]; then
|
||||
@@ -117,7 +117,7 @@ cD$all_plus char3
|
||||
cS$all_plus fifo
|
||||
EOT
|
||||
if test ! -r "$fromdir/block2.5"; then
|
||||
sed -e '/block2\.5/d' <"$chkfile" >"$chkfile.new"
|
||||
grep -v block2.5 <"$chkfile" >"$chkfile.new"
|
||||
mv "$chkfile.new" "$chkfile"
|
||||
fi
|
||||
diff $diffopt "$chkfile" "$outfile" || test_fail "test 4 failed"
|
||||
@@ -128,7 +128,7 @@ echo ""
|
||||
( cd "$todir" && rsync_ls_lR . ) > "$tmpdir/ls-to"
|
||||
diff $diffopt "$tmpdir/ls-from" "$tmpdir/ls-to"
|
||||
|
||||
if test -b "$fromdir/block2.5"; then
|
||||
if test -r "$fromdir/block2.5"; then
|
||||
set -x
|
||||
$RSYNC -aii --link-dest="$todir" "$fromdir/" "$chkdir/" \
|
||||
| tee "$outfile"
|
||||
@@ -143,7 +143,7 @@ hD$allspace char2
|
||||
hD$allspace char3
|
||||
hS$allspace fifo
|
||||
EOT
|
||||
diff $diffopt "$chkfile" "$outfile" || test_fail "test 4 failed"
|
||||
diff $diffopt "$chkfile" "$outfile" || test_fail "test 5 failed"
|
||||
fi
|
||||
|
||||
# The script would have aborted on error, so getting here means we've won.
|
||||
|
||||
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
|
||||
@@ -28,7 +28,7 @@ name2="$fromdir/name2"
|
||||
name3="$fromdir/name3"
|
||||
name4="$fromdir/name4"
|
||||
echo "This is the file" > "$name1"
|
||||
ln "$name1" "$name2" || fail "Can't create hardlink"
|
||||
ln "$name1" "$name2" || test_skipped "Can't create hardlink"
|
||||
ln "$name2" "$name3" || fail "Can't create hardlink"
|
||||
cp "$name2" "$name4" || fail "Can't copy file"
|
||||
cat $srcdir/*.c >"$fromdir/text"
|
||||
|
||||
@@ -17,7 +17,7 @@ outfile="$scratchdir/rsync.out"
|
||||
|
||||
makepath "$fromdir/foo"
|
||||
makepath "$fromdir/bar/baz"
|
||||
cp -p "$srcdir/configure.in" "$fromdir/foo/config1"
|
||||
cp -p "$srcdir/configure.ac" "$fromdir/foo/config1"
|
||||
cp -p "$srcdir/config.h.in" "$fromdir/foo/config2"
|
||||
cp -p "$srcdir/rsync.h" "$fromdir/bar/baz/rsync"
|
||||
chmod 600 "$fromdir"/foo/config? "$fromdir/bar/baz/rsync"
|
||||
@@ -66,7 +66,7 @@ diff $diffopt "$chkfile" "$outfile" || test_fail "test 1 failed"
|
||||
# Ensure there are no accidental directory-time problems.
|
||||
$RSYNC -a -f '-! */' "$fromdir/" "$todir"
|
||||
|
||||
cp -p "$srcdir/configure.in" "$fromdir/foo/config2"
|
||||
cp -p "$srcdir/configure.ac" "$fromdir/foo/config2"
|
||||
chmod 601 "$fromdir/foo/config2"
|
||||
$RSYNC -iplrH "$fromdir/" "$todir/" \
|
||||
| tee "$outfile"
|
||||
@@ -99,7 +99,7 @@ cLc$T.$dots foo/sym -> ../bar/baz/rsync
|
||||
EOT
|
||||
diff $diffopt "$chkfile" "$outfile" || test_fail "test 3 failed"
|
||||
|
||||
cp -p "$srcdir/configure.in" "$fromdir/foo/config2"
|
||||
cp -p "$srcdir/configure.ac" "$fromdir/foo/config2"
|
||||
chmod 600 "$fromdir/foo/config2"
|
||||
# Lack of -t is for unchanged hard-link stress-test!
|
||||
$RSYNC -vvplrH "$fromdir/" "$todir/" \
|
||||
|
||||
@@ -27,6 +27,7 @@ chkdir="$tmpdir/chk"
|
||||
all_plus='+++++++++'
|
||||
allspace=' '
|
||||
dots='.....' # trailing dots after changes
|
||||
tab_ch=' ' # a single tab character
|
||||
|
||||
# Berkley's nice.
|
||||
PATH="$PATH:/usr/ucb"
|
||||
@@ -100,6 +101,10 @@ rsync_ls_lR() {
|
||||
find "$@" -print | sort | sed 's/ /\\ /g' | xargs "$TOOLDIR/tls" $TLS_ARGS
|
||||
}
|
||||
|
||||
get_testuid() {
|
||||
id 2>/dev/null | sed 's/^[^0-9]*\([0-9][0-9]*\).*/\1/'
|
||||
}
|
||||
|
||||
check_perms() {
|
||||
perms=`"$TOOLDIR/tls" "$1" | sed 's/^[-d]\(.........\).*/\1/'`
|
||||
if test $perms = $2; then
|
||||
@@ -219,7 +224,7 @@ checkit() {
|
||||
eval "$1"
|
||||
status=$?
|
||||
if [ $status != 0 ]; then
|
||||
failed="YES";
|
||||
failed="$failed status=$status"
|
||||
fi
|
||||
|
||||
echo "-------------"
|
||||
@@ -227,7 +232,7 @@ checkit() {
|
||||
echo ""
|
||||
( cd "$2" && rsync_ls_lR . ) > "$tmpdir/ls-from"
|
||||
( cd "$3" && rsync_ls_lR . ) > "$tmpdir/ls-to"
|
||||
diff $diffopt "$tmpdir/ls-from" "$tmpdir/ls-to" || failed=YES
|
||||
diff $diffopt "$tmpdir/ls-from" "$tmpdir/ls-to" || failed="$failed dir-diff"
|
||||
|
||||
echo "-------------"
|
||||
echo "check how the files compare with diff:"
|
||||
@@ -235,15 +240,16 @@ checkit() {
|
||||
if [ "x$4" != x ]; then
|
||||
echo " === Skipping (as directed) ==="
|
||||
else
|
||||
diff -r $diffopt "$2" "$3" || failed=YES
|
||||
diff -r $diffopt "$2" "$3" || failed="$failed file-diff"
|
||||
fi
|
||||
|
||||
echo "-------------"
|
||||
if [ -z "$failed" ] ; then
|
||||
return 0
|
||||
else
|
||||
return 1
|
||||
fi
|
||||
|
||||
echo "Failed: $failed"
|
||||
return 1
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -18,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
|
||||
|
||||
|
||||
@@ -19,33 +19,41 @@ test_unsafe() {
|
||||
fi
|
||||
}
|
||||
|
||||
test_unsafe file from safe
|
||||
test_unsafe dir/file from safe
|
||||
test_unsafe dir/./file from safe
|
||||
test_unsafe dir/. from safe
|
||||
test_unsafe dir/ from safe
|
||||
test_unsafe file from safe
|
||||
test_unsafe dir/file from safe
|
||||
test_unsafe dir/./file from safe
|
||||
test_unsafe dir/. from safe
|
||||
test_unsafe dir/ from safe
|
||||
|
||||
test_unsafe /etc/passwd from unsafe
|
||||
test_unsafe //../etc/passwd from unsafe
|
||||
test_unsafe //./etc/passwd from unsafe
|
||||
test_unsafe /etc/passwd from unsafe
|
||||
test_unsafe //../etc/passwd from unsafe
|
||||
test_unsafe //./etc/passwd from unsafe
|
||||
|
||||
test_unsafe ./foo from safe
|
||||
test_unsafe ../foo from unsafe
|
||||
test_unsafe ../dest from/dir safe
|
||||
test_unsafe ./foo from safe
|
||||
test_unsafe ../foo from unsafe
|
||||
test_unsafe ./../foo from unsafe
|
||||
test_unsafe .//../foo from unsafe
|
||||
test_unsafe ./../foo from/.. unsafe
|
||||
test_unsafe ../dest from/dir safe
|
||||
test_unsafe ../../dest from//dir unsafe
|
||||
test_unsafe ..//../dest from/dir unsafe
|
||||
|
||||
test_unsafe .. from/file safe
|
||||
test_unsafe ../.. from/file unsafe
|
||||
test_unsafe dir/.. from safe
|
||||
test_unsafe dir/../.. from unsafe
|
||||
test_unsafe .. from/file safe
|
||||
test_unsafe ../.. from/file unsafe
|
||||
test_unsafe ..//.. from//file unsafe
|
||||
test_unsafe dir/.. from safe
|
||||
test_unsafe dir/../.. from unsafe
|
||||
test_unsafe dir/..//.. from unsafe
|
||||
|
||||
test_unsafe '' from unsafe
|
||||
test_unsafe '' from unsafe
|
||||
|
||||
# Based on tests from unsafe-links by Vladim<69>r Michl
|
||||
test_unsafe ../../unsafe/unsafefile from/safe unsafe
|
||||
test_unsafe ../files/file1 from/safe safe
|
||||
test_unsafe ../../unsafe/unsafefile from/safe unsafe
|
||||
test_unsafe ..//../unsafe/unsafefile from/safe unsafe
|
||||
test_unsafe ../files/file1 from/safe safe
|
||||
|
||||
test_unsafe ../../unsafe/unsafefile safe unsafe
|
||||
test_unsafe ../files/file1 safe unsafe
|
||||
test_unsafe ../../unsafe/unsafefile safe unsafe
|
||||
test_unsafe ../files/file1 safe unsafe
|
||||
|
||||
test_unsafe ../../unsafe/unsafefile `pwd`/from/safe safe
|
||||
test_unsafe ../files/file1 `pwd`/from/safe safe
|
||||
test_unsafe ../../unsafe/unsafefile `pwd`/from/safe safe
|
||||
test_unsafe ../files/file1 `pwd`/from/safe safe
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
# Test that rsync handles basic xattr preservation.
|
||||
|
||||
. $srcdir/testsuite/rsync.fns
|
||||
lnkdir="$tmpdir/lnk"
|
||||
|
||||
$RSYNC --version | grep ", xattrs" >/dev/null || test_skipped "Rsync is configured without xattr support"
|
||||
|
||||
@@ -18,8 +19,9 @@ case "`xattr 2>&1`" in
|
||||
xattr -s "$xnam" "$xval" "${@}"
|
||||
}
|
||||
xls() {
|
||||
xattr -l "${@}"
|
||||
xattr -l "${@}" | sed "s/^[ $tab_ch]*//"
|
||||
}
|
||||
RSYNC_PREFIX='rsync'
|
||||
RUSR='rsync.nonuser'
|
||||
;;
|
||||
*)
|
||||
@@ -32,11 +34,12 @@ case "`xattr 2>&1`" in
|
||||
xls() {
|
||||
getfattr -d "${@}"
|
||||
}
|
||||
RSYNC_PREFIX='user.rsync'
|
||||
RUSR='user.rsync'
|
||||
;;
|
||||
esac
|
||||
|
||||
makepath "$fromdir/foo/bar"
|
||||
makepath "$lnkdir" "$fromdir/foo/bar"
|
||||
echo now >"$fromdir/file0"
|
||||
echo something >"$fromdir/file1"
|
||||
echo else >"$fromdir/file2"
|
||||
@@ -48,7 +51,10 @@ makepath "$chkdir/foo"
|
||||
echo wow >"$chkdir/file1"
|
||||
cp_touch "$fromdir/foo/file3" "$chkdir/foo"
|
||||
|
||||
files='foo file0 file1 file2 foo/file3 file4 foo/bar/file5'
|
||||
dirs='foo foo/bar'
|
||||
files='file0 file1 file2 foo/file3 file4 foo/bar/file5'
|
||||
|
||||
uid_gid=`"$TOOLDIR/tls" "$fromdir/foo" | sed 's/^.* \([0-9][0-9]*\)\.\([0-9][0-9]*\) .*/\1:\2/'`
|
||||
|
||||
cd "$fromdir"
|
||||
|
||||
@@ -68,62 +74,116 @@ 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.dir4 'another dir test' foo/bar
|
||||
xset user.dir5 'one last one' foo/bar
|
||||
|
||||
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 $RUSR.equal 'this long attribute should remain the same and not need to be transferred' foo/file3 foo/bar/file5
|
||||
|
||||
xset user.dir0 'old extra value' "$chkdir/foo"
|
||||
xset user.dir1 'old dir value' "$chkdir/foo"
|
||||
|
||||
xset user.short 'old short' "$chkdir/file1"
|
||||
xset user.extra 'remove me' "$chkdir/file1"
|
||||
|
||||
xset user.foo 'old foo' "$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"
|
||||
case $0 in
|
||||
*hlink*)
|
||||
ln foo/bar/file5 foo/bar/file6 || test_skipped "Can't create hardlink"
|
||||
files="$files foo/bar/file6"
|
||||
dashH='-H'
|
||||
altDest='--link-dest'
|
||||
;;
|
||||
*)
|
||||
dashH=''
|
||||
altDest='--copy-dest'
|
||||
;;
|
||||
esac
|
||||
|
||||
xls $dirs $files >"$scratchdir/xattrs.txt"
|
||||
|
||||
# OK, let's try a simple xattr copy.
|
||||
checkit "$RSYNC -avX --super . '$chkdir/'" "$fromdir" "$chkdir"
|
||||
checkit "$RSYNC -avX $dashH --super . '$chkdir/'" "$fromdir" "$chkdir"
|
||||
|
||||
cd "$chkdir"
|
||||
xls $files | diff $diffopt "$scratchdir/xattrs.txt" -
|
||||
xls $dirs $files | diff $diffopt "$scratchdir/xattrs.txt" -
|
||||
|
||||
cd "$fromdir"
|
||||
|
||||
checkit "$RSYNC -aiX --super --copy-dest=../chk . ../to" "$fromdir" "$todir"
|
||||
if [ "$dashH" ]; then
|
||||
for fn in $files; do
|
||||
name=`basename $fn`
|
||||
ln $fn ../lnk/$name
|
||||
done
|
||||
fi
|
||||
|
||||
checkit "$RSYNC -aiX $dashH --super $altDest=../chk . ../to" "$fromdir" "$todir"
|
||||
|
||||
cd "$todir"
|
||||
xls $files | diff $diffopt "$scratchdir/xattrs.txt" -
|
||||
xls $dirs $files | diff $diffopt "$scratchdir/xattrs.txt" -
|
||||
|
||||
[ "$dashH" ] && rm -rf "$lnkdir"
|
||||
|
||||
cd "$fromdir"
|
||||
rm -rf "$todir"
|
||||
|
||||
xset user.nice 'this is nice, but different' file1
|
||||
|
||||
xls $files >"$scratchdir/xattrs.txt"
|
||||
xls $dirs $files >"$scratchdir/xattrs.txt"
|
||||
|
||||
checkit "$RSYNC -aiX --fake-super --link-dest=../chk . ../to" "$chkdir" "$todir"
|
||||
checkit "$RSYNC -aiX $dashH --fake-super --link-dest=../chk . ../to" "$chkdir" "$todir"
|
||||
|
||||
cd "$todir"
|
||||
xls $files | diff $diffopt "$scratchdir/xattrs.txt" -
|
||||
xls $dirs $files | diff $diffopt "$scratchdir/xattrs.txt" -
|
||||
|
||||
sed -n -e '/\.\/file1$/d' -e '/^[^ ][^ ]* *[^ ][^ ]* *[^ ][^ ]* *1 /p' "$scratchdir/ls-to" >"$scratchdir/ls-diff"
|
||||
sed -n -e '/^[^ ][^ ]* *[^ ][^ ]* *[^ ][^ ]* *1 /p' "$scratchdir/ls-to" >"$scratchdir/ls-diff-all"
|
||||
fgrep -v './file1' "$scratchdir/ls-diff-all" >"$scratchdir/ls-diff" || :
|
||||
if [ -s "$scratchdir/ls-diff" ]; then
|
||||
echo "Missing hard links on:"
|
||||
cat "$scratchdir/ls-diff"
|
||||
exit 1
|
||||
fi
|
||||
if [ ! -s "$scratchdir/ls-diff-all" ]; then
|
||||
echo "Too many hard links on file1!"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
cd "$chkdir"
|
||||
chmod go-rwx . $dirs $files
|
||||
|
||||
xset user.nice 'this is nice, but different' file1
|
||||
xset $RSYNC_PREFIX.%stat "40000 0,0 $uid_gid" $dirs
|
||||
xset $RSYNC_PREFIX.%stat "100000 0,0 $uid_gid" $files
|
||||
|
||||
xls $dirs $files >"$scratchdir/xattrs.txt"
|
||||
|
||||
cd "$fromdir"
|
||||
rm -rf "$todir"
|
||||
|
||||
# When run by a non-root tester, this checks if no-user-perm files/dirs can be copied.
|
||||
checkit "$RSYNC -aiX $dashH --fake-super --chmod=a= . ../to" "$chkdir" "$todir" # 2>"$scratchdir/errors.txt"
|
||||
|
||||
cd "$todir"
|
||||
xls $dirs $files | diff $diffopt "$scratchdir/xattrs.txt" -
|
||||
|
||||
cd "$fromdir"
|
||||
rm -rf "$todir" "$chkdir"
|
||||
|
||||
rsync -aX file1 file2
|
||||
rsync -aX file1 file2 ../chk/
|
||||
rsync -aX --del ../chk/ .
|
||||
rsync -aX file1 ../lnk/
|
||||
$RSYNC -aX file1 file2
|
||||
$RSYNC -aX file1 file2 ../chk/
|
||||
$RSYNC -aX --del ../chk/ .
|
||||
$RSYNC -aX file1 ../lnk/
|
||||
[ "$dashH" ] && ln "$chkdir/file1" ../lnk/extra-link
|
||||
|
||||
xls file1 file2 >"$scratchdir/xattrs.txt"
|
||||
|
||||
checkit "$RSYNC -aiiX --copy-dest=../lnk . ../to" "$chkdir" "$todir"
|
||||
checkit "$RSYNC -aiiX $dashH $altDest=../lnk . ../to" "$chkdir" "$todir"
|
||||
|
||||
[ "$dashH" ] && rm ../lnk/extra-link
|
||||
|
||||
cd "$todir"
|
||||
xls file1 file2 | diff $diffopt "$scratchdir/xattrs.txt" -
|
||||
@@ -132,7 +192,7 @@ cd "$fromdir"
|
||||
rm "$todir/file2"
|
||||
|
||||
echo extra >file1
|
||||
rsync -aX . ../chk/
|
||||
$RSYNC -aX . ../chk/
|
||||
|
||||
checkit "$RSYNC -aiiX . ../to" "$chkdir" "$todir"
|
||||
|
||||
|
||||
2
tls.c
2
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-2008 Wayne Davison
|
||||
* Copyright (C) 2003-2009 Wayne Davison
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
|
||||
17
token.c
17
token.c
@@ -3,7 +3,7 @@
|
||||
*
|
||||
* Copyright (C) 1996 Andrew Tridgell
|
||||
* Copyright (C) 1996 Paul Mackerras
|
||||
* Copyright (C) 2003-2008 Wayne Davison
|
||||
* Copyright (C) 2003-2009 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,12 +45,12 @@ static void add_suffix(struct suffix_tree **prior, char ltr, const char *str)
|
||||
|
||||
if (ltr == '[') {
|
||||
const char *after = strchr(str, ']');
|
||||
/* Just skip bogus character classes. */
|
||||
if (!after++)
|
||||
/* Treat "[foo" and "[]" as having a literal '['. */
|
||||
if (after && after++ != str+1) {
|
||||
while ((ltr = *str++) != ']')
|
||||
add_suffix(prior, ltr, after);
|
||||
return;
|
||||
while ((ltr = *str++) != ']')
|
||||
add_suffix(prior, ltr, after);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
for (node = *prior; node; prior = &node->sibling, node = node->sibling) {
|
||||
@@ -100,7 +100,6 @@ static void add_nocompress_suffixes(const char *str)
|
||||
} while (*++f != '/' && *f);
|
||||
*t++ = '\0';
|
||||
|
||||
fprintf(stderr, "adding `%s'\n", buf);
|
||||
add_suffix(&suftree, *buf, buf+1);
|
||||
}
|
||||
|
||||
@@ -193,6 +192,8 @@ void set_compression(const char *fname)
|
||||
return;
|
||||
|
||||
while (1) {
|
||||
if (isUpper(<r))
|
||||
ltr = toLower(<r);
|
||||
while (node->letter != ltr) {
|
||||
if (node->letter > ltr)
|
||||
return;
|
||||
@@ -599,7 +600,7 @@ static void see_deflate_token(char *buf, int32 len)
|
||||
rx_strm.next_out = (Bytef *)dbuf;
|
||||
rx_strm.avail_out = AVAIL_OUT_SIZE(CHUNK_SIZE);
|
||||
r = inflate(&rx_strm, Z_SYNC_FLUSH);
|
||||
if (r != Z_OK) {
|
||||
if (r != Z_OK && r != Z_BUF_ERROR) {
|
||||
rprintf(FERROR, "inflate (token) returned %d\n", r);
|
||||
exit_cleanup(RERR_STREAMIO);
|
||||
}
|
||||
|
||||
@@ -1,19 +1,10 @@
|
||||
#!/usr/bin/perl -i -p
|
||||
|
||||
# Make some hyphens unbreakable.
|
||||
s{(--\w[-\w]+)}{ $x = $1; $x =~ s/-/\\-/g; $x }eg;
|
||||
s/(?<!\\)-(['"\d*])/\\-$1/g;
|
||||
s#(['"(= /,])-(?!-)#$1\\-#g;
|
||||
s/(\\fB)-/$1\\-/g;
|
||||
s/(\[\w)-(\w\])/$1\\-$2/g;
|
||||
s{(\\f\(CW.*?\\fP)}{ $x = $1; $x =~ s/(?<!\\)-/\\-/g; $x }eg;
|
||||
s/(\.\w+)-/$1\\-/g;
|
||||
use strict;
|
||||
use warnings;
|
||||
|
||||
# We only need to use "\&'" or "\&." at the start of a line.
|
||||
s/(?<=.)\\\&(['.])/$1$2/g;
|
||||
|
||||
# Use an em-dash where appropriate.
|
||||
s/ \\?-{1,2} / \\(em /g;
|
||||
s/(?<=.)\\\&(['.])/$1/g;
|
||||
|
||||
# Some quotes turn into open/close quotes.
|
||||
s/'(.)'/\\(oq$1\\(cq/g;
|
||||
|
||||
10
uidlist.c
10
uidlist.c
@@ -3,7 +3,7 @@
|
||||
*
|
||||
* Copyright (C) 1996 Andrew Tridgell
|
||||
* Copyright (C) 1996 Paul Mackerras
|
||||
* Copyright (C) 2004-2008 Wayne Davison
|
||||
* Copyright (C) 2004-2009 Wayne Davison
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
@@ -39,8 +39,6 @@ extern int numeric_ids;
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#define GID_NONE ((gid_t)-1)
|
||||
|
||||
struct idlist {
|
||||
struct idlist *next;
|
||||
const char *name;
|
||||
@@ -103,12 +101,12 @@ static gid_t map_gid(gid_t id, const char *name)
|
||||
static int is_in_group(gid_t gid)
|
||||
{
|
||||
#ifdef HAVE_GETGROUPS
|
||||
static gid_t last_in = GID_NONE, last_out;
|
||||
static int ngroups = -2;
|
||||
static gid_t last_in;
|
||||
static int ngroups = -2, last_out = -1;
|
||||
static GETGROUPS_T *gidset;
|
||||
int n;
|
||||
|
||||
if (gid == last_in)
|
||||
if (gid == last_in && last_out >= 0)
|
||||
return last_out;
|
||||
if (ngroups < -1) {
|
||||
gid_t mygid = MY_GID();
|
||||
|
||||
293
util.c
293
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-2008 Wayne Davison
|
||||
* Copyright (C) 2003-2009 Wayne Davison
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
@@ -24,10 +24,10 @@
|
||||
#include "ifuncs.h"
|
||||
|
||||
extern int verbose;
|
||||
extern int dry_run;
|
||||
extern int module_id;
|
||||
extern int modify_window;
|
||||
extern int relative_paths;
|
||||
extern int preserve_times;
|
||||
extern int human_readable;
|
||||
extern int preserve_xattrs;
|
||||
extern char *module_dir;
|
||||
@@ -123,12 +123,11 @@ NORETURN void overflow_exit(const char *str)
|
||||
exit_cleanup(RERR_MALLOC);
|
||||
}
|
||||
|
||||
/* This returns 0 for success, 1 for a symlink if symlink time-setting
|
||||
* is not possible, or -1 for any other error. */
|
||||
int set_modtime(const char *fname, time_t modtime, mode_t mode)
|
||||
{
|
||||
#if !defined HAVE_LUTIMES || !defined HAVE_UTIMES
|
||||
if (S_ISLNK(mode))
|
||||
return 1;
|
||||
#endif
|
||||
static int switch_step = 0;
|
||||
|
||||
if (verbose > 2) {
|
||||
rprintf(FINFO, "set modtime of %s to (%ld) %s",
|
||||
@@ -136,38 +135,49 @@ int set_modtime(const char *fname, time_t modtime, mode_t mode)
|
||||
asctime(localtime(&modtime)));
|
||||
}
|
||||
|
||||
if (dry_run)
|
||||
return 0;
|
||||
|
||||
{
|
||||
#ifdef HAVE_UTIMES
|
||||
struct timeval t[2];
|
||||
t[0].tv_sec = time(NULL);
|
||||
t[0].tv_usec = 0;
|
||||
t[1].tv_sec = modtime;
|
||||
t[1].tv_usec = 0;
|
||||
# ifdef HAVE_LUTIMES
|
||||
if (S_ISLNK(mode)) {
|
||||
if (lutimes(fname, t) < 0)
|
||||
return errno == ENOSYS ? 1 : -1;
|
||||
return 0;
|
||||
}
|
||||
# endif
|
||||
return utimes(fname, t);
|
||||
#elif defined HAVE_STRUCT_UTIMBUF
|
||||
struct utimbuf tbuf;
|
||||
tbuf.actime = time(NULL);
|
||||
tbuf.modtime = modtime;
|
||||
return utime(fname,&tbuf);
|
||||
#elif defined HAVE_UTIME
|
||||
time_t t[2];
|
||||
t[0] = time(NULL);
|
||||
t[1] = modtime;
|
||||
return utime(fname,t);
|
||||
#else
|
||||
#error No file-time-modification routine found!
|
||||
switch (switch_step) {
|
||||
#ifdef HAVE_UTIMENSAT
|
||||
#include "case_N.h"
|
||||
if (do_utimensat(fname, modtime, 0) == 0)
|
||||
break;
|
||||
if (errno != ENOSYS)
|
||||
return -1;
|
||||
switch_step++;
|
||||
/* FALLTHROUGH */
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_LUTIMES
|
||||
#include "case_N.h"
|
||||
if (do_lutimes(fname, modtime, 0) == 0)
|
||||
break;
|
||||
if (errno != ENOSYS)
|
||||
return -1;
|
||||
switch_step++;
|
||||
/* FALLTHROUGH */
|
||||
#endif
|
||||
|
||||
#include "case_N.h"
|
||||
switch_step++;
|
||||
if (preserve_times & PRESERVE_LINK_TIMES) {
|
||||
preserve_times &= ~PRESERVE_LINK_TIMES;
|
||||
if (S_ISLNK(mode))
|
||||
return 1;
|
||||
}
|
||||
/* FALLTHROUGH */
|
||||
|
||||
#include "case_N.h"
|
||||
#ifdef HAVE_UTIMES
|
||||
if (do_utimes(fname, modtime, 0) == 0)
|
||||
break;
|
||||
#else
|
||||
if (do_utime(fname, modtime, 0) == 0)
|
||||
break;
|
||||
#endif
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* This creates a new directory with default permissions. Since there
|
||||
@@ -437,7 +447,7 @@ int robust_rename(const char *from, const char *to, const char *partialptr,
|
||||
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)
|
||||
@@ -806,7 +816,8 @@ int count_dir_elements(const char *p)
|
||||
return cnt;
|
||||
}
|
||||
|
||||
/* Turns multiple adjacent slashes into a single slash, drops all leading or
|
||||
/* 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
|
||||
@@ -821,9 +832,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_DOT_DIRS && *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++;
|
||||
}
|
||||
@@ -979,7 +997,10 @@ int change_dir(const char *dir, int set_path_only)
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
@@ -1003,8 +1024,9 @@ int change_dir(const char *dir, int set_path_only)
|
||||
errno = ENAMETOOLONG;
|
||||
return 0;
|
||||
}
|
||||
curr_dir[curr_dir_len] = '/';
|
||||
memcpy(curr_dir + curr_dir_len + 1, dir, len + 1);
|
||||
if (!(curr_dir_len && curr_dir[curr_dir_len-1] == '/'))
|
||||
curr_dir[curr_dir_len++] = '/';
|
||||
memcpy(curr_dir + curr_dir_len, dir, len + 1);
|
||||
|
||||
if (!set_path_only && chdir(curr_dir)) {
|
||||
curr_dir[curr_dir_len] = '\0';
|
||||
@@ -1025,6 +1047,34 @@ int change_dir(const char *dir, int set_path_only)
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* 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)
|
||||
{
|
||||
unsigned int len;
|
||||
|
||||
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");
|
||||
}
|
||||
|
||||
len = clean_fname(path, CFN_COLLAPSE_DOT_DOT_DIRS | CFN_DROP_TRAILING_DOT_DIR);
|
||||
|
||||
if (len_ptr)
|
||||
*len_ptr = len;
|
||||
|
||||
return path;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a quoted string with the full pathname of the indicated filename.
|
||||
* The string " (in MODNAME)" may also be appended. The returned pointer
|
||||
@@ -1112,12 +1162,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 = '/';
|
||||
@@ -1125,12 +1179,13 @@ int handle_partial_dir(const char *fname, int create)
|
||||
return 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine if a symlink points outside the current directory tree.
|
||||
/* Determine if a symlink points outside the current directory tree.
|
||||
* This is considered "unsafe" because e.g. when mirroring somebody
|
||||
* else's machine it might allow them to establish a symlink to
|
||||
* /etc/passwd, and then read it through a web server.
|
||||
*
|
||||
* Returns 1 if unsafe, 0 if safe.
|
||||
*
|
||||
* Null symlinks and absolute symlinks are always unsafe.
|
||||
*
|
||||
* Basically here we are concerned with symlinks whose target contains
|
||||
@@ -1138,17 +1193,11 @@ int handle_partial_dir(const char *fname, int create)
|
||||
* transferred directory. We are not allowed to go back up and
|
||||
* reenter.
|
||||
*
|
||||
* @param dest Target of the symlink in question.
|
||||
* "dest" is the target of the symlink in question.
|
||||
*
|
||||
* @param src Top source directory currently applicable. Basically this
|
||||
* is the first parameter to rsync in a simple invocation, but it's
|
||||
* modified by flist.c in slightly complex ways.
|
||||
*
|
||||
* @retval True if unsafe
|
||||
* @retval False is unsafe
|
||||
*
|
||||
* @sa t_unsafe.c
|
||||
**/
|
||||
* "src" is the top source directory currently applicable at the level
|
||||
* of the referenced symlink. This is usually the symlink's full path
|
||||
* (including its name), as referenced from the root of the transfer. */
|
||||
int unsafe_symlink(const char *dest, const char *src)
|
||||
{
|
||||
const char *name, *slash;
|
||||
@@ -1160,35 +1209,57 @@ int unsafe_symlink(const char *dest, const char *src)
|
||||
|
||||
/* find out what our safety margin is */
|
||||
for (name = src; (slash = strchr(name, '/')) != 0; name = slash+1) {
|
||||
if (strncmp(name, "../", 3) == 0) {
|
||||
depth = 0;
|
||||
} else if (strncmp(name, "./", 2) == 0) {
|
||||
/* nothing */
|
||||
} else {
|
||||
/* ".." segment starts the count over. "." segment is ignored. */
|
||||
if (*name == '.' && (name[1] == '/' || (name[1] == '.' && name[2] == '/'))) {
|
||||
if (name[1] == '.')
|
||||
depth = 0;
|
||||
} else
|
||||
depth++;
|
||||
}
|
||||
while (slash[1] == '/') slash++; /* just in case src isn't clean */
|
||||
}
|
||||
if (strcmp(name, "..") == 0)
|
||||
if (*name == '.' && name[1] == '.' && name[2] == '\0')
|
||||
depth = 0;
|
||||
|
||||
for (name = dest; (slash = strchr(name, '/')) != 0; name = slash+1) {
|
||||
if (strncmp(name, "../", 3) == 0) {
|
||||
/* if at any point we go outside the current directory
|
||||
then stop - it is unsafe */
|
||||
if (--depth < 0)
|
||||
return 1;
|
||||
} else if (strncmp(name, "./", 2) == 0) {
|
||||
/* nothing */
|
||||
} else {
|
||||
if (*name == '.' && (name[1] == '/' || (name[1] == '.' && name[2] == '/'))) {
|
||||
if (name[1] == '.') {
|
||||
/* if at any point we go outside the current directory
|
||||
then stop - it is unsafe */
|
||||
if (--depth < 0)
|
||||
return 1;
|
||||
}
|
||||
} else
|
||||
depth++;
|
||||
}
|
||||
while (slash[1] == '/') slash++;
|
||||
}
|
||||
if (strcmp(name, "..") == 0)
|
||||
if (*name == '.' && name[1] == '.' && name[2] == '\0')
|
||||
depth--;
|
||||
|
||||
return (depth < 0);
|
||||
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. */
|
||||
@@ -1197,27 +1268,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;
|
||||
@@ -1225,10 +1284,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;
|
||||
}
|
||||
|
||||
@@ -1241,8 +1313,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;
|
||||
}
|
||||
@@ -1566,6 +1638,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)
|
||||
{
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* Test suite for the wildmatch code.
|
||||
*
|
||||
* Copyright (C) 2003-2008 Wayne Davison
|
||||
* Copyright (C) 2003-2009 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
|
||||
|
||||
116
xattrs.c
116
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-2008 Wayne Davison
|
||||
* Copyright (C) 2006-2009 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
|
||||
@@ -32,6 +32,9 @@ extern int am_generator;
|
||||
extern int read_only;
|
||||
extern int list_only;
|
||||
extern int preserve_xattrs;
|
||||
extern int preserve_links;
|
||||
extern int preserve_devices;
|
||||
extern int preserve_specials;
|
||||
extern int checksum_seed;
|
||||
|
||||
#define RSYNC_XAL_INITIAL 5
|
||||
@@ -81,6 +84,8 @@ static char *namebuf = NULL;
|
||||
static item_list empty_xattr = EMPTY_ITEM_LIST;
|
||||
static item_list rsync_xal_l = EMPTY_ITEM_LIST;
|
||||
|
||||
static size_t prior_xattr_count = (size_t)-1;
|
||||
|
||||
/* ------------------------------------------------------------------------- */
|
||||
|
||||
static void rsync_xal_free(item_list *xalp)
|
||||
@@ -136,7 +141,7 @@ static ssize_t get_xattr_names(const char *fname)
|
||||
got_error:
|
||||
rsyserr(FERROR_XFER, errno,
|
||||
"get_xattr_names: llistxattr(\"%s\",%.0f) failed",
|
||||
fname, arg);
|
||||
full_fname(fname), arg);
|
||||
return -1;
|
||||
}
|
||||
list_len = sys_llistxattr(fname, NULL, 0);
|
||||
@@ -172,7 +177,7 @@ static char *get_xattr_data(const char *fname, const char *name, size_t *len_ptr
|
||||
return NULL;
|
||||
rsyserr(FERROR_XFER, errno,
|
||||
"get_xattr_data: lgetxattr(\"%s\",\"%s\",0) failed",
|
||||
fname, name);
|
||||
full_fname(fname), name);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@@ -189,11 +194,11 @@ static char *get_xattr_data(const char *fname, const char *name, size_t *len_ptr
|
||||
if (len == (size_t)-1) {
|
||||
rsyserr(FERROR_XFER, errno,
|
||||
"get_xattr_data: lgetxattr(\"%s\",\"%s\",%ld)"
|
||||
" failed", fname, name, (long)datum_len);
|
||||
" failed", full_fname(fname), name, (long)datum_len);
|
||||
} else {
|
||||
rprintf(FERROR_XFER,
|
||||
"get_xattr_data: lgetxattr(\"%s\",\"%s\",%ld)"
|
||||
" returned %ld\n", fname, name,
|
||||
" returned %ld\n", full_fname(fname), name,
|
||||
(long)datum_len, (long)len);
|
||||
}
|
||||
free(ptr);
|
||||
@@ -210,7 +215,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;
|
||||
@@ -281,6 +286,26 @@ int get_xattr(const char *fname, stat_x *sxp)
|
||||
{
|
||||
sxp->xattr = new(item_list);
|
||||
*sxp->xattr = empty_xattr;
|
||||
|
||||
if (S_ISREG(sxp->st.st_mode) || S_ISDIR(sxp->st.st_mode)) {
|
||||
/* Everyone supports this. */
|
||||
} else if (S_ISLNK(sxp->st.st_mode)) {
|
||||
#ifndef NO_SYMLINK_XATTRS
|
||||
if (!preserve_links)
|
||||
#endif
|
||||
return 0;
|
||||
} else if (IS_SPECIAL(sxp->st.st_mode)) {
|
||||
#ifndef NO_SPECIAL_XATTRS
|
||||
if (!preserve_specials)
|
||||
#endif
|
||||
return 0;
|
||||
} else if (IS_DEVICE(sxp->st.st_mode)) {
|
||||
#ifndef NO_DEVICE_XATTRS
|
||||
if (!preserve_devices)
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (rsync_xal_get(fname, sxp->xattr) < 0) {
|
||||
free_xattr(sxp);
|
||||
return -1;
|
||||
@@ -294,7 +319,7 @@ int copy_xattrs(const char *source, const char *dest)
|
||||
size_t datum_len;
|
||||
char *name, *ptr;
|
||||
#ifdef HAVE_LINUX_XATTRS
|
||||
int user_only = am_sender ? 0 : !am_root;
|
||||
int user_only = am_root <= 0;
|
||||
#endif
|
||||
|
||||
/* This puts the name list into the "namebuf" buffer. */
|
||||
@@ -319,8 +344,8 @@ int copy_xattrs(const char *source, const char *dest)
|
||||
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);
|
||||
"copy_xattrs: lsetxattr(\"%s\",\"%s\") failed",
|
||||
full_fname(dest), name);
|
||||
errno = save_errno;
|
||||
return -1;
|
||||
}
|
||||
@@ -381,7 +406,7 @@ static void rsync_xal_store(item_list *xalp)
|
||||
}
|
||||
|
||||
/* Send the make_xattr()-generated xattr list for this flist entry. */
|
||||
int send_xattr(stat_x *sxp, int f)
|
||||
int send_xattr(int f, stat_x *sxp)
|
||||
{
|
||||
int ndx = find_matching_xattr(sxp->xattr);
|
||||
|
||||
@@ -572,7 +597,7 @@ int recv_xattr_request(struct file_struct *file, int f_in)
|
||||
|
||||
if (F_XATTR(file) < 0) {
|
||||
rprintf(FERROR, "recv_xattr_request: internal data error!\n");
|
||||
exit_cleanup(RERR_STREAMIO);
|
||||
exit_cleanup(RERR_PROTOCOL);
|
||||
}
|
||||
lst += F_XATTR(file);
|
||||
|
||||
@@ -588,12 +613,12 @@ int recv_xattr_request(struct file_struct *file, int f_in)
|
||||
if (!cnt || rxa->num != num) {
|
||||
rprintf(FERROR, "[%s] could not find xattr #%d for %s\n",
|
||||
who_am_i(), num, f_name(file, NULL));
|
||||
exit_cleanup(RERR_STREAMIO);
|
||||
exit_cleanup(RERR_PROTOCOL);
|
||||
}
|
||||
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);
|
||||
exit_cleanup(RERR_PROTOCOL);
|
||||
}
|
||||
|
||||
if (am_sender) {
|
||||
@@ -623,7 +648,7 @@ int recv_xattr_request(struct file_struct *file, int f_in)
|
||||
/* ------------------------------------------------------------------------- */
|
||||
|
||||
/* receive and build the rsync_xattr_lists */
|
||||
void receive_xattr(struct file_struct *file, int f)
|
||||
void receive_xattr(int f, struct file_struct *file)
|
||||
{
|
||||
static item_list temp_xattr = EMPTY_ITEM_LIST;
|
||||
int count, num;
|
||||
@@ -637,14 +662,14 @@ void receive_xattr(struct file_struct *file, int f)
|
||||
if (ndx < 0 || (size_t)ndx > rsync_xal_l.count) {
|
||||
rprintf(FERROR, "receive_xattr: xa index %d out of"
|
||||
" range for %s\n", ndx, f_name(file, NULL));
|
||||
exit_cleanup(RERR_STREAMIO);
|
||||
exit_cleanup(RERR_PROTOCOL);
|
||||
}
|
||||
|
||||
if (ndx != 0) {
|
||||
F_XATTR(file) = ndx - 1;
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
if ((count = read_varint(f)) != 0) {
|
||||
(void)EXPAND_ITEM_LIST(&temp_xattr, rsync_xa, count);
|
||||
temp_xattr.count = 0;
|
||||
@@ -724,13 +749,15 @@ void receive_xattr(struct file_struct *file, int f)
|
||||
|
||||
/* Turn the xattr data in stat_x into cached xattr data, setting the index
|
||||
* values in the file struct. */
|
||||
void cache_xattr(struct file_struct *file, stat_x *sxp)
|
||||
void cache_tmp_xattr(struct file_struct *file, stat_x *sxp)
|
||||
{
|
||||
int ndx;
|
||||
|
||||
if (!sxp->xattr)
|
||||
return;
|
||||
|
||||
if (prior_xattr_count == (size_t)-1)
|
||||
prior_xattr_count = rsync_xal_l.count;
|
||||
ndx = find_matching_xattr(sxp->xattr);
|
||||
if (ndx < 0)
|
||||
rsync_xal_store(sxp->xattr); /* adds item to rsync_xal_l */
|
||||
@@ -738,6 +765,21 @@ void cache_xattr(struct file_struct *file, stat_x *sxp)
|
||||
F_XATTR(file) = ndx;
|
||||
}
|
||||
|
||||
void uncache_tmp_xattrs(void)
|
||||
{
|
||||
if (prior_xattr_count != (size_t)-1) {
|
||||
item_list *xattr_item = rsync_xal_l.items;
|
||||
item_list *xattr_start = xattr_item + prior_xattr_count;
|
||||
xattr_item += rsync_xal_l.count;
|
||||
rsync_xal_l.count = prior_xattr_count;
|
||||
while (xattr_item-- > xattr_start) {
|
||||
rsync_xal_free(xattr_item);
|
||||
free(xattr_item->items);
|
||||
}
|
||||
prior_xattr_count = (size_t)-1;
|
||||
}
|
||||
}
|
||||
|
||||
static int rsync_xal_set(const char *fname, item_list *xalp,
|
||||
const char *fnamecmp, stat_x *sxp)
|
||||
{
|
||||
@@ -745,6 +787,9 @@ 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];
|
||||
#ifdef HAVE_LINUX_XATTRS
|
||||
int user_only = am_root <= 0;
|
||||
#endif
|
||||
size_t name_len;
|
||||
int ret = 0;
|
||||
|
||||
@@ -785,7 +830,7 @@ static int rsync_xal_set(const char *fname, item_list *xalp,
|
||||
else if (sys_lsetxattr(fname, name, ptr, len) < 0) {
|
||||
rsyserr(FERROR_XFER, errno,
|
||||
"rsync_xal_set: lsetxattr(\"%s\",\"%s\") failed",
|
||||
fname, name);
|
||||
full_fname(fname), name);
|
||||
ret = -1;
|
||||
} else /* make sure caller sets mtime */
|
||||
sxp->st.st_mtime = (time_t)-1;
|
||||
@@ -806,7 +851,7 @@ static int rsync_xal_set(const char *fname, item_list *xalp,
|
||||
if (sys_lsetxattr(fname, name, rxas[i].datum, rxas[i].datum_len) < 0) {
|
||||
rsyserr(FERROR_XFER, errno,
|
||||
"rsync_xal_set: lsetxattr(\"%s\",\"%s\") failed",
|
||||
fname, name);
|
||||
full_fname(fname), name);
|
||||
ret = -1;
|
||||
} else /* make sure caller sets mtime */
|
||||
sxp->st.st_mtime = (time_t)-1;
|
||||
@@ -820,8 +865,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
|
||||
@@ -835,8 +880,8 @@ static int rsync_xal_set(const char *fname, item_list *xalp,
|
||||
if (i == xalp->count) {
|
||||
if (sys_lremovexattr(fname, name) < 0) {
|
||||
rsyserr(FERROR_XFER, errno,
|
||||
"rsync_xal_clear: lremovexattr(\"%s\",\"%s\") failed",
|
||||
fname, name);
|
||||
"rsync_xal_set: lremovexattr(\"%s\",\"%s\") failed",
|
||||
full_fname(fname), name);
|
||||
ret = -1;
|
||||
} else /* make sure caller sets mtime */
|
||||
sxp->st.st_mtime = (time_t)-1;
|
||||
@@ -861,6 +906,25 @@ int set_xattr(const char *fname, const struct file_struct *file,
|
||||
return -1;
|
||||
}
|
||||
|
||||
#ifdef NO_SPECIAL_XATTRS
|
||||
if (IS_SPECIAL(sxp->st.st_mode)) {
|
||||
errno = ENOTSUP;
|
||||
return -1;
|
||||
}
|
||||
#endif
|
||||
#ifdef NO_DEVICE_XATTRS
|
||||
if (IS_DEVICE(sxp->st.st_mode)) {
|
||||
errno = ENOTSUP;
|
||||
return -1;
|
||||
}
|
||||
#endif
|
||||
#ifdef NO_SYMLINK_XATTRS
|
||||
if (S_ISLNK(sxp->st.st_mode)) {
|
||||
errno = ENOTSUP;
|
||||
return -1;
|
||||
}
|
||||
#endif
|
||||
|
||||
ndx = F_XATTR(file);
|
||||
return rsync_xal_set(fname, lst + ndx, fnamecmp, sxp);
|
||||
}
|
||||
@@ -879,7 +943,7 @@ int set_xattr_acl(const char *fname, int is_access_acl, const char *buf, size_t
|
||||
if (sys_lsetxattr(fname, name, buf, buf_len) < 0) {
|
||||
rsyserr(FERROR_XFER, errno,
|
||||
"set_xattr_acl: lsetxattr(\"%s\",\"%s\") failed",
|
||||
fname, name);
|
||||
full_fname(fname), name);
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
@@ -967,7 +1031,7 @@ int set_stat_xattr(const char *fname, struct file_struct *file, mode_t new_mode)
|
||||
fst.st_mode &= (_S_IFMT | CHMOD_BITS);
|
||||
fmode = new_mode & (_S_IFMT | CHMOD_BITS);
|
||||
|
||||
if (IS_DEVICE(fmode) || IS_SPECIAL(fmode)) {
|
||||
if (IS_DEVICE(fmode)) {
|
||||
uint32 *devp = F_RDEV_P(file);
|
||||
rdev = MAKEDEV(DEV_MAJOR(devp), DEV_MINOR(devp));
|
||||
} else
|
||||
@@ -978,7 +1042,7 @@ int set_stat_xattr(const char *fname, struct file_struct *file, mode_t new_mode)
|
||||
| (S_ISDIR(fst.st_mode) ? 0700 : 0600);
|
||||
if (fst.st_mode != mode)
|
||||
do_chmod(fname, mode);
|
||||
if (!IS_DEVICE(fst.st_mode) && !IS_SPECIAL(fst.st_mode))
|
||||
if (!IS_DEVICE(fst.st_mode))
|
||||
fst.st_rdev = 0; /* just in case */
|
||||
|
||||
if (mode == fmode && fst.st_rdev == rdev
|
||||
|
||||
Reference in New Issue
Block a user