Compare commits

...

102 Commits

Author SHA1 Message Date
Wayne Davison
325c243210 Preparing for release of 3.0.1 2008-04-03 22:37:01 -07:00
Wayne Davison
4e90cfbfed A few more spec-file tweaks. 2008-04-01 20:00:08 -07:00
Wayne Davison
6fd2c27f38 Define a "srcdir" in the spec file and use it in the URLs for the
source files so that they use the unchanging src or src-preview
subdirectory location for the file.
2008-04-01 12:55:27 -07:00
Wayne Davison
19173d224a Tweaked rsync.spec to use "rsync" in place of "%{name}" in a few
places (which allows for easier creation of adjunct RPMs).
2008-03-31 14:10:07 -07:00
Wayne Davison
5b83829669 A simple change to change_pathname() to ensure that the error output
mentions the right path when dir == NULL.
2008-03-31 07:46:47 -07:00
Wayne Davison
8cd3c6dccf Preparing for release of 3.0.1pre3 2008-03-30 23:29:43 -07:00
Wayne Davison
29a89172f7 Improved the chdir() code:
- Renamed push_dir() to change_dir() and revised it a little so that it
  can chdir() to a relative path without an intervening chdir() back to
  the staring path.
- Renamed push_pathname() to change_pathname() and revised it to take
  different args and to only call path_is_daemon_excluded() on a new
  path (not a revisit of a file's already-checked path).
- Fixed change_pathname() to set the right pathname value when a chdir()
  call fails.
- Set orig_dir once outside of the change_pathname() function.
- Got rid of pop_dir().
2008-03-30 15:44:46 -07:00
Wayne Davison
2089375179 Some argc-based actions in parse_arguments() shouldn't happen on
the server side.
2008-03-30 08:05:50 -07:00
Wayne Davison
f8949e7647 Fixed a path-exclusion glitch when checking more than one arg. 2008-03-30 08:05:42 -07:00
Wayne Davison
84ecaa0eca Improved the code that protects a '.' dir from exclusion.
This fixed a glitch in the daemon-exclusion code that allowed
an exclude rule such as ".*" or "*/" to affect a '.' dir.
2008-03-29 23:06:18 -07:00
Wayne Davison
3f2d8d683a Extended a test to ensure that hard-linked distant files continues
to work in incremental-recursion mode.
2008-03-28 10:40:17 -07:00
Wayne Davison
fd2598022c Allow the file-list sending code to set XMIT_SAME_UID/XMIT_SAME_GID
when owner/group info isn't being preserved.  This helps to ensure
that the lower 8 bits of the xflags aren't 0, and is what older
rsync versions did.
2008-03-28 10:40:10 -07:00
Wayne Davison
b05c58cce6 Dump an extraneous empty line. 2008-03-28 10:30:11 -07:00
Wayne Davison
05805cd6b7 Preparing for release of 3.0.1pre2 2008-03-26 17:12:07 -07:00
Wayne Davison
a165be754b Mention two more NEWS items. 2008-03-26 17:04:29 -07:00
Wayne Davison
af3172c148 Ensure that a per-dir merge file is also loaded from implied directories
in the sender (was working in incremental mode).
2008-03-26 16:49:12 -07:00
Wayne Davison
487cb52615 Fixed the discovery of a prior finished hard-link when the entry
is old enough that it is no longer in the flist data.
2008-03-26 16:12:39 -07:00
Wayne Davison
9793bbb364 Improved a length check in parse_merge_name(). 2008-03-26 14:01:52 -07:00
Wayne Davison
f6f74b93ef Ensure that a per-dir merge file is also loaded from implied directories
in the generator (for protocol 30, at least).
2008-03-26 14:01:26 -07:00
Wayne Davison
7568ff448a Fixed the way rsync handles iconv-conversion problems in the file-list:
- If the sender cannot convert a name, the discarding of the entry now
  occurs soon enough to avoid affecting the sender's list (which was
  causing the file-list on the receiving side to be out of sync).
- If the receiver cannot convert a name, its transformation of the name
  into an empty name (which indicates that the entry should be skipped)
  is no longer thwarted by the clean_fname() call (which was changing
  the name into a ".").
2008-03-25 10:46:06 -07:00
Wayne Davison
56158b7e04 Preparing for release of 3.0.1pre1 2008-03-24 21:15:51 -07:00
Wayne Davison
798a9e4e74 Some more improvements for the packaging/release-rsync script:
- Check early if the version tag already exists, so it aborts right
  away if the release script can't do its work.
- Update the files in the "patches" dir while merging the master branch
  into the patch branches (done before creating the release patches for
  the rsync-patches tar file).
- Allow the user to ask to visit each patch when updating them.
- Pause after initial patch updating so that any extra patch changes
  can be done before the creating of the tar files.
- Ask for the GPG signing passphrase once for all signing commands.
2008-03-24 21:15:30 -07:00
Wayne Davison
c202b4fa96 Some improvements for support/patch-update:
- Added a --shell option which starts a sub-shell on each patch branch.
- Don't allow the user to exit a sub-shell if the branch is not clean.
- If the sub-shell exited with a non-zero exit status, prompt to see if
  the user wanted to abort rather than assuming that.
- Wait to start the new patch-file output until after the shell runs.
- Always return to the starting branch on exit.
2008-03-24 20:30:09 -07:00
Wayne Davison
1df02d13d3 Don't send daemon-config filter-action messages back to the user. 2008-03-24 10:14:59 -07:00
Wayne Davison
73cb6738b3 Improved --dirs/--no-dirs/--list-only option handling:
- Moved setting of list_only and xfer_dirs from main.c to options.c.
- Fixed the ability of the user to force --no-dirs.
- Added the --old-dirs/--old-d option to make it easier to interact
  in list-only mode with an older rsync.
- Suggest the use of --old-d instead of "-r --exclude='/*/*'".
2008-03-24 09:54:04 -07:00
Wayne Davison
ba8672dfab Added a couple more NEWS items. 2008-03-23 10:06:53 -07:00
Wayne Davison
a5e0bf3579 Properly handle a new patch-branch that is only available locally. 2008-03-23 09:53:15 -07:00
Wayne Davison
99ba99c74c Changed the way version numbering of pre-releases will be done in
the RPM spec file so that they order prior to the final release.
2008-03-23 00:10:12 -07:00
Wayne Davison
469ff84e29 More NEWS updates and improvements. 2008-03-22 22:33:04 -07:00
Wayne Davison
b5daf5300f Made the filename arg-parsing code skip args that have excluded path
components, returning the same errors that would occur if the path
elements didn't actually exist.  The glob_match() code was also
changed to no longer truncate an arg with an excluded path element
(it just omits excluded items from glob matching).
2008-03-22 15:33:18 -07:00
Wayne Davison
f5aeb6ff9b Added XFLG_DIR2WILD3 flag that the daemon uses to transform any
config-file dir/ exclude rule into a dir/*** rule.
2008-03-22 14:02:34 -07:00
Wayne Davison
4c74d44dab A couple fixes in add_rule() for XFLG_ABS_IF_SLASH:
- Remove the trailing slash earlier, so that it doesn't
  affect the XFLG_ABS_IF_SLASH check.
- Count the slashes earlier so that the XFLG_ABS_IF_SLASH
  can use it instead of using a strchr() all that could
  scan past the end of the input.
2008-03-22 12:30:43 -07:00
Wayne Davison
4a86fbcda0 Change ex_len to pre_len in add_rule(). 2008-03-22 12:21:41 -07:00
Wayne Davison
bc267e0f57 Improved ENSURE_MEMSPACE() macro and use it in more places in glob code. 2008-03-22 08:13:04 -07:00
Wayne Davison
fc05137846 Mention the most recent changes in the NEWS. 2008-03-21 17:50:01 -07:00
Wayne Davison
c085ece623 Some RPM spec file improvements:
- Added installation of new /etc/xinetd.d/rsync config file.
- Added commented-out lines to demonstrate how to use rsync-patches.
2008-03-21 17:11:20 -07:00
Wayne Davison
91f625cee0 Make glob_expand() return an indicator if the glob had no matches. 2008-03-21 15:00:28 -07:00
Wayne Davison
27b067f87b Changed d_name() to be a static inline function. 2008-03-21 07:26:25 -07:00
Wayne Davison
987a546756 A couple improvements to the new arg-globbing code:
- Put all the state variables into a single struct.
- Reuse the buffer memory for each glob_expand() call until a final
  call with a NULL pointer tells us to free it.
2008-03-21 07:22:34 -07:00
Wayne Davison
4d30f17671 Changed the arg-globbing routine to use a custom arg-globbing algorithm
that does not include any daemon-excluded items in the matches.  It is
also not subverted by the presence of one or more dot-dir elements in
an arg.
2008-03-20 23:30:09 -07:00
Wayne Davison
d48810ba5b Some improvements to the file-name cleaning code:
- Removed the CFN_KEEP_LEADING_DOT_DIR flag for clean_fname().
- Explicitly add an implied dot-dir to the transfer rather than keeping
  a leading a "./" prefix as a part of a relative pathname.
- Added the CFN_KEEP_DOT_DIRS flag for clean_fname().
- Added the SP_KEEP_DOT_DIRS flag for sanitize_path().
- Call clean_fname() a couple more times.
2008-03-20 22:39:29 -07:00
Wayne Davison
819bfe4599 Changed the name of the server_filter_list to be
daemon_filter_list, for improved clarity.
2008-03-20 10:42:43 -07:00
Wayne Davison
d2f6e19262 Fixed a bug in the truncating of daemon-excluded paths. 2008-03-20 10:35:53 -07:00
Wayne Davison
e889e0c43b A couple more support/rrsync tweaks:
- Die if the --server option is not first on the command-line.
- Don't allow the --daemon option by default.
2008-03-19 16:44:11 -07:00
Wayne Davison
6e0bf4d840 Some more minor changes for the skip/missing/dry_run code. 2008-03-19 08:59:44 -07:00
Matt McCutchen
83a8ca7b14 Unsnarl missing_below/dry_run logic.
The generator can skip a directory's contents altogether due to
--ignore-non-existing, a daemon exclude, or a mkdir failure.  On a
--dry-run, the generator can also note the missingness of a directory
while still scanning its contents.  These two scenarios were conflated
using a single set of missing_below/missing_dir variables in combination
with transient increments in dry_run; this caused at least three bugs.

Now recv_generator has separate variables for the two scenarios, called
skip_dir and dry_missing_dir, respectively.  For simplicity, we take the
F_DEPTH instead of having separate *_below variables.  We mark both
kinds of missing dirs with FLAG_MISSING_DIR.  (dry_run > 1) iff the
*root* of the destination does not exist; it is no longer incremented
for missing subdirs.  I added tests for the three fixed bugs in
missing.test.
2008-03-19 07:45:58 -07:00
Matt McCutchen
100200d0d2 Fix a poorly placed sentence in rsyncd.conf.yo. 2008-03-18 15:28:36 -04:00
Wayne Davison
f28bf7f401 My modified version of Matt's improvements to the sections on
the various filter parameters.
2008-03-18 11:41:00 -07:00
Wayne Davison
e0fd68f5ce Improved arg-path checking so that wildcards can't be used to
avoid a daemon-exclude.
2008-03-18 10:57:54 -07:00
Wayne Davison
cc12c488aa Use the missing_below code to make the daemon-exclusions
work better.
2008-03-18 10:10:13 -07:00
Wayne Davison
99c3e591b2 Reject a daemon-excluded destination. 2008-03-18 09:44:42 -07:00
Wayne Davison
1aefb7ef73 Output a non-existent-file error for server-excluded files instead of
silently ignoring them.
2008-03-18 09:16:24 -07:00
Matt McCutchen
d7b6774d82 More typo fixes. 2008-03-17 15:32:07 -04:00
Wayne Davison
d4c5cb2b01 A couple more changes for dealing with "checker" warnings. 2008-03-17 10:50:11 -07:00
Matt McCutchen
df476bfcff Fix typo in rsyncd.conf man page. 2008-03-17 11:30:08 -04:00
Wayne Davison
aa0e6b9977 Attempting to silence some more "checker" warnings. 2008-03-17 07:35:19 -07:00
Wayne Davison
1ba6468f1b Mention all the latest changes in the NEWS file. 2008-03-16 22:43:35 -07:00
Wayne Davison
f490102454 If we're not compiling one or more major options (ACLs, xattrs, & iconv),
try to turn off unused-parameter compiler warnings.
2008-03-16 21:51:07 -07:00
Wayne Davison
18f3cb6957 Changed stat() call to do_stat(). 2008-03-16 21:44:33 -07:00
Wayne Davison
7abcfd85b7 Moved declaration of "int i" outside the ifdef in send_protected_args(). 2008-03-16 20:39:16 -07:00
Wayne Davison
6de417d9d4 If the system's popt.h file is not found, use our provided popt code. 2008-03-16 20:35:18 -07:00
Wayne Davison
ffe8feb265 Added "const" to a couple more char * args. 2008-03-16 19:50:35 -07:00
Wayne Davison
c9b62cf375 Fixed hard-linking when some of the files can get skipped. This adds
the FLAG_SKIP_HLINK flag, which gets set on any hard-linked file that
the user wants to skip (e.g. via --ignore-existing, --append, etc.).
The code in hlink.c now deals with the skipped files instead of
triggering an assert() error.
2008-03-16 19:47:35 -07:00
Wayne Davison
7bc595785e Made the FLAG_MOUNT_DIR bit only honored on a directory. 2008-03-16 17:52:31 -07:00
Wayne Davison
022dec7aba Moved the --append check so that files that don't need to be transferred
still get their non-content attributes updated, and combining --append
with --hard-links will not prevent the discovery of unchanged files.
2008-03-16 17:50:28 -07:00
Wayne Davison
ddaef70ced Make the --ignore-existing option not overwrite a regular file with
a dir/symlink/device/special-file, just like it already refuses to
overwrite a non-regular file with a regular file.
2008-03-16 17:17:38 -07:00
Wayne Davison
2357a51e09 A daemon no longer tries to refuse the iconv option when it is not enabled. 2008-03-16 12:11:19 -07:00
Wayne Davison
24ded29ff6 Fixed a hang when using --remove-source-files in dry-run mode. 2008-03-16 06:56:26 -07:00
Wayne Davison
ddff23a7f9 Added missing $(CPPFLAGS) from the building of rounding.h. 2008-03-15 14:09:20 -07:00
Wayne Davison
53936ef935 Fixed the use of --protect-args (-s) with a daemon. 2008-03-15 11:56:18 -07:00
Wayne Davison
7f9bf6b710 Generate a helpful message when we get an option-error from a daemon
while requesting a file-listing and we suspect that the remote rsync
is complaining about the -d option.
2008-03-15 11:24:38 -07:00
Wayne Davison
cfdb27b0c1 Another optimization of "bp" adding when creating a file_struct. 2008-03-15 07:27:33 -07:00
Wayne Davison
fc3ca11040 Got rid of some useless uses of the -t option. 2008-03-15 07:26:46 -07:00
Wayne Davison
d6c9c3319b - Fixed a crash bug when backing up files with ACLs enabled and we
create a directory in the backup-path area.
- Fixed a bug where make_file() was setting F_PATHNAME() on the
  receiving side.
- A non-pool (temp-memory) file structure now stores the size of
  its extra_cnt value in the F_DEPTH() int so that unmake_file()
  can always be sure of how to free() the memory.
- The ACL-preserving code no longer allocates 4 more bytes per
  file entry than it needs.
- Got rid of a useless adding of the symlink length to "bp".
2008-03-15 00:44:53 -07:00
Wayne Davison
8afaef4219 Have configure check to see if /usr/include/popt/popt.h is around
(rather than /usr/include/popt.h), and use the included popt lib
if it is (to avoid a potential conflict due to our use of -I.).
2008-03-14 22:55:59 -07:00
Wayne Davison
11faa893ca (Matt) More itemize clarifications. 2008-03-13 17:45:13 -07:00
Wayne Davison
600b56b316 Clarify that the change/checksum itemize flag can be missing
when talking to older rsync versions.
2008-03-12 16:51:13 -07:00
Wayne Davison
ee39281d14 Fixed the 'T' itemized output for a symlink the right way this time. 2008-03-11 17:35:49 -07:00
Wayne Davison
0607c30700 - One more fix for the 'T' itemized output for a symlink when we're
the client on the receiving side of a protocol-29 connection.
2008-03-11 07:26:37 -07:00
Wayne Davison
492ad04277 (Matt) Add missing --no-y option. 2008-03-10 21:40:04 -07:00
Wayne Davison
1ed9018e69 Fixed some itemized logging failures:
- If a symlink/device/special-file changes its value without any
  attribute changes, the itemized event no longer gets dropped.
- We put a 'c' into the checksum/change field now to indicate when
  a symlink/device/special-file changes its value without changing
  its type.  This lets us properly interpret the --copy-links output
  to know which items are getting copied without changes and which
  are getting created with new content.
- Fixed the 'T' itemized output for a symlink when rsync tries to
  set the right time but fails due to lack of OS/disk support.
2008-03-10 21:39:01 -07:00
Wayne Davison
ff0e15804f Fixed the itemizing of perms with -E. 2008-03-09 19:50:51 -07:00
Wayne Davison
894e6299c1 Some popt improvements:
- Fixed a bug in short-opt parsing when an abutting arg has an '='.
- Allow a short-opt to be separated from its arg by an '='.
- Avoid an IBM-checker warning about an impossible case in a switch
  and a warning about a potential NULL-pointer dereference.
- Fixed a memory leak.
2008-03-08 11:02:40 -08:00
Wayne Davison
c080190365 Fixed the latest xattrs tests on OS X. 2008-03-07 17:13:38 -08:00
Wayne Davison
26f0e56587 Restore a long-attribute test that was temporarily disabled. 2008-03-07 16:45:26 -08:00
Wayne Davison
b4e6aac985 Fixed a syntax problem for non-HAVE_LINUX_ATTRS systems. 2008-03-07 16:41:09 -08:00
Wayne Davison
7c21776e54 Handle the very latest spot for the nightly dir. 2008-03-07 16:25:05 -08:00
Wayne Davison
d724dd186e Fixed the interaction of --fake-super with --link-dest & --xattrs.
Fixed the munging of non-user namespace xattrs w/--fake-super.
Fixed the sorting of received xattrs when name-munging occurs.
Added xattr tests to verify that these things stay fixed.
2008-03-07 16:23:21 -08:00
Wayne Davison
cbbd8e2e8b The --fake-super option conflicts with -XX (which copies internal
rsync xattrs literally).
2008-03-07 15:23:39 -08:00
Wayne Davison
af6241f7ad Simplify the description of what we're doing. 2008-03-06 09:40:46 -08:00
Wayne Davison
852e763b89 Added even more no-OPTION overrides. 2008-03-06 09:38:48 -08:00
Wayne Davison
0f71592015 Made the description of ignored symlink errors more accurate. 2008-03-06 09:37:26 -08:00
Wayne Davison
e63d3a29e2 Updated nightly-rsync and release-rsync to handle the new
ftp directory layout.
2008-03-05 00:22:55 -08:00
Wayne Davison
38cef641a5 Updated rrsync to deal with the latest 3.0.0's use of the -e option.
Added a couple more long options that might get passed.
2008-03-04 22:51:56 -08:00
Wayne Davison
6226396c4a Don't call utimes() on a dir that doesn't need its mtime changed. 2008-03-04 22:48:01 -08:00
Wayne Davison
89b47d43de - Made the itemize test check for CAN_HARDLINK_SYMLINK define instead
of running its own test using ln.
- Made the merge test call checkit with absolute paths so that some
  folk's cd command won't foul things up with extra output.
2008-03-04 21:46:27 -08:00
Wayne Davison
d1c06c2180 Fixing a problem with a NULL config_file pointer when accessing
a single-use daemon without no --config option specified.  Added
a test to ensure that this doesn't break in the future.
2008-03-03 18:33:11 -08:00
Wayne Davison
800a4485f3 Improved the error-checking when tweaking the files for a new release. 2008-03-03 12:33:15 -08:00
Wayne Davison
fede378577 Updated copyright year in --version output and improved the release
script to look for year changes in options.c and to get the version
defaults totally right in the prompts.
2008-03-03 11:19:48 -08:00
Wayne Davison
3bc207b9dd Fixed a thinko and a typo in the --append option. 2008-03-03 07:16:38 -08:00
Wayne Davison
ebac031925 Show the last compile error if we failed to create rounding.h. 2008-03-01 21:00:41 -08:00
Wayne Davison
3cbe640d3c Tweak the files to start work on the next release.
The work-in-progress version is 3.0.1dev.
2008-03-01 20:35:18 -08:00
44 changed files with 2045 additions and 1210 deletions

View File

@@ -82,7 +82,7 @@ flist.o: rounding.h
rounding.h: rounding.c rsync.h
@for r in 0 1 3; do \
if $(CC) $(CFLAGS) $(LDFLAGS) -o rounding -DEXTRA_ROUNDING=$$r -I. $(srcdir)/rounding.c >/dev/null 2>&1; then \
if $(CC) $(CFLAGS) $(CPPFLAGS) $(LDFLAGS) -o rounding -DEXTRA_ROUNDING=$$r -I. $(srcdir)/rounding.c >rounding.out 2>&1; then \
echo "#define EXTRA_ROUNDING $$r" >rounding.h; \
if test -f "$$HOME/build_farm/build_test.fns"; then \
echo "EXTRA_ROUNDING is $$r" >&2; \
@@ -92,9 +92,11 @@ rounding.h: rounding.c rsync.h
done
@rm -f rounding
@if test -f rounding.h; then : ; else \
echo "Failed to create rounding.h!"; \
cat rounding.out 1>&2; \
echo "Failed to create rounding.h!" 1>&2; \
exit 1; \
fi
@rm -f rounding.out
tls$(EXEEXT): $(TLS_OBJ)
$(CC) $(CFLAGS) $(LDFLAGS) -o $@ $(TLS_OBJ) $(LIBS)
@@ -109,7 +111,7 @@ TRIMSLASH_OBJ = trimslash.o syscall.o lib/compat.o lib/snprintf.o
trimslash$(EXEEXT): $(TRIMSLASH_OBJ)
$(CC) $(CFLAGS) $(LDFLAGS) -o $@ $(TRIMSLASH_OBJ) $(LIBS)
T_UNSAFE_OBJ = t_unsafe.o syscall.o util.o t_stub.o lib/compat.o lib/snprintf.o
T_UNSAFE_OBJ = t_unsafe.o syscall.o util.o t_stub.o lib/compat.o lib/snprintf.o lib/wildmatch.o
t_unsafe$(EXEEXT): $(T_UNSAFE_OBJ)
$(CC) $(CFLAGS) $(LDFLAGS) -o $@ $(T_UNSAFE_OBJ) $(LIBS)

383
NEWS
View File

@@ -1,341 +1,136 @@
NEWS for rsync 3.0.0 (1 Mar 2008)
Protocol: 30 (changed)
Changes since 2.6.9:
NEWS for rsync 3.0.1 (3 Apr 2008)
Protocol: 30 (unchanged)
Changes since 3.0.0:
NOTABLE CHANGES IN BEHAVIOR:
- The handling of implied directories when using --relative has changed to
send them as directories (e.g. no implied dir is ever sent as a symlink).
This avoids unexpected behavior and should not adversely affect most
people. If you're one of those rare individuals who relied upon having
an implied dir be duplicated as a symlink, you should specify the
transfer of the symlink and the transfer of the referent directory as
separate args. (See also --keep-dirlinks and --no-implied-dirs.)
Also, exclude rules no longer have a partial effect on implied dirs.
- Requesting a remote file-listing without specifying -r (--recursive) now
sends the -d (--dirs) option to the remote rsync rather than sending -r
along with an extra exclude of /*/*. If the remote rsync does not
understand the -d option (i.e. it is 2.6.3 or older), you will need to
either turn off -d (--no-d), or specify -r --exclude='/*/*' manually.
- In --dry-run mode, the last line of the verbose summary text is output
with a "(DRY RUN)" suffix to help remind you that no updates were made.
Similarly, --only-write-batch outputs "(BATCH ONLY)".
- A writable rsync daemon with "use chroot" disabled now defaults to a
symlink-munging behavior designed to make symlinks safer while also
allowing absolute symlinks to be stored and retrieved. This also has
the effect of making symlinks unusable while they're in the daemon's
hierarchy. See the daemon's "munge symlinks" parameter for details.
- Starting up an extra copy of an rsync daemon will not clobber the pidfile
for the running daemon -- if the pidfile exists, the new daemon will exit
with an error. This means that your wrapper script that starts the rsync
daemon should be made to handle lock-breaking (if you want any automatic
breaking of locks to be done).
- Added the 'c'-flag to the itemizing of non-regular files so that the
itemized output doesn't get hidden if there were no attribute changes,
and also so that the itemizing of a --copy-links run will distinguish
between copying an identical non-regular file and the creation of a
revised version with a new value (e.g. a changed symlink referent, a
new device number, etc.).
BUG FIXES:
- A daemon with "use chroot = no" and excluded items listed in the daemon
config file now properly checks an absolute-path arg specified for these
options: --compare-dest, --link-dest, --copy-dest, --partial-dir,
--backup-dir, --temp-dir, and --files-from.
- Fixed a crash bug when a single-use rsync daemon (via remote shell) was
run without specifying a --config=FILE option.
- A daemon can now be told to disable all user- and group-name translation
on a per-module basis. This avoids a potential problem with a writable
daemon module that has "use chroot" enabled -- if precautions weren't
taken, a user could try to add a missing library and get rsync to use
it. This makes rsync safer by default, and more configurable when id-
translation is not desired. See the daemon's "numeric ids" parameter
for full details.
- Fixed a crash when backing up a directory that has a default ACL.
- A chroot daemon can now indicate which part of its path should affect the
chroot call, and which part should become an inside-chroot path for the
module. This allows you to have outside-the-transfer paths (such as for
libraries) even when you enable chroot protection. The idiom used in the
rsyncd.conf file is: path = /chroot/dirs/./dirs/inside
- Fixed a bug in the handling of xattr values that could cause rsync to
not think that a file's extended attributes are up-to-date.
- If a file's data arrived successfully on the receiving side but the
rename of the temporary file to the destination file failed AND the
--remove-source-files (or the deprecated --remove-sent-files) option
was specified, rsync no longer erroneously removes the associated
source file.
- Fixed the working of --fake-super with --link-dest and --xattrs.
- Fixed the output of -ii when combined with one of the --*-dest options:
it now itemizes all the items, not just the changed ones.
- Fixed a hang when combining --dry-run with --remove-source-files.
- Made the output of all file types consistent when using a --*-dest
option. Prior versions would output too many creation events for
matching items.
- Fixed a bug with --iconv's handling of files that cannot be converted:
a failed name can no longer cause a transfer failure.
- The code that waits for a child pid now handles being interrupted by a
signal. This fixes a problem with the pre-xfer exec function not being
able to get the exit status from the script.
- Fixed the building of the rounding.h file on systems that need custom
CPPFLAGS to be used. Also improved the error reporting if the building
of rounding.h fails.
- A negated filter rule (i.e. with a '!' modifier) no longer loses the
negation when sending the filter rules to the remote rsync.
- Fixed the use of the --protect-args (-s) option when talking to a daemon.
- Fixed a problem with the --out-format (aka --log-format) option %f: it
no longer outputs superfluous directory info for a non-daemon rsync.
- Fixed the --ignore-existing option's protection of files on the receiver
that are non-regular files on the sender (e.g. if a symlink or a dir on
the sender is trying to replace a file on the receiver). The reverse
protection (protecting a dir/symlink/device from being replaced by a
file) was already working.
- Fixed a problem with -vv (double --verbose) and --stats when "pushing"
files (which includes local copies). Version 2.6.9 would complete the
copy, but exit with an error when the receiver output its memory stats.
- Fixed an assert failure if --hard-links is combined with an option that
can skip a file in a set of hard-linked files (i.e. --ignore-existing,
--append, etc.), without skipping all the files in the set.
- If --password-file is used on a non-daemon transfer, rsync now complains
and exits. This should help users figure out that they can't use this
option to control a remote shell's password prompt.
- Avoid setting the modify time on a directory that already has the right
modify time set. This avoids tweaking the dir's ctime.
- Make sure that directory permissions of a newly-created destination
directory are handled right when --perms is left off.
- Improved the daemon-exclude handling to do a better job of applying the
exclude rules to path entries. It also sends the user an error just as
if the files were actually missing (instead of silently ignoring the
user's args), and avoids sending the user the filter-action messages
for these non-user-initiated rules.
- The itemized output of a newly-created destination directory is now
output as a creation event, not a change event.
- Fixed some glitches with the dry-run code's missing-directory
handling, including a problem when combined with --fuzzy.
- Improved --hard-link so that more corner cases are handled correctly
when combined with options such as --link-dest and/or --ignore-existing.
- Fixed some glitches with the skipped-directory handling.
- The --append option no longer updates a file that has the same size.
- Fixed the 'T'-flag itemizing of symlinks when --time isn't preserved.
- Fixed a bug when combining --backup and --backup-dir with --inplace:
any missing backup directories are now created.
- Fixed a glitch in the itemizing of permissions with the -E option.
- Fixed a bug when using --backup and --inplace with --whole-file or
--read-batch: backup files are actually created now.
- The --append option's restricting of transfers to those that add data no
longer prevents the updating of non-content changes to otherwise up-to-
date files (i.e. those with the same content but differing permissions,
ownership, xattrs, etc.).
- The daemon pidfile is checked and created sooner in the startup sequence.
- Don't allow --fake-super to be specified with -XX (double --xattrs)
because the options conflict. If a daemon has "fake super" enabled,
it automatically downgrades a -XX request to -X.
- If a daemon module's "path" value is not an absolute pathname, the code
now makes it absolute internally (making it work properly).
- Fixed a couple bugs in the parsing of daemon-config excludes that could
make a floating exclude rule get treated as matching an absolute path.
- Ensure that a temporary file always has owner-write permission while we
are writing to it. This avoids problems with some network filesystems
when transfering read-only files.
- A daemon doesn't try to auto-refuse the "iconv" option if iconv-support
wasn't compiled in to the daemon (avoiding a warning in the logs).
- Any errors output about password-file reading no longer cause an error at
the end of the run about a partial transfer.
- Fixed the inclusion of per-dir merge files from implied dirs.
- The --read-batch option for protocol 30 now ensures that several more
options are set correctly for the current batch file: --iconv, --acls,
--xattrs, --inplace, --append, and --append-verify.
- Using --only-write-batch to a daemon receiver now works properly (older
versions would update some files while writing the batch).
- Avoid outputting a "file has vanished" message when the file is a broken
symlink and --copy-unsafe-links or --copy-dirlinks is used (the code
already handled this for --copy-links).
- Fixed the combination of --only-write-batch and --dry-run.
- Fixed rsync's ability to remove files that are not writable by the file's
owner when rsync is running as the same user.
- Fixed the support/rrsync script to work with the latest options that
rsync sends (including its flag-specifying use of -e to the server).
ENHANCEMENTS:
- A new incremental-recursion algorithm is now used when rsync is talking
to another 3.x version. This starts the transfer going more quickly
(before all the files have been found), and requires much less memory.
See the --recursive option in the manpage for some restrictions.
- Added the --old-dirs (--old-d) option to make it easier for a user to
ask for file-listings with older rsync versions (this is easier than
having to type "-r --exclude='/*/*'" manually).
- Lowered memory use in the non-incremental-recursion algorithm for typical
option values (usually saving from 21-29 bytes per file).
- When getting an error while asking an older rsync daemon for a file
listing, rsync will try to notice if the error is a rejection of the
--dirs (-d) option and let the user know how to work around the issue.
- The default --delete algorithm is now --delete-during when talking to a
3.x rsync. This is a faster scan than using --delete-before (which is
the default when talking to older rsync versions), and is compatible with
the new incremental recursion mode.
- Added a few more --no-OPTION overrides.
- Rsync now allows multiple remote-source args to be specified rather than
having to rely on a special space-splitting side-effect of the remote-
shell. Additional remote args must specify the same host or an empty one
(e.g. empty: :file1 or ::module/file2). For example, this means that
local use of brace expansion now works: rsync -av host:dir/{f1,f2} .
- Improved the documentation of the --append option.
- Added the --protect-args (-s) option, that tells rsync to send most of
the command-line args at the start of the transfer rather than as args
to the remote-shell command. This protects them from space-splitting,
and only interprets basic wildcard special shell characters (*?[).
- Added the --delete-delay option, which is a more efficient way to delete
files at the end of the transfer without needing a separate delete pass.
- Added the --acls (-A) option to preserve Access Control Lists. This is
an improved version of the prior patch that was available, and it even
supports OS X ACLs. If you need to have backward compatibility with old,
ACL-patched versions of rsync, apply the acls.diff file from the patches
dir.
- Added the --xattrs (-X) option to preserve extended attributes. This is
an improved version of the prior patch that was available, and it even
supports OS X xattrs (which includes their resource fork data). If you
need to have backward compatibility with old, xattr-patched versions of
rsync, apply the xattrs.diff file from the patches dir.
- Added the --fake-super option that allows a non-super user to preserve
all attributes of a file by using a special extended-attribute idiom.
It even supports the storing of foreign ACL data on your backup server.
There is also an analogous "fake super" parameter for an rsync daemon.
- Added the --iconv option, which allows rsync to convert filenames from
one character-set to another during the transfer. The default is to
make this feature available as long as your system has iconv_open().
If compilation fails, specify --disable-iconv to configure, and then
rebuild. If you want rsync to perform character-set conversions by
default, you can specify --enable-iconv=CONVERT_STRING with the default
value for the --iconv option that you wish to use. For example,
"--enable-iconv=." is a good choice. See the rsync manpage for an
explanation of the --iconv option's settings.
- A new daemon config parameter, "charset", lets you control the character-
set that is used during an --iconv transfer to/from a daemon module. You
can also set your daemon to refuse "no-iconv" if you want to force the
client to use an --iconv transfer (requiring an rsync 3.x client).
- Added the --skip-compress=LIST option to override the default list of
file suffixes that will not be compressed when using --compress (-z).
- The daemon's default for "dont compress" was extended to include:
*.7z *.mp[34] *.mov *.avi *.ogg *.jpg *.jpeg
The name-matching routine was also optimized to run more quickly.
- The --max-delete option now outputs a warning if it skipped any file
deletions, including a count of how many deletions were skipped. (Older
versions just silently stopped deleting things.)
- You may specify --max-delete=0 to a 3.0.0 client to request that it warn
about extraneous files without deleting anything. If you're not sure
what version the client is, you can use the less-obvious --max-delete=-1,
as both old and new versions will treat that as the same request (though
older versions don't warn).
- The --hard-link option now uses less memory on both the sending and
receiving side for all protocol versions. For protocol 30, the use of a
hashtable on the sending side allows us to more efficiently convey to the
receiver what files are linked together. This reduces the amount of data
sent over the socket by a considerable margin (rather than adding more
data), and limits the in-memory storage of the device+inode information
to just the sending side for the new protocol 30, or to the receiving
side when speaking an older protocol (note that older rsync versions kept
the device+inode information on both sides).
- The filter rules now support a perishable ("p") modifier that marks rules
that should not have an effect in a directory that is being deleted. e.g.
-f '-p .svn/' would only affect "live" .svn directories.
- Rsync checks all the alternate-destination args for validity (e.g.
--link-dest). This lets the user know when they specified a directory
that does not exist.
- If we get an error setting the time on a symlink, we don't complain about
it anymore (since some operating systems don't support that, and it's not
that important).
- Protocol 30 now uses MD5 checksums instead of MD4.
- Changed the --append option to not checksum the existing data in the
destination file, which speeds up file appending.
- Added the --append-verify option, which works like the older --append
option (verifying the existing data in the destination file). For
compatibility with older rsync versions, any use of --append that is
talking protocol 29 or older will revert to the --append-verify method.
- Added the --contimeout=SECONDS option that lets the user specify a
connection timeout for rsync daemon access.
- Documented and extended the support for the RSYNC_CONNECT_PROG variable
that can be used to enhance the client side of a daemon connection.
- Improved the dashes and double-quotes in the nroff manpage output.
- Rsync now supports a lot more --no-OPTION override options.
- Improved the documentation of the filter/exclude/include daemon
parameters.
INTERNAL:
- The file-list sorting algorithm now uses a sort that keeps any same-
named items in the same order as they were specified. This allows
rsync to always ensure that the first of the duplicates is the one
that will be included in the copy. The new sort is also faster
than the glibc version of qsort() and mergesort().
- Fixed a couple minor bugs in the included popt library (ones which I
sent to the official popt project for inclusion in the 1.14 release).
- Rsync now supports the transfer of 64-bit timestamps (time_t values).
- Fixed a stat() call that should have been do_stat() so that the proper
normal/64-bit stat() function gets called. (Was in an area that should
not have caused problems, though.)
- Made the file-deletion code use a little less stack when recursing
through a directory hierarchy of extraneous files.
- Fixed a build problem with older (2.x) versions of gcc.
- Added some isType() functions that make dealing with signed characters
easier without forcing variables via casts.
- Changed strcat/strcpy/sprintf function calls to use safer versions.
- Upgraded the included popt version to 1.10.2 and improved its use of
string-handling functions.
- Added missing prototypes for compatibility functions from the lib dir.
- Configure determines if iconv() has a const arg, allowing us to avoid a
compiler warning.
- Made the sending of some numbers more efficient for protocol 30.
- Make sure that a daemon process doesn't mind if the client was weird and
omitted the --server option.
- There are more internal logging categories available in protocol 30 than
the age-old FINFO and FERROR, including FERROR_XFER and FWARN. These new
categories allow some errors and warnings to go to stderr without causing
an erroneous end-of-run warning about some files not being able to be
transferred.
- Improved the use of "const" on pointers.
- Improved J.W.'s pool_alloc routines to add a way of incrementally freeing
older sections of a pool's memory.
- The getaddrinfo.c compatibility code in the "lib" dir was replaced with
some new code (derived from samba, derived from PostgreSQL) that has a
better license than the old code.
- Changed the file-glob code to do a directory scan without using the
"glob" and "glob.h". This lets us do the globbing with less memory
churn, and also avoid adding daemon-excluded items to the returned
args.
DEVELOPER RELATED:
- Rsync is now licensed under the GPLv3 or later.
- The configure script tries to get the user's compiler to not warn about
unused function parameters if the build is not including one or more of
the ACL/xattrs/iconv features.
- Rsync is now being maintained in a "git" repository instead of CVS
(though the old CVS repository still exists for historical access).
Several maintenance scripts were updated to work with git.
- The configure script now has better checks for figuring out if the
included popt code should be used or not.
- Generated files are no longer committed into the source repository. The
autoconf and autoheader commands are now automatically run during the
normal use of "configure" and "make". The latest dev versions of all
generated files can also be copied from the samba.org web site (see the
prepare-source script's fetch option).
- Fixed two testsuite glitches: avoid a failure if someone's "cd" command
outputs the current directory when cd-ing to a relative path, and made
the itemized test query how rsync was built to determine if it should
expect hard-linked symlinks or not.
- The "patches" directory of diff files is now built from branches in the
rsync git repository (branch patch/FOO creates file patches/FOO.diff).
This directory is now distributed in a separate separate tar file named
rsync-patches-VERSION.tar.gz instead of the main rsync-VERSION.tar.gz.
- Updated the testsuite to verify that various bug fixes remain fixed.
- The proto.h file is now built using a simple perl script rather than a
complex awk script, which proved to be more widely compatible.
- The RPM spec file was updated to have: (1) comments for how to use the
rsync-patch tar file, and (2) an /etc/xinetd.d/rsync file.
- When running the tests, we now put our per-test temp dirs into a sub-
directory named testtmp (which is created, if missing). This allows
someone to symlink the testtmp directory to another filesystem (which is
useful if the build dir's filesystem does not support ACLs and xattrs,
but another filesystem does).
- Rsync now has a way of handling protocol-version changes during the
development of a new protocol version. This causes any out-of-sync
versions to speak an older protocol rather than fail in a cryptic manner.
This addition makes it safer to deploy a pre-release version that may
interact with the public. This new exchange of sub-version info does not
interfere with the {MIN,MAX}_PROTOCOL_VERSION checking algorithm (which
does not have enough range to allow the main protocol number to be
incremented for every minor tweak in that happens during development).
- The csprotocol.txt file was updated to mention the daemon protocol change
in the 3.0.0 release.
- Updated the build scripts to work with a revised FTP directory
structure.

344
OLDNEWS
View File

@@ -1,3 +1,346 @@
NEWS for rsync 3.0.0 (1 Mar 2008)
Protocol: 30 (changed)
Changes since 2.6.9:
NOTABLE CHANGES IN BEHAVIOR:
- The handling of implied directories when using --relative has changed to
send them as directories (e.g. no implied dir is ever sent as a symlink).
This avoids unexpected behavior and should not adversely affect most
people. If you're one of those rare individuals who relied upon having
an implied dir be duplicated as a symlink, you should specify the
transfer of the symlink and the transfer of the referent directory as
separate args. (See also --keep-dirlinks and --no-implied-dirs.)
Also, exclude rules no longer have a partial effect on implied dirs.
- Requesting a remote file-listing without specifying -r (--recursive) now
sends the -d (--dirs) option to the remote rsync rather than sending -r
along with an extra exclude of /*/*. If the remote rsync does not
understand the -d option (i.e. it is 2.6.3 or older), you will need to
either turn off -d (--no-d), or specify -r --exclude='/*/*' manually.
- In --dry-run mode, the last line of the verbose summary text is output
with a "(DRY RUN)" suffix to help remind you that no updates were made.
Similarly, --only-write-batch outputs "(BATCH ONLY)".
- A writable rsync daemon with "use chroot" disabled now defaults to a
symlink-munging behavior designed to make symlinks safer while also
allowing absolute symlinks to be stored and retrieved. This also has
the effect of making symlinks unusable while they're in the daemon's
hierarchy. See the daemon's "munge symlinks" parameter for details.
- Starting up an extra copy of an rsync daemon will not clobber the pidfile
for the running daemon -- if the pidfile exists, the new daemon will exit
with an error. This means that your wrapper script that starts the rsync
daemon should be made to handle lock-breaking (if you want any automatic
breaking of locks to be done).
BUG FIXES:
- A daemon with "use chroot = no" and excluded items listed in the daemon
config file now properly checks an absolute-path arg specified for these
options: --compare-dest, --link-dest, --copy-dest, --partial-dir,
--backup-dir, --temp-dir, and --files-from.
- A daemon can now be told to disable all user- and group-name translation
on a per-module basis. This avoids a potential problem with a writable
daemon module that has "use chroot" enabled -- if precautions weren't
taken, a user could try to add a missing library and get rsync to use
it. This makes rsync safer by default, and more configurable when id-
translation is not desired. See the daemon's "numeric ids" parameter
for full details.
- A chroot daemon can now indicate which part of its path should affect the
chroot call, and which part should become an inside-chroot path for the
module. This allows you to have outside-the-transfer paths (such as for
libraries) even when you enable chroot protection. The idiom used in the
rsyncd.conf file is: path = /chroot/dirs/./dirs/inside
- If a file's data arrived successfully on the receiving side but the
rename of the temporary file to the destination file failed AND the
--remove-source-files (or the deprecated --remove-sent-files) option
was specified, rsync no longer erroneously removes the associated
source file.
- Fixed the output of -ii when combined with one of the --*-dest options:
it now itemizes all the items, not just the changed ones.
- Made the output of all file types consistent when using a --*-dest
option. Prior versions would output too many creation events for
matching items.
- The code that waits for a child pid now handles being interrupted by a
signal. This fixes a problem with the pre-xfer exec function not being
able to get the exit status from the script.
- A negated filter rule (i.e. with a '!' modifier) no longer loses the
negation when sending the filter rules to the remote rsync.
- Fixed a problem with the --out-format (aka --log-format) option %f: it
no longer outputs superfluous directory info for a non-daemon rsync.
- Fixed a problem with -vv (double --verbose) and --stats when "pushing"
files (which includes local copies). Version 2.6.9 would complete the
copy, but exit with an error when the receiver output its memory stats.
- If --password-file is used on a non-daemon transfer, rsync now complains
and exits. This should help users figure out that they can't use this
option to control a remote shell's password prompt.
- Make sure that directory permissions of a newly-created destination
directory are handled right when --perms is left off.
- The itemized output of a newly-created destination directory is now
output as a creation event, not a change event.
- Improved --hard-link so that more corner cases are handled correctly
when combined with options such as --link-dest and/or --ignore-existing.
- The --append option no longer updates a file that has the same size.
- Fixed a bug when combining --backup and --backup-dir with --inplace:
any missing backup directories are now created.
- Fixed a bug when using --backup and --inplace with --whole-file or
--read-batch: backup files are actually created now.
- The daemon pidfile is checked and created sooner in the startup sequence.
- If a daemon module's "path" value is not an absolute pathname, the code
now makes it absolute internally (making it work properly).
- Ensure that a temporary file always has owner-write permission while we
are writing to it. This avoids problems with some network filesystems
when transfering read-only files.
- Any errors output about password-file reading no longer cause an error at
the end of the run about a partial transfer.
- The --read-batch option for protocol 30 now ensures that several more
options are set correctly for the current batch file: --iconv, --acls,
--xattrs, --inplace, --append, and --append-verify.
- Using --only-write-batch to a daemon receiver now works properly (older
versions would update some files while writing the batch).
- Avoid outputting a "file has vanished" message when the file is a broken
symlink and --copy-unsafe-links or --copy-dirlinks is used (the code
already handled this for --copy-links).
- Fixed the combination of --only-write-batch and --dry-run.
- Fixed rsync's ability to remove files that are not writable by the file's
owner when rsync is running as the same user.
ENHANCEMENTS:
- A new incremental-recursion algorithm is now used when rsync is talking
to another 3.x version. This starts the transfer going more quickly
(before all the files have been found), and requires much less memory.
See the --recursive option in the manpage for some restrictions.
- Lowered memory use in the non-incremental-recursion algorithm for typical
option values (usually saving from 21-29 bytes per file).
- The default --delete algorithm is now --delete-during when talking to a
3.x rsync. This is a faster scan than using --delete-before (which is
the default when talking to older rsync versions), and is compatible with
the new incremental recursion mode.
- Rsync now allows multiple remote-source args to be specified rather than
having to rely on a special space-splitting side-effect of the remote-
shell. Additional remote args must specify the same host or an empty one
(e.g. empty: :file1 or ::module/file2). For example, this means that
local use of brace expansion now works: rsync -av host:dir/{f1,f2} .
- Added the --protect-args (-s) option, that tells rsync to send most of
the command-line args at the start of the transfer rather than as args
to the remote-shell command. This protects them from space-splitting,
and only interprets basic wildcard special shell characters (*?[).
- Added the --delete-delay option, which is a more efficient way to delete
files at the end of the transfer without needing a separate delete pass.
- Added the --acls (-A) option to preserve Access Control Lists. This is
an improved version of the prior patch that was available, and it even
supports OS X ACLs. If you need to have backward compatibility with old,
ACL-patched versions of rsync, apply the acls.diff file from the patches
dir.
- Added the --xattrs (-X) option to preserve extended attributes. This is
an improved version of the prior patch that was available, and it even
supports OS X xattrs (which includes their resource fork data). If you
need to have backward compatibility with old, xattr-patched versions of
rsync, apply the xattrs.diff file from the patches dir.
- Added the --fake-super option that allows a non-super user to preserve
all attributes of a file by using a special extended-attribute idiom.
It even supports the storing of foreign ACL data on your backup server.
There is also an analogous "fake super" parameter for an rsync daemon.
- Added the --iconv option, which allows rsync to convert filenames from
one character-set to another during the transfer. The default is to
make this feature available as long as your system has iconv_open().
If compilation fails, specify --disable-iconv to configure, and then
rebuild. If you want rsync to perform character-set conversions by
default, you can specify --enable-iconv=CONVERT_STRING with the default
value for the --iconv option that you wish to use. For example,
"--enable-iconv=." is a good choice. See the rsync manpage for an
explanation of the --iconv option's settings.
- A new daemon config parameter, "charset", lets you control the character-
set that is used during an --iconv transfer to/from a daemon module. You
can also set your daemon to refuse "no-iconv" if you want to force the
client to use an --iconv transfer (requiring an rsync 3.x client).
- Added the --skip-compress=LIST option to override the default list of
file suffixes that will not be compressed when using --compress (-z).
- The daemon's default for "dont compress" was extended to include:
*.7z *.mp[34] *.mov *.avi *.ogg *.jpg *.jpeg
The name-matching routine was also optimized to run more quickly.
- The --max-delete option now outputs a warning if it skipped any file
deletions, including a count of how many deletions were skipped. (Older
versions just silently stopped deleting things.)
- You may specify --max-delete=0 to a 3.0.0 client to request that it warn
about extraneous files without deleting anything. If you're not sure
what version the client is, you can use the less-obvious --max-delete=-1,
as both old and new versions will treat that as the same request (though
older versions don't warn).
- The --hard-link option now uses less memory on both the sending and
receiving side for all protocol versions. For protocol 30, the use of a
hashtable on the sending side allows us to more efficiently convey to the
receiver what files are linked together. This reduces the amount of data
sent over the socket by a considerable margin (rather than adding more
data), and limits the in-memory storage of the device+inode information
to just the sending side for the new protocol 30, or to the receiving
side when speaking an older protocol (note that older rsync versions kept
the device+inode information on both sides).
- The filter rules now support a perishable ("p") modifier that marks rules
that should not have an effect in a directory that is being deleted. e.g.
-f '-p .svn/' would only affect "live" .svn directories.
- Rsync checks all the alternate-destination args for validity (e.g.
--link-dest). This lets the user know when they specified a directory
that does not exist.
- If we get an ENOSYS error setting the time on a symlink, we don't
complain about it anymore (for those systems that even support the
setting of the modify-time on a symlink).
- Protocol 30 now uses MD5 checksums instead of MD4.
- Changed the --append option to not checksum the existing data in the
destination file, which speeds up file appending.
- Added the --append-verify option, which works like the older --append
option (verifying the existing data in the destination file). For
compatibility with older rsync versions, any use of --append that is
talking protocol 29 or older will revert to the --append-verify method.
- Added the --contimeout=SECONDS option that lets the user specify a
connection timeout for rsync daemon access.
- Documented and extended the support for the RSYNC_CONNECT_PROG variable
that can be used to enhance the client side of a daemon connection.
- Improved the dashes and double-quotes in the nroff manpage output.
- Rsync now supports a lot more --no-OPTION override options.
INTERNAL:
- The file-list sorting algorithm now uses a sort that keeps any same-
named items in the same order as they were specified. This allows
rsync to always ensure that the first of the duplicates is the one
that will be included in the copy. The new sort is also faster
than the glibc version of qsort() and mergesort().
- Rsync now supports the transfer of 64-bit timestamps (time_t values).
- Made the file-deletion code use a little less stack when recursing
through a directory hierarchy of extraneous files.
- Fixed a build problem with older (2.x) versions of gcc.
- Added some isType() functions that make dealing with signed characters
easier without forcing variables via casts.
- Changed strcat/strcpy/sprintf function calls to use safer versions.
- Upgraded the included popt version to 1.10.2 and improved its use of
string-handling functions.
- Added missing prototypes for compatibility functions from the lib dir.
- Configure determines if iconv() has a const arg, allowing us to avoid a
compiler warning.
- Made the sending of some numbers more efficient for protocol 30.
- Make sure that a daemon process doesn't mind if the client was weird and
omitted the --server option.
- There are more internal logging categories available in protocol 30 than
the age-old FINFO and FERROR, including FERROR_XFER and FWARN. These new
categories allow some errors and warnings to go to stderr without causing
an erroneous end-of-run warning about some files not being able to be
transferred.
- Improved the use of "const" on pointers.
- Improved J.W.'s pool_alloc routines to add a way of incrementally freeing
older sections of a pool's memory.
- The getaddrinfo.c compatibility code in the "lib" dir was replaced with
some new code (derived from samba, derived from PostgreSQL) that has a
better license than the old code.
DEVELOPER RELATED:
- Rsync is now licensed under the GPLv3 or later.
- Rsync is now being maintained in a "git" repository instead of CVS
(though the old CVS repository still exists for historical access).
Several maintenance scripts were updated to work with git.
- Generated files are no longer committed into the source repository. The
autoconf and autoheader commands are now automatically run during the
normal use of "configure" and "make". The latest dev versions of all
generated files can also be copied from the samba.org web site (see the
prepare-source script's fetch option).
- The "patches" directory of diff files is now built from branches in the
rsync git repository (branch patch/FOO creates file patches/FOO.diff).
This directory is now distributed in a separate separate tar file named
rsync-patches-VERSION.tar.gz instead of the main rsync-VERSION.tar.gz.
- The proto.h file is now built using a simple perl script rather than a
complex awk script, which proved to be more widely compatible.
- When running the tests, we now put our per-test temp dirs into a sub-
directory named testtmp (which is created, if missing). This allows
someone to symlink the testtmp directory to another filesystem (which is
useful if the build dir's filesystem does not support ACLs and xattrs,
but another filesystem does).
- Rsync now has a way of handling protocol-version changes during the
development of a new protocol version. This causes any out-of-sync
versions to speak an older protocol rather than fail in a cryptic manner.
This addition makes it safer to deploy a pre-release version that may
interact with the public. This new exchange of sub-version info does not
interfere with the {MIN,MAX}_PROTOCOL_VERSION checking algorithm (which
does not have enough range to allow the main protocol number to be
incremented for every minor tweak in that happens during development).
- The csprotocol.txt file was updated to mention the daemon protocol change
in the 3.0.0 release.
NEWS for rsync 2.6.9 (6 Nov 2006)
Protocol: 29 (unchanged)
Changes since 2.6.8:
@@ -2244,6 +2587,7 @@ Changes since 2.4.6:
Partial Protocol History
RELEASE DATE VER. DATE OF COMMIT* PROTOCOL
03 Apr 2008 3.0.1 30
01 Mar 2008 3.0.0 11 Nov 2006 30
06 Nov 2006 2.6.9 29
22 Apr 2006 2.6.8 29

View File

@@ -22,6 +22,7 @@
#include "rsync.h"
#include "ifuncs.h"
extern int quiet;
extern int verbose;
extern int dry_run;
extern int output_motd;
@@ -31,7 +32,9 @@ extern int am_server;
extern int am_daemon;
extern int am_root;
extern int rsync_port;
extern int protect_args;
extern int ignore_errors;
extern int preserve_xattrs;
extern int kluge_around_eof;
extern int daemon_over_rsh;
extern int sanitize_paths;
@@ -53,7 +56,7 @@ extern char *logfile_format;
extern char *files_from;
extern char *tmpdir;
extern struct chmod_mode_struct *chmod_modes;
extern struct filter_list_struct server_filter_list;
extern struct filter_list_struct daemon_filter_list;
extern char curr_dir[];
#ifdef ICONV_OPTION
extern char *iconv_opt;
@@ -211,7 +214,7 @@ int start_inband_exchange(int f_in, int f_out, const char *user, int argc, char
int sargc = 0;
char *p, *modname;
assert(argc > 0);
assert(argc > 0 && *argv != NULL);
if (**argv == '/') {
rprintf(FERROR,
@@ -313,6 +316,8 @@ int start_inband_exchange(int f_in, int f_out, const char *user, int argc, char
if (rl_nulls) {
for (i = 0; i < sargc; i++) {
if (!sargs[i]) /* stop at --protect-args NULL */
break;
write_sbuf(f_out, sargs[i]);
write_byte(f_out, 0);
}
@@ -323,6 +328,9 @@ int start_inband_exchange(int f_in, int f_out, const char *user, int argc, char
write_sbuf(f_out, "\n");
}
if (protect_args)
send_protected_args(f_out, sargs);
if (protocol_version < 23) {
if (protocol_version == 22 || !am_sender)
io_start_multiplex_in();
@@ -334,16 +342,24 @@ int start_inband_exchange(int f_in, int f_out, const char *user, int argc, char
}
static char *finish_pre_exec(pid_t pid, int fd, char *request,
int argc, char *argv[])
char **early_argv, char **argv)
{
int j, status = -1;
int j = 0, status = -1;
if (!request)
request = "(NONE)";
write_buf(fd, request, strlen(request)+1);
for (j = 0; j < argc; j++)
if (early_argv) {
for ( ; *early_argv; early_argv++)
write_buf(fd, *early_argv, strlen(*early_argv)+1);
j = 1; /* Skip arg0 name in argv. */
}
for ( ; argv[j]; j++) {
write_buf(fd, argv[j], strlen(argv[j])+1);
if (argv[j][0] == '.' && argv[j][1] == '\0')
break;
}
write_byte(fd, 0);
close(fd);
@@ -383,8 +399,8 @@ static int read_arg_from_pipe(int fd, char *buf, int limit)
static int rsync_module(int f_in, int f_out, int i, char *addr, char *host)
{
int argc, opt_cnt;
char **argv, *chroot_path = NULL;
int argc;
char **argv, **orig_argv, **orig_early_argv, *chroot_path = NULL;
char line[BIGPATHBUFLEN];
uid_t uid = (uid_t)-2; /* canonically "nobody" */
gid_t gid = (gid_t)-2;
@@ -489,19 +505,19 @@ static int rsync_module(int f_in, int f_out, int i, char *addr, char *host)
if ((p = strstr(module_dir, "/./")) != NULL) {
*p = '\0';
p += 2;
} else if ((p = strdup("/")) == NULL)
} else if ((p = strdup("/")) == NULL) /* MEMORY LEAK */
out_of_memory("rsync_module");
}
/* We do a push_dir() that doesn't actually call 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 (!push_dir(module_dir, 1))
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");
push_dir(line, 1); /* Restore curr_dir. */
change_dir(line, CD_SKIP_CHDIR); /* Restore curr_dir. */
if (use_chroot) {
chroot_path = module_dir;
@@ -516,25 +532,25 @@ static int rsync_module(int f_in, int f_out, int i, char *addr, char *host)
set_filter_dir(module_dir, module_dirlen);
p = lp_filter(i);
parse_rule(&server_filter_list, p, MATCHFLG_WORD_SPLIT,
XFLG_ABS_IF_SLASH);
parse_rule(&daemon_filter_list, p, MATCHFLG_WORD_SPLIT,
XFLG_ABS_IF_SLASH | XFLG_DIR2WILD3);
p = lp_include_from(i);
parse_filter_file(&server_filter_list, p, MATCHFLG_INCLUDE,
XFLG_ABS_IF_SLASH | XFLG_OLD_PREFIXES | XFLG_FATAL_ERRORS);
parse_filter_file(&daemon_filter_list, p, MATCHFLG_INCLUDE,
XFLG_ABS_IF_SLASH | XFLG_DIR2WILD3 | XFLG_OLD_PREFIXES | XFLG_FATAL_ERRORS);
p = lp_include(i);
parse_rule(&server_filter_list, p,
parse_rule(&daemon_filter_list, p,
MATCHFLG_INCLUDE | MATCHFLG_WORD_SPLIT,
XFLG_ABS_IF_SLASH | XFLG_OLD_PREFIXES);
XFLG_ABS_IF_SLASH | XFLG_DIR2WILD3 | XFLG_OLD_PREFIXES);
p = lp_exclude_from(i);
parse_filter_file(&server_filter_list, p, 0,
XFLG_ABS_IF_SLASH | XFLG_OLD_PREFIXES | XFLG_FATAL_ERRORS);
parse_filter_file(&daemon_filter_list, p, 0,
XFLG_ABS_IF_SLASH | XFLG_DIR2WILD3 | XFLG_OLD_PREFIXES | XFLG_FATAL_ERRORS);
p = lp_exclude(i);
parse_rule(&server_filter_list, p, MATCHFLG_WORD_SPLIT,
XFLG_ABS_IF_SLASH | XFLG_OLD_PREFIXES);
parse_rule(&daemon_filter_list, p, MATCHFLG_WORD_SPLIT,
XFLG_ABS_IF_SLASH | XFLG_DIR2WILD3 | XFLG_OLD_PREFIXES);
log_init(1);
@@ -657,12 +673,12 @@ static int rsync_module(int f_in, int f_out, int i, char *addr, char *host)
io_printf(f_out, "@ERROR: chroot failed\n");
return -1;
}
if (!push_dir(module_dir, 0))
if (!change_dir(module_dir, CD_NORMAL))
goto chdir_failed;
if (module_dirlen)
sanitize_paths = 1;
} else {
if (!push_dir(module_dir, 0)) {
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");
@@ -675,7 +691,7 @@ static int rsync_module(int f_in, int f_out, int i, char *addr, char *host)
munge_symlinks = !use_chroot || module_dirlen;
if (munge_symlinks) {
STRUCT_STAT st;
if (stat(SYMLINK_PREFIX, &st) == 0 && S_ISDIR(st.st_mode)) {
if (do_stat(SYMLINK_PREFIX, &st) == 0 && S_ISDIR(st.st_mode)) {
rprintf(FLOG, "Symlink munging is unsupported when a %s directory exists.\n",
SYMLINK_PREFIX);
io_printf(f_out, "@ERROR: daemon security issue -- contact admin\n", name);
@@ -730,24 +746,40 @@ static int rsync_module(int f_in, int f_out, int i, char *addr, char *host)
io_printf(f_out, "@RSYNCD: OK\n");
opt_cnt = read_args(f_in, name, line, sizeof line, rl_nulls, &argv, &argc, &request);
read_args(f_in, name, line, sizeof line, rl_nulls, &argv, &argc, &request);
orig_argv = argv;
verbose = 0; /* future verbosity is controlled by client options */
ret = parse_arguments(&argc, (const char ***) &argv);
if (protect_args && ret) {
orig_early_argv = orig_argv;
protect_args = 2;
read_args(f_in, name, line, sizeof line, 1, &argv, &argc, &request);
orig_argv = argv;
ret = parse_arguments(&argc, (const char ***) &argv);
} else
orig_early_argv = NULL;
if (pre_exec_pid) {
err_msg = finish_pre_exec(pre_exec_pid, pre_exec_fd, request,
opt_cnt, argv);
orig_early_argv, orig_argv);
}
verbose = 0; /* future verbosity is controlled by client options */
ret = parse_arguments(&argc, (const char ***) &argv, 0);
if (orig_early_argv)
free(orig_early_argv);
am_server = 1; /* Don't let someone try to be tricky. */
quiet = 0;
if (lp_ignore_errors(module_id))
ignore_errors = 1;
if (write_batch < 0)
dry_run = 1;
if (lp_fake_super(i))
if (lp_fake_super(i)) {
if (preserve_xattrs > 1)
preserve_xattrs = 1;
am_root = -1;
else if (am_root < 0) /* Treat --fake-super from client as --super. */
} else if (am_root < 0) /* Treat --fake-super from client as --super. */
am_root = 2;
if (filesfrom_fd == 0)
@@ -864,6 +896,17 @@ static void send_listing(int fd)
io_printf(fd,"@RSYNCD: EXIT\n");
}
static int load_config(int globals_only)
{
if (!config_file) {
if (am_server && am_root <= 0)
config_file = RSYNCD_USERCONF;
else
config_file = RSYNCD_SYSCONF;
}
return lp_load(config_file, globals_only);
}
/* this is called when a connection is established to a client
and we want to start talking. The setup of the system is done from
here */
@@ -879,7 +922,7 @@ int start_daemon(int f_in, int f_out)
* might cause log-file output to occur. This ensures that the
* "log file" param gets honored for the 2 non-forked use-cases
* (when rsync is run by init and run by a remote shell). */
if (!lp_load(config_file, 0))
if (!load_config(0))
exit_cleanup(RERR_SYNTAX);
addr = client_addr(f_in);
@@ -988,13 +1031,6 @@ static void become_daemon(void)
int daemon_main(void)
{
if (!config_file) {
if (am_server && am_root <= 0)
config_file = RSYNCD_USERCONF;
else
config_file = RSYNCD_SYSCONF;
}
if (is_a_socket(STDIN_FILENO)) {
int i;
@@ -1009,7 +1045,7 @@ int daemon_main(void)
return start_daemon(STDIN_FILENO, STDIN_FILENO);
}
if (!lp_load(config_file, 1)) {
if (!load_config(1)) {
fprintf(stderr, "Failed to parse config file: %s\n", config_file);
exit_cleanup(RERR_SYNTAX);
}

View File

@@ -271,6 +271,10 @@ void setup_protocol(int f_out,int f_in)
exit_cleanup(RERR_SYNTAX);
}
need_messages_from_generator = 1;
#if defined HAVE_LUTIMES && defined HAVE_UTIMES
} else if (!am_sender) {
receiver_symlink_times = 1;
#endif
}
if (need_unsorted_flist && (!am_sender || inc_recurse))

View File

@@ -5,7 +5,7 @@ AC_CONFIG_SRCDIR([byteorder.h])
AC_CONFIG_HEADER(config.h)
AC_PREREQ(2.59)
RSYNC_VERSION=3.0.0
RSYNC_VERSION=3.0.1
AC_SUBST(RSYNC_VERSION)
AC_MSG_NOTICE([Configuring rsync $RSYNC_VERSION])
@@ -311,8 +311,10 @@ AC_HEADER_SYS_WAIT
AC_CHECK_HEADERS(sys/fcntl.h sys/select.h fcntl.h sys/time.h sys/unistd.h \
unistd.h utime.h grp.h compat.h sys/param.h ctype.h sys/wait.h \
sys/ioctl.h sys/filio.h string.h stdlib.h sys/socket.h sys/mode.h \
sys/un.h sys/attr.h glob.h mcheck.h arpa/inet.h arpa/nameser.h locale.h \
netdb.h malloc.h float.h limits.h iconv.h libcharset.h langinfo.h)
sys/un.h sys/attr.h mcheck.h arpa/inet.h arpa/nameser.h locale.h \
netdb.h malloc.h float.h limits.h iconv.h libcharset.h langinfo.h \
sys/acl.h acl/libacl.h attr/xattr.h sys/xattr.h sys/extattr.h \
popt.h popt/popt.h)
AC_HEADER_MAJOR
AC_CACHE_CHECK([if makedev takes 3 args],rsync_cv_MAKEDEV_TAKES_3_ARGS,[
@@ -548,7 +550,7 @@ AC_FUNC_UTIME_NULL
AC_FUNC_ALLOCA
AC_CHECK_FUNCS(waitpid wait4 getcwd strdup chown chmod lchmod mknod mkfifo \
fchmod fstat ftruncate strchr readlink link utime utimes lutimes strftime \
memmove lchown vsnprintf snprintf vasprintf asprintf setsid glob strpbrk \
memmove lchown vsnprintf snprintf vasprintf asprintf setsid strpbrk \
strlcat strlcpy strtol mallinfo getgroups setgroups geteuid getegid \
setlocale setmode open64 lseek64 mkstemp64 mtrace va_copy __va_copy \
strerror putenv iconv_open locale_charset nl_langinfo getxattr \
@@ -654,6 +656,15 @@ fi
if test x"$with_included_popt" != x"yes"; then
AC_CHECK_LIB(popt, poptGetContext, , [with_included_popt=yes])
fi
if test x"$ac_cv_header_popt_popt_h" = x"yes"; then
# If the system has /usr/include/popt/popt.h, we enable the
# included popt because an attempt to "#include <popt/popt.h>"
# would use our included header file anyway (due to -I.), and
# might conflict with the system popt.
with_included_popt=yes
elif test x"$ac_cv_header_popt_h" != x"yes"; then
with_included_popt=yes
fi
AC_MSG_CHECKING([whether to use included libpopt])
if test x"$with_included_popt" = x"yes"; then
@@ -825,7 +836,6 @@ AC_SUBST(CC_SHOBJ_FLAG)
AC_SUBST(BUILD_POPT)
AC_SUBST(MAKE_MAN)
AC_CHECK_HEADERS(sys/acl.h acl/libacl.h)
AC_CHECK_FUNCS(_acl __acl _facl __facl)
#################################################
# check for ACL support
@@ -907,10 +917,6 @@ samba_cv_HAVE_ACL_GET_PERM_NP=yes,samba_cv_HAVE_ACL_GET_PERM_NP=no)])
esac
fi
AC_CHECK_HEADERS(attr/xattr.h)
AC_CHECK_HEADERS(sys/xattr.h)
AC_CHECK_HEADERS(sys/extattr.h)
#################################################
# check for extended attribute support
AC_MSG_CHECKING(whether to support extended attributes)
@@ -952,6 +958,23 @@ else
esac
fi
if test x"$enable_acl_support" = x"no" -o x"$enable_xattr_support" = x"no" -o x"$enable_iconv" = x"no"; then
AC_MSG_CHECKING([whether $CC supports -Wno-unused-parameter])
OLD_CFLAGS="$CFLAGS"
CFLAGS="$CFLAGS -Wno-unused-parameter"
AC_COMPILE_IFELSE([ ], [rsync_warn_flag=yes], [rsync_warn_flag=no])
AC_MSG_RESULT([$rsync_warn_flag])
if test x"$rsync_warn_flag" = x"no"; then
CFLAGS="$OLD_CFLAGS"
fi
fi
case "$CC" in
' checker'*|checker*)
AC_DEFINE(FORCE_FD_ZERO_MEMSET, 1, [Used to make "checker" understand that FD_ZERO() clears memory.])
;;
esac
AC_CONFIG_FILES([Makefile lib/dummy zlib/dummy popt/dummy shconfig])
AC_OUTPUT

View File

@@ -43,7 +43,7 @@ extern unsigned int module_dirlen;
struct filter_list_struct filter_list = { 0, 0, "" };
struct filter_list_struct cvs_filter_list = { 0, 0, " [global CVS]" };
struct filter_list_struct server_filter_list = { 0, 0, " [daemon]" };
struct filter_list_struct daemon_filter_list = { 0, 0, " [daemon]" };
/* Need room enough for ":MODS " prefix plus some room to grow. */
#define MAX_RULE_PREFIX (16)
@@ -52,6 +52,8 @@ struct filter_list_struct server_filter_list = { 0, 0, " [daemon]" };
#define MODIFIERS_INCL_EXCL "/!Crsp"
#define MODIFIERS_HIDE_PROTECT "/!p"
#define SLASH_WILD3_SUFFIX "/***"
/* The dirbuf is set by push_local_filters() to the current subdirectory
* relative to curr_dir that is being processed. The path always has a
* trailing slash appended, and the variable dirbuf_len contains the length
@@ -119,7 +121,7 @@ static void add_rule(struct filter_list_struct *listp, const char *pat,
{
struct filter_struct *ret;
const char *cp;
unsigned int ex_len;
unsigned int pre_len, suf_len, slash_cnt = 0;
if (verbose > 2) {
rprintf(FINFO, "[%s] add_rule(%s%.*s%s)%s\n",
@@ -145,22 +147,51 @@ static void add_rule(struct filter_list_struct *listp, const char *pat,
if (!(ret = new0(struct filter_struct)))
out_of_memory("add_rule");
if (pat_len > 1 && pat[pat_len-1] == '/') {
pat_len--;
mflags |= MATCHFLG_DIRECTORY;
}
for (cp = pat; cp < pat + pat_len; cp++) {
if (*cp == '/')
slash_cnt++;
}
if (!(mflags & (MATCHFLG_ABS_PATH | MATCHFLG_MERGE_FILE))
&& ((xflags & (XFLG_ANCHORED2ABS|XFLG_ABS_IF_SLASH) && *pat == '/')
|| (xflags & XFLG_ABS_IF_SLASH && strchr(pat, '/') != NULL))) {
|| (xflags & XFLG_ABS_IF_SLASH && slash_cnt))) {
mflags |= MATCHFLG_ABS_PATH;
if (*pat == '/')
ex_len = dirbuf_len - module_dirlen - 1;
pre_len = dirbuf_len - module_dirlen - 1;
else
ex_len = 0;
pre_len = 0;
} else
ex_len = 0;
if (!(ret->pattern = new_array(char, ex_len + pat_len + 1)))
pre_len = 0;
/* The daemon wants dir-exclude rules to get an appended "/" + "***". */
if (xflags & XFLG_DIR2WILD3
&& BITS_SETnUNSET(mflags, MATCHFLG_DIRECTORY, MATCHFLG_INCLUDE)) {
mflags &= ~MATCHFLG_DIRECTORY;
suf_len = sizeof SLASH_WILD3_SUFFIX - 1;
} else
suf_len = 0;
if (!(ret->pattern = new_array(char, pre_len + pat_len + suf_len + 1)))
out_of_memory("add_rule");
if (ex_len)
memcpy(ret->pattern, dirbuf + module_dirlen, ex_len);
strlcpy(ret->pattern + ex_len, pat, pat_len + 1);
pat_len += ex_len;
if (pre_len) {
memcpy(ret->pattern, dirbuf + module_dirlen, pre_len);
for (cp = ret->pattern; cp < ret->pattern + pre_len; cp++) {
if (*cp == '/')
slash_cnt++;
}
}
strlcpy(ret->pattern + pre_len, pat, pat_len + 1);
pat_len += pre_len;
if (suf_len) {
memcpy(ret->pattern + pat_len, SLASH_WILD3_SUFFIX, suf_len+1);
pat_len += suf_len;
slash_cnt++;
}
if (strpbrk(ret->pattern, "*[?")) {
mflags |= MATCHFLG_WILD;
@@ -178,11 +209,6 @@ static void add_rule(struct filter_list_struct *listp, const char *pat,
}
}
if (pat_len > 1 && ret->pattern[pat_len-1] == '/') {
ret->pattern[pat_len-1] = 0;
mflags |= MATCHFLG_DIRECTORY;
}
if (mflags & MATCHFLG_PERDIR_MERGE) {
struct filter_list_struct *lp;
unsigned int len;
@@ -226,10 +252,8 @@ static void add_rule(struct filter_list_struct *listp, const char *pat,
out_of_memory("add_rule");
}
mergelist_parents[mergelist_cnt++] = ret;
} else {
for (cp = ret->pattern; (cp = strchr(cp, '/')) != NULL; cp++)
ret->u.slash_cnt++;
}
} else
ret->u.slash_cnt = slash_cnt;
ret->match_flags = mflags;
@@ -295,7 +319,7 @@ static char *parse_merge_name(const char *merge_file, unsigned int *len_ptr,
strlcpy(to, merge_file, *len_ptr + 1);
merge_file = to;
}
if (!sanitize_path(fn, merge_file, r, dirbuf_depth)) {
if (!sanitize_path(fn, merge_file, r, dirbuf_depth, SP_DEFAULT)) {
rprintf(FERROR, "merge-file name overflows: %s\n",
merge_file);
return NULL;
@@ -308,12 +332,13 @@ static char *parse_merge_name(const char *merge_file, unsigned int *len_ptr,
/* If the name isn't in buf yet, it's wasn't absolute. */
if (fn != buf) {
if (dirbuf_len + fn_len >= MAXPATHLEN) {
int d_len = dirbuf_len - prefix_skip;
if (d_len + fn_len >= MAXPATHLEN) {
rprintf(FERROR, "merge-file name overflows: %s\n", fn);
return NULL;
}
memcpy(buf, dirbuf + prefix_skip, dirbuf_len - prefix_skip);
memcpy(buf + dirbuf_len - prefix_skip, fn, fn_len + 1);
memcpy(buf, dirbuf + prefix_skip, d_len);
memcpy(buf + d_len, fn, fn_len + 1);
fn_len = clean_fname(buf, CFN_COLLAPSE_DOT_DOT_DIRS);
}
@@ -517,13 +542,13 @@ void change_local_filter_dir(const char *dname, int dlen, int dir_depth)
filt_array[cur_depth] = push_local_filters(dname, dlen);
}
static int rule_matches(char *fname, struct filter_struct *ex, int name_is_dir)
static int rule_matches(const char *fname, struct filter_struct *ex, int name_is_dir)
{
int slash_handling, str_cnt = 0, anchored_match = 0;
int ret_match = ex->match_flags & MATCHFLG_NEGATE ? 0 : 1;
char *p, *pattern = ex->pattern;
const char *strings[16]; /* more than enough */
char *name = fname + (*fname == '/');
const char *name = fname + (*fname == '/');
if (!*name)
return 0;
@@ -596,7 +621,7 @@ static int rule_matches(char *fname, struct filter_struct *ex, int name_is_dir)
}
static void report_filter_result(char const *name,
static void report_filter_result(enum logcode code, char const *name,
struct filter_struct const *ent,
int name_is_dir, const char *type)
{
@@ -608,7 +633,7 @@ static void report_filter_result(char const *name,
static char *actions[2][2]
= { {"show", "hid"}, {"risk", "protect"} };
const char *w = who_am_i();
rprintf(FINFO, "[%s] %sing %s %s because of pattern %s%s%s\n",
rprintf(code, "[%s] %sing %s %s because of pattern %s%s%s\n",
w, actions[*w!='s'][!(ent->match_flags&MATCHFLG_INCLUDE)],
name_is_dir ? "directory" : "file", name, ent->pattern,
ent->match_flags & MATCHFLG_DIRECTORY ? "/" : "", type);
@@ -620,7 +645,8 @@ static void report_filter_result(char const *name,
* Return -1 if file "name" is defined to be excluded by the specified
* exclude list, 1 if it is included, and 0 if it was not matched.
*/
int check_filter(struct filter_list_struct *listp, char *name, int name_is_dir)
int check_filter(struct filter_list_struct *listp, enum logcode code,
const char *name, int name_is_dir)
{
struct filter_struct *ent;
@@ -628,22 +654,22 @@ int check_filter(struct filter_list_struct *listp, char *name, int name_is_dir)
if (ignore_perishable && ent->match_flags & MATCHFLG_PERISHABLE)
continue;
if (ent->match_flags & MATCHFLG_PERDIR_MERGE) {
int rc = check_filter(ent->u.mergelist, name,
int rc = check_filter(ent->u.mergelist, code, name,
name_is_dir);
if (rc)
return rc;
continue;
}
if (ent->match_flags & MATCHFLG_CVS_IGNORE) {
int rc = check_filter(&cvs_filter_list, name,
int rc = check_filter(&cvs_filter_list, code, name,
name_is_dir);
if (rc)
return rc;
continue;
}
if (rule_matches(name, ent, name_is_dir)) {
report_filter_result(name, ent, name_is_dir,
listp->debug_type);
report_filter_result(code, name, ent, name_is_dir,
listp->debug_type);
return ent->match_flags & MATCHFLG_INCLUDE ? 1 : -1;
}
}
@@ -1009,10 +1035,10 @@ void parse_filter_file(struct filter_list_struct *listp, const char *fname,
return;
if (*fname != '-' || fname[1] || am_server) {
if (server_filter_list.head) {
if (daemon_filter_list.head) {
strlcpy(line, fname, sizeof line);
clean_fname(line, CFN_COLLAPSE_DOT_DOT_DIRS);
if (check_filter(&server_filter_list, line, 0) < 0)
if (check_filter(&daemon_filter_list, FLOG, line, 0) < 0)
fp = NULL;
else
fp = fopen(line, "rb");

445
flist.c
View File

@@ -76,7 +76,7 @@ extern char curr_dir[MAXPATHLEN];
extern struct chmod_mode_struct *chmod_modes;
extern struct filter_list_struct filter_list;
extern struct filter_list_struct server_filter_list;
extern struct filter_list_struct daemon_filter_list;
#ifdef ICONV_OPTION
extern int filesfrom_convert;
@@ -97,7 +97,7 @@ int flist_eof = 0; /* all the file-lists are now known */
#define NORMAL_NAME 0
#define SLASH_ENDING_NAME 1
#define DOT_NAME 2
#define DOTDIR_NAME 2
/* Starting from protocol version 26, we always use 64-bit ino_t and dev_t
* internally, even if this platform does not allow files to have 64-bit inums.
@@ -232,33 +232,57 @@ int link_stat(const char *path, STRUCT_STAT *stp, int follow_dirlinks)
#endif
}
static inline int is_daemon_excluded(const char *fname, int is_dir)
{
if (daemon_filter_list.head
&& check_filter(&daemon_filter_list, FLOG, fname, is_dir) < 0) {
errno = ENOENT;
return 1;
}
return 0;
}
static inline int path_is_daemon_excluded(char *path, int ignore_filename)
{
if (daemon_filter_list.head) {
char *slash = path;
while ((slash = strchr(slash+1, '/')) != NULL) {
int ret;
*slash = '\0';
ret = check_filter(&daemon_filter_list, FLOG, path, 1);
*slash = '/';
if (ret < 0) {
errno = ENOENT;
return 1;
}
}
if (!ignore_filename
&& check_filter(&daemon_filter_list, FLOG, path, 1) < 0) {
errno = ENOENT;
return 1;
}
}
return 0;
}
/* This function is used to check if a file should be included/excluded
* from the list of files based on its name and type etc. The value of
* filter_level is set to either SERVER_FILTERS or ALL_FILTERS. */
static int is_excluded(char *fname, int is_dir, int filter_level)
static int is_excluded(const char *fname, int is_dir, int filter_level)
{
#if 0 /* This currently never happens, so avoid a useless compare. */
if (filter_level == NO_FILTERS)
return 0;
#endif
if (fname) {
/* never exclude '.', even if somebody does --exclude '*' */
if (fname[0] == '.' && !fname[1])
return 0;
/* Handle the -R version of the '.' dir. */
if (fname[0] == '/') {
int len = strlen(fname);
if (fname[len-1] == '.' && fname[len-2] == '/')
return 0;
}
}
if (server_filter_list.head
&& check_filter(&server_filter_list, fname, is_dir) < 0)
if (is_daemon_excluded(fname, is_dir))
return 1;
if (filter_level != ALL_FILTERS)
return 0;
if (filter_list.head
&& check_filter(&filter_list, fname, is_dir) < 0)
&& check_filter(&filter_list, FINFO, fname, is_dir) < 0)
return 1;
return 0;
}
@@ -269,7 +293,6 @@ static void send_directory(int f, struct file_list *flist,
static const char *pathname, *orig_dir;
static int pathname_len;
/* Make sure flist can hold at least flist->used + extra entries. */
static void flist_expand(struct file_list *flist, int extra)
{
@@ -315,34 +338,55 @@ static void flist_done_allocating(struct file_list *flist)
flist->pool_boundary = ptr;
}
int push_pathname(const char *dir, int len)
/* Call this with EITHER (1) "file, NULL, 0" to chdir() to the file's
* F_PATHNAME(), or (2) "NULL, dir, dirlen" to chdir() to the supplied dir,
* with dir == NULL taken to be the starting directory, and dirlen < 0
* indicating that strdup(dir) should be called and then the -dirlen length
* value checked to ensure that it is not daemon-excluded. */
int change_pathname(struct file_struct *file, const char *dir, int dirlen)
{
if (dir == pathname)
return 1;
if (!orig_dir)
orig_dir = strdup(curr_dir);
if (pathname && !pop_dir(orig_dir)) {
rsyserr(FERROR, errno, "pop_dir %s failed",
full_fname(orig_dir));
exit_cleanup(RERR_FILESELECT);
}
if (dir && !push_dir(dir, 0)) {
io_error |= IOERR_GENERAL;
rsyserr(FERROR, errno, "push_dir %s failed in %s",
full_fname(dir), curr_dir);
return 0;
if (dirlen < 0) {
char *cpy = strdup(dir);
if (*cpy != '/')
change_dir(orig_dir, CD_SKIP_CHDIR);
if (path_is_daemon_excluded(cpy, 0))
goto chdir_error;
dir = cpy;
dirlen = -dirlen;
} else {
if (file) {
if (pathname == F_PATHNAME(file))
return 1;
dir = F_PATHNAME(file);
if (dir)
dirlen = strlen(dir);
} else if (pathname == dir)
return 1;
if (dir && *dir != '/')
change_dir(orig_dir, CD_SKIP_CHDIR);
}
pathname = dir;
pathname_len = len >= 0 ? len : dir ? (int)strlen(dir) : 0;
pathname_len = dirlen;
if (!dir)
dir = orig_dir;
if (!change_dir(dir, CD_NORMAL)) {
chdir_error:
io_error |= IOERR_GENERAL;
rsyserr(FERROR, errno, "change_dir %s failed", full_fname(dir));
if (dir != orig_dir)
change_dir(orig_dir, CD_NORMAL);
pathname = NULL;
pathname_len = 0;
return 0;
}
return 1;
}
static void send_file_entry(int f, struct file_struct *file, int ndx, int first_ndx)
static void send_file_entry(int f, const char *fname, struct file_struct *file, int ndx, int first_ndx)
{
static time_t modtime;
static mode_t mode;
@@ -355,40 +399,10 @@ static void send_file_entry(int f, struct file_struct *file, int ndx, int first_
static gid_t gid;
static const char *user_name, *group_name;
static char lastname[MAXPATHLEN];
char fname[MAXPATHLEN];
int first_hlink_ndx = -1;
int l1, l2;
int xflags;
#ifdef ICONV_OPTION
if (ic_send != (iconv_t)-1) {
xbuf outbuf, inbuf;
INIT_CONST_XBUF(outbuf, fname);
if (file->dirname) {
INIT_XBUF_STRLEN(inbuf, (char*)file->dirname);
outbuf.size -= 2; /* Reserve room for '/' & 1 more char. */
if (iconvbufs(ic_send, &inbuf, &outbuf, 0) < 0)
goto convert_error;
outbuf.size += 2;
outbuf.buf[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,
"[%s] cannot convert filename: %s (%s)\n",
who_am_i(), f_name(file, fname), strerror(errno));
return;
}
outbuf.buf[outbuf.len] = '\0';
} else
#endif
f_name(file, fname);
/* Initialize starting value of xflags. */
if (protocol_version >= 30 && S_ISDIR(file->mode)) {
dir_count++;
@@ -424,28 +438,24 @@ static void send_file_entry(int f, struct file_struct *file, int ndx, int first_
}
} else if (protocol_version < 28)
rdev = MAKEDEV(0, 0);
if (preserve_uid) {
if ((uid_t)F_OWNER(file) == uid && *lastname)
xflags |= XMIT_SAME_UID;
else {
uid = F_OWNER(file);
if (!numeric_ids) {
user_name = add_uid(uid);
if (inc_recurse && user_name)
xflags |= XMIT_USER_NAME_FOLLOWS;
}
if (!preserve_uid || ((uid_t)F_OWNER(file) == uid && *lastname))
xflags |= XMIT_SAME_UID;
else {
uid = F_OWNER(file);
if (!numeric_ids) {
user_name = add_uid(uid);
if (inc_recurse && user_name)
xflags |= XMIT_USER_NAME_FOLLOWS;
}
}
if (preserve_gid) {
if ((gid_t)F_GROUP(file) == gid && *lastname)
xflags |= XMIT_SAME_GID;
else {
gid = F_GROUP(file);
if (!numeric_ids) {
group_name = add_gid(gid);
if (inc_recurse && group_name)
xflags |= XMIT_GROUP_NAME_FOLLOWS;
}
if (!preserve_gid || ((gid_t)F_GROUP(file) == gid && *lastname))
xflags |= XMIT_SAME_GID;
else {
gid = F_GROUP(file);
if (!numeric_ids) {
group_name = add_gid(gid);
if (inc_recurse && group_name)
xflags |= XMIT_GROUP_NAME_FOLLOWS;
}
}
if (file->modtime == modtime)
@@ -462,15 +472,14 @@ static void send_file_entry(int f, struct file_struct *file, int ndx, int first_
np->data = (void*)(long)(first_ndx + ndx + 1);
xflags |= XMIT_HLINK_FIRST;
}
xflags |= XMIT_HLINKED;
} else {
if (tmp_dev == dev) {
if (protocol_version >= 28)
xflags |= XMIT_SAME_DEV_pre30;
} else
dev = tmp_dev;
xflags |= XMIT_HLINKED;
}
xflags |= XMIT_HLINKED;
}
#endif
@@ -675,10 +684,11 @@ static struct file_struct *recv_file_entry(struct file_list *flist,
}
#endif
clean_fname(thisname, 0);
if (*thisname)
clean_fname(thisname, 0);
if (sanitize_paths)
sanitize_path(thisname, thisname, "", 0);
sanitize_path(thisname, thisname, "", 0, SP_DEFAULT);
if ((basename = strrchr(thisname, '/')) != NULL) {
int len = basename++ - thisname;
@@ -819,9 +829,9 @@ static struct file_struct *recv_file_entry(struct file_list *flist,
#endif
#ifdef SUPPORT_ACLS
/* We need one or two index int32s when we're preserving ACLs. */
if (preserve_acls)
extra_len += (S_ISDIR(mode) ? 2 : 1) * EXTRA_LEN;
/* Directories need an extra int32 for the default ACL. */
if (preserve_acls && S_ISDIR(mode))
extra_len += EXTRA_LEN;
#endif
if (always_checksum && S_ISREG(mode))
@@ -854,7 +864,6 @@ static struct file_struct *recv_file_entry(struct file_list *flist,
bp += FILE_STRUCT_LEN;
memcpy(bp, basename, basename_len);
bp += basename_len + linkname_len; /* skip space for symlink too */
#ifdef SUPPORT_HARD_LINKS
if (xflags & XMIT_HLINKED)
@@ -919,7 +928,7 @@ static struct file_struct *recv_file_entry(struct file_list *flist,
#ifdef SUPPORT_LINKS
if (linkname_len) {
bp = (char*)file->basename + basename_len;
bp += basename_len;
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);
@@ -931,7 +940,7 @@ static struct file_struct *recv_file_entry(struct file_list *flist,
} else {
read_sbuf(f, bp, linkname_len - 1);
if (sanitize_paths)
sanitize_path(bp, bp, "", lastdir_depth);
sanitize_path(bp, bp, "", lastdir_depth, SP_DEFAULT);
}
}
#endif
@@ -1014,6 +1023,7 @@ struct file_struct *make_file(const char *fname, struct file_list *flist,
const char *basename;
alloc_pool_t *pool;
STRUCT_STAT st;
int excl_ret;
char *bp;
if (strlcpy(thisname, fname, sizeof thisname) >= sizeof thisname) {
@@ -1022,7 +1032,7 @@ struct file_struct *make_file(const char *fname, struct file_list *flist,
}
clean_fname(thisname, 0);
if (sanitize_paths)
sanitize_path(thisname, thisname, "", 0);
sanitize_path(thisname, thisname, "", 0, SP_DEFAULT);
if (stp && S_ISDIR(stp->st_mode)) {
st = *stp; /* Needed for "symlink/." with --relative. */
@@ -1096,7 +1106,17 @@ struct file_struct *make_file(const char *fname, struct file_list *flist,
} else
flags &= ~FLAG_CONTENT_DIR;
if (is_excluded(thisname, S_ISDIR(st.st_mode) != 0, filter_level)) {
if (S_ISDIR(st.st_mode)) {
if (flags & FLAG_DOTDIR_NAME) {
/* A "." fname (or "/." fname in relative mode) is
* never excluded. No other trailing-dotdir names
* are possible. */
excl_ret = 0;
} else
excl_ret = is_excluded(thisname, 1, filter_level);
} else
excl_ret = is_excluded(thisname, 0, filter_level);
if (excl_ret) {
if (ignore_perishable)
non_perishable_cnt++;
return NULL;
@@ -1123,8 +1143,14 @@ struct file_struct *make_file(const char *fname, struct file_list *flist,
pool = dir_flist->file_pool;
} else
pool = flist->file_pool;
} else
} else {
#ifdef SUPPORT_ACLS
/* Directories need an extra int32 for the default ACL. */
if (preserve_acls && S_ISDIR(st.st_mode))
extra_len += EXTRA_LEN;
#endif
pool = NULL;
}
if (verbose > 2) {
rprintf(FINFO, "[%s] make_file(%s,*,%d)\n",
@@ -1172,7 +1198,6 @@ struct file_struct *make_file(const char *fname, struct file_list *flist,
bp += FILE_STRUCT_LEN;
memcpy(bp, basename, basename_len);
bp += basename_len + linkname_len; /* skip space for symlink too */
#ifdef SUPPORT_HARD_LINKS
if (preserve_hard_links && flist && flist->prev) {
@@ -1210,16 +1235,17 @@ struct file_struct *make_file(const char *fname, struct file_list *flist,
file->dirname = lastdir;
#ifdef SUPPORT_LINKS
if (linkname_len) {
bp = (char*)file->basename + basename_len;
memcpy(bp, linkname, linkname_len);
}
if (linkname_len)
memcpy(bp + basename_len, linkname, linkname_len);
#endif
if (always_checksum && am_sender && S_ISREG(st.st_mode))
file_checksum(thisname, tmp_sum, st.st_size);
F_PATHNAME(file) = pathname;
if (am_sender)
F_PATHNAME(file) = pathname;
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. */
@@ -1255,22 +1281,14 @@ struct file_struct *make_file(const char *fname, struct file_list *flist,
/* Only called for temporary file_struct entries created by make_file(). */
void unmake_file(struct file_struct *file)
{
int extra_cnt = file_extra_cnt + LEN64_BUMP(file);
#if EXTRA_ROUNDING > 0
if (extra_cnt & EXTRA_ROUNDING)
extra_cnt = (extra_cnt | EXTRA_ROUNDING) + 1;
#endif
free(REQ_EXTRA(file, extra_cnt));
free(REQ_EXTRA(file, F_DEPTH(file)));
}
static struct file_struct *send_file_name(int f, struct file_list *flist,
char *fname, STRUCT_STAT *stp,
const char *fname, STRUCT_STAT *stp,
int flags, int filter_level)
{
struct file_struct *file;
#if defined SUPPORT_ACLS || defined SUPPORT_XATTRS
stat_x sx;
#endif
file = make_file(fname, flist, stp, flags, filter_level);
if (!file)
@@ -1279,28 +1297,59 @@ static struct file_struct *send_file_name(int f, struct file_list *flist,
if (chmod_modes && !S_ISLNK(file->mode))
file->mode = tweak_mode(file->mode, chmod_modes);
if (f >= 0) {
char fbuf[MAXPATHLEN];
#if defined SUPPORT_ACLS || defined SUPPORT_XATTRS
stat_x sx;
#endif
#ifdef ICONV_OPTION
if (ic_send != (iconv_t)-1) {
xbuf outbuf, inbuf;
INIT_CONST_XBUF(outbuf, fbuf);
if (file->dirname) {
INIT_XBUF_STRLEN(inbuf, (char*)file->dirname);
outbuf.size -= 2; /* Reserve room for '/' & 1 more char. */
if (iconvbufs(ic_send, &inbuf, &outbuf, 0) < 0)
goto convert_error;
outbuf.size += 2;
outbuf.buf[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,
"[%s] cannot convert filename: %s (%s)\n",
who_am_i(), f_name(file, fbuf), strerror(errno));
return NULL;
}
outbuf.buf[outbuf.len] = '\0';
} else
#endif
f_name(file, fbuf);
#ifdef SUPPORT_ACLS
if (preserve_acls && !S_ISLNK(file->mode) && f >= 0) {
sx.st.st_mode = file->mode;
sx.acc_acl = sx.def_acl = NULL;
if (get_acl(fname, &sx) < 0)
return NULL;
}
if (preserve_acls && !S_ISLNK(file->mode)) {
sx.st.st_mode = file->mode;
sx.acc_acl = sx.def_acl = NULL;
if (get_acl(fname, &sx) < 0)
return NULL;
}
#endif
#ifdef SUPPORT_XATTRS
if (preserve_xattrs && f >= 0) {
sx.xattr = NULL;
if (get_xattr(fname, &sx) < 0)
return NULL;
}
if (preserve_xattrs) {
sx.xattr = NULL;
if (get_xattr(fname, &sx) < 0)
return NULL;
}
#endif
maybe_emit_filelist_progress(flist->used + flist_count_offset);
send_file_entry(f, fbuf, file, flist->used, flist->ndx_start);
flist_expand(flist, 1);
flist->files[flist->used++] = file;
if (f >= 0) {
send_file_entry(f, file, flist->used - 1, flist->ndx_start);
#ifdef SUPPORT_ACLS
if (preserve_acls && !S_ISLNK(file->mode)) {
send_acl(&sx, f);
@@ -1314,6 +1363,12 @@ static struct file_struct *send_file_name(int f, struct file_list *flist,
}
#endif
}
maybe_emit_filelist_progress(flist->used + flist_count_offset);
flist_expand(flist, 1);
flist->files[flist->used++] = file;
return file;
}
@@ -1521,18 +1576,16 @@ static void send_directory(int f, struct file_list *flist, char *fbuf, int len,
}
}
static char lastpath[MAXPATHLEN] = "";
static int lastpath_len = 0;
static struct file_struct *lastpath_struct;
static void send_implied_dirs(int f, struct file_list *flist, char *fname,
char *start, char *limit, int flags, char name_type)
{
static char lastpath[MAXPATHLEN] = "";
static int lastpath_len = 0;
static struct file_struct *lastpath_struct = NULL;
struct file_struct *file;
item_list *relname_list;
relnamecache **rnpp;
char *slash;
int len, need_new_dir;
int len, need_new_dir, depth = 0;
struct filter_list_struct save_filter_list = filter_list;
flags = (flags | FLAG_IMPLIED_DIR) & ~(FLAG_TOP_DIR | FLAG_CONTENT_DIR);
@@ -1545,12 +1598,31 @@ static void send_implied_dirs(int f, struct file_list *flist, char *fname,
need_new_dir = 0;
else
need_new_dir = 1;
} else
} else {
char *tp = fname, *lp = lastpath;
/* Skip any initial directories in our path that we
* have in common with lastpath. */
assert(start == fname);
for ( ; ; tp++, lp++) {
if (tp == limit) {
if (*lp == '/' || *lp == '\0')
goto done;
break;
}
if (*lp != *tp)
break;
if (*tp == '/') {
start = tp;
depth++;
}
}
need_new_dir = 1;
}
if (need_new_dir) {
int save_copy_links = copy_links;
int save_xfer_dirs = xfer_dirs;
char *slash;
copy_links = xfer_dirs = 1;
@@ -1558,7 +1630,10 @@ static void send_implied_dirs(int f, struct file_list *flist, char *fname,
for (slash = start; (slash = strchr(slash+1, '/')) != NULL; ) {
*slash = '\0';
send_file_name(f, flist, fname, NULL, flags, ALL_FILTERS);
file = send_file_name(f, flist, fname, NULL, flags, ALL_FILTERS);
depth++;
if (!inc_recurse && file && S_ISDIR(file->mode))
change_local_filter_dir(fname, strlen(fname), depth);
*slash = '/';
}
@@ -1567,7 +1642,8 @@ static void send_implied_dirs(int f, struct file_list *flist, char *fname,
if (file && !S_ISDIR(file->mode))
file = NULL;
lastpath_struct = file;
}
} else if (file && S_ISDIR(file->mode))
change_local_filter_dir(fname, strlen(fname), ++depth);
strlcpy(lastpath, fname, sizeof lastpath);
lastpath_len = limit - fname;
@@ -1611,10 +1687,8 @@ static void send1extra(int f, struct file_struct *file, struct file_list *flist)
f_name(file, fbuf);
dlen = strlen(fbuf);
if (F_PATHNAME(file) != pathname) {
if (!push_pathname(F_PATHNAME(file), -1))
exit_cleanup(RERR_FILESELECT);
}
if (!change_pathname(file, NULL, 0))
exit_cleanup(RERR_FILESELECT);
change_local_filter_dir(fbuf, dlen, send_dir_depth);
@@ -1779,13 +1853,14 @@ struct file_list *send_file_list(int f, int argc, char *argv[])
int64 start_write;
int use_ff_fd = 0;
int disable_buffering;
int flags = recurse ? FLAG_CONTENT_DIR : 0;
int arg_flags, flags = recurse ? FLAG_CONTENT_DIR : 0;
int reading_remotely = filesfrom_host != NULL;
int rl_flags = (reading_remotely ? 0 : RL_DUMP_COMMENTS)
#ifdef ICONV_OPTION
| (filesfrom_convert ? RL_CONVERT : 0)
#endif
| (eol_nulls || reading_remotely ? RL_EOL_NULLS : 0);
int implied_dot_dir = 0;
rprintf(FLOG, "building file list\n");
if (show_filelist_p())
@@ -1796,6 +1871,9 @@ 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 */
@@ -1813,9 +1891,9 @@ struct file_list *send_file_list(int f, int argc, char *argv[])
disable_buffering = io_start_buffering_out(f);
if (filesfrom_fd >= 0) {
if (argv[0] && !push_dir(argv[0], 0)) {
rsyserr(FERROR_XFER, errno, "push_dir %s failed in %s",
full_fname(argv[0]), curr_dir);
if (argv[0] && !change_dir(argv[0], CD_NORMAL)) {
rsyserr(FERROR_XFER, errno, "change_dir %s failed",
full_fname(argv[0]));
exit_cleanup(RERR_FILESELECT);
}
use_ff_fd = 1;
@@ -1827,13 +1905,13 @@ struct file_list *send_file_list(int f, int argc, char *argv[])
if (use_ff_fd) {
if (read_line(filesfrom_fd, fbuf, sizeof fbuf, rl_flags) == 0)
break;
sanitize_path(fbuf, fbuf, "", 0);
sanitize_path(fbuf, fbuf, "", 0, SP_KEEP_DOT_DIRS);
} else {
if (argc-- == 0)
break;
strlcpy(fbuf, *argv++, MAXPATHLEN);
if (sanitize_paths)
sanitize_path(fbuf, fbuf, "", 0);
sanitize_path(fbuf, fbuf, "", 0, SP_KEEP_DOT_DIRS);
}
len = strlen(fbuf);
@@ -1850,7 +1928,7 @@ struct file_list *send_file_list(int f, int argc, char *argv[])
fbuf[len++] = '.';
fbuf[len] = '\0';
}
name_type = DOT_NAME;
name_type = DOTDIR_NAME;
} else if (len > 1 && fbuf[len-1] == '.' && fbuf[len-2] == '.'
&& (len == 2 || fbuf[len-3] == '/')) {
if (len + 2 >= MAXPATHLEN)
@@ -1858,9 +1936,9 @@ struct file_list *send_file_list(int f, int argc, char *argv[])
fbuf[len++] = '/';
fbuf[len++] = '.';
fbuf[len] = '\0';
name_type = DOT_NAME;
name_type = DOTDIR_NAME;
} else if (fbuf[len-1] == '.' && (len == 1 || fbuf[len-2] == '/'))
name_type = DOT_NAME;
name_type = DOTDIR_NAME;
else
name_type = NORMAL_NAME;
@@ -1883,8 +1961,10 @@ struct file_list *send_file_list(int f, int argc, char *argv[])
*p = '\0';
if (p == fbuf)
dir = "/";
else
else {
dir = fbuf;
clean_fname(dir, 0);
}
fn = p + 3;
while (*fn == '/')
fn++;
@@ -1892,20 +1972,27 @@ struct file_list *send_file_list(int f, int argc, char *argv[])
*--fn = '\0'; /* ensure room for '.' */
} else
fn = fbuf;
len = clean_fname(fn, CFN_KEEP_LEADING_DOT_DIR
| CFN_KEEP_TRAILING_SLASH
/* A leading ./ can be used in relative mode to affect
* the dest dir without its name being in the path. */
if (*fn == '.' && fn[1] == '/' && !implied_dot_dir) {
send_file_name(f, flist, ".", NULL,
(flags | FLAG_IMPLIED_DIR) & ~FLAG_CONTENT_DIR,
ALL_FILTERS);
implied_dot_dir = 1;
}
len = clean_fname(fn, CFN_KEEP_TRAILING_SLASH
| CFN_DROP_TRAILING_DOT_DIR);
if (len == 1) {
if (fn[0] == '/') {
fn = "/.";
len = 2;
name_type = DOT_NAME;
name_type = DOTDIR_NAME;
} else if (fn[0] == '.')
name_type = DOT_NAME;
name_type = DOTDIR_NAME;
} else if (fn[len-1] == '/') {
fn[--len] = '\0';
if (len == 1 && *fn == '.')
name_type = DOT_NAME;
name_type = DOTDIR_NAME;
else
name_type = SLASH_ENDING_NAME;
}
@@ -1924,22 +2011,24 @@ struct file_list *send_file_list(int f, int argc, char *argv[])
if (!*fn) {
len = 1;
fn = ".";
name_type = DOT_NAME;
name_type = DOTDIR_NAME;
}
dirlen = dir ? strlen(dir) : 0;
if (dirlen != lastdir_len || memcmp(lastdir, dir, dirlen) != 0) {
if (!push_pathname(dir ? strdup(dir) : NULL, dirlen))
if (!change_pathname(NULL, dir, -dirlen))
continue;
lastdir = pathname;
lastdir_len = pathname_len;
} else if (!push_pathname(lastdir, lastdir_len))
} else if (!change_pathname(NULL, lastdir, lastdir_len))
continue;
if (fn != fbuf)
memmove(fbuf, fn, len + 1);
if (link_stat(fbuf, &st, copy_dirlinks || name_type != NORMAL_NAME) != 0) {
if (link_stat(fbuf, &st, copy_dirlinks || name_type != NORMAL_NAME) != 0
|| (name_type != DOTDIR_NAME && is_daemon_excluded(fbuf, S_ISDIR(st.st_mode)))
|| (relative_paths && path_is_daemon_excluded(fbuf, 1))) {
io_error |= IOERR_GENERAL;
rsyserr(FERROR_XFER, errno, "link_stat %s failed",
full_fname(fbuf));
@@ -1965,39 +2054,33 @@ struct file_list *send_file_list(int f, int argc, char *argv[])
} else if (implied_dirs && (p=strrchr(fbuf,'/')) && p != fbuf) {
/* Send the implied directories at the start of the
* source spec, so we get their permissions right. */
char *lp = lastpath, *slash = fbuf;
*p = '\0';
/* Skip any initial directories in our path that we
* have in common with lastpath. */
for (fn = fbuf; *fn && *lp == *fn; lp++, fn++) {
if (*fn == '/')
slash = fn;
}
*p = '/';
if (fn != p || (*lp && *lp != '/'))
send_implied_dirs(f, flist, fbuf, slash, p, flags, 0);
send_implied_dirs(f, flist, fbuf, fbuf, p, flags, 0);
}
if (one_file_system)
filesystem_dev = st.st_dev;
arg_flags = name_type == DOTDIR_NAME ? FLAG_DOTDIR_NAME : 0;
if (recurse || (xfer_dirs && name_type != NORMAL_NAME)) {
struct file_struct *file;
int top_flags = FLAG_TOP_DIR | FLAG_CONTENT_DIR | flags;
arg_flags |= FLAG_TOP_DIR | FLAG_CONTENT_DIR;
file = send_file_name(f, flist, fbuf, &st,
top_flags, ALL_FILTERS);
arg_flags | flags, ALL_FILTERS);
if (!file)
continue;
if (inc_recurse) {
if (name_type == DOT_NAME && file) {
if (name_type == DOTDIR_NAME) {
if (send_dir_depth < 0) {
send_dir_depth = 0;
change_local_filter_dir(fbuf, len, send_dir_depth);
}
send_directory(f, flist, fbuf, len, flags);
}
} else if (file)
} else
send_if_directory(f, flist, file, fbuf, len, flags);
} else
send_file_name(f, flist, fbuf, &st, flags, ALL_FILTERS);
send_file_name(f, flist, fbuf, &st, arg_flags | flags, ALL_FILTERS);
}
gettimeofday(&end_tv, NULL);

View File

@@ -27,7 +27,6 @@ extern int dry_run;
extern int do_xfers;
extern int stdout_format_has_i;
extern int logfile_format_has_i;
extern int receiver_symlink_times;
extern int am_root;
extern int am_server;
extern int am_daemon;
@@ -98,7 +97,7 @@ extern char *backup_dir;
extern char *backup_suffix;
extern int backup_suffix_len;
extern struct file_list *cur_flist, *first_flist, *dir_flist;
extern struct filter_list_struct server_filter_list;
extern struct filter_list_struct daemon_filter_list;
int ignore_perishable = 0;
int non_perishable_cnt = 0;
@@ -111,6 +110,7 @@ static char *deldelay_buf = NULL;
static int deldelay_fd = -1;
static int lull_mod;
static int dir_tweaking;
static int symlink_timeset_failed_flags;
static int need_retouch_dir_times;
static int need_retouch_dir_perms;
static const char *solo_file = NULL;
@@ -135,8 +135,12 @@ enum delret {
DR_SUCCESS = 0, DR_FAILURE, DR_AT_LIMIT, DR_NOT_EMPTY
};
/* Forward declaration for delete_item(). */
/* Forward declarations. */
static enum delret delete_dir_contents(char *fname, uint16 flags);
#ifdef SUPPORT_HARD_LINKS
static void handle_skipped_hlink(struct file_struct *file, int itemizing,
enum logcode code, int f_out);
#endif
static int is_backup_file(char *fn)
{
@@ -279,7 +283,7 @@ static enum delret delete_dir_contents(char *fname, uint16 flags)
for (j = dirlist->used; j--; ) {
struct file_struct *fp = dirlist->files[j];
if (fp->flags & FLAG_MOUNT_DIR) {
if (fp->flags & FLAG_MOUNT_DIR && S_ISDIR(fp->mode)) {
if (verbose > 1) {
rprintf(FINFO,
"mount point, %s, pins parent directory\n",
@@ -511,7 +515,7 @@ static void delete_in_dir(char *fbuf, struct file_struct *file, dev_t *fs_dev)
struct file_struct *fp = dirlist->files[i];
if (!F_IS_ACTIVE(fp))
continue;
if (fp->flags & FLAG_MOUNT_DIR) {
if (fp->flags & FLAG_MOUNT_DIR && S_ISDIR(fp->mode)) {
if (verbose > 1)
rprintf(FINFO, "cannot delete mount point: %s\n",
f_name(fp, NULL));
@@ -553,10 +557,13 @@ static void do_delete_pass(void)
for (j = 0; j < cur_flist->used; j++) {
struct file_struct *file = cur_flist->sorted[j];
if (!(file->flags & FLAG_CONTENT_DIR))
continue;
f_name(file, fbuf);
if (!(file->flags & FLAG_CONTENT_DIR)) {
change_local_filter_dir(fbuf, strlen(fbuf), F_DEPTH(file));
continue;
}
if (verbose > 1 && file->flags & FLAG_TOP_DIR)
rprintf(FINFO, "deleting in %s\n", fbuf);
@@ -582,10 +589,11 @@ int unchanged_attrs(const char *fname, struct file_struct *file, stat_x *sxp)
if (preserve_times && cmp_time(sxp->st.st_mtime, file->modtime) != 0)
return 0;
if (preserve_perms && !BITS_EQUAL(sxp->st.st_mode, file->mode, CHMOD_BITS))
return 0;
if (preserve_executability && ((sxp->st.st_mode & 0111 ? 1 : 0) ^ (file->mode & 0111 ? 1 : 0)))
if (preserve_perms) {
if (!BITS_EQUAL(sxp->st.st_mode, file->mode, CHMOD_BITS))
return 0;
} else if (preserve_executability
&& ((sxp->st.st_mode & 0111 ? 1 : 0) ^ (file->mode & 0111 ? 1 : 0)))
return 0;
if (am_root && uid_ndx && sxp->st.st_uid != (uid_t)F_OWNER(file))
@@ -622,24 +630,31 @@ void itemize(const char *fnamecmp, struct file_struct *file, int ndx, int statre
int keep_time = !preserve_times ? 0
: S_ISDIR(file->mode) ? preserve_times > 1 :
#if defined HAVE_LUTIMES && defined HAVE_UTIMES
(receiver_symlink_times && !(file->flags & FLAG_TIME_FAILED)) ||
#endif
1;
#else
!S_ISLNK(file->mode);
#endif
if (S_ISREG(file->mode) && F_LENGTH(file) != sxp->st.st_size)
iflags |= ITEM_REPORT_SIZE;
if ((iflags & (ITEM_TRANSFER|ITEM_LOCAL_CHANGE) && !keep_time
&& !(iflags & ITEM_MATCHED)
if (file->flags & FLAG_TIME_FAILED) { /* symlinks only */
if (iflags & ITEM_LOCAL_CHANGE)
iflags |= symlink_timeset_failed_flags;
} else if (keep_time
? cmp_time(file->modtime, sxp->st.st_mtime) != 0
: iflags & (ITEM_TRANSFER|ITEM_LOCAL_CHANGE) && !(iflags & ITEM_MATCHED)
&& (!(iflags & ITEM_XNAME_FOLLOWS) || *xname))
|| (keep_time && cmp_time(file->modtime, sxp->st.st_mtime) != 0))
iflags |= ITEM_REPORT_TIME;
#if !defined HAVE_LCHMOD && !defined HAVE_SETATTRLIST
if (S_ISLNK(file->mode)) {
;
} else
#endif
if ((preserve_perms || preserve_executability)
&& !BITS_EQUAL(sxp->st.st_mode, file->mode, CHMOD_BITS))
if (preserve_perms) {
if (!BITS_EQUAL(sxp->st.st_mode, file->mode, CHMOD_BITS))
iflags |= ITEM_REPORT_PERMS;
} else if (preserve_executability
&& ((sxp->st.st_mode & 0111 ? 1 : 0) ^ (file->mode & 0111 ? 1 : 0)))
iflags |= ITEM_REPORT_PERMS;
if (uid_ndx && am_root && (uid_t)F_OWNER(file) != sxp->st.st_uid)
iflags |= ITEM_REPORT_OWNER;
@@ -1155,8 +1170,7 @@ static int try_dests_non(struct file_struct *file, char *fname, int ndx,
if (itemizing && stdout_format_has_i
&& (verbose > 1 || stdout_format_has_i > 1)) {
int chg = compare_dest && type != TYPE_DIR ? 0
: ITEM_LOCAL_CHANGE
+ (match_level == 3 ? ITEM_XNAME_FOLLOWS : 0);
: ITEM_LOCAL_CHANGE + (match_level == 3 ? ITEM_XNAME_FOLLOWS : 0);
char *lp = match_level == 3 ? "" : NULL;
itemize(cmpbuf, file, ndx, 0, sxp, chg + ITEM_MATCHED, 0, lp);
}
@@ -1202,22 +1216,34 @@ static void list_file_entry(struct file_struct *f)
static int phase = 0;
static int dflt_perms;
static int implied_dirs_are_missing;
/* Helper for recv_generator's skip_dir and dry_missing_dir tests. */
static BOOL is_below(struct file_struct *file, struct file_struct *subtree)
{
return F_DEPTH(file) > F_DEPTH(subtree)
&& (!implied_dirs_are_missing || f_name_has_prefix(file, subtree));
}
/* Acts on the indicated item in cur_flist whose name is fname. If a dir,
* make sure it exists, and has the right permissions/timestamp info. For
* all other non-regular files (symlinks, etc.) we create them here. For
* regular files that have changed, we try to find a basis file and then
* start sending checksums. The ndx is the file's unique index value.
*
* When fname is non-null, it must point to a MAXPATHLEN buffer!
* The fname parameter must point to a MAXPATHLEN buffer! (e.g it gets
* passed to delete_item(), which can use it during a recursive delete.)
*
* Note that f_out is set to -1 when doing final directory-permission and
* modification-time repair. */
static void recv_generator(char *fname, struct file_struct *file, int ndx,
int itemizing, enum logcode code, int f_out)
{
static int missing_below = -1, excluded_below = -1;
static const char *parent_dirname = "";
static struct file_struct *missing_dir = NULL, *excluded_dir = NULL;
/* Missing dir not created due to --dry-run; will still be scanned. */
static struct file_struct *dry_missing_dir = NULL;
/* Missing dir whose contents are skipped altogether due to
* --ignore-non-existing, daemon exclude, or mkdir failure. */
static struct file_struct *skip_dir = NULL;
static struct file_list *fuzzy_dirlist = NULL;
static int need_fuzzy_dirlist = 0;
struct file_struct *fuzzy_file = NULL;
@@ -1229,7 +1255,6 @@ static void recv_generator(char *fname, struct file_struct *file, int ndx,
char *fnamecmp, *partialptr, *backupptr = NULL;
char fnamecmpbuf[MAXPATHLEN];
uchar fnamecmp_type;
int implied_dirs_are_missing = relative_paths && !implied_dirs && protocol_version < 30;
int del_opts = delete_mode || force_delete ? DEL_RECURSE : 0;
int is_dir = !S_ISDIR(file->mode) ? 0
: inc_recurse && ndx != cur_flist->ndx_start - 1 ? -1
@@ -1246,48 +1271,44 @@ static void recv_generator(char *fname, struct file_struct *file, int ndx,
return;
}
if (server_filter_list.head) {
int filtered = check_filter(&server_filter_list, fname, is_dir) < 0;
if (is_dir < 0 && filtered)
if (skip_dir) {
if (is_below(file, skip_dir)) {
if (is_dir)
file->flags |= FLAG_MISSING_DIR;
#ifdef SUPPORT_HARD_LINKS
else if (F_IS_HLINKED(file))
handle_skipped_hlink(file, itemizing, code, f_out);
#endif
return;
if (excluded_below >= 0) {
if (F_DEPTH(file) > excluded_below
&& (!implied_dirs_are_missing || f_name_has_prefix(file, excluded_dir)))
goto skipping;
excluded_below = -1;
}
if (filtered) {
if (is_dir) {
excluded_below = F_DEPTH(file);
excluded_dir = file;
}
skipping:
skip_dir = NULL;
}
if (daemon_filter_list.head) {
if (check_filter(&daemon_filter_list, FLOG, fname, is_dir) < 0) {
if (is_dir < 0)
return;
#ifdef SUPPORT_HARD_LINKS
if (F_IS_HLINKED(file))
handle_skipped_hlink(file, itemizing, code, f_out);
#endif
rprintf(FERROR_XFER,
"skipping daemon-excluded file \"%s\"\n",
fname);
"skipping daemon-excluded %s \"%s\"\n",
is_dir ? "directory" : "file", fname);
if (is_dir)
goto skipping_dir_contents;
return;
}
}
if (missing_below >= 0) {
if (F_DEPTH(file) <= missing_below
|| (implied_dirs_are_missing && !f_name_has_prefix(file, missing_dir))) {
if (dry_run)
dry_run--;
missing_below = -1;
} else if (!dry_run) {
if (is_dir)
file->flags |= FLAG_MISSING_DIR;
return;
}
}
#ifdef SUPPORT_ACLS
sx.acc_acl = sx.def_acl = NULL;
#endif
#ifdef SUPPORT_XATTRS
sx.xattr = NULL;
#endif
if (dry_run > 1) {
if (dry_run > 1 || (dry_missing_dir && is_below(file, dry_missing_dir))) {
parent_is_dry_missing:
if (fuzzy_dirlist) {
flist_free(fuzzy_dirlist);
fuzzy_dirlist = NULL;
@@ -1297,13 +1318,17 @@ static void recv_generator(char *fname, struct file_struct *file, int ndx,
stat_errno = ENOENT;
} else {
const char *dn = file->dirname ? file->dirname : ".";
dry_missing_dir = NULL;
if (parent_dirname != dn && strcmp(parent_dirname, dn) != 0) {
if (relative_paths && !implied_dirs
&& do_stat(dn, &sx.st) < 0
&& create_directory_path(fname) < 0) {
rsyserr(FERROR_XFER, errno,
"recv_generator: mkdir %s failed",
full_fname(dn));
&& do_stat(dn, &sx.st) < 0) {
if (dry_run)
goto parent_is_dry_missing;
if (create_directory_path(fname) < 0) {
rsyserr(FERROR_XFER, errno,
"recv_generator: mkdir %s failed",
full_fname(dn));
}
}
if (fuzzy_dirlist) {
flist_free(fuzzy_dirlist);
@@ -1332,14 +1357,13 @@ static void recv_generator(char *fname, struct file_struct *file, int ndx,
if (is_dir) {
if (is_dir < 0)
return;
if (missing_below < 0) {
if (dry_run)
dry_run++;
missing_below = F_DEPTH(file);
missing_dir = file;
}
skip_dir = file;
file->flags |= FLAG_MISSING_DIR;
}
#ifdef SUPPORT_HARD_LINKS
else if (F_IS_HLINKED(file))
handle_skipped_hlink(file, itemizing, code, f_out);
#endif
if (verbose > 1) {
rprintf(FINFO, "not creating new %s \"%s\"\n",
is_dir ? "directory" : "file", fname);
@@ -1351,6 +1375,17 @@ static void recv_generator(char *fname, struct file_struct *file, int ndx,
&& !am_root && sx.st.st_uid == our_uid)
del_opts |= DEL_NO_UID_WRITE;
if (ignore_existing > 0 && statret == 0
&& (!is_dir || !S_ISDIR(sx.st.st_mode))) {
if (verbose > 1 && is_dir >= 0)
rprintf(FINFO, "%s exists\n", fname);
#ifdef SUPPORT_HARD_LINKS
if (F_IS_HLINKED(file))
handle_skipped_hlink(file, itemizing, code, f_out);
#endif
goto cleanup;
}
if (is_dir) {
if (!implied_dirs && file->flags & FLAG_IMPLIED_DIR)
goto cleanup;
@@ -1378,10 +1413,10 @@ static void recv_generator(char *fname, struct file_struct *file, int ndx,
goto skipping_dir_contents;
statret = -1;
}
if (dry_run && statret != 0 && missing_below < 0) {
missing_below = F_DEPTH(file);
missing_dir = file;
dry_run++;
if (dry_run && statret != 0) {
if (!dry_missing_dir)
dry_missing_dir = file;
file->flags |= FLAG_MISSING_DIR;
}
real_ret = statret;
real_sx = sx;
@@ -1414,8 +1449,7 @@ static void recv_generator(char *fname, struct file_struct *file, int ndx,
skipping_dir_contents:
rprintf(FERROR,
"*** Skipping any contents from this failed directory ***\n");
missing_below = F_DEPTH(file);
missing_dir = file;
skip_dir = file;
file->flags |= FLAG_MISSING_DIR;
goto cleanup;
}
@@ -1448,9 +1482,13 @@ static void recv_generator(char *fname, struct file_struct *file, int ndx,
DEV_MINOR(devp) = minor(real_sx.st.st_dev);
}
}
else if (delete_during && f_out != -1 && !phase && dry_run < 2
&& (file->flags & FLAG_CONTENT_DIR))
delete_in_dir(fname, file, &real_sx.st.st_dev);
else if (delete_during && f_out != -1 && !phase
&& !(file->flags & FLAG_MISSING_DIR)) {
if (file->flags & FLAG_CONTENT_DIR)
delete_in_dir(fname, file, &real_sx.st.st_dev);
else
change_local_filter_dir(fname, strlen(fname), F_DEPTH(file));
}
goto cleanup;
}
@@ -1534,7 +1572,7 @@ static void recv_generator(char *fname, struct file_struct *file, int ndx,
set_file_attrs(fname, file, NULL, NULL, 0);
if (itemizing) {
itemize(fname, file, ndx, statret, &sx,
ITEM_LOCAL_CHANGE, 0, NULL);
ITEM_LOCAL_CHANGE|ITEM_REPORT_CHANGE, 0, NULL);
}
if (code != FNONE && verbose)
rprintf(code, "%s -> %s\n", fname, sl);
@@ -1618,7 +1656,7 @@ static void recv_generator(char *fname, struct file_struct *file, int ndx,
set_file_attrs(fname, file, NULL, NULL, 0);
if (itemizing) {
itemize(fname, file, ndx, statret, &sx,
ITEM_LOCAL_CHANGE, 0, NULL);
ITEM_LOCAL_CHANGE|ITEM_REPORT_CHANGE, 0, NULL);
}
if (code != FNONE && verbose)
rprintf(code, "%s\n", fname);
@@ -1656,16 +1694,14 @@ static void recv_generator(char *fname, struct file_struct *file, int ndx,
goto cleanup;
}
if (ignore_existing > 0 && statret == 0) {
if (verbose > 1)
rprintf(FINFO, "%s exists\n", fname);
goto cleanup;
}
if (update_only > 0 && statret == 0
&& cmp_time(sx.st.st_mtime, file->modtime) > 0) {
if (verbose > 1)
rprintf(FINFO, "%s is newer\n", fname);
#ifdef SUPPORT_HARD_LINKS
if (F_IS_HLINKED(file))
handle_skipped_hlink(file, itemizing, code, f_out);
#endif
goto cleanup;
}
@@ -1705,7 +1741,7 @@ static void recv_generator(char *fname, struct file_struct *file, int ndx,
} else
partialptr = NULL;
if (statret != 0 && fuzzy_dirlist && dry_run <= 1) {
if (statret != 0 && fuzzy_dirlist) {
int j = find_fuzzy(file, fuzzy_dirlist);
if (j >= 0) {
fuzzy_file = fuzzy_dirlist->files[j];
@@ -1735,9 +1771,6 @@ static void recv_generator(char *fname, struct file_struct *file, int ndx,
goto cleanup;
}
if (append_mode > 0 && sx.st.st_size >= F_LENGTH(file))
goto cleanup;
if (fnamecmp_type <= FNAMECMP_BASIS_DIR_HIGH)
;
else if (fnamecmp_type == FNAMECMP_FUZZY)
@@ -1762,6 +1795,14 @@ static void recv_generator(char *fname, struct file_struct *file, int ndx,
goto cleanup;
}
if (append_mode > 0 && sx.st.st_size >= F_LENGTH(file)) {
#ifdef SUPPORT_HARD_LINKS
if (F_IS_HLINKED(file))
handle_skipped_hlink(file, itemizing, code, f_out);
#endif
goto cleanup;
}
prepare_to_open:
if (partialptr) {
sx.st = partial_st;
@@ -1849,7 +1890,7 @@ static void recv_generator(char *fname, struct file_struct *file, int ndx,
rprintf(FINFO, "generating and sending sums for %d\n", ndx);
notify_others:
if (remove_source_files && !delay_updates && !phase)
if (remove_source_files && !delay_updates && !phase && !dry_run)
increment_active_files(ndx, itemizing, code);
if (inc_recurse && !dry_run)
cur_flist->in_progress++;
@@ -1861,7 +1902,7 @@ static void recv_generator(char *fname, struct file_struct *file, int ndx,
if (itemizing) {
int iflags = ITEM_TRANSFER;
if (always_checksum > 0)
iflags |= ITEM_REPORT_CHECKSUM;
iflags |= ITEM_REPORT_CHANGE;
if (fnamecmp_type != FNAMECMP_FNAME)
iflags |= ITEM_BASIS_TYPE_FOLLOWS;
if (fnamecmp_type == FNAMECMP_FUZZY)
@@ -1918,6 +1959,28 @@ static void recv_generator(char *fname, struct file_struct *file, int ndx,
return;
}
#ifdef SUPPORT_HARD_LINKS
static void handle_skipped_hlink(struct file_struct *file, int itemizing,
enum logcode code, int f_out)
{
char fbuf[MAXPATHLEN];
int new_last_ndx;
struct file_list *save_flist = cur_flist;
/* If we skip the last item in a chain of links and there was a
* prior non-skipped hard-link waiting to finish, finish it now. */
if ((new_last_ndx = skip_hard_link(file, &cur_flist)) < 0)
return;
file = cur_flist->files[new_last_ndx - cur_flist->ndx_start];
cur_flist->in_progress--; /* undo prior increment */
f_name(file, fbuf);
recv_generator(fbuf, file, new_last_ndx, itemizing, code, f_out);
cur_flist = save_flist;
}
#endif
static void touch_up_dirs(struct file_list *flist, int ndx)
{
static int counter = 0;
@@ -1949,8 +2012,12 @@ static void touch_up_dirs(struct file_list *flist, int ndx)
fname = f_name(file, NULL);
if (!(file->mode & S_IWUSR))
do_chmod(fname, file->mode);
if (need_retouch_dir_times)
set_modtime(fname, file->modtime, file->mode);
if (need_retouch_dir_times) {
STRUCT_STAT st;
if (link_stat(fname, &st, 0) == 0
&& cmp_time(st.st_mtime, file->modtime) != 0)
set_modtime(fname, file->modtime, file->mode);
}
if (allowed_lull && !(counter % lull_mod))
maybe_send_keepalive();
else if (!(counter & 0xFF))
@@ -2068,6 +2135,9 @@ void generate_files(int f_out, const char *local_name)
dir_tweaking = !(list_only || solo_file || dry_run);
need_retouch_dir_times = preserve_times > 1;
lull_mod = allowed_lull * 5;
symlink_timeset_failed_flags = ITEM_REPORT_TIME
| (protocol_version >= 30 || !am_server ? ITEM_REPORT_TIMEFAIL : 0);
implied_dirs_are_missing = relative_paths && !implied_dirs && protocol_version < 30;
if (verbose > 2)
rprintf(FINFO, "generator starting pid=%ld\n", (long)getpid());
@@ -2112,16 +2182,18 @@ void generate_files(int f_out, const char *local_name)
f_name(fp, fbuf);
ndx = cur_flist->ndx_start - 1;
recv_generator(fbuf, fp, ndx, itemizing, code, f_out);
if (delete_during && dry_run < 2 && !list_only) {
if (BITS_SETnUNSET(fp->flags, FLAG_CONTENT_DIR, FLAG_MISSING_DIR)) {
if (delete_during && dry_run < 2 && !list_only
&& !(fp->flags & FLAG_MISSING_DIR)) {
if (fp->flags & FLAG_CONTENT_DIR) {
dev_t dirdev;
if (one_file_system) {
uint32 *devp = F_DIR_DEV_P(fp);
dirdev = MAKEDEV(DEV_MAJOR(devp), DEV_MINOR(devp));
} else
dirdev = MAKEDEV(0, 0);
delete_in_dir(f_name(fp, fbuf), fp, &dirdev);
}
delete_in_dir(fbuf, fp, &dirdev);
} else
change_local_filter_dir(fbuf, strlen(fbuf), F_DEPTH(fp));
}
}
for (i = cur_flist->low; i <= cur_flist->high; i++) {

92
hlink.c
View File

@@ -125,12 +125,16 @@ static void match_gnums(int32 *ndx_list, int ndx_count)
prev = -1;
} else if (CVAL(node->data, 0) == 0) {
struct file_list *flist;
struct file_struct *fp;
prev = IVAL(node->data, 1);
flist = flist_for_ndx(prev);
assert(flist != NULL);
fp = flist->files[prev - flist->ndx_start];
fp->flags &= ~FLAG_HLINK_LAST;
if (flist)
flist->files[prev - flist->ndx_start]->flags &= ~FLAG_HLINK_LAST;
else {
/* We skipped all prior files in this
* group, so mark this as a "first". */
file->flags |= FLAG_HLINK_FIRST;
prev = -1;
}
} else
prev = -1;
} else {
@@ -240,21 +244,42 @@ static int maybe_hard_link(struct file_struct *file, int ndx,
}
/* Figure out if a prior entry is still there or if we just have a
* cached name for it. Never called with a FLAG_HLINK_FIRST entry. */
static char *check_prior(int prev_ndx, int gnum, struct file_list **flist_p)
* cached name for it. */
static char *check_prior(struct file_struct *file, int gnum,
int *prev_ndx_p, struct file_list **flist_p)
{
struct file_list *flist = flist_for_ndx(prev_ndx);
struct file_struct *fp;
struct ht_int32_node *node;
int prev_ndx = F_HL_PREV(file);
if (flist) {
*flist_p = flist;
return NULL;
while (1) {
struct file_list *flist;
if (prev_ndx < 0
|| (flist = flist_for_ndx(prev_ndx)) == NULL)
break;
fp = flist->files[prev_ndx - flist->ndx_start];
if (!(fp->flags & FLAG_SKIP_HLINK)) {
*prev_ndx_p = prev_ndx;
*flist_p = flist;
return NULL;
}
F_HL_PREV(file) = prev_ndx = F_HL_PREV(fp);
}
node = hashtable_find(prior_hlinks, gnum, 0);
assert(node != NULL && node->data);
assert(CVAL(node->data, 0) != 0);
return node->data;
if ((node = hashtable_find(prior_hlinks, gnum, 0)) != NULL) {
assert(node->data != NULL);
if (CVAL(node->data, 0) != 0) {
*prev_ndx_p = -1;
*flist_p = NULL;
return node->data;
}
/* The prior file must have been skipped. */
F_HL_PREV(file) = -1;
}
*prev_ndx_p = -1;
*flist_p = NULL;
return NULL;
}
/* Only called if FLAG_HLINKED is set and FLAG_HLINK_FIRST is not. Returns:
@@ -268,12 +293,20 @@ int hard_link_check(struct file_struct *file, int ndx, const char *fname,
char *realname, *prev_name;
struct file_list *flist;
int gnum = inc_recurse ? F_HL_GNUM(file) : -1;
int prev_ndx = F_HL_PREV(file);
int prev_ndx;
prev_name = realname = check_prior(prev_ndx, gnum, &flist);
prev_name = realname = check_prior(file, gnum, &prev_ndx, &flist);
if (!prev_name) {
struct file_struct *prev_file = flist->files[prev_ndx - flist->ndx_start];
struct file_struct *prev_file;
if (!flist) {
/* The previous file was skipped, so this one is
* treated as if it were the first in its group. */
return 0;
}
prev_file = flist->files[prev_ndx - flist->ndx_start];
/* Is the previous link not complete yet? */
if (!(prev_file->flags & FLAG_HLINK_DONE)) {
@@ -294,8 +327,8 @@ int hard_link_check(struct file_struct *file, int ndx, const char *fname,
/* There is a finished file to link with! */
if (!(prev_file->flags & FLAG_HLINK_FIRST)) {
/* The previous previous is FIRST when prev is not. */
prev_ndx = F_HL_PREV(prev_file);
prev_name = realname = check_prior(prev_ndx, gnum, &flist);
prev_name = realname = check_prior(prev_file, gnum, &prev_ndx, &flist);
assert(prev_name != NULL || flist != NULL);
/* Update our previous pointer to point to the FIRST. */
F_HL_PREV(file) = prev_ndx;
}
@@ -474,4 +507,25 @@ void finish_hard_link(struct file_struct *file, const char *fname, int fin_ndx,
out_of_memory("finish_hard_link");
}
}
int skip_hard_link(struct file_struct *file, struct file_list **flist_p)
{
struct file_list *flist;
int prev_ndx;
file->flags |= FLAG_SKIP_HLINK;
if (!(file->flags & FLAG_HLINK_LAST))
return -1;
check_prior(file, F_HL_GNUM(file), &prev_ndx, &flist);
if (prev_ndx >= 0) {
file = flist->files[prev_ndx - flist->ndx_start];
if (file->flags & (FLAG_HLINK_DONE|FLAG_FILE_SENT))
return -1;
file->flags |= FLAG_HLINK_LAST;
*flist_p = flist;
}
return prev_ndx;
}
#endif

View File

@@ -57,6 +57,16 @@ from_wire_mode(int mode)
return mode;
}
static inline char *
d_name(struct dirent *di)
{
#ifdef HAVE_BROKEN_READDIR
return (di->d_name - 2);
#else
return di->d_name;
#endif
}
static inline int
isDigit(const char *ptr)
{

55
io.c
View File

@@ -45,6 +45,7 @@ extern int inc_recurse;
extern int io_error;
extern int eol_nulls;
extern int flist_eof;
extern int list_only;
extern int read_batch;
extern int csum_length;
extern int protect_args;
@@ -104,6 +105,7 @@ static int defer_forwarding_messages = 0, defer_forwarding_keep = 0;
static int select_timeout = SELECT_TIMEOUT;
static int active_filecnt = 0;
static OFF_T active_bytecnt = 0;
static int first_message = 1;
static char int_byte_extra[64] = {
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* (00 - 3F)/4 */
@@ -112,6 +114,9 @@ static char int_byte_extra[64] = {
2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 4, 4, 5, 6, /* (C0 - FF)/4 */
};
#define REMOTE_OPTION_ERROR "rsync: on remote machine: -"
#define REMOTE_OPTION_ERROR2 ": unknown option"
enum festatus { FES_SUCCESS, FES_REDO, FES_NO_SEND };
static void readfd(int fd, char *buffer, size_t N);
@@ -321,6 +326,36 @@ static void msg_flush(void)
}
}
static void check_for_d_option_error(const char *msg)
{
static char rsync263_opts[] = "BCDHIKLPRSTWabceghlnopqrtuvxz";
char *colon;
int saw_d = 0;
if (*msg != 'r'
|| strncmp(msg, REMOTE_OPTION_ERROR, sizeof REMOTE_OPTION_ERROR - 1) != 0)
return;
msg += sizeof REMOTE_OPTION_ERROR - 1;
if (*msg == '-' || (colon = strchr(msg, ':')) == NULL
|| strncmp(colon, REMOTE_OPTION_ERROR2, sizeof REMOTE_OPTION_ERROR2 - 1) != 0)
return;
for ( ; *msg != ':'; msg++) {
if (*msg == 'd')
saw_d = 1;
else if (*msg == 'e')
break;
else if (strchr(rsync263_opts, *msg) == NULL)
return;
}
if (saw_d) {
rprintf(FWARNING,
"*** Try using \"--old-d\" if remote rsync is <= 2.6.3 ***\n");
}
}
/* Read a message from the MSG_* fd and handle it. This is called either
* during the early stages of being a local sender (up through the sending
* of the file list) or when we're the generator (to fetch the messages
@@ -838,8 +873,8 @@ int read_line(int fd, char *buf, size_t bufsiz, int flags)
return s - buf;
}
int read_args(int f_in, char *mod_name, char *buf, size_t bufsiz, int rl_nulls,
char ***argv_p, int *argc_p, char **request_p)
void read_args(int f_in, char *mod_name, char *buf, size_t bufsiz, int rl_nulls,
char ***argv_p, int *argc_p, char **request_p)
{
int maxargs = MAX_ARGS;
int dot_pos = 0;
@@ -853,14 +888,14 @@ int read_args(int f_in, char *mod_name, char *buf, size_t bufsiz, int rl_nulls,
if (!(argv = new_array(char *, maxargs)))
out_of_memory("read_args");
if (mod_name)
if (mod_name && !protect_args)
argv[argc++] = "rsyncd";
while (1) {
if (read_line(f_in, buf, bufsiz, rl_flags) == 0)
break;
if (argc == maxargs) {
if (argc == maxargs-1) {
maxargs += MAX_ARGS;
if (!(argv = realloc_array(argv, char *, maxargs)))
out_of_memory("read_args");
@@ -883,11 +918,12 @@ int read_args(int f_in, char *mod_name, char *buf, size_t bufsiz, int rl_nulls,
dot_pos = argc;
}
}
argv[argc] = NULL;
glob_expand(NULL, NULL, NULL, NULL);
*argc_p = argc;
*argv_p = argv;
return dot_pos ? dot_pos : argc;
}
int io_start_buffering_out(int f_out)
@@ -1119,6 +1155,13 @@ static int readfd_unbuffered(int fd, char *buf, size_t len)
}
read_loop(fd, line, msg_bytes);
rwrite((enum logcode)tag, line, msg_bytes, 1);
if (first_message) {
if (list_only && !am_sender && tag == 1) {
line[msg_bytes] = '\0';
check_for_d_option_error(line);
}
first_message = 0;
}
break;
default:
rprintf(FERROR, "unexpected tag %d [%s]\n",

24
log.c
View File

@@ -632,15 +632,21 @@ static void log_formatted(enum logcode code, const char *format, const char *op,
? iflags & ITEM_XNAME_FOLLOWS ? 'h' : 'c'
: !(iflags & ITEM_TRANSFER) ? '.'
: !local_server && *op == 's' ? '<' : '>';
c[1] = S_ISDIR(file->mode) ? 'd'
: IS_SPECIAL(file->mode) ? 'S'
: IS_DEVICE(file->mode) ? 'D'
: S_ISLNK(file->mode) ? 'L' : 'f';
c[2] = !(iflags & ITEM_REPORT_CHECKSUM) ? '.' : 'c';
c[3] = !(iflags & ITEM_REPORT_SIZE) ? '.' : 's';
c[4] = !(iflags & ITEM_REPORT_TIME) ? '.'
: !preserve_times || (!receiver_symlink_times && S_ISLNK(file->mode))
? 'T' : 't';
if (S_ISLNK(file->mode)) {
c[1] = 'L';
c[3] = '.';
c[4] = !(iflags & ITEM_REPORT_TIME) ? '.'
: !preserve_times || !receiver_symlink_times
|| (iflags & ITEM_REPORT_TIMEFAIL) ? 'T' : 't';
} else {
c[1] = S_ISDIR(file->mode) ? 'd'
: IS_SPECIAL(file->mode) ? 'S'
: IS_DEVICE(file->mode) ? 'D' : 'f';
c[3] = !(iflags & ITEM_REPORT_SIZE) ? '.' : 's';
c[4] = !(iflags & ITEM_REPORT_TIME) ? '.'
: !preserve_times ? 'T' : 't';
}
c[2] = !(iflags & ITEM_REPORT_CHANGE) ? '.' : 'c';
c[5] = !(iflags & ITEM_REPORT_PERMS) ? '.' : 'p';
c[6] = !(iflags & ITEM_REPORT_OWNER) ? '.' : 'o';
c[7] = !(iflags & ITEM_REPORT_GROUP) ? '.' : 'g';

115
main.c
View File

@@ -78,10 +78,7 @@ extern char *batch_name;
extern char *password_file;
extern char curr_dir[MAXPATHLEN];
extern struct file_list *first_flist;
extern struct filter_list_struct server_filter_list;
#ifdef ICONV_OPTION
extern iconv_t ic_send;
#endif
extern struct filter_list_struct daemon_filter_list;
uid_t our_uid;
int local_server = 0;
@@ -334,7 +331,7 @@ static pid_t do_cmd(char *cmd, char *machine, char *user, char **remote_argv, in
{
int i, argc = 0;
char *args[MAX_ARGS];
pid_t ret;
pid_t pid;
int dash_l_set = 0;
if (!read_batch && !local_server) {
@@ -344,7 +341,7 @@ static pid_t do_cmd(char *cmd, char *machine, char *user, char **remote_argv, in
cmd = rsh_env;
if (!cmd)
cmd = RSYNC_RSH;
cmd = strdup(cmd);
cmd = strdup(cmd); /* MEMORY LEAK */
if (!cmd)
goto oom;
@@ -453,7 +450,7 @@ static pid_t do_cmd(char *cmd, char *machine, char *user, char **remote_argv, in
batch_gen_fd = from_gen_pipe[0];
*f_out_p = from_gen_pipe[1];
*f_in_p = batch_fd;
ret = -1; /* no child pid */
pid = (pid_t)-1; /* no child pid */
#ifdef ICONV_CONST
setup_iconv();
#endif
@@ -463,54 +460,20 @@ static pid_t do_cmd(char *cmd, char *machine, char *user, char **remote_argv, in
if (whole_file < 0 && !write_batch)
whole_file = 1;
set_allow_inc_recurse();
ret = local_child(argc, args, f_in_p, f_out_p, child_main);
pid = local_child(argc, args, f_in_p, f_out_p, child_main);
#ifdef ICONV_CONST
setup_iconv();
#endif
} else {
pid = piped_child(args, f_in_p, f_out_p);
#ifdef ICONV_CONST
setup_iconv();
#endif
if (protect_args) {
int fd;
#ifdef ICONV_OPTION
int convert = ic_send != (iconv_t)-1;
xbuf outbuf, inbuf;
if (convert)
alloc_xbuf(&outbuf, 1024);
#endif
ret = piped_child(args, f_in_p, f_out_p);
for (i = 0; args[i]; i++) {} /* find first NULL */
args[i] = "rsync"; /* set a new arg0 */
if (verbose > 1)
print_child_argv("protected args:", args + i + 1);
fd = *f_out_p;
do {
#ifdef ICONV_OPTION
if (convert) {
INIT_XBUF_STRLEN(inbuf, args[i]);
iconvbufs(ic_send, &inbuf, &outbuf,
ICB_EXPAND_OUT | ICB_INCLUDE_BAD | ICB_INCLUDE_INCOMPLETE);
outbuf.buf[outbuf.len] = '\0';
write_buf(fd, outbuf.buf, outbuf.len + 1);
outbuf.len = 0;
} else
#endif
write_buf(fd, args[i], strlen(args[i]) + 1);
} while (args[++i]);
write_byte(fd, 0);
#ifdef ICONV_OPTION
if (convert)
free(outbuf.buf);
#endif
} else
ret = piped_child(args, f_in_p, f_out_p);
if (protect_args)
send_protected_args(*f_out_p, args);
}
return ret;
return pid;
oom:
out_of_memory("do_cmd");
@@ -544,12 +507,20 @@ static char *get_local_name(struct file_list *flist, char *dest_path)
if (!dest_path || list_only)
return NULL;
if (daemon_filter_list.head
&& (check_filter(&daemon_filter_list, FLOG, dest_path, 0 != 0) < 0
|| check_filter(&daemon_filter_list, FLOG, dest_path, 1 != 0) < 0)) {
rprintf(FERROR, "skipping daemon-excluded destination \"%s\"\n",
dest_path);
exit_cleanup(RERR_FILESELECT);
}
/* See what currently exists at the destination. */
if ((statret = do_stat(dest_path, &st)) == 0) {
/* If the destination is a dir, enter it and use mode 1. */
if (S_ISDIR(st.st_mode)) {
if (!push_dir(dest_path, 0)) {
rsyserr(FERROR, errno, "push_dir#1 %s failed",
if (!change_dir(dest_path, CD_NORMAL)) {
rsyserr(FERROR, errno, "change_dir#1 %s failed",
full_fname(dest_path));
exit_cleanup(RERR_FILESELECT);
}
@@ -608,8 +579,8 @@ static char *get_local_name(struct file_list *flist, char *dest_path)
dry_run++;
}
if (!push_dir(dest_path, dry_run > 1)) {
rsyserr(FERROR, errno, "push_dir#2 %s failed",
if (!change_dir(dest_path, dry_run > 1 ? CD_SKIP_CHDIR : CD_NORMAL)) {
rsyserr(FERROR, errno, "change_dir#2 %s failed",
full_fname(dest_path));
exit_cleanup(RERR_FILESELECT);
}
@@ -628,8 +599,8 @@ static char *get_local_name(struct file_list *flist, char *dest_path)
dest_path = "/";
*cp = '\0';
if (!push_dir(dest_path, 0)) {
rsyserr(FERROR, errno, "push_dir#3 %s failed",
if (!change_dir(dest_path, CD_NORMAL)) {
rsyserr(FERROR, errno, "change_dir#3 %s failed",
full_fname(dest_path));
exit_cleanup(RERR_FILESELECT);
}
@@ -721,8 +692,8 @@ static void do_server_sender(int f_in, int f_out, int argc, char *argv[])
}
if (!relative_paths) {
if (!push_dir(dir, 0)) {
rsyserr(FERROR, errno, "push_dir#3 %s failed",
if (!change_dir(dir, CD_NORMAL)) {
rsyserr(FERROR, errno, "change_dir#3 %s failed",
full_fname(dir));
exit_cleanup(RERR_FILESELECT);
}
@@ -891,8 +862,8 @@ static void do_server_recv(int f_in, int f_out, int argc, char *argv[])
char *dir = argv[0];
argc--;
argv++;
if (!am_daemon && !push_dir(dir, 0)) {
rsyserr(FERROR, errno, "push_dir#4 %s failed",
if (!am_daemon && !change_dir(dir, CD_NORMAL)) {
rsyserr(FERROR, errno, "change_dir#4 %s failed",
full_fname(dir));
exit_cleanup(RERR_FILESELECT);
}
@@ -931,25 +902,25 @@ static void do_server_recv(int f_in, int f_out, int argc, char *argv[])
if (sanitize_paths) {
char **dir_p;
for (dir_p = basis_dir; *dir_p; dir_p++)
*dir_p = sanitize_path(NULL, *dir_p, NULL, curr_dir_depth);
*dir_p = sanitize_path(NULL, *dir_p, NULL, curr_dir_depth, SP_DEFAULT);
if (partial_dir)
partial_dir = sanitize_path(NULL, partial_dir, NULL, curr_dir_depth);
partial_dir = sanitize_path(NULL, partial_dir, NULL, curr_dir_depth, SP_DEFAULT);
}
check_alt_basis_dirs();
if (server_filter_list.head) {
if (daemon_filter_list.head) {
char **dir_p;
struct filter_list_struct *elp = &server_filter_list;
struct filter_list_struct *elp = &daemon_filter_list;
for (dir_p = basis_dir; *dir_p; dir_p++) {
char *dir = *dir_p;
if (*dir == '/')
dir += module_dirlen;
if (check_filter(elp, dir, 1) < 0)
if (check_filter(elp, FLOG, dir, 1) < 0)
goto options_rejected;
}
if (partial_dir && *partial_dir == '/'
&& check_filter(elp, partial_dir + module_dirlen, 1) < 0) {
&& check_filter(elp, FLOG, partial_dir + module_dirlen, 1) < 0) {
options_rejected:
rprintf(FERROR,
"Your options have been rejected by the server.\n");
@@ -1067,11 +1038,6 @@ int client_run(int f_in, int f_out, pid_t pid, int argc, char *argv[])
io_start_multiplex_out();
}
if (argc == 0) {
list_only |= 1;
xfer_dirs |= 1;
}
send_filter_list(read_batch ? -1 : f_out);
if (filesfrom_fd >= 0) {
@@ -1182,8 +1148,6 @@ static int start_client(int argc, char *argv[])
static char *dotarg[1] = { "." };
p = dotarg[0];
remote_argv = dotarg;
list_only |= 1;
xfer_dirs |= 1;
}
remote_argc = 1;
@@ -1255,10 +1219,6 @@ static int start_client(int argc, char *argv[])
}
remote_argv[i] = arg;
}
if (argc == 0) {
list_only |= 1;
xfer_dirs |= 1;
}
}
if (daemon_over_rsh < 0)
@@ -1447,7 +1407,7 @@ int main(int argc,char *argv[])
setlocale(LC_CTYPE, "");
#endif
if (!parse_arguments(&argc, (const char ***) &argv, 1)) {
if (!parse_arguments(&argc, (const char ***) &argv)) {
/* FIXME: We ought to call the same error-handling
* code here, rather than relying on getopt. */
option_error();
@@ -1468,11 +1428,11 @@ int main(int argc,char *argv[])
SIGACTION(SIGXFSZ, SIG_IGN);
#endif
/* Initialize push_dir here because on some old systems getcwd
/* Initialize change_dir() here because on some old systems getcwd
* (implemented by forking "pwd" and reading its output) doesn't
* work when there are other child processes. Also, on all systems
* that implement getcwd that way "pwd" can't be found after chroot. */
push_dir(NULL, 0);
change_dir(NULL, CD_NORMAL);
init_flist();
@@ -1496,7 +1456,6 @@ int main(int argc,char *argv[])
read_stream_flags(batch_fd);
else
write_stream_flags(batch_fd);
}
if (write_batch < 0)
dry_run = 1;
@@ -1512,7 +1471,7 @@ int main(int argc,char *argv[])
char buf[MAXPATHLEN];
protect_args = 2;
read_args(STDIN_FILENO, NULL, buf, sizeof buf, 1, &argv, &argc, NULL);
if (!parse_arguments(&argc, (const char ***) &argv, 1)) {
if (!parse_arguments(&argc, (const char ***) &argv)) {
option_error();
exit_cleanup(RERR_SYNTAX);
}

110
options.c
View File

@@ -25,11 +25,12 @@
#include "zlib/zlib.h"
extern int module_id;
extern int local_server;
extern int sanitize_paths;
extern int daemon_over_rsh;
extern unsigned int module_dirlen;
extern struct filter_list_struct filter_list;
extern struct filter_list_struct server_filter_list;
extern struct filter_list_struct daemon_filter_list;
int make_backups = 0;
@@ -259,7 +260,7 @@ static void print_rsync_version(enum logcode f)
rprintf(f, "%s version %s protocol version %d%s\n",
RSYNC_NAME, RSYNC_VERSION, PROTOCOL_VERSION, subprotocol);
rprintf(f, "Copyright (C) 1996-2007 by Andrew Tridgell, Wayne Davison, and others.\n");
rprintf(f, "Copyright (C) 1996-2008 by Andrew Tridgell, Wayne Davison, and others.\n");
rprintf(f, "Web site: http://rsync.samba.org/\n");
rprintf(f, "Capabilities:\n");
rprintf(f, " %d-bit files, %d-bit inums, %d-bit timestamps, %d-bit long ints,\n",
@@ -474,6 +475,8 @@ static struct poptOption long_options[] = {
{"dirs", 'd', POPT_ARG_VAL, &xfer_dirs, 2, 0, 0 },
{"no-dirs", 0, POPT_ARG_VAL, &xfer_dirs, 0, 0, 0 },
{"no-d", 0, POPT_ARG_VAL, &xfer_dirs, 0, 0, 0 },
{"old-dirs", 0, POPT_ARG_VAL, &xfer_dirs, 4, 0, 0 },
{"old-d", 0, POPT_ARG_VAL, &xfer_dirs, 4, 0, 0 },
{"perms", 'p', POPT_ARG_VAL, &preserve_perms, 1, 0, 0 },
{"no-perms", 0, POPT_ARG_VAL, &preserve_perms, 0, 0, 0 },
{"no-p", 0, POPT_ARG_VAL, &preserve_perms, 0, 0, 0 },
@@ -536,8 +539,11 @@ static struct poptOption long_options[] = {
{"ignore-existing", 0, POPT_ARG_NONE, &ignore_existing, 0, 0, 0 },
{"max-size", 0, POPT_ARG_STRING, &max_size_arg, OPT_MAX_SIZE, 0, 0 },
{"min-size", 0, POPT_ARG_STRING, &min_size_arg, OPT_MIN_SIZE, 0, 0 },
{"sparse", 'S', POPT_ARG_NONE, &sparse_files, 0, 0, 0 },
{"inplace", 0, POPT_ARG_NONE, &inplace, 0, 0, 0 },
{"sparse", 'S', POPT_ARG_VAL, &sparse_files, 1, 0, 0 },
{"no-sparse", 0, POPT_ARG_VAL, &sparse_files, 0, 0, 0 },
{"no-S", 0, POPT_ARG_VAL, &sparse_files, 0, 0, 0 },
{"inplace", 0, POPT_ARG_VAL, &inplace, 1, 0, 0 },
{"no-inplace", 0, POPT_ARG_VAL, &inplace, 0, 0, 0 },
{"append", 0, POPT_ARG_NONE, 0, OPT_APPEND, 0, 0 },
{"append-verify", 0, POPT_ARG_VAL, &append_mode, 2, 0, 0 },
{"no-append", 0, POPT_ARG_VAL, &append_mode, 0, 0, 0 },
@@ -550,8 +556,10 @@ static struct poptOption long_options[] = {
{"delete-excluded", 0, POPT_ARG_NONE, &delete_excluded, 0, 0, 0 },
{"remove-sent-files",0, POPT_ARG_VAL, &remove_source_files, 2, 0, 0 }, /* deprecated */
{"remove-source-files",0,POPT_ARG_VAL, &remove_source_files, 1, 0, 0 },
{"force", 0, POPT_ARG_NONE, &force_delete, 0, 0, 0 },
{"ignore-errors", 0, POPT_ARG_NONE, &ignore_errors, 0, 0, 0 },
{"force", 0, POPT_ARG_VAL, &force_delete, 1, 0, 0 },
{"no-force", 0, POPT_ARG_VAL, &force_delete, 0, 0, 0 },
{"ignore-errors", 0, POPT_ARG_VAL, &ignore_errors, 1, 0, 0 },
{"no-ignore-errors", 0, POPT_ARG_VAL, &ignore_errors, 0, 0, 0 },
{"max-delete", 0, POPT_ARG_INT, &max_delete, 0, 0, 0 },
{0, 'F', POPT_ARG_NONE, 0, 'F', 0, 0 },
{"filter", 'f', POPT_ARG_STRING, 0, OPT_FILTER, 0, 0 },
@@ -570,11 +578,13 @@ static struct poptOption long_options[] = {
{"compare-dest", 0, POPT_ARG_STRING, 0, OPT_COMPARE_DEST, 0, 0 },
{"copy-dest", 0, POPT_ARG_STRING, 0, OPT_COPY_DEST, 0, 0 },
{"link-dest", 0, POPT_ARG_STRING, 0, OPT_LINK_DEST, 0, 0 },
{"fuzzy", 'y', POPT_ARG_NONE, &fuzzy_basis, 0, 0, 0 },
{"fuzzy", 'y', POPT_ARG_VAL, &fuzzy_basis, 1, 0, 0 },
{"no-fuzzy", 0, POPT_ARG_VAL, &fuzzy_basis, 0, 0, 0 },
{"no-y", 0, POPT_ARG_VAL, &fuzzy_basis, 0, 0, 0 },
{"compress", 'z', POPT_ARG_NONE, 0, 'z', 0, 0 },
{"no-compress", 0, POPT_ARG_VAL, &do_compression, 0, 0, 0 },
{"skip-compress", 0, POPT_ARG_STRING, &skip_compress, 0, 0, 0 },
{"no-z", 0, POPT_ARG_VAL, &do_compression, 0, 0, 0 },
{"skip-compress", 0, POPT_ARG_STRING, &skip_compress, 0, 0, 0 },
{"compress-level", 0, POPT_ARG_INT, &def_compress_level, 'z', 0, 0 },
{0, 'P', POPT_ARG_NONE, 0, 'P', 0, 0 },
{"progress", 0, POPT_ARG_VAL, &do_progress, 1, 0, 0 },
@@ -584,7 +594,9 @@ static struct poptOption long_options[] = {
{"partial-dir", 0, POPT_ARG_STRING, &partial_dir, 0, 0, 0 },
{"delay-updates", 0, POPT_ARG_VAL, &delay_updates, 1, 0, 0 },
{"no-delay-updates", 0, POPT_ARG_VAL, &delay_updates, 0, 0, 0 },
{"prune-empty-dirs",'m', POPT_ARG_NONE, &prune_empty_dirs, 0, 0, 0 },
{"prune-empty-dirs",'m', POPT_ARG_VAL, &prune_empty_dirs, 1, 0, 0 },
{"no-prune-empty-dirs",0,POPT_ARG_VAL, &prune_empty_dirs, 0, 0, 0 },
{"no-m", 0, POPT_ARG_VAL, &prune_empty_dirs, 0, 0, 0 },
{"log-file", 0, POPT_ARG_STRING, &logfile_name, 0, 0, 0 },
{"log-file-format", 0, POPT_ARG_STRING, &logfile_format, 0, 0, 0 },
{"out-format", 0, POPT_ARG_STRING, &stdout_format, 0, 0, 0 },
@@ -613,6 +625,7 @@ static struct poptOption long_options[] = {
{"timeout", 0, POPT_ARG_INT, &io_timeout, 0, 0, 0 },
{"no-timeout", 0, POPT_ARG_VAL, &io_timeout, 0, 0, 0 },
{"contimeout", 0, POPT_ARG_INT, &connect_timeout, 0, 0, 0 },
{"no-contimeout", 0, POPT_ARG_VAL, &connect_timeout, 0, 0, 0 },
{"rsh", 'e', POPT_ARG_STRING, &shell_cmd, 0, 0, 0 },
{"rsync-path", 0, POPT_ARG_STRING, &rsync_path, 0, 0, 0 },
{"temp-dir", 'T', POPT_ARG_STRING, &tmpdir, 0, 0, 0 },
@@ -622,7 +635,9 @@ static struct poptOption long_options[] = {
#endif
{"ipv4", '4', POPT_ARG_VAL, &default_af_hint, AF_INET, 0, 0 },
{"ipv6", '6', POPT_ARG_VAL, &default_af_hint, AF_INET6, 0, 0 },
{"8-bit-output", '8', POPT_ARG_NONE, &allow_8bit_chars, 0, 0, 0 },
{"8-bit-output", '8', POPT_ARG_VAL, &allow_8bit_chars, 1, 0, 0 },
{"no-8-bit-output", 0, POPT_ARG_VAL, &allow_8bit_chars, 0, 0, 0 },
{"no-8", 0, POPT_ARG_VAL, &allow_8bit_chars, 0, 0, 0 },
{"qsort", 0, POPT_ARG_NONE, &use_qsort, 0, 0, 0 },
{"address", 0, POPT_ARG_STRING, &bind_address, 0, 0, 0 },
{"port", 0, POPT_ARG_INT, &rsync_port, 0, 0, 0 },
@@ -877,7 +892,7 @@ static void create_refuse_error(int which)
*
* @retval 0 on error, with err_buf containing an explanation
**/
int parse_arguments(int *argc_p, const char ***argv_p, int frommain)
int parse_arguments(int *argc_p, const char ***argv_p)
{
static poptContext pc;
char *ref = lp_refuse_options(module_id);
@@ -889,8 +904,10 @@ int parse_arguments(int *argc_p, const char ***argv_p, int frommain)
set_refuse_options(ref);
if (am_daemon) {
set_refuse_options("log-file*");
#ifdef ICONV_OPTION
if (!*lp_charset(module_id))
set_refuse_options("iconv");
#endif
}
#ifdef ICONV_OPTION
@@ -1017,8 +1034,8 @@ int parse_arguments(int *argc_p, const char ***argv_p, int frommain)
case OPT_INCLUDE_FROM:
arg = poptGetOptArg(pc);
if (sanitize_paths)
arg = sanitize_path(NULL, arg, NULL, 0);
if (server_filter_list.head) {
arg = sanitize_path(NULL, arg, NULL, 0, SP_DEFAULT);
if (daemon_filter_list.head) {
int rej;
char *dir, *cp = strdup(arg);
if (!cp)
@@ -1027,7 +1044,7 @@ int parse_arguments(int *argc_p, const char ***argv_p, int frommain)
goto options_rejected;
dir = cp + (*cp == '/' ? module_dirlen : 0);
clean_fname(dir, CFN_COLLAPSE_DOT_DOT_DIRS);
rej = check_filter(&server_filter_list, dir, 0) < 0;
rej = check_filter(&daemon_filter_list, FLOG, dir, 0) < 0;
free(cp);
if (rej)
goto options_rejected;
@@ -1080,8 +1097,7 @@ int parse_arguments(int *argc_p, const char ***argv_p, int frommain)
break;
case 'q':
if (frommain)
quiet++;
quiet++;
break;
case 'x':
@@ -1259,7 +1275,7 @@ int parse_arguments(int *argc_p, const char ***argv_p, int frommain)
}
}
if (human_readable && argc == 2) {
if (human_readable && argc == 2 && !am_server) {
/* Allow the old meaning of 'h' (--help) on its own. */
usage(FINFO);
exit_cleanup(0);
@@ -1278,12 +1294,11 @@ int parse_arguments(int *argc_p, const char ***argv_p, int frommain)
}
#endif
if (protect_args == 1) {
if (!frommain)
protect_args = 0;
else if (am_server)
return 1;
}
if (protect_args == 1 && am_server)
return 1;
*argv_p = argv = poptGetArgs(pc);
*argc_p = argc = count_args(argv);
#ifndef SUPPORT_LINKS
if (preserve_links && !am_sender) {
@@ -1303,7 +1318,13 @@ int parse_arguments(int *argc_p, const char ***argv_p, int frommain)
}
#endif
#ifndef SUPPORT_XATTRS
#ifdef SUPPORT_XATTRS
if (am_root < 0 && preserve_xattrs > 1) {
snprintf(err_buf, sizeof err_buf,
"--fake-super conflicts with -XX\n");
return 0;
}
#else
if (am_root < 0) {
snprintf(err_buf, sizeof err_buf,
"--fake-super requires an rsync with extended attributes enabled\n");
@@ -1366,8 +1387,16 @@ int parse_arguments(int *argc_p, const char ***argv_p, int frommain)
xfer_dirs = 1;
}
if (xfer_dirs < 1)
xfer_dirs = recurse || list_only;
if (argc < 2 && !read_batch && !am_server)
list_only |= 1;
if (xfer_dirs >= 4) {
parse_rule(&filter_list, "- /*/*", 0, 0);
recurse = xfer_dirs = 1;
} else if (recurse)
xfer_dirs = 1;
else if (xfer_dirs < 0)
xfer_dirs = list_only ? 1 : 0;
if (relative_paths < 0)
relative_paths = files_from? 1 : 0;
@@ -1416,27 +1445,24 @@ int parse_arguments(int *argc_p, const char ***argv_p, int frommain)
need_messages_from_generator = 1;
}
*argv_p = argv = poptGetArgs(pc);
*argc_p = argc = count_args(argv);
if (sanitize_paths) {
int i;
for (i = argc; i-- > 0; )
argv[i] = sanitize_path(NULL, argv[i], "", 0);
argv[i] = sanitize_path(NULL, argv[i], "", 0, SP_KEEP_DOT_DIRS);
if (tmpdir)
tmpdir = sanitize_path(NULL, tmpdir, NULL, 0);
tmpdir = sanitize_path(NULL, tmpdir, NULL, 0, SP_DEFAULT);
if (backup_dir)
backup_dir = sanitize_path(NULL, backup_dir, NULL, 0);
backup_dir = sanitize_path(NULL, backup_dir, NULL, 0, SP_DEFAULT);
}
if (server_filter_list.head && !am_sender) {
struct filter_list_struct *elp = &server_filter_list;
if (daemon_filter_list.head && !am_sender) {
struct filter_list_struct *elp = &daemon_filter_list;
if (tmpdir) {
char *dir;
if (!*tmpdir)
goto options_rejected;
dir = tmpdir + (*tmpdir == '/' ? module_dirlen : 0);
clean_fname(dir, CFN_COLLAPSE_DOT_DOT_DIRS);
if (check_filter(elp, dir, 1) < 0)
if (check_filter(elp, FLOG, dir, 1) < 0)
goto options_rejected;
}
if (backup_dir) {
@@ -1445,7 +1471,7 @@ int parse_arguments(int *argc_p, const char ***argv_p, int frommain)
goto options_rejected;
dir = backup_dir + (*backup_dir == '/' ? module_dirlen : 0);
clean_fname(dir, CFN_COLLAPSE_DOT_DOT_DIRS);
if (check_filter(elp, dir, 1) < 0)
if (check_filter(elp, FLOG, dir, 1) < 0)
goto options_rejected;
}
}
@@ -1634,14 +1660,14 @@ int parse_arguments(int *argc_p, const char ***argv_p, int frommain)
}
} else {
if (sanitize_paths)
files_from = sanitize_path(NULL, files_from, NULL, 0);
if (server_filter_list.head) {
files_from = sanitize_path(NULL, files_from, NULL, 0, SP_DEFAULT);
if (daemon_filter_list.head) {
char *dir;
if (!*files_from)
goto options_rejected;
dir = files_from + (*files_from == '/' ? module_dirlen : 0);
clean_fname(dir, CFN_COLLAPSE_DOT_DOT_DIRS);
if (check_filter(&server_filter_list, dir, 0) < 0)
if (check_filter(&daemon_filter_list, FLOG, dir, 0) < 0)
goto options_rejected;
}
filesfrom_fd = open(files_from, O_RDONLY|O_BINARY);
@@ -1711,8 +1737,8 @@ void server_options(char **args, int *argc_p)
argstr[x++] = 'n';
if (preserve_links)
argstr[x++] = 'l';
if ((list_only && !recurse) || xfer_dirs > 1
|| (xfer_dirs && !recurse && delete_mode && am_sender))
if ((xfer_dirs >= 2 && xfer_dirs < 4)
|| (xfer_dirs && !recurse && (list_only || (delete_mode && am_sender))))
argstr[x++] = 'd';
if (am_sender) {
if (keep_dirlinks)
@@ -1815,7 +1841,7 @@ void server_options(char **args, int *argc_p)
}
#endif
if (protect_args) /* initial args break here */
if (protect_args && !local_server) /* unprotected args stop here */
args[ac++] = NULL;
if (list_only > 1)

6
packaging/bin/gpg Executable file
View File

@@ -0,0 +1,6 @@
#!/bin/sh -e
# This script gets git to run gpg with a --passphrase-file option.
PATH=`echo $PATH | sed 's/^[^:]*://'`
gpg --batch --passphrase-file=$GPG_PASSFILE "${@}"

View File

@@ -1,9 +1,12 @@
Summary: A fast, versatile, remote (and local) file-copying tool
Name: rsync
Version: 3.0.0
Version: 3.0.1
%define fullversion %{version}
Release: 1
%define srcdir src
Group: Applications/Internet
Source: http://rsync.samba.org/ftp/rsync/rsync-%{version}.tar.gz
Source0: http://rsync.samba.org/ftp/rsync/%{srcdir}/rsync-%{fullversion}.tar.gz
Source1: http://rsync.samba.org/ftp/rsync/%{srcdir}/rsync-patches-%{fullversion}.tar.gz
URL: http://rsync.samba.org/
Prefix: %{_prefix}
@@ -22,9 +25,18 @@ destination. Rsync is widely used for backups and mirroring and as an
improved copy command for everyday use.
%prep
%setup -q
# Choose one -- setup source only, or setup source + rsync-patches:
%setup -q -n rsync-%{fullversion}
#%setup -q -b1 -n rsync-%{fullversion}
# If you you used "%setup -q -b1", choose the patches you wish to apply:
#patch -p1 <patches/acls.diff
#patch -p1 <patches/xattrs.diff
#patch -p1 <patches/remote-option.diff
#patch -p1 <patches/db.diff
%build
#./prepare-source
%configure
make
@@ -34,16 +46,26 @@ rm -rf $RPM_BUILD_ROOT
%makeinstall
mkdir -p $RPM_BUILD_ROOT/etc/xinetd.d
install -m 644 packaging/lsb/rsync.xinetd $RPM_BUILD_ROOT/etc/xinetd.d/rsync
#install -p -m 755 support/rsyncdb $RPM_BUILD_ROOT/usr/bin/rsyncdb
%clean
rm -rf $RPM_BUILD_ROOT
%files
%defattr(-,root,root)
%doc COPYING README tech_report.tex
%{_prefix}/bin/rsync
%config(noreplace) /etc/xinetd.d/rsync
%{_prefix}/bin/rsync*
%{_mandir}/man1/rsync.1*
%{_mandir}/man5/rsyncd.conf.5*
%changelog
* Sat Mar 01 2008 Wayne Davison <wayned@samba.org>
Released 3.0.0.
* Thu Apr 03 2008 Wayne Davison <wayned@samba.org>
Released 3.0.1.
* Fri Mar 21 2008 Wayne Davison <wayned@samba.org>
Added installation of /etc/xinetd.d/rsync file and some commented-out
lines that demonstrate how to use the rsync-patches tar file.

View File

@@ -0,0 +1,13 @@
# default: off
# description: The rsync server is a good addition to an ftp server, as it
# allows crc checksumming etc.
service rsync
{
disable = yes
socket_type = stream
wait = no
user = root
server = /usr/bin/rsync
server_args = --daemon
log_on_failure += USERID
}

View File

@@ -14,8 +14,8 @@ use strict;
use Getopt::Long;
use Date::Format;
# Where the local copy of /home/ftp/pub/rsync/nightly should be updated.
our $dest = $ENV{HOME} . '/samba-rsync-ftp/nightly';
# Where the local copy of /home/ftp/pub/rsync/dev/nightly should be updated.
our $dest = $ENV{HOME} . '/samba-rsync-ftp/dev/nightly';
our $nightly_symlink = "$dest/rsync-HEAD.tar.gz";
our($make_tar, $upload, $help_opt);
@@ -104,7 +104,7 @@ if ($upload) {
if (defined $ENV{RSYNC_PARTIAL_DIR}) {
$opt = " -f 'R $ENV{RSYNC_PARTIAL_DIR}'";
}
system "rsync$opt -aviHP --delete-after . samba.org:/home/ftp/pub/rsync/nightly";
system "rsync$opt -aviHP --delete-after . samba.org:/home/ftp/pub/rsync/dev/nightly";
}
exit;

View File

@@ -7,16 +7,25 @@ use strict;
# ~/samba-rsync-ftp dir will be ready to be rsynced to samba.org.
use Cwd;
use Term::ReadKey;
use Date::Format;
my $dest = $ENV{HOME} . '/samba-rsync-ftp';
my $passfile = $ENV{HOME} . '/.rsyncpass';
my $path = $ENV{PATH};
my $cl_today = time2str('* %a %b %d %Y', time);
my $ztoday = time2str('%d %b %Y', time);
my $now = time;
my $cl_today = time2str('* %a %b %d %Y', $now);
my $year = time2str('%Y', $now);
my $ztoday = time2str('%d %b %Y', $now);
(my $today = $ztoday) =~ s/^0//;
my $curdir = Cwd::cwd;
END {
unlink($passfile);
}
my @extra_files;
open(IN, '<', 'Makefile.in') or die "Couldn't open Makefile.in: $!\n";
while (<IN>) {
@@ -49,23 +58,23 @@ close IN;
die "The checkout is not clean:\n", $status unless $status =~ /\nnothing to commit \(working directory clean\)/;
die "The checkout is not on the master branch.\n" unless $status =~ /^# On branch master\n/;
my $lastversion;
my $confversion;
open(IN, '<', 'configure.in') or die $!;
while (<IN>) {
if (/^RSYNC_VERSION=(.*)/) {
$lastversion = $1;
$confversion = $1;
last;
}
}
close IN;
die "Unable to find RSYNC_VERSION in configure.in\n" unless defined $confversion;
open(IN, '<', 'OLDNEWS') or die $!;
$_ = <IN>;
close IN;
my($lastrelease) = /(\d+\.\d+\.\d+)/;
my($lastversion) = /(\d+\.\d+\.\d+)/;
$lastversion = $lastrelease if $lastversion =~ /dev$/;
my $version = $lastversion;
my $version = $confversion;
$version =~ s/dev/pre1/ || $version =~ s/pre(\d+)/ 'pre' . ($1 + 1) /e;
print "Please enter the version number of this release: [$version] ";
@@ -75,31 +84,46 @@ if ($_ eq '.') {
} elsif ($_ ne '') {
$version = $_;
}
$lastversion = $lastrelease unless $version =~ s/[-.]*pre[-.]*/pre/;
die "Invalid version: `$version'\n" unless $version =~ /^[\d.]+(pre\d+)?$/;
if (`git tag -l v$version` ne '') {
print "Tag v$version already exists.\n\nDelete tag or quit? [q/del] ";
$_ = <STDIN>;
exit 1 unless /^del/i;
system "git tag -d v$version";
}
if ($version =~ s/[-.]*pre[-.]*/pre/ && $confversion !~ /dev$/) {
$lastversion = $confversion;
}
print "Enter the previous version to produce a patch against: [$lastversion] ";
chomp($_ = <STDIN>);
$lastversion = $_ if $_ ne '';
$lastversion =~ s/[-.]*pre[-.]*/pre/;
my $release = 1;
my $pre = $version =~ /(pre\d+)/ ? $1 : '';
my $release = $pre ? '0.1' : '1';
print "Please enter the RPM release number of this release: [$release] ";
chomp($_ = <STDIN>);
$release = $_ if $_ ne '';
$release .= ".$pre" if $pre;
my $diffdir;
my $skipping;
my($srcdir,$srcdiffdir,$lastsrcdir,$skipping);
if ($lastversion =~ /pre/) {
if ($version !~ /pre/) {
if (!$pre) {
die "You should not diff a release version against a pre-release version.\n";
}
$diffdir = "$dest/old-previews";
$srcdir = $srcdiffdir = $lastsrcdir = 'src-previews';
$skipping = ' ** SKIPPING **';
} elsif ($version =~ /pre/) {
$diffdir = $dest;
} elsif ($pre) {
$srcdir = $srcdiffdir = 'src-previews';
$lastsrcdir = 'src';
$skipping = ' ** SKIPPING **';
} else {
$diffdir = "$dest/old-versions";
$srcdir = $lastsrcdir = 'src';
$srcdiffdir = 'src-diffs';
$skipping = '';
}
@@ -108,14 +132,16 @@ print "\n", $break, <<EOT;
\$lastversion is "$lastversion"
\$dest is "$dest"
\$curdir is "$curdir"
\$diffdir is "$diffdir"
\$srcdir is "$srcdir"
\$srcdiffdir is "$srcdiffdir"
\$lastsrcdir is "$lastsrcdir"
\$release is "$release"
About to:
- make sure that SUBPROTOCOL_VERSION is 0$skipping
- tweak the version in configure.in and the spec files
- tweak NEWS and OLDNEWS to update the release date$skipping
- tweak the date in the *.yo files and generate the man pages
- tweak the date in the *.yo files and generate the manpages
- generate configure.sh, config.h.in, and proto.h
- page through the differences
@@ -123,34 +149,54 @@ EOT
print "<Press Enter to continue> ";
$_ = <STDIN>;
my @tweak_files = ( glob('packaging/*.spec'), glob('packaging/*/*.spec'),
glob('*.yo'), qw( configure.in ) );
(my $finalversion = $version) =~ s/pre\d+//;
my %specvars = ( 'Version:' => $finalversion, 'Release:' => $release,
'%define fullversion' => "\%{version}$pre", 'Released' => "$version.",
'%define srcdir' => $srcdir );
my @tweak_files = ( glob('packaging/*.spec'), glob('packaging/*/*.spec'), glob('*.yo'),
qw( configure.in rsync.h NEWS OLDNEWS options.c ) );
if ($version !~ /pre/) {
push(@tweak_files, qw( rsync.h NEWS OLDNEWS ));
}
foreach my $fn (@tweak_files) {
open(IN, '<', $fn) or die $!;
undef $/; $_ = <IN>; $/ = "\n";
close IN;
if ($fn =~ /configure/) {
s/^RSYNC_VERSION=.*/RSYNC_VERSION=$version/m;
s/^RSYNC_VERSION=.*/RSYNC_VERSION=$version/m
or die "Unable to update RSYNC_VERSION in $fn\n";
} elsif ($fn =~ /\.spec/) {
s/^(Version:) .*/$1 $version/m;
s/^(Release:) .*/$1 $release/m;
s/^(Released) .*/$1 $version./m;
s/^\* \w\w\w \w\w\w \d\d \d\d\d\d (.*)/$cl_today $1/m;
while (my($str, $val) = each %specvars) {
s/^\Q$str\E .*/$str $val/m
or die "Unable to update $str in $fn\n";
}
s/^\* \w\w\w \w\w\w \d\d \d\d\d\d (.*)/$cl_today $1/m
or die "Unable to update ChangeLog header in $fn\n";
} elsif ($fn =~ /\.yo/) {
s/^(manpage\([^)]+\)\(\d+\)\()[^)]+(\).*)/$1$today$2/m;
s/^(This man ?page is current for version) \S+ (of rsync)/$1 $version $2/m;
} elsif ($fn eq 'NEWS') {
s/^(NEWS for rsync \Q$version\E) \(UNRELEASED\)\s*\n/$1 ($today)\n/mi
or die "Couldn't update NEWS file with release date!\n";
s/^(manpage\([^)]+\)\(\d+\)\()[^)]+(\).*)/$1$today$2/m
or die "Unable to update date in manpage() header in $fn\n";
s/^(This man ?page is current for version) \S+ (of rsync)/$1 $version $2/m
or die "Unable to update current version info in $fn\n";
} elsif ($fn eq 'rsync.h') {
s/(#define\s+SUBPROTOCOL_VERSION)\s+\d+/$1 0/;
s/(#define\s+SUBPROTOCOL_VERSION)\s+\d+/$1 0/
or die "Unable to find SUBPROTOCOL_VERSION define in $fn\n";
next if $pre;
} elsif ($fn eq 'NEWS') {
s/^(NEWS for rsync \Q$finalversion\E) \(UNRELEASED\)\s*\n/$1 ($today)\n/mi
or die "The first line of $fn is not in the right format. It must be:\n"
. "NEWS for rsync $finalversion (UNRELEASED)\n";
next if $pre;
} elsif ($fn eq 'OLDNEWS') {
s/^\t\S\S\s\S\S\S\s\d\d\d\d(\t\Q$version\E)/\t$ztoday$1/m
or die "Couldn't update OLDNEWS file with release date!\n";
s/^\t\S\S\s\S\S\S\s\d\d\d\d(\t\Q$finalversion\E)/\t$ztoday$1/m
or die "Unable to find \"?? ??? $year\t$finalversion\" line in $fn\n";
next if $pre;
} elsif ($fn eq 'options.c') {
if (s/(Copyright \(C\) 2002-)(\d+)( Wayne Davison)/$1$year$3/
&& $2 ne $year) {
die "Copyright comments need to be updated to $year in all files!\n";
}
# Adjust the year in the --version output.
s/(rprintf\(f, "Copyright \(C\) 1996-)(\d+)/$1$year/
or die "Unable to find Copyright string in --version output of $fn\n";
next if $2 eq $year;
} else {
die "Unrecognized file in \@tweak_files: $fn\n";
}
@@ -165,80 +211,85 @@ system "git diff --color | less -p '^diff .*'";
my $srctar_name = "rsync-$version.tar.gz";
my $pattar_name = "rsync-patches-$version.tar.gz";
my $diff_name = "rsync-$lastversion-$version.diffs.gz";
my $srctar_file = "$dest/$srctar_name";
my $pattar_file = "$dest/$pattar_name";
my $diff_file = "$dest/$diff_name";
my $lasttar_file = "$dest/rsync-$lastversion.tar.gz";
my $srctar_file = "$dest/$srcdir/$srctar_name";
my $pattar_file = "$dest/$srcdir/$pattar_name";
my $diff_file = "$dest/$srcdiffdir/$diff_name";
my $news_file = "$dest/$srcdir/rsync-$version-NEWS";
my $lasttar_file = "$dest/$lastsrcdir/rsync-$lastversion.tar.gz";
print $break, <<EOT;
About to:
- commit all changes
- tag this release as v$version
- move the old tar/diff files into the appropriate old-* dirs
- hard-link the moved tar/diff files on samba.org
- create release tar, "$srctar_name"
- create patches tar, "$pattar_name"
- commit all version changes
- merge the master branch into the patch/* branches
- update the files in the "patches" dir and OPTIONALLY
(if you type 'y') to launch a shell for each patch
EOT
print "<Press Enter OR 'y' to continue> ";
my $ans = <STDIN>;
system "git commit -a -m 'Preparing for release of $version'" and exit 1;
print "Updating files in \"patches\" dir ...\n";
system "support/patch-update";
if ($ans =~ /^y/i) {
print "\nVisiting all \"patch/*\" branches ...\n";
system "support/patch-update --shell";
}
print $break, <<EOT;
About to:
- create signed tag for this release: v$version
- create release diffs, "$diff_name"
- update patch branches and generate patch/* files
- update README, *NEWS, TODO, and ChangeLog
- update rsync*.html man pages
- create release tar, "$srctar_name"
- generate rsync-$version/patches/* files
- create patches tar, "$pattar_name"
- update top-level README, *NEWS, TODO, and ChangeLog
- update top-level rsync*.html manpages
- gpg-sign the release files
- update hard-linked top-level release files$skipping
EOT
print "<Press Enter to continue> ";
$_ = <STDIN>;
system "git commit -a -m 'Preparing for release of $version'" and exit 1;
print "\nSign the tag:";
system "git tag -s -m 'Version $version.' v$version" and exit 1;
my $passphrase;
while (1) {
ReadMode('noecho');
print "\nEnter your GPG pass-phrase: ";
chomp($passphrase = <STDIN>);
ReadMode(0);
print "\n";
# Extract some files from the old tar before we do the shuffle.
# Briefly create a temp file with the passphrase for git's tagging use.
my $oldmask = umask 077;
unlink($passfile);
open(OUT, '>', $passfile) or die $!;
print OUT $passphrase, "\n";
close OUT;
umask $oldmask;
$ENV{'GPG_PASSFILE'} = $passfile;
# We want to use our passphrase-providing "gpg" script, so modify the PATH.
$ENV{PATH} = "packaging/bin:$path";
$_ = `git tag -s -m 'Version $version.' v$version 2>&1`;
$ENV{PATH} = $path;
unlink($passfile);
print $_;
next if /bad passphrase/;
last unless /failed/;
exit 1;
}
# Extract the generated files from the old tar.
@_ = @extra_files;
map { s#^#rsync-$lastversion/# } @_;
system "tar xzf $lasttar_file @_";
rename("rsync-$lastversion", 'a');
# When creating a pre-release after a normal release, there's nothing to move.
if ($diffdir ne $dest) {
chdir($dest) or die $!;
print "Shuffling old files ...\n";
# We need to run this regardless of $lastversion's "pre"ness.
my @moved_files;
foreach my $fn (glob('rsync*pre*.tar.gz*'), glob('rsync*pre*-NEWS')) {
link($fn, "old-previews/$fn") or die $!;
push(@moved_files, $fn);
}
if ($version !~ /pre/) {
foreach my $fn (glob('rsync*.tar.gz*'), glob('rsync*-NEWS')) {
next if $fn =~ /^rsync.*pre/;
link($fn, "old-versions/$fn") or die $!;
push(@moved_files, $fn);
}
foreach my $fn (glob('rsync*pre*.diffs.gz*')) {
unlink($fn);
}
foreach my $fn (glob('rsync*.diffs.gz*')) {
link($fn, "old-patches/$fn") or die $!;
push(@moved_files, $fn);
}
}
# Optimize our future upload (in the absence of --detect-renamed) by
# using rsync to hard-link the above files on samba.org.
system "rsync -avHOC --include='rsync*.gz*' --include='old-*/' --exclude='*' . samba.org:/home/ftp/pub/rsync";
foreach (@moved_files) {
unlink($_);
}
chdir($curdir) or die $!;
}
print "Creating $diff_file ...\n";
system "./config.status Makefile; make gen; rsync -a @extra_files b/";
my $sed_script = 's:^((---|\+\+\+) [ab]/[^\t]+)\t.*:\1:';
@@ -251,26 +302,41 @@ system "git archive --format=tar --prefix=rsync-$version/ v$version | tar xf -";
system "support/git-set-file-times --prefix=rsync-$version/";
system "fakeroot tar czf $srctar_file rsync-$version; rm -rf rsync-$version";
print "Updating files in \"rsync-$version/patches\" dir ...\n";
mkdir("rsync-$version", 0755);
mkdir("rsync-$version/patches", 0755);
system "support/patch-update --skip-check --gen=rsync-$version/patches";
print "Creating $pattar_file ...\n";
system "fakeroot tar chzf $pattar_file rsync-$version/patches; rm -rf rsync-$version";
print "Updating the other files in $dest ...\n";
system "rsync -a README NEWS OLDNEWS TODO $dest";
unlink("$dest/rsync-$version-NEWS");
link("$dest/NEWS", "$dest/rsync-$version-NEWS");
unlink($news_file);
link("$dest/NEWS", $news_file);
system "git log --name-status | gzip -9 >$dest/ChangeLog.gz";
system "yodl2html -o $dest/rsync.html rsync.yo";
system "yodl2html -o $dest/rsyncd.conf.html rsyncd.conf.yo";
chdir($dest) or die $!;
my $cnt = 0;
foreach my $fn ($srctar_name, $pattar_name, $diff_name) {
print ++$cnt, ". Sign file \"$fn\":";
system "gpg -ba $fn";
foreach my $fn ($srctar_file, $pattar_file, $diff_file) {
unlink("$fn.asc");
open(GPG, '|-', "gpg --batch --passphrase-fd=0 -ba $fn") or die $!;
print GPG $passphrase, "\n";
close GPG;
}
if (!$pre) {
system "rm $dest/rsync-*{.tar.gz,.asc,-NEWS} $dest/src-preview/rsync-*diffs.gz";
foreach my $fn ($srctar_file, "$srctar_file.asc",
$pattar_file, "$pattar_file.asc",
$diff_file, "$diff_file.asc", $news_file) {
(my $top_fn = $fn) =~ s#/src(-\w+)?/#/#;
link($fn, $top_fn);
}
}
print $break, <<'EOT';
Local changes are done. When you're satisfied, push the git repository

View File

@@ -809,16 +809,20 @@ int poptGetNextOpt(poptContext con)
*oe++ = '\0';
/* XXX longArg is mapped back to persistent storage. */
longArg = origOptString + (oe - localOptString);
}
} else
oe = NULL;
opt = findOption(con->options, optString, '\0', &cb, &cbData,
singleDash);
if (!opt && !singleDash)
return POPT_ERROR_BADOPT;
if (!opt && oe)
oe[-1] = '='; /* restore overwritten '=' */
}
if (!opt) {
con->os->nextCharArg = origOptString + 1;
longArg = NULL;
} else {
if (con->os == con->optionStack &&
opt->argInfo & POPT_ARGFLAG_STRIP)
@@ -856,7 +860,7 @@ int poptGetNextOpt(poptContext con)
origOptString++;
if (*origOptString != '\0')
con->os->nextCharArg = origOptString;
con->os->nextCharArg = origOptString + (*origOptString == '=');
}
/*@=branchstate@*/

View File

@@ -121,7 +121,7 @@ getArgDescrip(const struct poptOption * opt,
if (opt->argDescrip) return D_(translation_domain, opt->argDescrip);
switch (opt->argInfo & POPT_ARG_MASK) {
case POPT_ARG_NONE: return POPT_("NONE");
/*case POPT_ARG_NONE: return POPT_("NONE");*/ /* impossible */
#ifdef DYING
case POPT_ARG_VAL: return POPT_("VAL");
#else
@@ -767,6 +767,9 @@ static int showShortOptions(const struct poptOption * opt, FILE * fp,
char * s = (str != NULL ? str : memset(alloca(300), 0, 300));
int len = 0;
if (s == NULL)
return 0;
/*@-boundswrite@*/
if (opt != NULL)
for (; (opt->longName || opt->shortName || opt->arg); opt++) {

View File

@@ -163,8 +163,10 @@ int poptConfigFileToString(FILE *fp, char ** argstrp, /*@unused@*/ UNUSED(int fl
p++;
linelen = strlen(p);
if (linelen >= maxlinelen-1)
if (linelen >= maxlinelen-1) {
free(argstr);
return POPT_ERROR_OVERFLOW; /* XXX line too long */
}
if (*p == '\0' || *p == '\n') continue; /* line is empty */
if (*p == '#') continue; /* comment line */

View File

@@ -55,7 +55,7 @@ extern char *tmpdir;
extern char *partial_dir;
extern char *basis_dir[];
extern struct file_list *cur_flist, *first_flist, *dir_flist;
extern struct filter_list_struct server_filter_list;
extern struct filter_list_struct daemon_filter_list;
static struct bitbag *delayed_bits = NULL;
static int phase = 0, redoing = 0;
@@ -489,8 +489,8 @@ int recv_files(int f_in, char *local_name)
cleanup_got_literal = 0;
if (server_filter_list.head
&& check_filter(&server_filter_list, fname, 0) < 0) {
if (daemon_filter_list.head
&& check_filter(&daemon_filter_list, FLOG, fname, 0) < 0) {
rprintf(FERROR, "attempt to hack rsync failed.\n");
exit_cleanup(RERR_PROTOCOL);
}
@@ -555,8 +555,8 @@ int recv_files(int f_in, char *local_name)
fnamecmp = fnamecmpbuf;
break;
}
if (!fnamecmp || (server_filter_list.head
&& check_filter(&server_filter_list, fname, 0) < 0)) {
if (!fnamecmp || (daemon_filter_list.head
&& check_filter(&daemon_filter_list, FLOG, fname, 0) < 0)) {
fnamecmp = fname;
fnamecmp_type = FNAMECMP_FNAME;
}

39
rsync.c
View File

@@ -41,7 +41,6 @@ extern int am_generator;
extern int am_starting_up;
extern int allow_8bit_chars;
extern int protocol_version;
extern int receiver_symlink_times;
extern int uid_ndx;
extern int gid_ndx;
extern int inc_recurse;
@@ -206,6 +205,42 @@ int iconvbufs(iconv_t ic, xbuf *in, xbuf *out, int flags)
}
#endif
void send_protected_args(int fd, char *args[])
{
int i;
#ifdef ICONV_OPTION
int convert = ic_send != (iconv_t)-1;
xbuf outbuf, inbuf;
if (convert)
alloc_xbuf(&outbuf, 1024);
#endif
for (i = 0; args[i]; i++) {} /* find first NULL */
args[i] = "rsync"; /* set a new arg0 */
if (verbose > 1)
print_child_argv("protected args:", args + i + 1);
do {
#ifdef ICONV_OPTION
if (convert) {
INIT_XBUF_STRLEN(inbuf, args[i]);
iconvbufs(ic_send, &inbuf, &outbuf,
ICB_EXPAND_OUT | ICB_INCLUDE_BAD | ICB_INCLUDE_INCOMPLETE);
outbuf.buf[outbuf.len] = '\0';
write_buf(fd, outbuf.buf, outbuf.len + 1);
outbuf.len = 0;
} else
#endif
write_buf(fd, args[i], strlen(args[i]) + 1);
} while (args[++i]);
write_byte(fd, 0);
#ifdef ICONV_OPTION
if (convert)
free(outbuf.buf);
#endif
}
int read_ndx_and_attrs(int f_in, int *iflag_ptr, uchar *type_ptr,
char *buf, int *len_ptr)
{
@@ -400,7 +435,7 @@ int set_file_attrs(const char *fname, struct file_struct *file, stat_x *sxp,
}
if (ret == 0) /* ret == 1 if symlink could not be set */
updated = 1;
else if (receiver_symlink_times)
else
file->flags |= FLAG_TIME_FAILED;
}

31
rsync.h
View File

@@ -67,7 +67,8 @@
#define FLAG_FILE_SENT (1<<1) /* sender/receiver/generator */
#define FLAG_DIR_CREATED (1<<1) /* generator */
#define FLAG_CONTENT_DIR (1<<2) /* sender/receiver/generator */
#define FLAG_MOUNT_DIR (1<<3) /* sender/generator */
#define FLAG_MOUNT_DIR (1<<3) /* sender/generator (dirs only) */
#define FLAG_SKIP_HLINK (1<<3) /* receiver/generator (w/FLAG_HLINKED) */
#define FLAG_DUPLICATE (1<<4) /* sender */
#define FLAG_MISSING_DIR (1<<4) /* generator */
#define FLAG_HLINKED (1<<5) /* receiver/generator (checked on all types) */
@@ -82,6 +83,7 @@
/* These flags are passed to functions but not stored. */
#define FLAG_DIVERT_DIRS (1<<16)/* sender */
#define FLAG_DOTDIR_NAME (1<<17)/* sender */
#define BITS_SET(val,bits) (((val) & (bits)) == (bits))
#define BITS_SETnUNSET(val,onbits,offbits) (((val) & ((onbits)|(offbits))) == (onbits))
@@ -144,8 +146,9 @@
#define XFLG_FATAL_ERRORS (1<<0)
#define XFLG_OLD_PREFIXES (1<<1)
#define XFLG_ANCHORED2ABS (1<<2)
#define XFLG_ABS_IF_SLASH (1<<3)
#define XFLG_ANCHORED2ABS (1<<2) /* leading slash indicates absolute */
#define XFLG_ABS_IF_SLASH (1<<3) /* leading or interior slash is absolute */
#define XFLG_DIR2WILD3 (1<<4) /* dir/ match gets trailing *** added */
#define ATTRS_REPORT (1<<0)
#define ATTRS_SKIP_MTIME (1<<1)
@@ -166,8 +169,9 @@
/* For use by the itemize_changes code */
#define ITEM_REPORT_ATIME (1<<0)
#define ITEM_REPORT_CHECKSUM (1<<1)
#define ITEM_REPORT_SIZE (1<<2)
#define ITEM_REPORT_CHANGE (1<<1)
#define ITEM_REPORT_SIZE (1<<2) /* regular files only */
#define ITEM_REPORT_TIMEFAIL (1<<2) /* symlinks only */
#define ITEM_REPORT_TIME (1<<3)
#define ITEM_REPORT_PERMS (1<<4)
#define ITEM_REPORT_OWNER (1<<5)
@@ -187,11 +191,17 @@
#define SIGNIFICANT_ITEM_FLAGS (~(\
ITEM_BASIS_TYPE_FOLLOWS | ITEM_XNAME_FOLLOWS | ITEM_LOCAL_CHANGE))
#define CFN_KEEP_LEADING_DOT_DIR (1<<0)
#define CFN_KEEP_DOT_DIRS (1<<0)
#define CFN_KEEP_TRAILING_SLASH (1<<1)
#define CFN_DROP_TRAILING_DOT_DIR (1<<2)
#define CFN_COLLAPSE_DOT_DOT_DIRS (1<<3)
#define SP_DEFAULT 0
#define SP_KEEP_DOT_DIRS (1<<0)
#define CD_NORMAL 0
#define CD_SKIP_CHDIR 1
/* Log-message categories. FLOG only goes to the log file, not the client;
* FCLIENT is the opposite. */
enum logcode {
@@ -331,10 +341,6 @@ enum msgcode {
#endif
#endif
#ifdef HAVE_GLOB_H
#include <glob.h>
#endif
/* these are needed for the uid/gid mapping code */
#include <pwd.h>
#include <grp.h>
@@ -1105,6 +1111,11 @@ size_t strlcat(char *d, const char *s, size_t bufsize);
#define MY_GID() getgid()
#endif
#ifdef FORCE_FD_ZERO_MEMSET
#undef FD_ZERO
#define FD_ZERO(fdsetp) memset(fdsetp, 0, sizeof (fd_set))
#endif
extern int verbose;
#ifndef HAVE_INET_NTOP

View File

@@ -1,5 +1,5 @@
mailto(rsync-bugs@samba.org)
manpage(rsync)(1)(1 Mar 2008)()()
manpage(rsync)(1)(3 Apr 2008)()()
manpagename(rsync)(a fast, versatile, remote (and local) file-copying tool)
manpagesynopsis()
@@ -723,9 +723,12 @@ receiving user.
dit(bf(--append)) This causes rsync to update a file by appending data onto
the end of the file, which presumes that the data that already exists on
the receiving side is identical with the start of the file on the sending
side. Any files that are the same size or shorter on the receiving size
are skipped. Files that do not yet exist on the receiving side are also
sent, since they are considered to have 0 length. Implies bf(--inplace),
side. If a file needs to be transferred and its size on the receiver is
the same or longer than the size on the sender, the file is skipped. This
does not interfere with the updating of a file's non-content attributes
(e.g. permissions, ownership, etc.) when the file does not need to be
transferred, nor does it affect the updating of any non-regular files.
Implies bf(--inplace),
but does not conflict with bf(--sparse) (since it is always extending a
file's length).
@@ -748,11 +751,15 @@ bf(--recursive) option, rsync will skip all directories it encounters (and
output a message to that effect for each one). If you specify both
bf(--dirs) and bf(--recursive), bf(--recursive) takes precedence.
This option is implied by the bf(--list-only) option (including an implied
The bf(--dirs) option is implied by the bf(--files-from) option
or the bf(--list-only) option (including an implied
bf(--list-only) usage) if bf(--recursive) wasn't specified (so that
directories are seen in the listing). Specify bf(--no-dirs) (or bf(--no-d))
if you want to override this. This option is also implied by
bf(--files-from).
if you want to turn this off.
There is also a backward-compatibility helper option, bf(--old-dirs) (or
bf(--old-d)) that tells rsync to use a hack of "-r --exclude='/*/*'" to get
an older rsync to list a single directory without recursing.
dit(bf(-l, --links)) When symlinks are encountered, recreate the
symlink on the destination.
@@ -1674,15 +1681,20 @@ a "?" (this can happen when talking to an older rsync).
The attribute that is associated with each letter is as follows:
quote(itemization(
it() A bf(c) means the checksum of the file is different and will be
updated by the file transfer (requires bf(--checksum)).
it() A bf(s) means the size of the file is different and will be updated
it() A bf(c) means either that a regular file has a different checksum
(requires bf(--checksum)) or that a symlink, device, or special file has
a changed value.
Note that if you are sending files to an rsync prior to 3.0.1, this
change flag will be present only for checksum-differing regular files.
it() A bf(s) means the size of a regular file is different and will be updated
by the file transfer.
it() A bf(t) means the modification time is different and is being updated
to the sender's value (requires bf(--times)). An alternate value of bf(T)
means that the modification time will be set to the transfer time, which happens
when a file/symlink/device is updated without bf(--times) and when a
symlink is changed and the receiver can't set its time.
(Note: when using an rsync 3.0.0 client, you might see the bf(s) flag combined
with bf(t) instead of the proper bf(T) flag for this time-setting failure.)
it() A bf(p) means the permissions are different and are being updated to
the sender's value (requires bf(--perms)).
it() An bf(o) means the owner is different and is being updated to the
@@ -2864,7 +2876,7 @@ url(http://rsync.samba.org/)(http://rsync.samba.org/)
manpagesection(VERSION)
This man page is current for version 3.0.0 of rsync.
This man page is current for version 3.0.1 of rsync.
manpagesection(INTERNAL OPTIONS)

View File

@@ -1,5 +1,5 @@
mailto(rsync-bugs@samba.org)
manpage(rsyncd.conf)(5)(1 Mar 2008)()()
manpage(rsyncd.conf)(5)(3 Apr 2008)()()
manpagename(rsyncd.conf)(configuration file for rsync in daemon mode)
manpagesynopsis()
@@ -314,56 +314,54 @@ daemon side to behave as if the bf(--fake-user) command-line option had
been specified. This allows the full attributes of a file to be stored
without having to have the daemon actually running as root.
dit(bf(filter)) The "filter" option allows you to specify a space-separated
list of filter rules that the daemon will not allow to be read or written.
This is only superficially equivalent to the client specifying these
patterns with the bf(--filter) option. Only one "filter" option may be
specified, but it may contain as many rules as you like, including
merge-file rules. Note that per-directory merge-file rules do not provide
as much protection as global rules, but they can be used to make bf(--delete)
work better when a client downloads the daemon's files (if the per-dir
merge files are included in the transfer).
dit(bf(filter)) The daemon has its own filter chain that determines what files
it will let the client access. This chain is not sent to the client and is
independent of any filters the client may have specified. Files excluded by
the daemon filter chain (bf(daemon-excluded) files) are treated as non-existent
if the client tries to pull them, are skipped with an error message if the
client tries to push them (triggering exit code 23), and are never deleted from
the module. You can use daemon filters to prevent clients from downloading or
tampering with private administrative files, such as files you may add to
support uid/gid name translations.
dit(bf(exclude)) The "exclude" option allows you to specify a
space-separated list of patterns that the daemon will not allow to be read
or written. This is only superficially equivalent to the client
specifying these patterns with the bf(--exclude) option. Only one "exclude"
option may be specified, but you can use "-" and "+" before patterns to
specify exclude/include.
The daemon filter chain is built from the "filter", "include from", "include",
"exclude from", and "exclude" parameters, in that order of priority. Anchored
patterns are anchored at the root of the module. To prevent access to an
entire subtree, for example, "/secret", you em(must) exclude everything in the
subtree; the easiest way to do this is with a triple-star pattern like
"/secret/***".
Because this exclude list is not passed to the client it only applies on
the daemon: that is, it excludes files received by a client when receiving
from a daemon and files deleted on a daemon when sending to a daemon, but
it doesn't exclude files from being deleted on a client when receiving
from a daemon.
The "filter" parameter takes a space-separated list of daemon filter rules,
though it is smart enough to know not to split a token at an internal space in
a rule (e.g. "- /foo - /bar" is parsed as two rules). You may specify one or
more merge-file rules using the normal syntax. Only one "filter" parameter can
apply to a given module in the config file, so put all the rules you want in a
single parameter. Note that per-directory merge-file rules do not provide as
much protection as global rules, but they can be used to make bf(--delete) work
better during a client download operation if the per-dir merge files are
included in the transfer and the client requests that they be used.
When you want to exclude a directory and all its contents, it is safest to
use a rule that does both, such as "/some/dir/***" (the three stars tells
rsync to exclude the directory itself and everything inside it). This is
better than just excluding the directory alone with "/some/dir/", as it
helps to guard against attempts to trick rsync into accessing files deeper
in the hierarchy.
dit(bf(exclude)) The "exclude" parameter takes a space-separated list of daemon
exclude patterns. As with the client bf(--exclude) option, patterns can be
qualified with "- " or "+ " to explicitly indicate exclude/include. Only one
"exclude" parameter can apply to a given module. See the "filter" parameter
for a description of how excluded files affect the daemon.
dit(bf(exclude from)) The "exclude from" option specifies a filename
on the daemon that contains exclude patterns, one per line.
This is only superficially equivalent
to the client specifying the bf(--exclude-from) option with an equivalent file.
See the "exclude" option above.
dit(bf(include)) Use an "include" to override the effects of the "exclude"
parameter. Only one "include" parameter can apply to a given module. See the
"filter" parameter for a description of how excluded files affect the daemon.
dit(bf(include)) The "include" option allows you to specify a
space-separated list of patterns which rsync should not exclude. This is
only superficially equivalent to the client specifying these patterns with
the bf(--include) option because it applies only on the daemon. This is
useful as it allows you to build up quite complex exclude/include rules.
Only one "include" option may be specified, but you can use "+" and "-"
before patterns to switch include/exclude. See the "exclude" option
above.
dit(bf(exclude from)) The "exclude from" parameter specifies the name of a file
on the daemon that contains daemon exclude patterns, one per line. Only one
"exclude from" parameter can apply to a given module; if you have multiple
exclude-from files, you can specify them as a merge file in the "filter"
parameter. See the "filter" parameter for a description of how excluded files
affect the daemon.
dit(bf(include from)) The "include from" option specifies a filename
on the daemon that contains include patterns, one per line. This is
only superficially equivalent to the client specifying the
bf(--include-from) option with a equivalent file.
See the "exclude" option above.
dit(bf(include from)) Analogue of "exclude from" for a file of daemon include
patterns. Only one "include from" parameter can apply to a given module. See
the "filter" parameter for a description of how excluded files affect the
daemon.
dit(bf(incoming chmod)) This option allows you to specify a set of
comma-separated chmod strings that will affect the permissions of all
@@ -456,7 +454,7 @@ tt( fe80::%link1/ffff:ffff:ffff:ffff::)nl()
)
You can also combine "hosts allow" with a separate "hosts deny"
option. If both options are specified then the "hosts allow" option s
option. If both options are specified then the "hosts allow" option is
checked first and a match results in the client being able to
connect. The "hosts deny" option is then checked and a match means
that the host is rejected. If the host does not match either the
@@ -702,7 +700,7 @@ url(http://rsync.samba.org/)(http://rsync.samba.org/)
manpagesection(VERSION)
This man page is current for version 3.0.0 of rsync.
This man page is current for version 3.0.1 of rsync.
manpagesection(CREDITS)

View File

@@ -135,7 +135,7 @@ void successful_send(int ndx)
}
file = flist->files[ndx - flist->ndx_start];
if (!push_pathname(F_PATHNAME(file), -1))
if (!change_pathname(file, NULL, 0))
return;
f_name(file, fname);
@@ -221,7 +221,7 @@ void send_files(int f_in, int f_out)
} else {
path = slash = "";
}
if (!push_pathname(F_PATHNAME(file), -1))
if (!change_pathname(file, NULL, 0))
continue;
f_name(file, fname);

View File

@@ -4,13 +4,19 @@
# is included in the rrsync script.
use strict;
our(%short_no_arg, %short_with_num, %long_opt);
our %short_no_arg;
our %short_with_num;
our %long_opt = (
'no-i-r' => 0,
'fake-super' => 0,
'log-file' => 3,
);
our $last_long_opt;
open(IN, '../options.c') or die "Unable to open ../options.c: $!\n";
while (<IN>) {
if (/\Qargstr[x++]\E = '(.)'/) {
if (/\Qargstr[x++]\E = '([^.ie])'/) {
$short_no_arg{$1} = 1;
undef $last_long_opt;
} elsif (/\Qasprintf(\E[^,]+, "-([a-zA-Z0-9])\%l?[ud]"/) {

View File

@@ -14,6 +14,7 @@ my $tmp_dir = "patches.$$";
&Getopt::Long::Configure('bundling');
&usage if !&GetOptions(
'skip-check' => \( my $skip_branch_check ),
'shell|s' => \( my $launch_shell ),
'gen:s' => \( my $incl_generated_files ),
'help|h' => \( my $help_opt ),
);
@@ -27,13 +28,10 @@ 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';
open(IN, '-|', 'git status') or die $!;
my $status = join('', <IN>);
close IN;
unless ($skip_branch_check) {
die "The checkout is not clean:\n", $status unless $status =~ /\nnothing to commit \(working directory clean\)/;
my($status, $is_clean, $starting_branch) = &check_git_status;
if (!$skip_branch_check && !$is_clean) {
die "The checkout is not clean:\n", $status;
}
my($starting_branch) = $status =~ /^# On branch (.+)\n/;
my @extra_files;
open(IN, '<', 'Makefile.in') or die "Couldn't open Makefile.in: $!\n";
@@ -55,19 +53,21 @@ if ($incl_generated_files) {
}
my $last_touch = time;
my(@patches, %local_patch);
my(%patches, %local_patch);
# Start by finding all patches so that we can load all possible parents.
open(PIPE, '-|', 'git', 'branch', '-a') or die $!;
while (<PIPE>) {
if (m# origin/patch/(.*)#) {
push(@patches, $1);
$patches{$1} = 1;
} elsif (m# patch/(.*)#) {
$local_patch{$1} = 1;
$patches{$1} = $local_patch{$1} = 1;
}
}
close PIPE;
my @patches = sort keys %patches;
my(%parent, %description);
foreach my $patch (@patches) {
my $branch = ($local_patch{$patch} ? '' : 'origin/') . "patch/$patch";
@@ -99,7 +99,7 @@ if (@ARGV) {
my %completed;
foreach my $patch (@patches) {
next if $completed{$patch}++;
update_patch($patch);
last unless update_patch($patch);
}
if ($incl_generated_files) {
@@ -130,22 +130,33 @@ sub update_patch
sleep 1 if $incl_generated_files && $last_touch == time;
if ($local_patch{$patch}) {
system "git checkout patch/$patch" and exit 1;
system "git checkout patch/$patch" and return 0;
} else {
system "git checkout --track -b patch/$patch origin/patch/$patch" and exit 1;
system "git checkout --track -b patch/$patch origin/patch/$patch" and return 0;
}
my $ok = system("git merge $parent") == 0;
if (!$ok || $launch_shell) {
print qq|"git merge $parent" incomplete -- please fix.\n| if !$ok;
$ENV{PS1} = "[$parent] patch/$patch: ";
while (1) {
if (system($ENV{SHELL}) != 0) {
print "Abort? [n/y] ";
$_ = <STDIN>;
next unless /^y/i;
return 0;
}
($status, $is_clean) = &check_git_status;
last if $is_clean;
print $status;
}
}
open(OUT, '>', "$patches_dir/$patch.diff") or die $!;
print OUT $description{$patch}, "\n";
if (system("git merge $parent") != 0) {
print qq|"git merge $parent" incomplete -- please fix.\n|;
$ENV{PS1} = "[$parent] patch/$patch: ";
system $ENV{SHELL} and exit 1;
}
if ($incl_generated_files) {
system "./config.status Makefile && make gen && rsync -a @extra_files $tmp_dir/$patch/" and exit 1;
system "./config.status Makefile && make gen && rsync -a @extra_files $tmp_dir/$patch/";
}
$last_touch = time;
@@ -175,10 +186,22 @@ sub update_patch
}
close OUT;
1;
}
exit;
sub check_git_status
{
open(IN, '-|', 'git status') or die $!;
my $status = join('', <IN>);
close IN;
my $is_clean = $status =~ /\nnothing to commit \(working directory clean\)/;
my($starting_branch) = $status =~ /^# On branch (.+)\n/;
($status, $is_clean, $starting_branch);
}
sub usage
{
die <<EOT;

View File

@@ -39,6 +39,7 @@ die "$0: Restricted directory does not exist!\n" if $subdir ne '/' && !-d $subdi
my $command = $ENV{SSH_ORIGINAL_COMMAND};
die "$0: Not invoked via sshd\n$Usage" unless defined $command;
die "$0: SSH_ORIGINAL_COMMAND='$command' is not rsync\n" unless $command =~ s/^rsync\s+//;
die "$0: --server option is not first\n" unless $command =~ /^--server\s/;
our $am_sender = $command =~ /^--server\s+--sender\s/; # Restrictive on purpose!
die "$0 -ro: sending to read-only server not allowed\n" if $ro && !$am_sender;
@@ -65,7 +66,7 @@ our %long_opt = (
'compress-level' => 1,
'copy-dest' => 2,
'copy-unsafe-links' => 0,
'daemon' => 0,
'daemon' => -1,
'delay-updates' => 0,
'delete' => 0,
'delete-after' => 0,
@@ -74,6 +75,7 @@ our %long_opt = (
'delete-during' => 0,
'delete-excluded' => 0,
'existing' => 0,
'fake-super' => 0,
'files-from' => 3,
'force' => 0,
'from0' => 0,
@@ -84,6 +86,7 @@ our %long_opt = (
'inplace' => 0,
'link-dest' => 2,
'list-only' => 0,
'log-file' => 3,
'log-format' => 1,
'max-delete' => 1,
'max-size' => 1,
@@ -110,6 +113,7 @@ our %long_opt = (
'super' => 0,
'temp-dir' => 2,
'timeout' => 1,
'use-qsort' => 0,
);
### END of options data produced by the cull_options script. ###
@@ -139,7 +143,7 @@ while ($command =~ /((?:[^\s\\]+|\\.[^\s\\]*)+)/g) {
if ($_ eq '.') {
$in_options = 0;
} else {
next if /^-$short_no_arg+(e\d+\.\d+)?$/o || /^-$short_with_num\d+$/o;
next if /^-$short_no_arg+(e\d*\.\w*)?$/o || /^-$short_with_num\d+$/o;
my($opt,$arg) = /^--([^=]+)(?:=(.*))?$/;
my $disabled;

View File

@@ -167,9 +167,9 @@ int do_chmod(const char *path, mode_t mode)
code = 1;
#endif
} else
code = chmod(path, mode & CHMOD_BITS);
code = chmod(path, mode & CHMOD_BITS); /* DISCOURAGED FUNCTION */
if (code != 0 && (preserve_perms || preserve_executability))
return code;
return code;
return 0;
}
#endif
@@ -282,12 +282,3 @@ OFF_T do_lseek(int fd, OFF_T offset, int whence)
return lseek(fd, offset, whence);
#endif
}
char *d_name(struct dirent *di)
{
#ifdef HAVE_BROKEN_READDIR
return (di->d_name - 2);
#else
return di->d_name;
#endif
}

View File

@@ -29,7 +29,7 @@ int module_dirlen = 0;
mode_t orig_umask = 002;
char *partial_dir;
char *module_dir;
struct filter_list_struct server_filter_list;
struct filter_list_struct daemon_filter_list;
void rprintf(UNUSED(enum logcode code), const char *format, ...)
{
@@ -56,8 +56,8 @@ struct filter_list_struct server_filter_list;
exit(code);
}
int check_filter(UNUSED(struct filter_list_struct *listp), UNUSED(char *name),
UNUSED(int name_is_dir))
int check_filter(UNUSED(struct filter_list_struct *listp), UNUSED(enum logcode code),
UNUSED(const char *name), UNUSED(int name_is_dir))
{
/* This function doesn't really get called in this test context, so
* just return 0. */

View File

@@ -24,8 +24,29 @@
. "$suitedir/rsync.fns"
SSH="$scratchdir/pretend-ssh"
cat >"$SSH" <<'EOT'
while : ; do
case "$1" in
-*) shift ;;
localhost) shift; break ;;
*) exit 1 ;;
esac
done
eval "${@}"
EOT
chmod +x "$SSH"
build_rsyncd_conf
cd "$scratchdir"
ln -s test-rsyncd.conf rsyncd.conf
$RSYNC -ve $SSH --rsync-path="$RSYNC" localhost::
RSYNC_CONNECT_PROG="$RSYNC --config=$conf --daemon"
export RSYNC_CONNECT_PROG

View File

@@ -97,7 +97,7 @@ sleep 1
$RSYNC -Di "$fromdir/block3" "$todir/block" \
| tee "$outfile"
cat <<EOT >"$chkfile"
cD..T.$dots block3
cDc.T.$dots block3
EOT
diff $diffopt "$chkfile" "$outfile" || test_fail "test 3 failed"
@@ -106,8 +106,8 @@ $RSYNC -aiHvv "$fromdir/" "$todir/" \
filter_outfile
cat <<EOT >"$chkfile"
.d..t.$dots ./
cD..t.$dots block
cD$allspace block2
cDc.t.$dots block
cDc...$dots block2
cD$all_plus block3
hD$all_plus block2.5 => block3
cD$all_plus char

View File

@@ -38,9 +38,20 @@ echo "extra extra" >>"$todir/name1"
checkit "$RSYNC -aHivv --no-whole-file '$fromdir/' '$todir/'" "$fromdir" "$todir"
# Add a new link in a new subdirectory to test that we don't try to link
# the files before the directory gets created.
mkdir "$fromdir/subdir"
ln "$name1" "$fromdir/subdir/new-file"
# the files before the directory gets created. We also create a bunch of
# extra files to ensure that an incremental-recursion transfer works across
# distant files.
makepath "$fromdir/subdir/down/deep"
files=''
for x in 0 1 2 3 4 5 6 7 8 9 a b c d e f g h i j k l m n o p q r s t u v w x y z; do
for y in 0 1 2 3 4 5 6 7 8 9 a b c d e f g h i j k l m n o p q r s t u v w x y z; do
files="$files $x$y"
done
done
(cd "$fromdir/subdir"; touch $files)
ln "$name1" "$fromdir/subdir/down/deep/new-file"
rm "$todir/text"
checkit "$RSYNC -aHivv '$fromdir/' '$todir/'" "$fromdir" "$todir"

View File

@@ -25,16 +25,15 @@ umask 0
ln -s ../bar/baz/rsync "$fromdir/foo/sym"
umask 022
ln "$fromdir/foo/config1" "$fromdir/foo/extra"
rm -f "$to2dir"
# Check if the OS can hard-link symlinks or not.
# (Note: the link we check MUST NOT point to a valid file!)
ln -s no-such-dir "$to2dir"
if ln "$to2dir" "$to2dir.test" 2>/dev/null; then
# Check if rsync is set to hard-link symlinks.
confile=`echo "$scratchdir" | sed 's;/testtmp/itemize$;/config.h;'`
if egrep '^#define CAN_HARDLINK_SYMLINK 1' "$confile" >/dev/null; then
L=hL
else
L=cL
fi
rm -f "$to2dir" "$to2dir.test"
# Check if rsync can preserve time on symlinks
case "$RSYNC" in
@@ -97,7 +96,7 @@ cat <<EOT >"$chkfile"
.d..t.$dots foo/
.f..t.$dots foo/config1
>fcstp$dots foo/config2
cL.$T.$dots foo/sym -> ../bar/baz/rsync
cLc$T.$dots foo/sym -> ../bar/baz/rsync
EOT
diff $diffopt "$chkfile" "$outfile" || test_fail "test 3 failed"
@@ -158,8 +157,8 @@ $RSYNC -ivvplrtH --copy-dest=../to "$fromdir/" "$to2dir/" \
| tee "$outfile"
filter_outfile
case `tail -1 "$outfile"` in
cL..t*)
sym_dots="..t.$dots"
cLc.t*)
sym_dots="c.t.$dots"
L_sym_dots="cL$sym_dots"
is_uptodate='-> ../bar/baz/rsync'
echo "cL$sym_dots foo/sym $is_uptodate" >"$chkfile.extra"

View File

@@ -51,7 +51,7 @@ $RSYNC -av --existing -f 'exclude,! */' from2/ from3/
$RSYNC -av --existing -f 'exclude,! */' from1/ chk/
$RSYNC -av --existing -f 'exclude,! */' from3/ chk/
checkit "$RSYNC -avv deep/arg-test shallow from1/ from2/ from3/ to/" chk to
checkit "$RSYNC -avv deep/arg-test shallow from1/ from2/ from3/ to/" "$chkdir" "$todir"
# The script would have aborted on error, so getting here means we've won.
exit 0

27
testsuite/missing.test Normal file
View File

@@ -0,0 +1,27 @@
#! /bin/sh
# This program is distributable under the terms of the GNU GPL (see
# COPYING).
# Test three bugs fixed by my redoing of the missing_below logic.
. $srcdir/testsuite/rsync.fns
makepath "$fromdir/subdir" "$todir"
echo data >"$fromdir/subdir/file"
echo data >"$todir/other"
# Test 1: Too much "not creating new..." output on a dry run
$RSYNC -n -r --ignore-non-existing -vv "$fromdir/" "$todir/" | tee "$scratchdir/out"
if grep 'not creating new.*subdir/file' "$scratchdir/out" >/dev/null; then
test_fail 'test 1 failed'
fi
# Test 2: Attempt to make a fuzzy dirlist for a dir not created on a dry run
$RSYNC -n -r -R --no-implied-dirs -y "$fromdir/./subdir/file" "$todir/" \
|| test_fail 'test 2 failed'
# Test 3: --delete-after pass skipped when last dir is dry-missing
$RSYNC -n -r --delete-after -i "$fromdir/" "$todir/" | tee "$scratchdir/out"
grep '^\*deleting * other' "$scratchdir/out" >/dev/null \
|| test_fail 'test 3 failed'

View File

@@ -20,6 +20,7 @@ case "`xattr 2>&1`" in
xls() {
xattr -l "${@}"
}
RUSR='rsync.nonuser'
;;
*)
xset() {
@@ -31,6 +32,7 @@ case "`xattr 2>&1`" in
xls() {
getfattr -d "${@}"
}
RUSR='user.rsync'
;;
esac
@@ -65,25 +67,25 @@ xset user.long 'a long attribute for our new file that tests to ensure that this
xset user.foo 'new foo' foo/file3 foo/bar/file5
xset user.bar 'new bar' foo/file3 foo/bar/file5
xset user.long 'this is also a long attribute that will be truncated in the initial data send' foo/file3 foo/bar/file5
xset user.equal 'this long attribute should remain the same and not need to be transferred' foo/file3 foo/bar/file5
xset $RUSR.equal 'this long attribute should remain the same and not need to be transferred' foo/file3 foo/bar/file5
xset user.short 'old short' "$chkdir/file1"
xset user.extra 'remove me' "$chkdir/file1"
xset user.foo 'old foo' "$chkdir/foo/file3"
xset user.equal 'this long attribute should remain the same and not need to be transferred' "$chkdir/foo/file3"
xset $RUSR.equal 'this long attribute should remain the same and not need to be transferred' "$chkdir/foo/file3"
xls $files >"$scratchdir/xattrs.txt"
# OK, let's try a simple xattr copy.
checkit "$RSYNC -avX . '$chkdir/'" "$fromdir" "$chkdir"
checkit "$RSYNC -avX --super . '$chkdir/'" "$fromdir" "$chkdir"
cd "$chkdir"
xls $files | diff $diffopt "$scratchdir/xattrs.txt" -
cd "$fromdir"
checkit "$RSYNC -aiX --copy-dest=../chk . ../to" "$fromdir" "$todir"
checkit "$RSYNC -aiX --super --copy-dest=../chk . ../to" "$fromdir" "$todir"
cd "$todir"
xls $files | diff $diffopt "$scratchdir/xattrs.txt" -
@@ -95,10 +97,17 @@ xls $files >"$scratchdir/xattrs.txt"
rm -rf "$todir"
checkit "$RSYNC -aiX --link-dest=../chk . ../to" "$chkdir" "$todir"
checkit "$RSYNC -aiX --fake-super --link-dest=../chk . ../to" "$chkdir" "$todir"
cd "$todir"
xls $files | diff $diffopt "$scratchdir/xattrs.txt" -
sed -n -e '/\.\/file1$/d' -e '/^[^ ][^ ]* *[^ ][^ ]* *[^ ][^ ]* *1 /p' "$scratchdir/ls-to" >"$scratchdir/ls-diff"
if [ -s "$scratchdir/ls-diff" ]; then
echo "Missing hard links on:"
cat "$scratchdir/ls-diff"
exit 1
fi
# The script would have aborted on error, so getting here means we've won.
exit 0

2
tls.c
View File

@@ -35,7 +35,7 @@
* change. */
#include "rsync.h"
#include "popt.h"
#include <popt.h>
#include "lib/sysxattrs.h"
#define PROGRAM "tls"

322
util.c
View File

@@ -33,7 +33,7 @@ extern char *module_dir;
extern unsigned int module_dirlen;
extern mode_t orig_umask;
extern char *partial_dir;
extern struct filter_list_struct server_filter_list;
extern struct filter_list_struct daemon_filter_list;
int sanitize_paths = 0;
@@ -503,82 +503,172 @@ int lock_range(int fd, int offset, int len)
return fcntl(fd,F_SETLK,&lock) == 0;
}
static int filter_server_path(char *arg)
{
char *s;
#define ENSURE_MEMSPACE(buf, type, sz, req) \
if ((req) > sz && !(buf = realloc_array(buf, type, sz = MAX(sz * 2, req)))) \
out_of_memory("glob_expand")
if (server_filter_list.head) {
for (s = arg; (s = strchr(s, '/')) != NULL; ) {
*s = '\0';
if (check_filter(&server_filter_list, arg, 1) < 0) {
/* We must leave arg truncated! */
return 1;
}
*s++ = '/';
static inline void call_glob_match(const char *name, int len, int from_glob,
char *arg, int abpos, int fbpos);
static struct glob_data {
char *arg_buf, *filt_buf, **argv;
int absize, fbsize, maxargs, argc;
} glob;
static void glob_match(char *arg, int abpos, int fbpos)
{
int len;
char *slash;
while (*arg == '.' && arg[1] == '/') {
if (fbpos < 0) {
ENSURE_MEMSPACE(glob.filt_buf, char, glob.fbsize, glob.absize);
memcpy(glob.filt_buf, glob.arg_buf, abpos + 1);
fbpos = abpos;
}
ENSURE_MEMSPACE(glob.arg_buf, char, glob.absize, abpos + 3);
glob.arg_buf[abpos++] = *arg++;
glob.arg_buf[abpos++] = *arg++;
glob.arg_buf[abpos] = '\0';
}
return 0;
if ((slash = strchr(arg, '/')) != NULL) {
*slash = '\0';
len = slash - arg;
} else
len = strlen(arg);
if (strpbrk(arg, "*?[")) {
struct dirent *di;
DIR *d;
if (!(d = opendir(abpos ? glob.arg_buf : ".")))
return;
while ((di = readdir(d)) != NULL) {
char *dname = d_name(di);
if (dname[0] == '.' && (dname[1] == '\0'
|| (dname[1] == '.' && dname[2] == '\0')))
continue;
if (!wildmatch(arg, dname))
continue;
call_glob_match(dname, strlen(dname), 1,
slash ? arg + len + 1 : NULL,
abpos, fbpos);
}
closedir(d);
} else {
call_glob_match(arg, len, 0,
slash ? arg + len + 1 : NULL,
abpos, fbpos);
}
if (slash)
*slash = '/';
}
void glob_expand(char *s, char ***argv_ptr, int *argc_ptr, int *maxargs_ptr)
static inline void call_glob_match(const char *name, int len, int from_glob,
char *arg, int abpos, int fbpos)
{
char **argv = *argv_ptr;
int argc = *argc_ptr;
int maxargs = *maxargs_ptr;
#if !defined HAVE_GLOB || !defined HAVE_GLOB_H
if (argc == maxargs) {
maxargs += MAX_ARGS;
if (!(argv = realloc_array(argv, char *, maxargs)))
out_of_memory("glob_expand");
*argv_ptr = argv;
*maxargs_ptr = maxargs;
}
if (!*s)
s = ".";
s = argv[argc++] = strdup(s);
filter_server_path(s);
#else
glob_t globbuf;
char *use_buf;
if (maxargs <= argc)
return;
if (!*s)
s = ".";
ENSURE_MEMSPACE(glob.arg_buf, char, glob.absize, abpos + len + 2);
memcpy(glob.arg_buf + abpos, name, len);
abpos += len;
glob.arg_buf[abpos] = '\0';
if (fbpos >= 0) {
ENSURE_MEMSPACE(glob.filt_buf, char, glob.fbsize, fbpos + len + 2);
memcpy(glob.filt_buf + fbpos, name, len);
fbpos += len;
glob.filt_buf[fbpos] = '\0';
use_buf = glob.filt_buf;
} else
use_buf = glob.arg_buf;
if (from_glob || arg) {
STRUCT_STAT st;
int is_dir;
if (do_stat(glob.arg_buf, &st) != 0)
return;
is_dir = S_ISDIR(st.st_mode) != 0;
if (arg && !is_dir)
return;
if (daemon_filter_list.head
&& check_filter(&daemon_filter_list, FLOG, use_buf, is_dir) < 0)
return;
}
if (arg) {
glob.arg_buf[abpos++] = '/';
glob.arg_buf[abpos] = '\0';
if (fbpos >= 0) {
glob.filt_buf[fbpos++] = '/';
glob.filt_buf[fbpos] = '\0';
}
glob_match(arg, abpos, fbpos);
} else {
ENSURE_MEMSPACE(glob.argv, char *, glob.maxargs, glob.argc + 1);
if (!(glob.argv[glob.argc++] = strdup(glob.arg_buf)))
out_of_memory("glob_match");
}
}
/* This routine performs wild-card expansion of the pathname in "arg". Any
* daemon-excluded files/dirs will not be matched by the wildcards. Returns 0
* if a wild-card string is the only returned item (due to matching nothing). */
int glob_expand(const char *arg, char ***argv_p, int *argc_p, int *maxargs_p)
{
int ret, save_argc;
char *s;
if (!arg) {
if (glob.filt_buf)
free(glob.filt_buf);
free(glob.arg_buf);
memset(&glob, 0, sizeof glob);
return -1;
}
if (sanitize_paths)
s = sanitize_path(NULL, s, "", 0);
else
s = strdup(s);
if (!s)
out_of_memory("glob_expand");
memset(&globbuf, 0, sizeof globbuf);
if (!filter_server_path(s))
glob(s, 0, NULL, &globbuf);
if (MAX((int)globbuf.gl_pathc, 1) > maxargs - argc) {
maxargs += globbuf.gl_pathc + MAX_ARGS;
if (!(argv = realloc_array(argv, char *, maxargs)))
out_of_memory("glob_expand");
*argv_ptr = argv;
*maxargs_ptr = maxargs;
}
if (globbuf.gl_pathc == 0)
argv[argc++] = s;
s = sanitize_path(NULL, arg, "", 0, SP_KEEP_DOT_DIRS);
else {
int i;
free(s);
for (i = 0; i < (int)globbuf.gl_pathc; i++) {
if (!(argv[argc++] = strdup(globbuf.gl_pathv[i])))
out_of_memory("glob_expand");
}
s = strdup(arg);
if (!s)
out_of_memory("glob_expand");
clean_fname(s, CFN_KEEP_DOT_DIRS
| CFN_KEEP_TRAILING_SLASH
| CFN_COLLAPSE_DOT_DOT_DIRS);
}
globfree(&globbuf);
#endif
*argc_ptr = argc;
ENSURE_MEMSPACE(glob.arg_buf, char, glob.absize, MAXPATHLEN);
*glob.arg_buf = '\0';
glob.argc = save_argc = *argc_p;
glob.argv = *argv_p;
glob.maxargs = *maxargs_p;
ENSURE_MEMSPACE(glob.argv, char *, glob.maxargs, 100);
glob_match(s, 0, -1);
/* The arg didn't match anything, so add the failed arg to the list. */
if (glob.argc == save_argc) {
ENSURE_MEMSPACE(glob.argv, char *, glob.maxargs, glob.argc + 1);
glob.argv[glob.argc++] = s;
ret = 0;
} else {
free(s);
ret = 1;
}
*maxargs_p = glob.maxargs;
*argv_p = glob.argv;
*argc_p = glob.argc;
return ret;
}
/* This routine is only used in daemon mode. */
void glob_expand_module(char *base1, char *arg, char ***argv_ptr, int *argc_ptr, int *maxargs_ptr)
void glob_expand_module(char *base1, char *arg, char ***argv_p, int *argc_p, int *maxargs_p)
{
char *p, *s;
char *base = base1;
@@ -600,7 +690,7 @@ void glob_expand_module(char *base1, char *arg, char ***argv_ptr, int *argc_ptr,
for (s = arg; *s; s = p + base_len) {
if ((p = strstr(s, base)) != NULL)
*p = '\0'; /* split it at this point */
glob_expand(s, argv_ptr, argc_ptr, maxargs_ptr);
glob_expand(s, argv_p, argc_p, maxargs_p);
if (!p)
break;
}
@@ -687,13 +777,13 @@ int count_dir_elements(const char *p)
return cnt;
}
/* Turns multiple adjacent slashes into a single slash, drops interior "."
* elements, drops an intial "./" unless CFN_KEEP_LEADING_DOT_DIR is flagged,
* will even drop a trailing '.' after a '/' if CFN_DROP_TRAILING_DOT_DIR is
* flagged, removes a trailing slash (perhaps after removing the aforementioned
* dot) unless CFN_KEEP_TRAILING_SLASH is flagged, will even collapse ".."
* elements (except at the start of the string) if CFN_COLLAPSE_DOT_DOT_DIRS
* is flagged. If the resulting name would be empty, we return ".". */
/* Turns multiple adjacent slashes into a single slash, drops all leading or
* interior "." elements unless CFN_KEEP_DOT_DIRS is flagged. Will also drop
* a trailing '.' after a '/' if CFN_DROP_TRAILING_DOT_DIR is flagged, removes
* a trailing slash (perhaps after removing the aforementioned dot) unless
* CFN_KEEP_TRAILING_SLASH is flagged, and will also collapse ".." elements
* (except at the start) if CFN_COLLAPSE_DOT_DOT_DIRS is flagged. If the
* resulting name would be empty, returns ".". */
unsigned int clean_fname(char *name, int flags)
{
char *limit = name - 1, *t = name, *f = name;
@@ -704,7 +794,7 @@ unsigned int clean_fname(char *name, int flags)
if ((anchored = *f == '/') != 0)
*t++ = *f++;
else if (flags & CFN_KEEP_LEADING_DOT_DIR && *f == '.' && f[1] == '/') {
else if (flags & CFN_KEEP_DOT_DIRS && *f == '.' && f[1] == '/') {
*t++ = *f++;
*t++ = *f++;
}
@@ -716,7 +806,7 @@ unsigned int clean_fname(char *name, int flags)
}
if (*f == '.') {
/* discard interior "." dirs */
if (f[1] == '/') {
if (f[1] == '/' && !(flags & CFN_KEEP_DOT_DIRS)) {
f += 2;
continue;
}
@@ -773,10 +863,11 @@ unsigned int clean_fname(char *name, int flags)
* ALWAYS collapses ".." elements (except for those at the start of the
* string up to "depth" deep). If the resulting name would be empty,
* change it into a ".". */
char *sanitize_path(char *dest, const char *p, const char *rootdir, int depth)
char *sanitize_path(char *dest, const char *p, const char *rootdir, int depth,
int flags)
{
char *start, *sanp;
int rlen = 0, leave_one_dotdir = relative_paths;
int rlen = 0, drop_dot_dirs = !relative_paths || !(flags & SP_KEEP_DOT_DIRS);
if (dest != p) {
int plen = strlen(p);
@@ -799,21 +890,22 @@ char *sanitize_path(char *dest, const char *p, const char *rootdir, int depth)
}
}
if (drop_dot_dirs) {
while (*p == '.' && p[1] == '/')
p += 2;
}
start = sanp = dest + rlen;
/* This loop iterates once per filename component in p, pointing at
* the start of the name (past any prior slash) for each iteration. */
while (*p) {
/* discard leading or extra slashes */
if (*p == '/') {
p++;
continue;
}
/* this loop iterates once per filename component in p.
* both p (and sanp if the original had a slash) should
* always be left pointing after a slash
*/
if (*p == '.' && (p[1] == '/' || p[1] == '\0')) {
if (leave_one_dotdir && p[1])
leave_one_dotdir = 0;
else {
if (drop_dot_dirs) {
if (*p == '.' && (p[1] == '/' || p[1] == '\0')) {
/* skip "." component */
p++;
continue;
@@ -826,10 +918,8 @@ char *sanitize_path(char *dest, const char *p, const char *rootdir, int depth)
if (sanp != start) {
/* back up sanp one level */
--sanp; /* now pointing at slash */
while (sanp > start && sanp[-1] != '/') {
/* skip back up to slash */
while (sanp > start && sanp[-1] != '/')
sanp--;
}
}
continue;
}
@@ -853,7 +943,7 @@ char *sanitize_path(char *dest, const char *p, const char *rootdir, int depth)
/* Like chdir(), but it keeps track of the current directory (in the
* global "curr_dir"), and ensures that the path size doesn't overflow.
* Also cleans the path using the clean_fname() function. */
int push_dir(const char *dir, int set_path_only)
int change_dir(const char *dir, int set_path_only)
{
static int initialised;
unsigned int len;
@@ -871,21 +961,26 @@ int push_dir(const char *dir, int set_path_only)
if (len == 1 && *dir == '.')
return 1;
if ((*dir == '/' ? len : curr_dir_len + 1 + len) >= sizeof curr_dir) {
errno = ENAMETOOLONG;
return 0;
}
if (!set_path_only && chdir(dir))
return 0;
if (*dir == '/') {
if (len >= sizeof curr_dir) {
errno = ENAMETOOLONG;
return 0;
}
if (!set_path_only && chdir(dir))
return 0;
memcpy(curr_dir, dir, len + 1);
curr_dir_len = len;
} else {
curr_dir[curr_dir_len++] = '/';
memcpy(curr_dir + curr_dir_len, dir, len + 1);
curr_dir_len += len;
if (curr_dir_len + 1 + len >= sizeof curr_dir) {
errno = ENAMETOOLONG;
return 0;
}
curr_dir[curr_dir_len] = '/';
memcpy(curr_dir + curr_dir_len + 1, dir, len + 1);
if (!set_path_only && chdir(curr_dir)) {
curr_dir[curr_dir_len] = '\0';
return 0;
}
}
curr_dir_len = clean_fname(curr_dir, CFN_COLLAPSE_DOT_DOT_DIRS);
@@ -896,28 +991,7 @@ int push_dir(const char *dir, int set_path_only)
}
if (verbose >= 5 && !set_path_only)
rprintf(FINFO, "[%s] push_dir(%s)\n", who_am_i(), curr_dir);
return 1;
}
/**
* Reverse a push_dir() call. You must pass in an absolute path
* that was copied from a prior value of "curr_dir".
**/
int pop_dir(const char *dir)
{
if (chdir(dir))
return 0;
curr_dir_len = strlcpy(curr_dir, dir, sizeof curr_dir);
if (curr_dir_len >= sizeof curr_dir)
curr_dir_len = sizeof curr_dir - 1;
if (sanitize_paths)
curr_dir_depth = count_dir_elements(curr_dir + module_dirlen);
if (verbose >= 5)
rprintf(FINFO, "[%s] pop_dir(%s)\n", who_am_i(), curr_dir);
rprintf(FINFO, "[%s] change_dir(%s)\n", who_am_i(), curr_dir);
return 1;
}
@@ -977,13 +1051,13 @@ char *partial_dir_fname(const char *fname)
fn = fname;
if ((int)pathjoin(t, sz, partial_dir, fn) >= sz)
return NULL;
if (server_filter_list.head) {
if (daemon_filter_list.head) {
t = strrchr(partial_fname, '/');
*t = '\0';
if (check_filter(&server_filter_list, partial_fname, 1) < 0)
if (check_filter(&daemon_filter_list, FLOG, partial_fname, 1) < 0)
return NULL;
*t = '/';
if (check_filter(&server_filter_list, partial_fname, 0) < 0)
if (check_filter(&daemon_filter_list, FLOG, partial_fname, 0) < 0)
return NULL;
}

View File

@@ -62,9 +62,12 @@ extern int checksum_seed;
#endif
#define RPRE_LEN ((int)sizeof RSYNC_PREFIX - 1)
#define XSTAT_ATTR RSYNC_PREFIX "%stat"
#define XACC_ACL_ATTR RSYNC_PREFIX "%aacl"
#define XDEF_ACL_ATTR RSYNC_PREFIX "%dacl"
#define XSTAT_SUFFIX "stat"
#define XSTAT_ATTR RSYNC_PREFIX "%" XSTAT_SUFFIX
#define XACC_ACL_SUFFIX "aacl"
#define XACC_ACL_ATTR RSYNC_PREFIX "%" XACC_ACL_SUFFIX
#define XDEF_ACL_SUFFIX "dacl"
#define XDEF_ACL_ATTR RSYNC_PREFIX "%" XDEF_ACL_SUFFIX
typedef struct {
char *datum, *name;
@@ -231,7 +234,10 @@ static int rsync_xal_get(const char *fname, item_list *xalp)
if (name_len > RPRE_LEN && name[RPRE_LEN] == '%'
&& HAS_PREFIX(name, RSYNC_PREFIX)) {
if ((am_sender && preserve_xattrs < 2)
|| (am_root < 0 && strcmp(name, XSTAT_ATTR) == 0))
|| (am_root < 0
&& (strcmp(name+RPRE_LEN+1, XSTAT_SUFFIX) == 0
|| strcmp(name+RPRE_LEN+1, XACC_ACL_SUFFIX) == 0
|| strcmp(name+RPRE_LEN+1, XDEF_ACL_SUFFIX) == 0)))
continue;
}
@@ -253,14 +259,6 @@ static int rsync_xal_get(const char *fname, item_list *xalp)
} else
name_offset = datum_len;
#ifdef HAVE_LINUX_XATTRS
if (am_root < 0 && name_len > RPRE_LEN && name[RPRE_LEN] != '%'
&& HAS_PREFIX(name, RSYNC_PREFIX)) {
name += RPRE_LEN;
name_len -= RPRE_LEN;
}
#endif
rxa = EXPAND_ITEM_LIST(xalp, rsync_xa, RSYNC_XAL_INITIAL);
rxa->name = ptr + name_offset;
memcpy(rxa->name, name, name_len);
@@ -352,25 +350,32 @@ int send_xattr(stat_x *sxp, int f)
int count = sxp->xattr->count;
write_varint(f, count);
for (rxa = sxp->xattr->items; count--; rxa++) {
size_t name_len = rxa->name_len;
const char *name = rxa->name;
/* Strip the rsync prefix from disguised namespaces. */
if (name_len > RPRE_LEN
#ifdef HAVE_LINUX_XATTRS
write_varint(f, rxa->name_len);
write_varint(f, rxa->datum_len);
write_buf(f, rxa->name, rxa->name_len);
#else
/* We strip the rsync prefix from disguised namespaces
* and put everything else in the user namespace. */
if (HAS_PREFIX(rxa->name, RSYNC_PREFIX)
&& rxa->name[RPRE_LEN] != '%') {
write_varint(f, rxa->name_len - RPRE_LEN);
write_varint(f, rxa->datum_len);
write_buf(f, rxa->name + RPRE_LEN, rxa->name_len - RPRE_LEN);
} else {
write_varint(f, rxa->name_len + UPRE_LEN);
write_varint(f, rxa->datum_len);
write_buf(f, USER_PREFIX, UPRE_LEN);
write_buf(f, rxa->name, rxa->name_len);
&& am_root < 0
#endif
&& name[RPRE_LEN] != '%' && HAS_PREFIX(name, RSYNC_PREFIX)) {
name += RPRE_LEN;
name_len -= RPRE_LEN;
}
#ifndef HAVE_LINUX_XATTRS
else {
/* Put everything else in the user namespace. */
name_len += UPRE_LEN;
}
#endif
write_varint(f, name_len);
write_varint(f, rxa->datum_len);
#ifndef HAVE_LINUX_XATTRS
if (name_len > rxa->name_len) {
write_buf(f, USER_PREFIX, UPRE_LEN);
name_len -= UPRE_LEN;
}
#endif
write_buf(f, name, name_len);
if (rxa->datum_len > MAX_FULL_DATUM)
write_buf(f, rxa->datum + 1, MAX_DIGEST_LEN);
else
@@ -574,6 +579,11 @@ void receive_xattr(struct file_struct *file, int f)
{
static item_list temp_xattr = EMPTY_ITEM_LIST;
int count, num;
#ifdef HAVE_LINUX_XATTRS
int need_sort = 0;
#else
int need_sort = 1;
#endif
int ndx = read_varint(f);
if (ndx < 0 || (size_t)ndx > rsync_xal_l.count) {
@@ -624,6 +634,7 @@ void receive_xattr(struct file_struct *file, int f)
name -= RPRE_LEN;
name_len += RPRE_LEN;
memcpy(name, RSYNC_PREFIX, RPRE_LEN);
need_sort = 1;
}
#else
/* This OS only has a user namespace, so we either
@@ -655,6 +666,9 @@ void receive_xattr(struct file_struct *file, int f)
rxa->num = num;
}
if (need_sort && count > 1)
qsort(temp_xattr.items, count, sizeof (rsync_xa), rsync_xal_compare_names);
ndx = rsync_xal_l.count; /* pre-incremented count */
rsync_xal_store(&temp_xattr); /* adds item to rsync_xal_l */
@@ -684,7 +698,8 @@ static int rsync_xal_set(const char *fname, item_list *xalp,
ssize_t list_len;
size_t i, len;
char *name, *ptr, sum[MAX_DIGEST_LEN];
int name_len, ret = 0;
size_t name_len;
int ret = 0;
/* This puts the current name list into the "namebuf" buffer. */
if ((list_len = get_xattr_names(fname)) < 0)