Compare commits

...

398 Commits

Author SHA1 Message Date
Wayne Davison
618c8a73db Preparing for release of 2.6.3 2004-09-30 16:36:42 +00:00
Wayne Davison
aa0ea373cd Mention the enhancement that was made (quite a while ago) to the
daemon's wildcard-expansion limit (formerly 1000 items, now memory
limited).
2004-09-30 10:46:43 +00:00
Wayne Davison
6c3fda83ba Refined the text of a few of the news items. 2004-09-30 09:58:39 +00:00
Wayne Davison
a3571c6cce - Mention the fix for lost output with 2>&1.
- Prepare the file for the 2.6.3 final release.
2004-09-30 09:37:38 +00:00
Wayne Davison
6fcedb7dbe Mention the (anticipated) 2.6.3 release date. 2004-09-30 09:36:29 +00:00
Wayne Davison
18882701d2 Set our stderr output to blocking I/O to avoid any loss of output. 2004-09-29 17:58:07 +00:00
Wayne Davison
30c041f9ad Changed the errors concerning the secrets file to output with FLOG
instead of FERROR.
2004-09-24 17:04:05 +00:00
Wayne Davison
be7cf82299 - Make sure that match_address() always restores the "tok" string,
even on error.
- Turned the various FERROR messages into (the more proper) FLOG.
2004-09-24 16:50:07 +00:00
Wayne Davison
fde045cd77 Turned the various FERROR messages into (the more proper) FLOG. 2004-09-24 16:39:41 +00:00
Wayne Davison
183150b741 Added some more --inplace info (i.e. it implies --partial and conflicts
with 3 basis-file-affecting options).
2004-09-23 21:15:04 +00:00
Wayne Davison
a2570930e8 Made the refused-option message clearer, like Paul suggested. 2004-09-23 17:39:05 +00:00
Wayne Davison
fdb6716c0f Create a FIFO using mkfifo. 2004-09-23 16:34:43 +00:00
Wayne Davison
a20a88d235 Assume that gettimeofday() takes two arguments when cross-compiling. 2004-09-23 16:00:44 +00:00
Wayne Davison
48d3ff94c9 Only output major/minor info for a character/block device, not for
a FIFO or a socket.
2004-09-23 05:33:48 +00:00
Wayne Davison
a33857da09 Mention that --partial-dir now sets an exclude that helps to avoid
losing the partial data when deleting, and avoid copying any partial
data from the sender.
2004-09-22 04:14:43 +00:00
Wayne Davison
13791b1eeb If the partial-dir value is relative, add a directory-exclude for it
to the end of the user's exclude list.
2004-09-22 04:12:13 +00:00
Wayne Davison
9a5e37fca8 In get_exclude_tok(), if XFLG_DIRECTORY was passed in the xflags,
set MATCHFLG_DIRECTORY in the mflags we return.
2004-09-22 04:11:15 +00:00
Wayne Davison
3e976df0fb Added XFLG_DIRECTORY define. 2004-09-22 04:10:10 +00:00
Wayne Davison
42afed9c1a Preparing for release of 2.6.3pre2 2004-09-21 16:10:35 +00:00
Wayne Davison
37c36e2692 Mention the daemon-socket-connection change. 2004-09-21 15:47:20 +00:00
Wayne Davison
7fbc7031f4 Mentioned a couple more changes. 2004-09-21 15:31:33 +00:00
Wayne Davison
9f004a9ea9 The delete_one() function no longer needs to handle the case where
it thinks it is removing a directory and it is really removing a
symlink.
2004-09-21 09:24:06 +00:00
Wayne Davison
23f4587f2b - Turned readlink_stat() into a static function.
- Made readlink_stat() no longer honor keep_dirlinks.
- The make_file() function now checks keep_dirlinks late in the
  function so that it only transforms a symlink to a local dir
  into a directory if the receiver also has a directory by that
  name.  This makes the use of --delete with --keep-dirlinks
  work much better.
2004-09-21 09:24:02 +00:00
Wayne Davison
4d8f5b0ae7 - Fixed a problem with the $bakdir value.
- Made the files have better contents to copy.
- Also test --backup without --backup-dir.
2004-09-20 19:50:04 +00:00
Wayne Davison
89389a29ef Output a backup message when verbose > 1 and we did a copy prior
to an --inplace update.
2004-09-20 19:47:59 +00:00
Wayne Davison
29fe3961ab Output the same backup-message prefix when verbose > 1 regardless of
the setting of --backup-dir.
2004-09-20 19:46:45 +00:00
Wayne Davison
4e8a085ac9 Use $diffopt instead of -u. 2004-09-20 05:17:57 +00:00
Wayne Davison
fb22c2774d Got rid of a superfluous static buffer. 2004-09-20 05:01:38 +00:00
Wayne Davison
7d059d4c37 A simple test of the backup functionality. 2004-09-20 04:59:01 +00:00
Wayne Davison
9715c5899a Improved a comment. 2004-09-20 04:17:42 +00:00
Wayne Davison
cc07f21211 Mention the new RSYNC_PARTIAL_DIR environment variable. 2004-09-18 17:37:54 +00:00
Wayne Davison
b4d1e854ef Document the new RSYNC_PARTIAL_DIR environment variable. 2004-09-18 17:35:20 +00:00
Wayne Davison
075aa18fd4 Look for the RSYNC_PARTIAL_DIR environment variable when --partial
was specified (and --partial-dir was not).
2004-09-18 17:34:56 +00:00
Wayne Davison
e0204f5621 Mention that older rsync versions had a problem with --link-dest and
how to work around it.
2004-09-18 01:49:19 +00:00
Wayne Davison
a9ac4411e5 Mention the latest changes. 2004-09-17 16:53:51 +00:00
Wayne Davison
50b31539c2 - Added the ability to parse a literal IPv6 address in an "rsync:" URL
(e.g. rsync://[2001:638:500:101::21]:873/module/dir).
- Improved a couple --files-from error messages.
2004-09-17 16:50:53 +00:00
Wayne Davison
56194bcd95 When outputting the flist info (in a debug-level of verbosity) we
now mention the UID of the file when we are the sender (as well as
when we are root).
2004-09-17 16:39:34 +00:00
Wayne Davison
eb8ffa9040 Actually, since the close calls shouldn't fail (now that listener
is properly set to -1 on close), we don't really need to play the
save-errno game after all.
2004-09-16 17:22:31 +00:00
Wayne Davison
a7a1cc2c75 Make sure that /etc and /bin actually are readable before we try
to list them.
2004-09-16 17:16:36 +00:00
Wayne Davison
ab217f7ffa - Set "listener" to -1 after we close it so that the error-handler
doesn't try to re-close it.
- Set blocking I/O before the second (final) connect() call.
2004-09-16 17:09:46 +00:00
Wayne Davison
a20c9893e4 Don't try to optimize-away the sending of the --delete option if
--delete-after was specified (since we don't know what the protocol
version will be yet).
2004-09-08 07:33:06 +00:00
Wayne Davison
3bb400ca14 If --backup was used with --inplace, we don't limit the basis-file
matches (as we normally would) because the receiver is using the
backup-file as the basis-file.
2004-09-07 21:45:19 +00:00
Wayne Davison
cd6aa5b5c0 When --backup is used with --inplace, we make a copy of the destination
file into its backup spot while generating the checksums.
2004-09-07 21:44:02 +00:00
Wayne Davison
dc55d7bdab If we're making backups with --inplace, use the backup file as the
basis file while still updating the real destination file inplace.
2004-09-07 21:34:26 +00:00
Wayne Davison
8b115ac8dc Turn off make_backups during the redo phase, just like the receiver. 2004-09-07 21:32:36 +00:00
Wayne Davison
c94e4afbfa Moved the code that determines the backup filename into a new function
named get_backup_name().
2004-09-07 21:29:26 +00:00
Wayne Davison
6566d205e2 Made full_write() non-static. 2004-09-07 21:26:26 +00:00
Wayne Davison
e484f0cc04 W mustn't backup an inplace file in finish_transfer(). 2004-09-07 20:37:36 +00:00
Wayne Davison
bd397b8cba Reject the use of --compare-dest or --link-dest with --inplace
(it will take extra code to suppor this).
2004-09-07 20:36:36 +00:00
Wayne Davison
f8c8ef9eac When we say we're skipping a non-regular file, actually skip it. 2004-09-07 19:49:09 +00:00
Wayne Davison
72c19bb3de A minor optimization to the partial-dir code. 2004-09-07 17:03:51 +00:00
Wayne Davison
89f7eff382 Fix the case where a partial-dir file exists but the destination
file does not.
2004-09-07 16:50:07 +00:00
Wayne Davison
b90a6d9ff6 Mention that --whole-file interferes with the reuse of a --partial-dir
file.
2004-09-07 16:49:10 +00:00
Wayne Davison
584ba4ebae Fixed a typo Paul pointed out. 2004-09-05 21:30:00 +00:00
Wayne Davison
ba3db4795e Allow the use of the --exclude*/--include* options to a server
process again, but make sure that the user didn't specify a
server-excluded file for one of the --*-from options.
2004-08-26 17:39:48 +00:00
Wayne Davison
59d73bf3d2 Some fixes & clarifications for the BATCH MODE section. 2004-08-18 07:50:36 +00:00
Wayne Davison
919ca3a3cc Few few more minor improvements to the existing change items. 2004-08-18 07:49:03 +00:00
Wayne Davison
5886edfac2 Corrected/enhanced a comment. 2004-08-18 07:00:17 +00:00
Wayne Davison
d414962af4 One more NEWS tweak. 2004-08-12 21:02:13 +00:00
Wayne Davison
8fb7db245a Mention the security fix. 2004-08-12 20:58:33 +00:00
Wayne Davison
6f0fc27e33 Got rid of one item. 2004-08-12 20:48:05 +00:00
Wayne Davison
9c54ad58f8 Preparing for release of 2.6.3pre1 2004-08-12 20:06:57 +00:00
Wayne Davison
f55c2dfc03 One last minor tweak to clean_fname(). 2004-08-12 20:04:47 +00:00
Wayne Davison
675ef1aa3a Tweaked the USAGE section a tad and added an ADVANCED USAGE section
that discusses how to request multiple names from a remote rsync.
2004-08-12 19:31:23 +00:00
Wayne Davison
ef57235623 Improved the build rule for getfsdev and added getfsdev.o to the
files we cleanup.
2004-08-12 18:59:03 +00:00
Wayne Davison
d66d07e883 If system won't let us set chmod bits, fall back to testing without
them set.
2004-08-12 18:51:35 +00:00
Wayne Davison
b92693daba - Made clean_flist()'s collapsing of ".." dirs optional by adding
a "BOOL collapse_dot_dot" arg.
- Improved some comments.
2004-08-12 18:20:14 +00:00
Wayne Davison
58b1999e08 Call clean_flist() with its new "collapse_dot_dot" arg. 2004-08-12 18:20:07 +00:00
Wayne Davison
8e5f029e02 One (hopefully) last change to the sanitize_path() code. 2004-08-12 10:13:45 +00:00
Wayne Davison
2d41264e9e Simplified sanitize_path() logic a little. 2004-08-12 09:32:16 +00:00
Wayne Davison
82c6be7edf More improvements and a couple missing items. 2004-08-12 01:27:26 +00:00
Wayne Davison
0219d4dfba Improved a comment. 2004-08-12 00:58:01 +00:00
Wayne Davison
391516da51 Got rid of a comment that became inapplicable. 2004-08-12 00:52:58 +00:00
Wayne Davison
1d6b8f9ad2 - Call sanitize_path() with updated args.
- Added count_dir_elements() function.
- Changed the args for sanitize_path() so that the caller can request
  the value for the rootdir and so that the caller tells us the current
  subdir depth instead of sending us a string that we have to figure it
  out from.
- Make sure that sanitize_path() doesn't mis-parse multiple adjacent
  slashes.
2004-08-11 23:41:06 +00:00
Wayne Davison
10796f4b6e Call sanitize_path() with updated args. 2004-08-11 23:41:03 +00:00
Wayne Davison
33ffd7c37d - Set the var lastdir_depth when setting lastdir.
- Call sanitize_path() with updated args.
2004-08-11 23:41:00 +00:00
Wayne Davison
21d1e929a0 Ignore new getfsdev executable. 2004-08-11 17:33:52 +00:00
Wayne Davison
d0bc3520de Make the text of the --times (-t) option more correct on what
happens if it is omitted.
2004-08-11 17:24:37 +00:00
Wayne Davison
9f18657889 A minor improvement in check_one_exclude(). 2004-08-10 18:15:33 +00:00
Wayne Davison
c16d69b292 Mention the early-chmod change. 2004-08-09 20:58:26 +00:00
Wayne Davison
ebeacb36fb Set each file's permissions and modtime before it gets renamed. 2004-08-09 20:57:10 +00:00
Wayne Davison
6558854dbe Do some simple tests with various read-only and set[ug]id files. 2004-08-09 20:52:35 +00:00
Wayne Davison
7d9d5d9478 Added a rule for building getfsdev and for requiring it to run "test". 2004-08-09 20:51:44 +00:00
Wayne Davison
630f548ff4 Made robust_rename() return a 1 if it had to copy the file. 2004-08-09 20:48:38 +00:00
Wayne Davison
100b62bb69 Output a device string for each file given on the command-line. 2004-08-09 20:46:54 +00:00
Wayne Davison
e012b94f21 Fixed a bug in clean_fname() that could sometimes leave a "dir/.."
sequence uncollapsed.
2004-08-07 20:56:41 +00:00
Wayne Davison
3104620cf0 Made clean_fname() return the length of the string. 2004-08-06 22:36:55 +00:00
Wayne Davison
ebdd24d6d0 An improved clean_fname() routine that is more efficient and will also
collapse ".." dirs that aren't at the start of the path.  Care was taken
to ensure that the cleaning of a name that goes over the socket is done
in the same way as the old code (because both sides call clean_fname()
on those file-list names).  This ensures compatibility with older rsync
versions.
2004-08-06 21:24:14 +00:00
Wayne Davison
7cd72c79ec Set "eob" correctly in add_exclude_file(). 2004-08-05 22:58:17 +00:00
Wayne Davison
84a6379565 Merged alloc_sanitize_path() into sanitize_path(), adding an extra arg
that indicates the destination dir for the resulting path (if the dest
is NULL, a buffer will be allocated) and having it return a value.
2004-08-05 21:57:11 +00:00
Wayne Davison
0a5f12720e Use the new sanitize_path() calling syntax. 2004-08-05 21:57:09 +00:00
Wayne Davison
73f7af0e88 If dry_run is > 1 then the destination directory was missing, so we
set stat_errno to ENOENT and statret to -1 without calling stat().
2004-08-05 18:18:36 +00:00
Wayne Davison
e5a96f0f54 In get_local_name(), if we would have created the destination dir but
were prevented by dry_run being set, increment dry_run so that the
generator knows that all the files are missing.
2004-08-05 18:17:44 +00:00
Wayne Davison
d73e7f6edd In set_refuse_options(): make sure we scan the whole list of options
and avoid complaining about a wild-card spec that actually matches
one or more options.
2004-08-04 21:20:34 +00:00
Wayne Davison
61542c41de Decided that we don't need to limit the block size after all now
that the map_file() code handles large block sizes better.
2004-08-03 15:41:16 +00:00
Wayne Davison
bd1a581bee Use MAX_MAP_SIZE in the args to map_file(). 2004-08-03 15:37:54 +00:00
Wayne Davison
6e8a1782ab - Changed the calling syntax for map_file() so that it takes both
a (possibly approximate) window size and an optional block size
  (which is used to round-up the window size if it is non-zero).
- Don't set window_start behind the supplied offset in map_ptr().
2004-08-03 08:05:29 +00:00
Wayne Davison
96d910c770 Call map_file() with its new args, including a suggested window
size.
2004-08-03 08:05:27 +00:00
Wayne Davison
7560c17adc We call map_ptr() with a data range than includes any unmatched data
(which we might need to reference again) in addition to the current
rolling-checksum block (this prevents the unmatched data from being
lost when we slide the buffer and read more data).
2004-08-03 08:05:23 +00:00
Wayne Davison
9cd339eb39 - Changed the description for --block-size in the --help text.
- Use the new MAX_BLOCK_SIZE to limit the block_size value.
2004-08-03 08:05:20 +00:00
Wayne Davison
f310029387 - Added define for MAX_BLOCK_SIZE.
- Increased the MAX_MAP_SIZE.
2004-08-03 08:05:17 +00:00
Wayne Davison
3ed8eb3f9c Updated the description of the --block-size option. 2004-08-03 07:58:48 +00:00
Wayne Davison
007351494d Mention the open64()/mkstemp64() configure change. 2004-08-02 22:06:17 +00:00
Wayne Davison
6dcb93208d Don't use mkstemp() if the OS has open64() but not mkstemp64(). 2004-08-02 21:56:07 +00:00
Wayne Davison
84e1a698bf Test for functions open64() and mkstemp64(). 2004-08-02 21:54:49 +00:00
Wayne Davison
0d7638eafd Got rid of trailing whitespace. 2004-08-02 16:49:20 +00:00
Wayne Davison
86e2f445f7 Mention the "refuse options" change. 2004-08-02 07:41:04 +00:00
Wayne Davison
093e816c37 Allow better wildcard matching against the short-option letters in
the "refuse options" handling.
2004-08-02 07:40:34 +00:00
Wayne Davison
1cb0a3edc6 Document the improved "refuse options" syntax. 2004-08-02 05:01:36 +00:00
Wayne Davison
06a5054273 - Extended the "refuse options" daemon setting to allow wildcards
and to allow single-letter option names.
- No need to send the various --delete* options or the --force option
  from the receiver to the sender.
2004-08-02 05:00:30 +00:00
Wayne Davison
acd0299243 Got rid of unused externs. 2004-08-02 04:50:33 +00:00
Wayne Davison
dca68b0aad - Changed "read so far" to "received so far".
- Output the who_am_i() information in the socket read/write errors to
  make it a little clearer who is complaining about what (for those
  familiar with rsync, at least -- e.g. it will help when users report
  errors).
2004-08-02 02:43:54 +00:00
Wayne Davison
c3ea09906d - Changed all the errors in parse_arguments() to use the err_buf so
that a client talking to a daemon server actually gets the error.
- If a daemon has a list of exclusions, apply that list to various
  options to ensure that an excluded file can't be affected.
- Fixed an arg-checking problem when --files-from got passed to a
  daemon.
2004-07-31 20:09:54 +00:00
Wayne Davison
bf4679e8a0 If we need to return an error during the startup phase and the other
side is expecting us to send them a files-from list, send the list
terminator before sending the error.
2004-07-31 19:55:42 +00:00
Wayne Davison
c4054610c8 Don't allow a --partial-dir setting to overwrite a server-excluded
file (affects a daemon receiver only).
2004-07-31 18:13:20 +00:00
Wayne Davison
f6c0d3d70b - Document the change to --copy-links.
- Improved the "OUTPUT CHANGES" section.
2004-07-31 16:20:28 +00:00
Wayne Davison
ef855d198e Document the old side-effect to --copy-links and that it no longer
happens in a modern rsync w/o --keep-dirlinks.
2004-07-31 16:19:14 +00:00
Wayne Davison
81b07870c8 One call to link_stat() (in set_perms()) needed to honor the setting
of keep_dirlinks if the current item is a directory.
2004-07-31 16:15:41 +00:00
Wayne Davison
bb6721dce6 Reset copy_links in the receiver. 2004-07-31 16:14:27 +00:00
Wayne Davison
446a2987cd Prominently mention the changes to the text that gets output. 2004-07-31 03:33:05 +00:00
Wayne Davison
4de2a17409 Changed "wrote"/"written" to "sent" and "read" to "received" in
the text that is output.
2004-07-31 03:32:42 +00:00
Wayne Davison
99d24f77ed - Mention the "list = no" change in error handling.
- Improved a few of the NEWS items.
2004-07-30 22:46:07 +00:00
Wayne Davison
c0422cea9f If someone is denied access to a "list = no" module, lie and tell them
that the module is "Unknown" (so the user can't probe to find unlisted
modules).
2004-07-30 20:07:52 +00:00
Wayne Davison
8b6ad0193d Don't ignore case in lp_number() because the rest of the daemon code
can't handle the case where the module name doesn't exactly match the
string the user provided.
2004-07-30 20:05:37 +00:00
Wayne Davison
33eff8bfd6 If we reject a name due to a server-exclude, someone is trying to hack
rsync (because the generator would not have included this file).  Respond
with an exit.
2004-07-30 07:02:37 +00:00
Wayne Davison
65af3dab03 Document the latest changes. 2004-07-29 18:08:16 +00:00
Wayne Davison
065a605270 Got rid of bogus compare_dest scan in skip_file() -- it must checksum
the same file that we used for the stat() (in the parent routine).
2004-07-29 16:45:48 +00:00
Wayne Davison
a7260c4037 Added the new --partial-dir option. 2004-07-29 16:06:38 +00:00
Wayne Davison
44cad59f2b Document the new --partial-dir option. 2004-07-29 16:06:34 +00:00
Wayne Davison
c52461f911 Check the error return of flush_write_file(). 2004-07-29 07:37:27 +00:00
Wayne Davison
7f459268d9 Added close_multiplexing_in() and renamed io_multiplexing_close()
to close_multiplexing_out().
2004-07-29 07:24:45 +00:00
Wayne Davison
9eeb3b9c88 Call the new close_multiplexing_in() function in the generator. 2004-07-29 07:24:00 +00:00
Wayne Davison
d1b31da71e If we fail writing to the socket and we're receiving error messages
from the other side via a multiplexed input, read the socket to see
if we get some errors that would explain why they went away.
2004-07-29 07:09:46 +00:00
Wayne Davison
89e540e638 One more inplace code tweak. 2004-07-29 06:59:30 +00:00
Wayne Davison
fab65a5bc2 Some minor fixes and improvements for the inplace code. 2004-07-29 06:40:26 +00:00
Wayne Davison
e7d13fe532 - Explicitly save the stat()'s errno so that we can be sure we're
testing the right thing lower down (and so that future code doesn't
  always have to remember to save it off and restore it).
- Improved a chunk of link_dest code.
- Handle the removal of a non-regular file without so much duplicated
  code.
2004-07-28 10:04:06 +00:00
Wayne Davison
ecc81fce17 Use the new safe_fname() function. 2004-07-26 16:36:59 +00:00
Wayne Davison
b4afd23c30 Allow safe_fname() to tweak up to two name at a time. 2004-07-26 16:34:36 +00:00
Wayne Davison
af1a3f9b6e Use safe_fname() in full_fname(). 2004-07-26 15:59:51 +00:00
Wayne Davison
820b6c9aa0 Added safe_fname() that converts any newlines in a name into '?'s. 2004-07-26 15:52:25 +00:00
Wayne Davison
3cb22c204c Made a comment better. 2004-07-26 05:38:02 +00:00
Wayne Davison
7432ccf4ed Some batch-mode changes. 2004-07-24 16:51:58 +00:00
Wayne Davison
6a48e792c1 Made the new option-twiddling message only output when verbose. 2004-07-24 16:51:16 +00:00
Wayne Davison
9459290ae7 Call read_stream_flags() as soon as we open the batch file for
reading.
2004-07-24 16:40:41 +00:00
Wayne Davison
741d654495 Call write_stream_flags() from start_write_batch(). 2004-07-24 16:39:53 +00:00
Wayne Davison
d3e182af09 Added write_stream_flags() to write the state of certain flags into
the batchfile and read_stream_flags() to read and twiddle the same
flags.  This ensures that the batchfile reading doesn't get confused
about what data to expect from the socket.
2004-07-24 16:38:49 +00:00
Wayne Davison
d9b4d267c7 Tweaked a compound line. 2004-07-23 16:59:38 +00:00
Wayne Davison
58c5c24555 Added a comment. 2004-07-23 16:59:22 +00:00
Wayne Davison
341c9a137f Some basic batch-mode tests. 2004-07-23 02:13:34 +00:00
Wayne Davison
871446fc98 Chris added a missing "not" to a comment. 2004-07-23 01:40:22 +00:00
Wayne Davison
0abda1b176 Fixed the opening comments. 2004-07-23 01:39:19 +00:00
Wayne Davison
394bcdb5e3 If we sucessfully renamed a file that has multiple links to it, unlink()
it to ensure that rename() didn't lie to us (which it does if you try to
rename() a file over another link to the same file).
2004-07-22 22:52:39 +00:00
Wayne Davison
28deecca55 Changed NO_INT64 to INT64_IS_OFF_T because off_t might actually be
64 bits.  The code now only complains if int64 is really too short.
2004-07-22 19:28:45 +00:00
Wayne Davison
4db88e5b8f Some --help text fixes. 2004-07-22 15:43:28 +00:00
Wayne Davison
75b243a51d Some more --inplace improvements. 2004-07-22 15:41:09 +00:00
Wayne Davison
9bccfc429c Should always call finish_transfer() for inplace handling, just like
for keep_partial handling.
2004-07-22 15:31:06 +00:00
Wayne Davison
077e59b769 The inplace handling in finish_transfer() now passes PERMS_SKIP_MTIME
to set_perms() if ok_to_set_time wasn't specified.
2004-07-22 15:30:04 +00:00
Wayne Davison
007e3c0e9a Need to output the "failed verification" error before sending the
MSG_REDO so that the output comes out in the right order.
2004-07-22 08:16:35 +00:00
Wayne Davison
e2bc412669 Added a warning message when a file fails to verify, letting the user
know if we retained it or discarded it.  Especially useful for batch-
reading mode where the old code could look like it did the update when
it really silently failed.
2004-07-22 04:15:18 +00:00
Wayne Davison
e344209582 Added even more double-quoting. 2004-07-22 03:23:04 +00:00
Wayne Davison
e76ca1458c No need to check both delete_after and delete_mode since the former
implies the latter.
2004-07-22 02:52:57 +00:00
Wayne Davison
16cc9ca2c9 In read_batch mode, we read ints from the new batch_gen_fd pipe and
only process the updates from the batch file when the generator has
indicated that it is ready (which ensures that all the necessary
dirs have been created).
2004-07-21 23:59:37 +00:00
Wayne Davison
8c90957ff5 Got rid of read_batch special case. 2004-07-21 23:59:33 +00:00
Wayne Davison
c0d8e84c9d Setup for read_batch mode a little differently:
- Avoid calling local_child().
- Create a pipe that lets the generator send us index values.
- Set batch_gen_fd for the receiver to read the pipe.
2004-07-21 23:59:31 +00:00
Wayne Davison
b0ad542928 Added batch_gen_fd. 2004-07-21 23:59:28 +00:00
Wayne Davison
727b35f665 In read_batch mode, we now let the code write out the index value
to the f_out pipe before we return from recv_generator().  This gives
the receiver something to sync with so that it doesn't rush ahead of
us (which could be bad if we didn't have a chance to create the
destination dirs yet).
2004-07-21 23:59:25 +00:00
Wayne Davison
aa4343211f Don't write out the protocol_version number in read_batch mode. 2004-07-21 23:59:22 +00:00
Wayne Davison
3611989355 Complain if the user combines --read-batch with --files-from. 2004-07-21 22:50:11 +00:00
Wayne Davison
3381b77d71 Improved the test a little. 2004-07-21 21:06:13 +00:00
Wayne Davison
dce70db374 Adding a test for the --compare-dest option. 2004-07-21 20:58:32 +00:00
Wayne Davison
2adbcdc7ea A couple am_sender checks (one negated) were not needed. 2004-07-21 20:17:02 +00:00
Wayne Davison
7e5fa372cf Call map_file() with the new block_size arg (had to delay the
call to map_file() until the block size was known).
2004-07-20 21:35:58 +00:00
Wayne Davison
6e45e1dd86 - Call map_file() with the new block_size arg (had to delay the
call to map_file() until the block size was known).
- Got rid of the setting of max_map_size.
2004-07-20 21:35:55 +00:00
Wayne Davison
7f290d5c82 - Added a new block_size arg to map_file(). Use it to set the
new def_window_size member variable.
- Got rid of max_map_size global (we use def_window_size now).
2004-07-20 21:35:52 +00:00
Wayne Davison
b6609cafae - Got rid of cleanup_buf (map-file cleanup is not needed).
- Renamed the cleanup_fd* vars.
2004-07-20 21:35:49 +00:00
Wayne Davison
efa95a1842 Call map_file() with its new block_size arg. 2004-07-20 21:35:46 +00:00
Wayne Davison
51bd4f0f3a Tweaked an error message. 2004-07-20 21:10:20 +00:00
Wayne Davison
562b61695e Added a def_window_size variable to struct map_struct. 2004-07-20 21:08:33 +00:00
Wayne Davison
98f51bfb56 - More batch-file improvements.
- A few spelling fixes.
2004-07-20 18:12:50 +00:00
Wayne Davison
73f0ce69e7 We now append the exclude list as a "here" document to the end of
the BATCH.sh file.
2004-07-20 17:07:55 +00:00
Wayne Davison
cf338ab1be Made write_sbuf() non-static. 2004-07-20 16:57:18 +00:00
Wayne Davison
66a9dc9639 Changed write_batch_argvs_file() to new write_batch_shell_file()
call (with extra arg).
2004-07-19 17:11:41 +00:00
Wayne Davison
8ed9d849dc Added new function discard_receive_data(). 2004-07-19 17:05:01 +00:00
Wayne Davison
5ebab6c10c - Don't allow some crafty user to try to force us to update a
server-excluded file.
- If get_tmpname() fails we need to discard the update using
  receive_data().
2004-07-19 16:37:30 +00:00
Wayne Davison
e7a69008e6 Do a better job of writing out the BATCH.sh file (i.e. quote special
characters and spaces in args, omit all the source args, omit the
include/exclude args if we can).
2004-07-19 08:27:17 +00:00
Wayne Davison
73e015683c Changed batch.rsync_argvs to batch.sh. 2004-07-19 03:59:35 +00:00
Wayne Davison
b462781fd0 Fixed the argv munging to work properly regardless of whether the
user specified a trailing '=VALUE' or put the value in a separate
arg.
2004-07-19 00:53:49 +00:00
Wayne Davison
93095cbe99 A very minor optimization was made to read_sbuf(), read_byte(),
write_sbuf(), and write_byte().
2004-07-17 21:17:34 +00:00
Wayne Davison
399371e7b5 - Improved the warning about --inplace.
- Fixed the sentence describing how to read standard input with
  --read-batch.
2004-07-17 16:44:16 +00:00
Wayne Davison
d7142e2328 Moved the read_batch abort check below the code that handles the
symlinks and devices.
2004-07-17 16:29:10 +00:00
Wayne Davison
1f75bb1066 Revamped some of the io variables and calls to make the various I/O
functions seemlessly work on fds that aren't for the main socket. This
involved changing some fd-variable names (to make them clearer), adding
io_set_sock_fds(), and making input buffering have a better enabled
flag (via an allocated buffer, just like the output buffering).  I also
got rid of the fd arg to some functions where the fd arg could only
specify the input or output fd for the socket (which we already know).
2004-07-17 15:20:00 +00:00
Wayne Davison
088adfacc1 Got rid of the arg to io_start_multiplex_out(). 2004-07-17 15:19:57 +00:00
Wayne Davison
da3478b2a7 - Got rid of the arg to the io_start_multiplex_{in,out}() calls.
- Call io_set_sock_fds().
2004-07-17 15:19:54 +00:00
Wayne Davison
5126ed1ef0 Changed a MIN() to a MAX() when setting max_map_size. 2004-07-17 10:59:14 +00:00
Wayne Davison
61fb21ad28 Mention the new --inplace option. 2004-07-17 00:00:27 +00:00
Wayne Davison
a3221d2ac1 My version of Mark Curtis's --inplace option. 2004-07-16 20:06:24 +00:00
Wayne Davison
2c713fcdfa Added a check for ftruncate. 2004-07-16 20:04:20 +00:00
Wayne Davison
afd8bdb907 Avoid some useless memory copying. 2004-07-16 18:08:52 +00:00
Wayne Davison
efd5ee5786 - Limit the maximum block size we compute for a file.
- Set max_map_size based on the current file's block size (so that
  map_ptr() is more efficient with large blocks).
2004-07-16 18:04:23 +00:00
Wayne Davison
510b4cd4d5 Added a max_map_size variable, initialized to MAX_MAP_SIZE. 2004-07-16 18:02:30 +00:00
Wayne Davison
de584c658c Limit the block-size that the user can specify. 2004-07-16 18:01:30 +00:00
Wayne Davison
6eb770bbcc Improved a sentence about --whole-file. 2004-07-16 17:14:55 +00:00
Wayne Davison
c7e11bfdc0 Make wf_writeBufSize based on a multiple of WRITE_SIZE instead
of the unrelated MAX_MAP_SIZE.
2004-07-16 01:32:02 +00:00
Wayne Davison
94327ff0c2 - Complain and die if --dry-run is used with a batch option.
- Improved the warning if a batch option gets sent to the server.
2004-07-15 19:06:32 +00:00
Wayne Davison
4602eafa87 Changed the batch examples to show how to do a remote read-batch
without first transferring the batch file.
2004-07-15 19:04:54 +00:00
Wayne Davison
bb3edc3b47 Expanded the comment on the new batch code. 2004-07-15 19:03:50 +00:00
Wayne Davison
c769702fe5 Mention that "-" can be used with --read-batch for reading from stdin. 2004-07-15 17:56:11 +00:00
Wayne Davison
dbbab0c4d2 Allow --read-batch=- to indicate stdin. 2004-07-15 17:01:51 +00:00
Wayne Davison
9b3318b0df We no longer refer to a batch "prefix". 2004-07-15 16:27:02 +00:00
Wayne Davison
0fac7fe8b8 Mention new batch-mode changes. 2004-07-15 03:13:09 +00:00
Wayne Davison
b9f592fbf5 My modified version of Chris Shoemaker's improved batch-file handling. 2004-07-15 02:20:08 +00:00
Wayne Davison
c7b1a56b3d Mention recent changes. 2004-07-14 17:11:53 +00:00
Wayne Davison
3896bca4d8 Tweaked some single-line ifs. 2004-07-14 16:41:10 +00:00
Wayne Davison
9774cc3344 The "len" to generate_and_send_sums() is supposed to be an OFF_T. 2004-07-14 16:40:08 +00:00
Wayne Davison
d3979b025d Committed a space-tweak from Chris Shoemaker. 2004-07-14 16:39:08 +00:00
Wayne Davison
01966df4f7 Improved the write_batch_argvs_file() routine so that it doesn't
need the character buffers and so that it properly removes the
hostname from the destination arg.
2004-07-14 07:20:18 +00:00
Wayne Davison
f38bd4a072 Got rid of the disable_deltas_p() function (the whole_file value
is now fully set before the generator forks).
2004-07-13 01:45:51 +00:00
Wayne Davison
b1df18d76f We now conditionally turn on whole_file in do_cmd() right before
calling local_child().
2004-07-13 01:44:03 +00:00
Wayne Davison
7daccb8e72 In generate_files(), changed arg "f" to "f_out", as Chris Shoemaker
suggested.
2004-07-12 20:42:48 +00:00
Wayne Davison
bb91a624f1 Made hard_link_check() compile when SUPPORT_HARD_LINKS isn't enabled. 2004-07-12 07:03:28 +00:00
Wayne Davison
a04d77bcbc Use want_i instead of last_i+1. 2004-07-07 08:38:40 +00:00
Wayne Davison
25bd99451c Make the GID_NONE define a little safer. 2004-07-07 08:25:13 +00:00
Wayne Davison
ed43d0a76d Added some missing $(srcdir) references. 2004-07-04 08:56:31 +00:00
Wayne Davison
066a844c4e Changed a "for" loop into a "do ... while" loop. 2004-07-04 08:07:23 +00:00
Wayne Davison
5e252dea4b Optimized away a loop in hash_search(). 2004-07-02 23:35:30 +00:00
Wayne Davison
d2a918b454 Some formatting tweaks. 2004-07-02 18:23:57 +00:00
Wayne Davison
da38e779ea Moved the verbose message about renaming the finished file down into
finish_transfer() so that it only gets output when we're actually going
to rename the file.
2004-07-02 18:13:53 +00:00
Wayne Davison
8186ae6bc0 Tweaked some formatting. 2004-07-02 18:12:24 +00:00
Wayne Davison
e1f67417d7 Some simple whitespace tweaks. 2004-06-30 07:27:30 +00:00
Wayne Davison
fd322eef82 Made recv_generator static. 2004-06-29 19:19:00 +00:00
Wayne Davison
d3a4375f78 Optimized away a call to cmp_modtime() for a compare-dest file. 2004-06-29 16:22:54 +00:00
Wayne Davison
78112d305b Mention the extended argv-overflow checking. 2004-06-29 15:13:18 +00:00
Wayne Davison
f7c3ee9932 Tweaked an overly-long line. 2004-06-29 15:12:01 +00:00
Wayne Davison
e7a392c77c A few more improvements to the anti-overflow args[] checking. 2004-06-28 17:45:40 +00:00
Wayne Davison
887e553f05 Make sure that do_cmd() doesn't overflow its arg-pointer array
(which was also made larger).
2004-06-28 17:25:14 +00:00
Wayne Davison
beb227ddf1 Got rid of a couple unneeded assignments. 2004-06-24 04:46:02 +00:00
Wayne Davison
84acca07ae Restoring correct skip_file() return semantics. 2004-06-23 21:21:19 +00:00
Wayne Davison
cc1e997dcd Thought skip_file() wasn't returning 1 for "skip" and 0 or "keep"
so I reversed the return.
2004-06-23 16:51:21 +00:00
Wayne Davison
a7026ba90a Fixed a newly-introduced problem in read_timeout() where FD_ZERO(&w_fds)
wasn't always called before w_fds was used.
2004-06-23 01:13:09 +00:00
Wayne Davison
3a69fad0f6 Some trivial format tweaks. 2004-06-20 21:48:06 +00:00
Wayne Davison
40564811ee Mentioned the latest socket change and fixed a few typos. 2004-06-20 20:37:06 +00:00
Wayne Davison
dcd08dc51c Restored the code in the IPV6_V6ONLY section that checks the
return value from setsockopt() with one improvement:  if the
user has used --ipv6 (-6) we don't discard the IPv6 socket.
This should help people using older Linux kernels that don't
implement IPv6 support quite right.
2004-06-20 19:51:19 +00:00
Wayne Davison
fdf57ede8c Tweaked a comment. 2004-06-20 19:47:05 +00:00
Wayne Davison
bd717af8ab Must not call check_timeout() before checking the errno value. 2004-06-19 07:09:57 +00:00
Wayne Davison
c54f5170bf Added some missing changes. 2004-06-19 06:55:58 +00:00
Wayne Davison
eae4e1f9f0 Some minor improved sentences. 2004-06-19 05:52:45 +00:00
Wayne Davison
9c513d678d Tweaked some comments. 2004-06-18 16:55:12 +00:00
Wayne Davison
d16c245fc4 Some helpful comments from Chris Shoemaker. 2004-06-18 16:50:20 +00:00
Wayne Davison
ec8290c897 Fixed some typos in a comment, moved an extern, and made a few
minor format tweaks.
2004-06-18 16:30:24 +00:00
Wayne Davison
b293a7f62c Improved a comment. 2004-06-18 16:29:21 +00:00
Wayne Davison
d67c8bdfc3 Moved the externs to the top and made a few trivial format tweaks. 2004-06-18 16:22:14 +00:00
Wayne Davison
e2ccd3578c Got rid of some trailing whitespace. 2004-06-18 16:00:33 +00:00
Wayne Davison
4e834af140 If --partial was specified, make sure that make_backup is turned
off during the second (retry) phase of the transfer to avoid
making a second backup of a file (which would lose the original).
2004-06-14 15:09:36 +00:00
Wayne Davison
7e5614383d Added a short msleep() after option_error() before we exit. This
ensures that the remote client has time to read our error message
while it is trying to write data to us before it gets a socket
error.
2004-06-13 14:18:48 +00:00
Wayne Davison
eb84a83b47 Changed the new code in delete_one() so that some compilers
don't complain about returning a value from a void function.
2004-06-12 21:30:07 +00:00
Wayne Davison
2c2898a388 Mention the bugfix in option-parsing error-reporting from a daemon. 2004-06-12 18:27:04 +00:00
Wayne Davison
1732b6c037 - Changed some FERROR log calls to FLOG.
- Improved the option-error-reporting to actually get the error back
  to the user (by getting I/O multiplexing started).
2004-06-12 18:22:39 +00:00
Wayne Davison
314f459161 - Made readlink_stat() and link_stat() optionally follow a symlink
to a dir.  This fixes deletions inside "kept" symlinked dirs.
- Call link_stat() with its new arg (for --keep-dirlinks support).
2004-06-11 07:40:57 +00:00
Wayne Davison
83926d3cae Make sure that keep_dirlinks is turned off for the sender. 2004-06-11 07:40:54 +00:00
Wayne Davison
6218c7bf42 - Moved --keep-dirlinks code over to flist.c.
- Call link_stat() with its new arg (for --keep-dirlinks support).
2004-06-11 07:40:51 +00:00
Wayne Davison
566fce3237 Made delete_one() handle a failed rmdir on a symlink when
--keep-dirlinks was specified.
2004-06-11 07:40:48 +00:00
Wayne Davison
373ef16010 Call link_stat() with its new arg (for --keep-dirlinks support). 2004-06-11 07:40:45 +00:00
Wayne Davison
ea76e76104 In set_filesystem(), call do_stat(), not link_stat() to ensure
that we get the directory behind it all.
2004-06-11 05:02:59 +00:00
Wayne Davison
9fd62d1588 The mkdir code should be using do_stat(), not do_lstat() to copy
each existing dir's mode & owner info.
2004-06-10 16:43:52 +00:00
Wayne Davison
b7061c82b4 Allow the argv list the daemon uses for globbing its args to grow. 2004-06-09 21:51:07 +00:00
Wayne Davison
6fb812f747 Removed some excessive parens. 2004-06-09 21:43:28 +00:00
Wayne Davison
40e8d11e64 Mentioned a couple more bugfixes. 2004-06-09 21:42:33 +00:00
Wayne Davison
73042aae5b Restore UNUSED() macro (the prior problems that prompted me to remove
it appear to have been a build-farm bug).
2004-06-09 21:41:21 +00:00
Wayne Davison
e5ce3bcf2c Needed to enclose the new symlink-warning code in an
"#if SUPPORT_LINKS" conditional.
2004-06-09 19:23:56 +00:00
Wayne Davison
c399d22a19 Renamed read_unbuffered() to readfd_unbuffered() so that it matches
writefd_unbuffered().
2004-06-09 03:07:50 +00:00
Wayne Davison
1ea087a794 - Made the maximum-fd computation prior to a select() use the same idiom
in both the read and write code (also use a better variable name).
- Made the bytes-available code at the end of the select() loop use the
  same flow of control in the read and the write code.
2004-06-08 22:18:04 +00:00
Wayne Davison
00bdf89977 Improved a comment in read_msg_fd() and made the byte-reading code
in read_timeout() a little better.
2004-06-08 16:23:54 +00:00
Wayne Davison
0bb4d17634 Improved rwrite() in two ways:
- We no longer assume that the buffer is null terminated (daemon
  mode would ignore the len when logging a message).
- Errors in daemon mode are now sent to both the log and the user.
2004-06-07 22:51:14 +00:00
Wayne Davison
f9c6b3e7d6 Increase the size of the message-receving buffer for error
messages sent from the receiver to the generator.
2004-06-07 22:47:01 +00:00
Wayne Davison
9e5a5ddb4c Changed a few FINFO messages to FLOG. 2004-06-07 22:33:01 +00:00
Wayne Davison
8c0d6a8432 Got rid of some am_daemon games in option_error(). 2004-06-07 22:05:22 +00:00
Wayne Davison
553f93758a Updated some exclude information that has changed. 2004-06-07 21:40:11 +00:00
Wayne Davison
a4a7e64c19 Don't report a "file vanished" error if a symlink points to nowhere
and -L was specified.
2004-06-07 19:59:20 +00:00
Wayne Davison
22832c30a0 Updated a couple things. 2004-06-06 20:41:01 +00:00
Wayne Davison
1a21666286 Tell folks to go to the bug-tracking page to report bugs. 2004-06-06 20:36:56 +00:00
Wayne Davison
4033b80b51 - Got rid of some useless calls to msg_list_push().
- Added a couple checks to ensure that the receiver doesn't mix two
  clashing kinds of writes on the msg_fd_out pipe.
- Made sure that the read code in the receiver flushes the msg_fd_out
  pipe, if needed.
2004-06-06 19:15:58 +00:00
Wayne Davison
99218d821b If the user specifies a small io_timeout value, lower select_timeout. 2004-06-06 19:02:40 +00:00
Wayne Davison
e626b29e10 Make sure our select calls don't sleep for over one minute at a time,
even when io_timeout is a longer value (though the code in options.c
might set it to a shorter value if io_timeout is small).
2004-06-06 19:02:09 +00:00
Wayne Davison
f89b936801 Don't use single-line "if (condition) statement;" idiom. 2004-06-06 18:36:22 +00:00
Wayne Davison
17f59e818d Mention changes to the patches dir. 2004-06-05 21:23:59 +00:00
Wayne Davison
b5bd5542eb Neatened up some of the glob-expand code and made a few other
minor tweaks.
2004-06-05 20:26:56 +00:00
Wayne Davison
2e94e70e2b Some superficial code tweaks. 2004-06-05 19:59:03 +00:00
Wayne Davison
4e1f385711 Mentioned new --keep-dirlinks option. 2004-06-05 16:19:02 +00:00
Wayne Davison
716e73d483 New --keep-dirlinks option. 2004-06-05 16:16:30 +00:00
Wayne Davison
5b36173d11 Mention new SSH_* vars. 2004-06-03 17:20:33 +00:00
Wayne Davison
b2ef4f6134 The daemon-over-ssh code now looks for $SSH_CONNECTION and $SSH2_CLIENT
as well as $SSH_CLIENT to figure out the remote IP address.
2004-06-03 17:20:21 +00:00
Wayne Davison
c7be6dec11 - Added older news from NEWS file.
- Added missing releases from the Partial Protocol History section.
2004-06-01 21:27:52 +00:00
Wayne Davison
bd1574b208 Moved older news to OLDNEWS. 2004-06-01 21:27:12 +00:00
Wayne Davison
f376e67420 Got rid of an unneeded character pointer in send_file_entry(). 2004-05-29 21:21:17 +00:00
Wayne Davison
ef0bc0abff Mention the --bwlimit change. 2004-05-28 19:42:06 +00:00
Wayne Davison
71e586304b Improvements to make --bwlimit work better. 2004-05-27 22:09:31 +00:00
Wayne Davison
3c74c3a358 Set a new variable, bwlimit_writemax, based on the value of the bwlimit
option.
2004-05-27 21:51:53 +00:00
Wayne Davison
edad5898f2 Got rid of a superfluous call to gettimeofday(). 2004-05-24 22:59:16 +00:00
Wayne Davison
fa0c1939ed The various include/exclude options are not used on the server side,
so if someone is trying something funny, just quit.
2004-05-24 18:38:05 +00:00
Wayne Davison
9a5ade185c Made full_fname()'s char-pointer arg const. 2004-05-24 08:10:22 +00:00
Wayne Davison
f1dd0f27cb - Properly quote the $excl references.
- Moved the creation of our .cvsignore exclude file.
2004-05-24 00:16:07 +00:00
Wayne Davison
f9e5a0cde2 Improved the depth calculation in sanitize_path() so that it properly
handles a trailing slash, a leading slash, and an empty string.
2004-05-23 23:46:56 +00:00
Wayne Davison
ead751c62b Moved a couple lines. 2004-05-22 19:29:53 +00:00
Wayne Davison
0058c58edd A few minor improvements to the existing items. 2004-05-22 19:24:24 +00:00
Wayne Davison
221ddb9456 Fixed a typo in the sending of the --checksum-seed option to the server. 2004-05-22 06:09:22 +00:00
Wayne Davison
65e2487096 Fixed the comment for get_exclude_tok(). 2004-05-22 05:32:20 +00:00
Wayne Davison
0501f36390 Tweaked the alloc/realloc code in flist_expand(). 2004-05-21 23:22:14 +00:00
Wayne Davison
96981b9cff Tell rsync to preserve permissions. 2004-05-21 10:06:09 +00:00
Wayne Davison
f51e87f5ad Another new option. 2004-05-21 10:00:21 +00:00
Wayne Davison
cb213f1c1b Got rid of a compiler warning (which was only output by certain
compilers).
2004-05-21 09:59:49 +00:00
Wayne Davison
c8d895de26 Added the --checksum-seed option. 2004-05-21 09:44:32 +00:00
Wayne Davison
e51094b721 - Improved option_error() to make sure that the user sees the error in
daemon mode.
- Got rid of some repetitious outputting of the same error-message.
2004-05-21 09:41:38 +00:00
Wayne Davison
b03bded70b Document a couple more changes. 2004-05-21 09:29:17 +00:00
Wayne Davison
ee1df1ccae If --backup was specified without a --backup-dir, don't preserve the
directory timestamps.
2004-05-21 08:43:03 +00:00
Wayne Davison
bc6ebcd248 Moved a few externs. 2004-05-21 08:40:25 +00:00
Wayne Davison
ba582f753a Changed sum_init() to take a seed value as an arg instead of always
using checksum_init.  This fixes an authentication problem in server
mode (as pointed out by Craig Barratt).
2004-05-21 08:27:04 +00:00
Wayne Davison
cbd85b472e - Mention the change to the daemon-mode's exclude handling.
- Mention the new "write only" daemon-config option.
- Fixed another entry to refer to the right files.
2004-05-19 22:20:56 +00:00
Wayne Davison
7a92ded39a Added the "write only" option to the daemon config file. 2004-05-19 22:19:19 +00:00
Wayne Davison
831f05df51 A few minor text improvements. 2004-05-18 09:54:52 +00:00
Wayne Davison
0d94a6a66c Added a little more quoting. 2004-05-18 09:47:42 +00:00
Wayne Davison
3e35c34b6b Output a message when we skip a server-excluded file. 2004-05-18 08:50:17 +00:00
Wayne Davison
03a9ca0a97 Document the latest changes. 2004-05-18 01:13:14 +00:00
Wayne Davison
6f481bb0e0 - Use fromdir, todir, and tmpdir instead of FROM, TO, and TMP.
- Added chkdir.
- Quote the dir expansions to avoid problems with spaces.
- Added "exclude = foobar.baz" the the rsync.conf file we create.
2004-05-18 00:41:55 +00:00
Wayne Davison
f98cc5685d Test that a config-file-specified exclude works right. 2004-05-18 00:41:51 +00:00
Wayne Davison
9135621ff9 Quote the dir expansions to avoid problems with spaces. 2004-05-18 00:41:49 +00:00
Wayne Davison
8624daa7f8 - Use fromdir and todir instead of FROM and TO.
- Quote the dir expansions to avoid problems with spaces.
2004-05-18 00:41:46 +00:00
Wayne Davison
3051c46dc3 - Use $suitedir to find rsync.fns.
- Use tmpdir instead of TMP.
2004-05-18 00:41:43 +00:00
Wayne Davison
e920830ec5 Use $suitedir to find rsync.fns. 2004-05-18 00:41:40 +00:00
Wayne Davison
7892e5ac77 - Use $suitedir to find rsync.fns.
- The values of fromdir, todir, and chkdir are already set.
2004-05-18 00:41:38 +00:00
Wayne Davison
b0e9bafc78 - Use $suitedir to find rsync.fns.
- The values of fromdir and todir are already set.
2004-05-18 00:41:35 +00:00
Wayne Davison
44aa070770 Removing obsoleted test.sh file (we used the runtests.sh framework for
some time now).
2004-05-18 00:32:36 +00:00
Wayne Davison
97f9dcae6a If the server has excluded a file, we now exclude it from being
uploaded as well as downloaded.
2004-05-18 00:14:10 +00:00
Wayne Davison
8cbf495a57 Renamed free_exclude_list() to clear_exclude_list(). 2004-05-16 23:54:12 +00:00
Wayne Davison
c1b29492c5 Moved the setting of ret->match_flags up a little in make_exclude(). 2004-05-16 14:08:34 +00:00
Wayne Davison
669a31924e - Save some memory in each exclude_struct item by dumping the "include"
and "directory" ints and using bits in the match_flags value instead.
- Added defines for the new match-flag values, including a new one that
  lets get_exclude_tok() properly return an indication that it parsed
  the list-clearing token.
2004-05-16 07:28:24 +00:00
Wayne Davison
5e972dcf34 - Switched the "include" and "directory" ints into bits in match_flags.
- Made some length vars unsigned.
2004-05-16 07:28:21 +00:00
Wayne Davison
8fcdc444df - Improved rsyserr() to prefix RSYNC_NAME (as the TODO requested),
to construct the string in a better manner, and to have a buffer
  big enough to hold a full MAXPATHLEN filename plus some error
  text.
- Fixed some comments referring to vsprintf() returning -1 -- our
  configuration process now ensures that we replace such a function
  with our own lib version.
2004-05-15 19:31:16 +00:00
Wayne Davison
619d21ffc9 - Complain about an exclude that was too long and then dump it
(used to be silently truncated).
- Include extra space in our exclude-reading buffers so that we
  can fit a 2-char prefix and a trailing slash and still handle
  a MAXPATHLEN name.
2004-05-15 19:31:13 +00:00
Wayne Davison
d62bcc17f3 Changed rprintf() calls that included strerror() to use rsyserr(). 2004-05-15 19:31:10 +00:00
Wayne Davison
982e05bbd5 Changed rprintf() calls that included strerror() to use rsyserr(). 2004-05-15 19:31:10 +00:00
Wayne Davison
a3c8b36863 Added rsyserr(). 2004-05-15 19:31:05 +00:00
Wayne Davison
630e3c408b Whitespace tweaks. 2004-05-15 19:09:42 +00:00
Wayne Davison
1082b52bd4 Changing if (!write_batch) in front of send_exclude_list() to
if (!read_batch) -- fixes hang.
2004-05-15 18:51:21 +00:00
Wayne Davison
914f3066bb Added a "gen" rule to remake various generated files: configure,
config.h.in, proto.h, rsync.1, and rsyncd.conf.5 .
2004-05-15 00:48:11 +00:00
Wayne Davison
de91e75724 In the debug output, distinguish between a user-requested clearing
of the exclude list and the popping of the local exclude list that
occurs when we finish each subdir.
2004-05-14 21:23:41 +00:00
Wayne Davison
384431886a Changed PERMS_SKIP_TIME to PERMS_SKIP_MTIME. 2004-05-13 18:51:22 +00:00
Wayne Davison
82b302d928 Got rid of some useless externs. 2004-05-13 18:41:17 +00:00
Wayne Davison
4ecc9e6b64 The finish_transfer() call takes an arg that specifies if we should set the
modtime or not on the finished file.  It calls set_perms(), which now takes a
flag arg that allows us to specify if we want to skip the modtime modification.
2004-05-13 07:08:25 +00:00
Wayne Davison
55e50d890b If the file did not transfer correctly, only save it if --partial was
specified.  We also skip the setting of the modtime too on a partial
copy (that way the partial file won't be confused with an up-to-date
copy of the original).
2004-05-13 07:08:22 +00:00
Wayne Davison
6e86c951d7 Call finish_transfer() with its new arg. Also put the externs
at the top and got rid of some trailing whitespace.
2004-05-13 07:08:18 +00:00
Wayne Davison
c41b52c487 Use the new PERMS_REPORT flag when calling set_perms(). 2004-05-13 06:55:01 +00:00
Wayne Davison
5c6fc4a6a3 Added PERMS_REPORT and PERMS_SKIP_TIME. 2004-05-13 06:53:23 +00:00
Wayne Davison
edecdad54d If we got a read-error on a file, make sure that the whole-file
checksum we send to the receiver is wrong (so they won't save
the bogus file).
2004-05-13 06:46:20 +00:00
Wayne Davison
5291364f1d Don't force the modtime on our backup dirs -- the dirs in the
backup hierarchy should have their own timestamps.
2004-05-13 06:34:03 +00:00
Wayne Davison
41cc97ae64 In send_files(), changed the name of the map_struct variable from
"buf" to "mbuf" (so that it wouldn't be so similar to the "buff"
variable nor use a name that is more typically a char* buffer).
2004-05-11 19:53:16 +00:00
Wayne Davison
bf2b7ddfc5 Use memset() to initialize a new map_struct. 2004-05-11 19:46:56 +00:00
Wayne Davison
eb0cbdaa90 Got rid of an unused extern. 2004-05-11 17:25:16 +00:00
Wayne Davison
0d0142e812 Got rid of unused externs. 2004-05-11 17:25:01 +00:00
Wayne Davison
a43e21e05c Let's just remove all the UNUSED() macros for now. 2004-05-08 22:49:58 +00:00
Wayne Davison
4135d091a6 Changed the non-globbing version of glob_expand_one() so that it
checks the maxargs argument instead of leaving it unused.
2004-05-08 20:03:39 +00:00
Wayne Davison
534407b1f4 One more attempt to get HP-UX's cc to build popt successfully. 2004-05-08 19:50:22 +00:00
Wayne Davison
18cc8c7ef1 Improved a comment and got rid of some trailing whitespace. 2004-05-08 19:37:28 +00:00
Wayne Davison
58c9b4b7f6 Tweaked the sizeof syntax and some multi-statement lines. 2004-05-08 19:26:53 +00:00
Wayne Davison
cde719f49f Changed the order of the msgcode enum so that new items now get added
at the start (which avoids the need for trailing-comma changes on old
entries when new ones are added).
2004-05-08 18:48:09 +00:00
Wayne Davison
38cab94d9a - Improved the get_secret()'s function comments, made it accept a line
that doesn't end with a newline, and optimized it a bit.
- Improved getpassf() to work if the line does not end with a newline.
2004-05-08 18:18:42 +00:00
Wayne Davison
6ed6d7f5a8 Improved the function comments for read_line() and slightly tweaked
its code.  Also changed "IO" to "I/O" in various comments.
2004-05-08 18:03:43 +00:00
Wayne Davison
e40a46de71 Document the -4, -6, --ipv4, --ipv6 options. 2004-05-07 00:18:37 +00:00
Wayne Davison
c5bf99a1c2 Correct a typo. 2004-05-06 21:29:36 +00:00
Wayne Davison
2c7d63c765 - Updated the comments for open_socket_in().
- Changed open_socket_in() to return an array of ints with a trailing -1
  value to indicate the end of the list.
- Use the out_of_memory() routine to complain about no memory.
- Undid the recent IPV6_V6ONLY change, as I think it would prevent the
  use of IPv6 sockets on some older systems.
- If we get an EADDRINUSE error and this is not the first socket in the
  list, suggest that the user try --ipv4 or --ipv6.
- When forking, the child now closes all the open bound sockets, not just
  one of them (I'm not talking about the fd from accept(), obviously).
2004-05-06 21:26:46 +00:00
Wayne Davison
3dd22903ac Introduced long-option names for -4 and -6. 2004-05-06 21:08:01 +00:00
Wayne Davison
d8d36af452 If we need to set IPV6_V6ONLY but setsockopt() fails, close the
socket and skip it.
2004-05-05 22:17:48 +00:00
Wayne Davison
e610e50f9c Added missing extern for read_batch. 2004-05-05 17:15:03 +00:00
Wayne Davison
935c64173f Don't force the whole-file option when using read-batch. 2004-05-05 16:23:49 +00:00
Wayne Davison
377dbd2075 Calls to make_bak_dir() should only happen when we fail to create a
file/dir/etc. with errno == ENOENT.
2004-05-04 03:10:45 +00:00
Wayne Davison
93272700d2 A slight refinement to my last patch. 2004-05-03 01:24:10 +00:00
Wayne Davison
d508258ad8 Fixed crash bug that can affect --delete in certain circumstances. 2004-05-03 01:18:07 +00:00
Wayne Davison
f57b2e6150 Got rid of a TODO comment that was fixed long ago. 2004-05-02 17:04:14 +00:00
Wayne Davison
af45f9e27e Renamed variable STRIP to INSTALL_STRIP to avoid an accidental match
with an environment variable in OpenBSD.
2004-05-02 16:52:52 +00:00
Wayne Davison
4c4d61b046 Got rid of trailing comma in an enum. 2004-05-02 16:34:33 +00:00
Wayne Davison
7561c3e132 Moved some news items under new headings. 2004-04-30 21:10:58 +00:00
Wayne Davison
1514ad2a80 Changed the order that ssh and rsh are mentioned. 2004-04-30 20:39:29 +00:00
Wayne Davison
d8195637d4 Additional testing confirmed the limited scope of the sources affected
by the -R sorting bug.
2004-04-30 19:14:52 +00:00
Wayne Davison
c8d771a0fb Preparing for release of 2.6.2 2004-04-30 18:03:33 +00:00
Wayne Davison
9130776c4e Mention the last few tweaks that made it into 2.6.2. 2004-04-30 17:53:51 +00:00
Wayne Davison
9eac94a4dd Improved the program that checks for broken large-file locking. 2004-04-30 17:38:22 +00:00
Wayne Davison
6e06d2f31a Don't rely on the local shell's wildcard expansion to make the test
work right -- it might not be quite as compatible as we need.
2004-04-30 17:24:49 +00:00
Wayne Davison
6a6d21136a Only refer to AI_NUMERICHOST if it is defined. 2004-04-30 16:10:45 +00:00
Wayne Davison
f28bd83346 Fixed a few typos. 2004-04-30 15:46:41 +00:00
Wayne Davison
96fb478eae Mention the desire to improve how a daemon returns errors. 2004-04-29 21:12:46 +00:00
Wayne Davison
8752b3fcd8 Describe the changes for 2.6.2. 2004-04-29 21:09:33 +00:00
Wayne Davison
55ffed7e42 Preparing for release of 2.6.2pre1 2004-04-29 20:36:22 +00:00
Wayne Davison
e00df64bae Got rid of unused check for sys/sysctl.h. 2004-04-29 19:40:17 +00:00
Wayne Davison
080ddf58ae Fixed a sorting problem when an entry has an empty (but not NULL)
dirname (which I had thought impossible, but it appears to occur
with --relative in some instances).
2004-04-29 19:37:15 +00:00
Wayne Davison
4ce48a5bfd Restore old behavior of logging most daemon errors instead of sending
them to the user.  This should eventually be improved to duplicate
some of these messages to the user to keep them informed about what
went wrong.
2004-04-29 19:34:31 +00:00
Wayne Davison
20bf7f847f Undefined __attribute__ in some circumstances. 2004-04-28 17:35:08 +00:00
Wayne Davison
b66d00853b Fixed the use of an uninitialized variable in map_uid() and map_gid(). 2004-04-28 17:31:31 +00:00
Wayne Davison
8b602edda4 In copy_file(), check len < 0 before checking the close() return values. 2004-04-27 19:59:37 +00:00
Wayne Davison
9f27cd8ca6 Check the return code from close() and output an error if it
fails.
2004-04-27 19:51:33 +00:00
71 changed files with 3898 additions and 2874 deletions

View File

@@ -21,3 +21,4 @@ tls
trimslash
t_unsafe
wildtest
getfsdev

View File

@@ -44,11 +44,11 @@ OBJS=$(OBJS1) $(OBJS2) $(OBJS3) $(DAEMON_OBJ) $(LIBOBJ) $(ZLIBOBJ) @BUILD_POPT@
TLS_OBJ = tls.o syscall.o lib/permstring.o
# Programs we must have to run the test cases
CHECK_PROGS = rsync$(EXEEXT) tls$(EXEEXT) getgroups$(EXEEXT) \
CHECK_PROGS = rsync$(EXEEXT) tls$(EXEEXT) getgroups$(EXEEXT) getfsdev$(EXEEXT) \
trimslash$(EXEEXT) t_unsafe$(EXEEXT) wildtest$(EXEEXT)
# Objects for CHECK_PROGS to clean
CHECK_OBJS=getgroups.o t_stub.o t_unsafe.o trimslash.o wildtest.o
CHECK_OBJS=getgroups.o getfsdev.o t_stub.o t_unsafe.o trimslash.o wildtest.o
# note that the -I. is needed to handle config.h when using VPATH
.c.o:
@@ -58,18 +58,16 @@ CHECK_OBJS=getgroups.o t_stub.o t_unsafe.o trimslash.o wildtest.o
all: rsync$(EXEEXT)
man: rsync.1 rsyncd.conf.5
install: all
-mkdir -p ${DESTDIR}${bindir}
${INSTALLCMD} ${STRIP} -m 755 rsync$(EXEEXT) ${DESTDIR}${bindir}
${INSTALLCMD} ${INSTALL_STRIP} -m 755 rsync$(EXEEXT) ${DESTDIR}${bindir}
-mkdir -p ${DESTDIR}${mandir}/man1
-mkdir -p ${DESTDIR}${mandir}/man5
${INSTALLMAN} -m 644 $(srcdir)/rsync.1 ${DESTDIR}${mandir}/man1
${INSTALLMAN} -m 644 $(srcdir)/rsyncd.conf.5 ${DESTDIR}${mandir}/man5
install-strip:
$(MAKE) STRIP='-s' install
$(MAKE) INSTALL_STRIP='-s' install
rsync$(EXEEXT): $(OBJS)
$(CC) $(CFLAGS) $(LDFLAGS) -o $@ $(OBJS) $(LIBS)
@@ -82,6 +80,9 @@ tls$(EXEEXT): $(TLS_OBJ)
getgroups$(EXEEXT): getgroups.o
$(CC) $(CFLAGS) $(LDFLAGS) -o $@ getgroups.o $(LIBS)
getfsdev$(EXEEXT): getfsdev.o
$(CC) $(CFLAGS) $(LDFLAGS) -o $@ getfsdev.o $(LIBS)
TRIMSLASH_OBJ = trimslash.o syscall.o
trimslash$(EXEEXT): $(TRIMSLASH_OBJ)
$(CC) $(CFLAGS) $(LDFLAGS) -o $@ $(TRIMSLASH_OBJ) $(LIBS)
@@ -90,17 +91,15 @@ T_UNSAFE_OBJ = t_unsafe.o syscall.o util.o t_stub.o lib/compat.o lib/snprintf.o
t_unsafe$(EXEEXT): $(T_UNSAFE_OBJ)
$(CC) $(CFLAGS) $(LDFLAGS) -o $@ $(T_UNSAFE_OBJ) $(LIBS)
# I don't like these rules because CVS can skew the timestamps and
# produce spurious warnings, and also make "make install" fail if the
# source directory can no longer be found. Since we don't rebuild
# automatically they're kind of lame anyhow.
gen: $(srcdir)/configure $(srcdir)/config.h.in proto man
#Makefile: Makefile.in configure config.status
# echo "WARNING: You need to run ./config.status --recheck"
man: $(srcdir)/rsync.1 $(srcdir)/rsyncd.conf.5
# don't actually run autoconf, just issue a warning
#configure: configure.in
# echo "WARNING: you need to rerun autoconf"
$(srcdir)/configure: $(srcdir)/configure.in $(srcdir)/aclocal.m4
cd $(srcdir); autoconf
$(srcdir)/config.h.in: $(srcdir)/configure.in $(srcdir)/aclocal.m4
cd $(srcdir); autoheader
$(srcdir)/rsync.1: $(srcdir)/rsync.yo
yodl2man -o $(srcdir)/rsync.1 $(srcdir)/rsync.yo
@@ -109,7 +108,12 @@ $(srcdir)/rsyncd.conf.5: $(srcdir)/rsyncd.conf.yo
yodl2man -o $(srcdir)/rsyncd.conf.5 $(srcdir)/rsyncd.conf.yo
proto:
cat $(srcdir)/*.c $(srcdir)/lib/compat.c | awk -f $(srcdir)/mkproto.awk > $(srcdir)/proto.h
cat $(srcdir)/*.c $(srcdir)/lib/compat.c | awk -f $(srcdir)/mkproto.awk >$(srcdir)/proto.h.new
if diff $(srcdir)/proto.h $(srcdir)/proto.h.new >/dev/null; then \
rm $(srcdir)/proto.h.new; \
else \
mv $(srcdir)/proto.h.new $(srcdir)/proto.h; \
fi
clean: cleantests
rm -f *~ $(OBJS) $(TLS_OBJ) $(CHECK_PROGS) $(CHECK_OBJS)
@@ -146,9 +150,6 @@ test: check
# There seems to be no standard way to specify some variables as
# exported from a Makefile apart from listing them like this.
# TODO: Tests that depend on built test aide programs like tls need to
# know where the build directory is.
# This depends on building rsync; if we need any helper programs it
# should depend on them too.

350
NEWS
View File

@@ -1,190 +1,252 @@
NEWS for rsync 2.6.1 (26 Apr 2004)
Protocol: 28 (changed)
Changes since 2.6.0:
NEWS for rsync 2.6.3 (30 Sep 2004)
Protocol: 28 (unchanged)
Changes since 2.6.2:
SECURITY FIXES:
- Paths sent to an rsync daemon are more thoroughly sanitized when
chroot is not used. If you're running a non-read-only rsync
daemon with chroot disabled, *please upgrade*, ESPECIALLY if the
user privs you run rsync under is anything above "nobody".
- A bug in the sanitize_path routine (which affects a non-chrooted
rsync daemon) could allow a user to craft a pathname that would get
transformed into an absolute path for certain options (but not for
file-transfer names). If you're running an rsync daemon with chroot
disabled, *please upgrade*, ESPECIALLY if the user privs you run
rsync under is anything above "nobody".
ENHANCEMENTS:
OUTPUT CHANGES (ATTN: those using a script to parse the verbose output):
- Lower memory use, more optimal transfer of data over the socket,
and lower CPU usage (see the INTERNAL section for details).
- Please note that the 2-line footer (output when verbose) now uses the
term "sent" instead of "wrote" and "received" instead of "read". If
you are not parsing the numeric values out of this footer, a script
would be better off using the empty line prior to the footer as the
indicator that the verbose output is over.
- The output from the --stats option was similarly affected to change
"written" to "sent" and "read" to "received".
- The RSYNC_PROXY environment variable can now contain a
"USER:PASS@" prefix before the "HOST:PORT" information.
(Bardur Arantsson)
- Rsync ensures that a filename that contains a newline gets mentioned
with each newline transformed into a question mark (which prevents a
filename from causing an empty line to be output).
- The --progress output now mentions how far along in the transfer
we are, including both a count of files transferred and a
percentage of the total file-count that we've processed. It also
shows better current-rate-of-transfer and remaining-transfer-time
values.
- The configure script now accepts --with-rsyncd-conf=PATH to
override the default value of the /etc/rsyncd.conf file.
- Added a couple extra diffs in the "patches" dir, removed the ones
that got applied, and rebuilt the rest.
- Documentation changes now attempt to describe some often mis-
understood features more clearly.
- The "backed up ..." message that is output when at least 2 --verbose
options are specified is now the same both with and without the
--backup-dir option.
BUG FIXES:
- When -x (--one-file-system) is combined with -L (--copy-links) or
--copy-unsafe-links, no symlinked files are skipped, even if the
referent file is on a different filesystem.
- Fixed a crash bug that might appear when --delete was used and
multiple source directories were specified.
- The --link-dest code now works properly for a non-root user when
(1) the UIDs of the source and destination differ and -o was
specified, or (2) when the group of the source can't be used on
the destination and -g was specified.
- Fixed a 32-bit truncation of the file length when generating the
checksums.
- Fixed a bug in the handling of -H (hard-links) that might cause
the expanded PATH/NAME value of the current item to get
overwritten (due to an expanded-name caching bug).
- We now reset the "new data has been sent" flag at the start of
each file we send. This makes sure that an interrupted transfer
with the --partial option set doesn't keep a shorter temp file
than the current basis file when no new data has been transfered
over the wire for that file.
- The --backup code no longer attempts to create some directories
over and over again (generating warnings along the way).
- Fixed a byte-order problem in --batch-mode on big-endian machines.
(Jay Fenlason)
- Fixed a bug in the reading of the secrets file (by the daemon) and
the password file (by the client): the files no longer need to be
terminated by a newline for their content to be read in.
- Fixed configure bug when running "./configure --disable-ipv6".
- If a file has a read error on the sending side or the reconstructed
data doesn't match the expected checksum (perhaps due to the basis
file changing during the transfer), the receiver will no longer
retain the resulting file unless the --partial option was specified.
(Note: for the read-error detection to work, neither side can be
older than 2.6.3 -- older receivers will always retain the file, and
older senders don't tell the receiver that the file had a read
error.)
- Fixed "make test" bug when build dir is not the source dir.
- If a file gets resent in a single transfer and the --backup option
is enabled, rsync no longer performs a duplicate backup (it used to
overwrite the original file in the backup area).
- When using --cvs-exclude, the exclude items we get from a
per-directory's .cvsignore file once again only affect that one
directory (not all following directories too). The items are also
now properly word-split and parsed without any +/- prefix parsing.
- Files specified in the daemon's "exclude" or "exclude from" config
items are now excluded from being uploaded (assuming that the module
allows uploading at all) in addition to the old download exclusion.
- When specifying the USER@HOST: prefix for a file, the USER part
can now contain an '@', if needed (i.e. the last '@' is used to
find the HOST, not the first).
- Got rid of a potential hang in the receiver when near the end of a
phase.
- Fixed some bugs in the handling of group IDs for non-root users:
(1) It properly handles a group that the sender didn't have a name
for (it would previously skip changing the group on any files in
that group). (2) If --numeric-ids is used, rsync no longer
attempts to set groups that the user doesn't have the permission
to set.
- When using --backup without a --backup-dir, rsync no longer preserves
the modify time on directories. This avoids confusing NFS.
- Fixed the "refuse options" setting in the rsyncd.conf file.
- When --copy-links (-L) is specified, we now output a separate error
for a symlink that has no referent instead of claiming that a file
"vanished".
- Improved the -x (--one-file-system) flag's handling of any mount-
point directories we encounter. It is both more optimal (in that
it no longer does a useless scan of the contents of the mount-
point dirs) and also fixes a bug where a remapped mount of the
original filesystem could get discovered in a subdir we should be
ignoring.
- The --copy-links (-L) option no longer has the side-effect of telling
the receiving side to follow symlinks. See the --keep-dirlinks
option (mentioned below) for a way to specify that behavior.
- Rsync no longer discards a double-slash at the start of a filename
when trying to open the file. It also no longer constructs names
that start with a double slash (unless the user supplied them).
- Error messages from the daemon server's option-parsing (such as
refused options) are now successfully transferred back to the client
(the server used to fail to send the message because the socket
wasn't in the right state for the message to get through).
- Path-specifying options to a daemon should now work the same with
or without chroot turned on. Previously, such a option (such as
--link-dest) would get its absolute path munged into a relative
one if chroot was not on, making that setting fairly useless.
Rsync now transforms the path into one that is based on the
module's base dir when chroot is not enabled.
- Most transfer errors that occur during a daemon transfer are now
returned to the user in addition to being logged (some messages are
intended to be daemon-only and are not affected by this).
- Fixed compilation problem on Tru64 Unix (having to do with
sockaddr.sa_len and sockaddr.sin_len).
- Fixed a bug in the daemon authentication code when using one of the
batch-processing options.
- Fixed a compatibility problem interacting with older rsync
versions that might send us an empty --suffix value without
telling us that --backup-dir was specified.
- We try to work around some buggy IPv6 implementations that fail to
implement IPV6_V6ONLY. This should fix the "address in use" error
that some daemons get when running on an OS with a buggy IPv6
implementation. Also, if the new code gets this error, we might
suggest that the user specify --ipv4 or --ipv6 (if we think it will
help).
- The "hosts allow" option for a daemon-over-remote-shell process
now has improved support for IPv6 addresses and a fix for systems
that have a length field in their socket structs.
- When the remote rsync dies, make a better effort to recover any error
messages it may have sent before dying (the local rsync used to just
die with a socket-write error).
- Fixed the ability to request an empty backup --suffix when sending
files to an rsync daemon.
- When using --delete and a --backup-dir that contains files that are
hard-linked to their destination equivalents, rsync now makes sure
that removed files really get removed (avoids a really weird rename()
behavior).
- Avoid a bogus run-time complaint about a lack of 64-bit integers when
the int64 type is defined as an off_t and it actually has 64-bits.
- Added a configure check for open64() without mkstemp64() so that we
can avoid using mkstemp() when such a combination is encountered.
This bypasses a problem writing out large temp files on OSes such as
AIX and HP-UX.
- Fixed an age-old crash problem with --read-batch on a local copy
(rsync was improperly assuming --whole-file for the local copy).
- When --dry-run (-n) is used and the destination directory does not
exist, rsync now produces a correct report of files that would be
sent instead of dying with a chdir() error.
- Fixed a bug that could cause a slow-to-connect rsync daemon to die
with an error instead of waiting for the connection to finish.
- Fixed an ssh interaction that could cause output to be lost when the
user chose to combine the output of rsync's stdout and stderr (e.g.
using the "2>&1").
ENHANCEMENTS:
- Added the --partial-dir=DIR option that lets you specify where to
(temporarily) put a partially transferred file (instead of over-
writing the destination file). E.g. --partial-dir=.rsync-partial
Also added support for the RSYNC_PARTIAL_DIR environment variable
that, when found, transforms a regular --partial option (such as
the convenient -P option) into one that also specifies a directory.
- Added --keep-dirlinks (-K), which allows you to symlink a directory
onto another partition on the receiving side and have rsync treat it
as matching a normal directory from the sender.
- Added the --inplace option that tells rsync to write each destination
file without using a temporary file. The matching of existing data
in the destination file can be severely limited by this, but there
are also cases where this is more efficient (such as appending data).
Use only when needed (see the man page for more details).
- Added the "write only" option for the daemon's config file.
- Added long-option names for -4 and -6 (namely --ipv4 and --ipv6)
and documented all these options in the man page.
- Improved the handling of the --bwlimit option so that it's less
bursty, more accurate, and works properly over a larger range of
values.
- The rsync daemon-over-ssh code now looks for SSH_CONNECTION and
SSH2_CLIENT in addition to SSH_CLIENT to figure out the IP address.
- Added the --checksum-seed=N option for advanced users.
- Batch writing/reading has a brand-new implementation that is simpler,
fixes a few weird problems with the old code (such as no longer
sprinkling the batch files into different dirs or even onto different
systems), and is much less intrusive into the code (making it easier
to maintain for the future). The new code generates just one data
file instead of three, which makes it possible to read the batch on
stdin via a remote shell. Also, the old requirement of forcing the
same fixed checksum-seed for all batch processing has been removed.
- If an rsync daemon has a module set with "list = no" (which hides its
presence in the list of available modules), a user that fails to
authenticate gets the same "unknown module" error that they would get
if the module were actually unknown (while still logging the real
error to the daemon's log file). This prevents fishing for module
names.
- The daemon's "refuse options" config item now allows you to match
option names using wildcards and/or the single-letter option names.
- Each transferred file now gets its permissions and modified-time
updated before the temp-file gets moved into place. Previously, the
finished file would have a very brief window where its permissions
disallowed all group and world access.
- Added the ability to parse a literal IPv6 address in an "rsync:" URL
(e.g. rsync://[2001:638:500:101::21]:873/module/dir).
- The daemon's wildcard expanding code can now handle more than 1000
filenames (it's now limited by memory instead of having a hard-wired
limit).
INTERNAL:
- Most of the I/O is now buffered, which results in a pretty large
speedup when running under MS Windows. (Craig Barratt)
- Some cleanup in the exclude code has saved some per-exclude memory
and made the code easier to maintain.
- Optimizations to the name-handling/comparing code have made some
significant reductions in user-CPU time for large file sets.
- Improved the argv-overflow checking for a remote command that has a
lot of args.
- Some cleanup of the variable types make the code more consistent.
- Use rsyserr() in the various places that were still calling rprintf()
with strerror() as an arg.
- Reduced memory requirements of hard link preservation.
(J.W. Schultz)
- If an rsync daemon is listening on multiple sockets (to handle both
IPv4 and IPv6 to a single port), we now close all the unneeded file
handles after we accept a connection (we used to close just one of
them).
- Implemented a new algorithm for hard-link handling that speeds up
the code significantly. (J.W. Schultz and Wayne Davison)
- Optimized the handling of larger block sizes (rsync used to slow to a
crawl if the block size got too large).
- The --hard-link option now uses the first existing file in the
group of linked files as the basis for the transfer. This
prevents the sub-optimal transfer of a file's data when a new
hardlink is added on the sending side and it sorts alphabetically
earlier in the list than the files that are already present on the
receiving side.
- Optimized away a loop in hash_search().
- Dropped support for protocol versions less than 20 (2.3.0 released
15 Mar 1999) and activated warnings for protocols less than 25
(2.5.0 released 23 Aug 2001). (Wayne Davison and J.W. Schultz,
severally)
- Some improvements to the sanitize_path() and clean_fname() functions
makes them more efficient and produce better results (while still
being compatible with the file-name cleaning that gets done on both
sides when sending the file-list).
- More optimal data transmission for --hard-links (protocol 28).
- Got rid of alloc_sanitize_path() after adding a destination-buffer
arg to sanitize_path() made it possible to put all the former's
functionality into the latter.
- More optimal data transmission for --checksum (protocol 28).
- The file-list that is output when at least 4 verbose options are
specified reports the uid value on the sender even when rsync is
not running as root (since we might be sending to a root receiver).
- Less memory is used when --checksum is specified.
BUILD CHANGES:
- Less memory is used in the file list (a per-file savings).
- Added a "gen" target to rebuild most of the generated files,
including configure, config.h.in, the man pages, and proto.h.
- The generator is now better about not modifying the file list
during the transfer in order to avoid a copy-on-write memory
bifurcation (on systems where fork() uses shared memory).
Previously, rsync's shared memory would slowly become unshared,
resulting in real memory usage nearly doubling on the receiving
side by the end of the transfer. Now, as long as permissions
are being preserved, the shared memory should remain that way
for the entire transfer.
- If "make proto" doesn't find some changes in the prototypes, the
proto.h file is left untouched (its time-stamp used to always be
updated).
- Changed hardlink info and file_struct + strings to use allocation
pools. This reduces memory use for large file-sets and permits
freeing memory to the OS. (J.W. Schultz)
- The variable $STRIP (that is optionally set by the install-strip
target's rule) was changed to $INSTALL_STRIP because some systems
have $STRIP already set in the environment.
- The 2 pipes used between the receiver and generator processes
(which are forked on the same machine) were reduced to 1 pipe and
the protocol improved so that (1) it is now impossible to have the
"redo" pipe fill up and hang rsync, and (2) trailing messages from
the receiver don't get lost on their way through the generator
over to the sender (which mainly affected hard-link messages and
verbose --stats output).
- Fixed a build problem when SUPPORT_HARD_LINKS isn't defined.
- Improved the internal uid/gid code to be more portable and a
little more optimized.
- When cross-compiling, the gettimeofday() function is now assumed to
be a modern version that takes two-args (since we can't test it).
- The device numbers sent when using --devices are now sent as
separate major/minor values with 32-bit accuracy (protocol 28).
Previously, the copied devices were sent as a single 32-bit
number. This will make inter-operation of 64-bit binaries more
compatible with their 32-bit brethren (with both ends of the
connection are using protocol 28). Note that optimizations in the
binary protocol for sending the device numbers often results in
fewer bytes being used than before, even though more precision is
now available.
DEVELOPER RELATED:
- Some cleanup of the exclude/include structures and its code made
things clearer (internally), simpler, and more efficient.
- The scripts in the testsuite dir were cleaned up a bit and a few
new tests added.
- Some new diffs were added to the patches dir, and some accepted
ones were removed.
- The reading & writing of the file-list in batch-mode is now
handled by the same code that sends & receives the list over the
wire. This makes it much easier to maintain. (Note that the
batch code is still considered to be experimental.)

240
OLDNEWS
View File

@@ -1,3 +1,240 @@
NEWS for rsync 2.6.2 (30 Apr 2004)
Protocol: 28 (unchanged)
Changes since 2.6.1:
BUG FIXES:
- Fixed a major bug in the sorting of the filenames when --relative
is used for some sources (just sources such as "/" and "/*" were
affected). This fix ensures that we ask for the right file-list
item when requesting changes from the sender.
- Rsync now checks the return value of the close() function to
better report disk-full problems on an NFS file system.
- Restored the old daemon-server behavior of logging error messages
rather than returning them to the user. (A better long-term fix
will be sought in the future.)
- An obscure uninitialized-variable bug was fixed in the uid/gid
code. (This bug probably had no ill effects.)
BUILD CHANGES:
- Got rid of the configure check for sys/sysctl.h (it wasn't used
and was causing a problem on some systems). Also improved the
broken-largefile-locking test to try to avoid failure due to an
NFS build-dir.
- Fixed a compile problem on systems that don't define
AI_NUMERICHOST.
- Fixed a compile problem in the popt source for compilers that
don't support __attribute__.
DEVELOPER RELATED:
- Improved the testsuite's "merge" test to work on OSF1.
- Two new diffs were added to the patches dir.
NEWS for rsync 2.6.1 (26 Apr 2004)
Protocol: 28 (changed)
Changes since 2.6.0:
SECURITY FIXES:
- Paths sent to an rsync daemon are more thoroughly sanitized when
chroot is not used. If you're running a non-read-only rsync
daemon with chroot disabled, *please upgrade*, ESPECIALLY if the
user privs you run rsync under is anything above "nobody".
ENHANCEMENTS:
- Lower memory use, more optimal transfer of data over the socket,
and lower CPU usage (see the INTERNAL section for details).
- The RSYNC_PROXY environment variable can now contain a
"USER:PASS@" prefix before the "HOST:PORT" information.
(Bardur Arantsson)
- The --progress output now mentions how far along in the transfer
we are, including both a count of files transferred and a
percentage of the total file-count that we've processed. It also
shows better current-rate-of-transfer and remaining-transfer-time
values.
- Documentation changes now attempt to describe some often mis-
understood features more clearly.
BUG FIXES:
- When -x (--one-file-system) is combined with -L (--copy-links) or
--copy-unsafe-links, no symlinked files are skipped, even if the
referent file is on a different filesystem.
- The --link-dest code now works properly for a non-root user when
(1) the UIDs of the source and destination differ and -o was
specified, or (2) when the group of the source can't be used on
the destination and -g was specified.
- Fixed a bug in the handling of -H (hard-links) that might cause
the expanded PATH/NAME value of the current item to get
overwritten (due to an expanded-name caching bug).
- We now reset the "new data has been sent" flag at the start of
each file we send. This makes sure that an interrupted transfer
with the --partial option set doesn't keep a shorter temp file
than the current basis file when no new data has been transfered
over the wire for that file.
- Fixed a byte-order problem in --batch-mode on big-endian machines.
(Jay Fenlason)
- When using --cvs-exclude, the exclude items we get from a
per-directory's .cvsignore file once again only affect that one
directory (not all following directories too). The items are also
now properly word-split and parsed without any +/- prefix parsing.
- When specifying the USER@HOST: prefix for a file, the USER part
can now contain an '@', if needed (i.e. the last '@' is used to
find the HOST, not the first).
- Fixed some bugs in the handling of group IDs for non-root users:
(1) It properly handles a group that the sender didn't have a name
for (it would previously skip changing the group on any files in
that group). (2) If --numeric-ids is used, rsync no longer
attempts to set groups that the user doesn't have the permission
to set.
- Fixed the "refuse options" setting in the rsyncd.conf file.
- Improved the -x (--one-file-system) flag's handling of any mount-
point directories we encounter. It is both more optimal (in that
it no longer does a useless scan of the contents of the mount-
point dirs) and also fixes a bug where a remapped mount of the
original filesystem could get discovered in a subdir we should be
ignoring.
- Rsync no longer discards a double-slash at the start of a filename
when trying to open the file. It also no longer constructs names
that start with a double slash (unless the user supplied them).
- Path-specifying options to a daemon should now work the same with
or without chroot turned on. Previously, such a option (such as
--link-dest) would get its absolute path munged into a relative
one if chroot was not on, making that setting fairly useless.
Rsync now transforms the path into one that is based on the
module's base dir when chroot is not enabled.
- Fixed a compatibility problem interacting with older rsync
versions that might send us an empty --suffix value without
telling us that --backup-dir was specified.
- The "hosts allow" option for a daemon-over-remote-shell process
now has improved support for IPv6 addresses and a fix for systems
that have a length field in their socket structs.
- Fixed the ability to request an empty backup --suffix when sending
files to an rsync daemon.
INTERNAL:
- Most of the I/O is now buffered, which results in a pretty large
speedup when running under MS Windows. (Craig Barratt)
- Optimizations to the name-handling/comparing code have made some
significant reductions in user-CPU time for large file sets.
- Some cleanup of the variable types make the code more consistent.
- Reduced memory requirements of hard link preservation.
(J.W. Schultz)
- Implemented a new algorithm for hard-link handling that speeds up
the code significantly. (J.W. Schultz and Wayne Davison)
- The --hard-link option now uses the first existing file in the
group of linked files as the basis for the transfer. This
prevents the sub-optimal transfer of a file's data when a new
hardlink is added on the sending side and it sorts alphabetically
earlier in the list than the files that are already present on the
receiving side.
- Dropped support for protocol versions less than 20 (2.3.0 released
15 Mar 1999) and activated warnings for protocols less than 25
(2.5.0 released 23 Aug 2001). (Wayne Davison and J.W. Schultz,
severally)
- More optimal data transmission for --hard-links (protocol 28).
- More optimal data transmission for --checksum (protocol 28).
- Less memory is used when --checksum is specified.
- Less memory is used in the file list (a per-file savings).
- The generator is now better about not modifying the file list
during the transfer in order to avoid a copy-on-write memory
bifurcation (on systems where fork() uses shared memory).
Previously, rsync's shared memory would slowly become unshared,
resulting in real memory usage nearly doubling on the receiving
side by the end of the transfer. Now, as long as permissions
are being preserved, the shared memory should remain that way
for the entire transfer.
- Changed hardlink info and file_struct + strings to use allocation
pools. This reduces memory use for large file-sets and permits
freeing memory to the OS. (J.W. Schultz)
- The 2 pipes used between the receiver and generator processes
(which are forked on the same machine) were reduced to 1 pipe and
the protocol improved so that (1) it is now impossible to have the
"redo" pipe fill up and hang rsync, and (2) trailing messages from
the receiver don't get lost on their way through the generator
over to the sender (which mainly affected hard-link messages and
verbose --stats output).
- Improved the internal uid/gid code to be more portable and a
little more optimized.
- The device numbers sent when using --devices are now sent as
separate major/minor values with 32-bit accuracy (protocol 28).
Previously, the copied devices were sent as a single 32-bit
number. This will make inter-operation of 64-bit binaries more
compatible with their 32-bit brethren (with both ends of the
connection are using protocol 28). Note that optimizations in the
binary protocol for sending the device numbers often results in
fewer bytes being used than before, even though more precision is
now available.
- Some cleanup of the exclude/include structures and its code made
things clearer (internally), simpler, and more efficient.
- The reading & writing of the file-list in batch-mode is now
handled by the same code that sends & receives the list over the
wire. This makes it much easier to maintain. (Note that the
batch code is still considered to be experimental.)
BUILD CHANGES:
- The configure script now accepts --with-rsyncd-conf=PATH to
override the default value of the /etc/rsyncd.conf file.
- Fixed configure bug when running "./configure --disable-ipv6".
- Fixed compilation problem on Tru64 Unix (having to do with
sockaddr.sa_len and sockaddr.sin_len).
DEVELOPER RELATED:
- Fixed "make test" bug when build dir is not the source dir.
- Added a couple extra diffs in the "patches" dir, removed the ones
that got applied, and rebuilt the rest.
NEWS for rsync 2.6.0 (1 Jan 2004)
Protocol: 27 (changed)
Changes since 2.5.7:
@@ -553,6 +790,9 @@ Changes since 2.4.6:
Partial Protocol History
RELEASE DATE VER. DATE OF COMMIT PROTOCOL
30 Sep 2004 2.6.3 28
30 Apr 2004 2.6.2 28
26 Apr 2004 2.6.1 08 Jan 2004 28
01 Jan 2004 2.6.0 10 Apr 2003 27 (MAX=40)
04 Dec 2003 2.5.7 26
26 Jan 2003 2.5.6 26

11
README
View File

@@ -29,9 +29,9 @@ and see the manual for more information.
SETUP
-----
Rsync normally uses rsh or ssh for communication. It does not need to
Rsync normally uses ssh or rsh for communication. It does not need to
be setuid and requires no special privileges for installation. You
must, however, have a working rsh or ssh system. Using ssh is
must, however, have a working ssh or rsh system. Using ssh is
recommended for its security features.
Alternatively, rsync can run in `daemon' mode, listening on a socket.
@@ -77,7 +77,7 @@ BUG REPORTS
If you have web access then please look at
http://rsync.samba.org
http://rsync.samba.org/
That page contains links to the current bug list, and information on
how to report a bug well. You might also like to try searching the
@@ -86,9 +86,8 @@ mailing list archives at
http://mail-archive.com/rsync@lists.samba.org/
Please send bug reports to
rsync@lists.samba.org
To send a bug report, follow the instructions on the bug-tracking
page of the web site.
CVS TREE

14
TODO
View File

@@ -21,13 +21,12 @@ SOCKS 2002/01/23
FAT support
Allow forcing arbitrary permissions 2002/03/12
--diff david.e.sewell 2002/03/15
Add daemon --no-detach and --no-fork options
Add daemon --no-fork option
Create more granular verbosity jw 2003/05/15
DOCUMENTATION --------------------------------------------------------
Update README
Keep list of open issues and todos on the web site
Update web site from CVS
Perhaps redo manual as SGML
LOGGING --------------------------------------------------------------
@@ -326,7 +325,7 @@ Allow forcing arbitrary permissions 2002/03/12
-- --
Add daemon --no-detach and --no-fork options
Add daemon --no-fork option
Very useful for debugging. Also good when running under a
daemon-monitoring process that tries to restart the service when the
@@ -362,11 +361,6 @@ Keep list of open issues and todos on the web site
-- --
Update web site from CVS
-- --
Perhaps redo manual as SGML
The man page is getting rather large, and there is more information
@@ -425,7 +419,9 @@ Improve error messages
our load? (Debian #28416) Probably fixed now, but a test case would
be good.
When running as a daemon, some errors should both be returned to the
user and logged. This will make interacting with a daemon less
cryptic.
-- --

View File

@@ -88,9 +88,13 @@ static int match_address(char *addr, char *tok)
/* Fail quietly if tok is a hostname (not an address) */
if (strspn(tok, ".0123456789") != len
#ifdef INET6
&& !strchr(tok, ':')
&& strchr(tok, ':') == NULL
#endif
) return 0;
) {
if (p)
*p = '/';
return 0;
}
memset(&hints, 0, sizeof(hints));
hints.ai_family = PF_UNSPEC;
@@ -99,17 +103,18 @@ static int match_address(char *addr, char *tok)
hints.ai_flags = AI_NUMERICHOST;
#endif
gai = getaddrinfo(addr, NULL, &hints, &resa);
if (gai) return 0;
if (getaddrinfo(addr, NULL, &hints, &resa) != 0) {
if (p)
*p = '/';
return 0;
}
gai = getaddrinfo(tok, NULL, &hints, &rest);
if (p)
*p++ = '/';
if (gai) {
rprintf(FERROR,
"error matching address %s: %s\n",
tok,
gai_strerror(gai));
if (gai != 0) {
rprintf(FLOG, "error matching address %s: %s\n",
tok, gai_strerror(gai));
freeaddrinfo(resa);
return 0;
}
@@ -152,7 +157,7 @@ static int match_address(char *addr, char *tok)
}
#endif
default:
rprintf(FERROR,"unknown family %u\n", rest->ai_family);
rprintf(FLOG, "unknown family %u\n", rest->ai_family);
ret = 0;
goto out;
}
@@ -169,14 +174,14 @@ static int match_address(char *addr, char *tok)
#ifdef HAVE_STRTOL
bits = strtol(p, &ep, 10);
if (!*p || *ep) {
rprintf(FERROR,"malformed mask in %s\n", tok);
rprintf(FLOG, "malformed mask in %s\n", tok);
ret = 0;
goto out;
}
#else
for (pp = (unsigned char *)p; *pp; pp++) {
if (!isascii(*pp) || !isdigit(*pp)) {
rprintf(FERROR,"malformed mask in %s\n", tok);
rprintf(FLOG, "malformed mask in %s\n", tok);
ret = 0;
goto out;
}
@@ -188,7 +193,7 @@ static int match_address(char *addr, char *tok)
goto out;
}
if (bits < 0 || bits > (addrlen << 3)) {
rprintf(FERROR,"malformed mask in %s\n", tok);
rprintf(FLOG, "malformed mask in %s\n", tok);
ret = 0;
goto out;
}

View File

@@ -1,17 +1,17 @@
/* -*- c-file-style: "linux"; -*-
Copyright (C) 1998-2000 by Andrew Tridgell
Copyright (C) 1998-2000 by Andrew Tridgell
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
@@ -20,6 +20,9 @@
/* support rsync authentication */
#include "rsync.h"
extern char *password_file;
extern int am_root;
/***************************************************************************
encode a buffer using base64 - simple and slow algorithm. null terminates
the result.
@@ -54,7 +57,7 @@ static void gen_challenge(char *addr, char *challenge)
char input[32];
struct timeval tv;
memset(input, 0, sizeof(input));
memset(input, 0, sizeof input);
strlcpy((char *)input, addr, 17);
sys_gettimeofday(&tv);
@@ -62,121 +65,131 @@ static void gen_challenge(char *addr, char *challenge)
SIVAL(input, 20, tv.tv_usec);
SIVAL(input, 24, getpid());
sum_init();
sum_update(input, sizeof(input));
sum_init(0);
sum_update(input, sizeof input);
sum_end(challenge);
}
/* return the secret for a user from the sercret file. maximum length
is len. null terminate it */
/* Return the secret for a user from the secret file, null terminated.
* Maximum length is len (not counting the null). */
static int get_secret(int module, char *user, char *secret, int len)
{
char *fname = lp_secrets_file(module);
int fd, found=0;
char line[MAXPATHLEN];
char *p, *pass=NULL;
STRUCT_STAT st;
int ok = 1;
extern int am_root;
int fd, ok = 1;
char ch, *p;
if (!fname || !*fname) return 0;
if (!fname || !*fname)
return 0;
fd = open(fname,O_RDONLY);
if (fd == -1) return 0;
if ((fd = open(fname, O_RDONLY)) < 0)
return 0;
if (do_stat(fname, &st) == -1) {
rsyserr(FERROR, errno, "stat(%s)", fname);
rsyserr(FLOG, errno, "stat(%s)", fname);
ok = 0;
} else if (lp_strict_modes(module)) {
if ((st.st_mode & 06) != 0) {
rprintf(FERROR,"secrets file must not be other-accessible (see strict modes option)\n");
rprintf(FLOG, "secrets file must not be other-accessible (see strict modes option)\n");
ok = 0;
} else if (am_root && (st.st_uid != 0)) {
rprintf(FERROR,"secrets file must be owned by root when running as root (see strict modes)\n");
rprintf(FLOG, "secrets file must be owned by root when running as root (see strict modes)\n");
ok = 0;
}
}
if (!ok) {
rprintf(FERROR,"continuing without secrets file\n");
rprintf(FLOG, "continuing without secrets file\n");
close(fd);
return 0;
}
while (!found) {
int i = 0;
memset(line, 0, sizeof line);
while ((size_t) i < (sizeof(line)-1)) {
if (read(fd, &line[i], 1) != 1) {
memset(line, 0, sizeof(line));
close(fd);
return 0;
}
if (line[i] == '\r') continue;
if (line[i] == '\n') break;
i++;
}
line[i] = 0;
if (line[0] == '#') continue;
p = strchr(line,':');
if (!p) continue;
*p = 0;
if (strcmp(user, line)) continue;
pass = p+1;
found = 1;
if (*user == '#') {
/* Reject attempt to match a comment. */
close(fd);
return 0;
}
close(fd);
if (!found) return 0;
/* Try to find a line that starts with the user name and a ':'. */
p = user;
while (1) {
if (read(fd, &ch, 1) != 1) {
close(fd);
return 0;
}
if (ch == '\n')
p = user;
else if (p) {
if (*p == ch)
p++;
else if (!*p && ch == ':')
break;
else
p = NULL;
}
}
/* Slurp the secret into the "secret" buffer. */
p = secret;
while (len > 0) {
if (read(fd, p, 1) != 1 || *p == '\n')
break;
if (*p == '\r')
continue;
p++;
len--;
}
*p = '\0';
close(fd);
strlcpy(secret, pass, len);
return 1;
}
static char *getpassf(char *filename)
{
char buffer[100];
int fd=0;
STRUCT_STAT st;
int ok = 1;
extern int am_root;
char *envpw=getenv("RSYNC_PASSWORD");
char buffer[512], *p;
int fd, n, ok = 1;
char *envpw = getenv("RSYNC_PASSWORD");
if (!filename) return NULL;
if (!filename)
return NULL;
if ( (fd=open(filename,O_RDONLY)) == -1) {
if ((fd = open(filename,O_RDONLY)) < 0) {
rsyserr(FERROR, errno, "could not open password file \"%s\"",filename);
if (envpw) rprintf(FERROR,"falling back to RSYNC_PASSWORD environment variable.\n");
if (envpw)
rprintf(FERROR, "falling back to RSYNC_PASSWORD environment variable.\n");
return NULL;
}
if (do_stat(filename, &st) == -1) {
rsyserr(FERROR, errno, "stat(%s)", filename);
ok = 0;
} else if ((st.st_mode & 06) != 0) {
rprintf(FERROR,"password file must not be other-accessible\n");
ok = 0;
} else if (am_root && (st.st_uid != 0)) {
} else if (am_root && st.st_uid != 0) {
rprintf(FERROR,"password file must be owned by root when running as root\n");
ok = 0;
}
if (!ok) {
rprintf(FERROR,"continuing without password file\n");
if (envpw) rprintf(FERROR,"using RSYNC_PASSWORD environment variable.\n");
if (envpw)
rprintf(FERROR, "using RSYNC_PASSWORD environment variable.\n");
close(fd);
return NULL;
}
if (envpw) rprintf(FERROR,"RSYNC_PASSWORD environment variable ignored\n");
if (envpw)
rprintf(FERROR, "RSYNC_PASSWORD environment variable ignored\n");
buffer[sizeof(buffer)-1]='\0';
if (read(fd,buffer,sizeof(buffer)-1) > 0)
{
char *p = strtok(buffer,"\n\r");
close(fd);
if (p) p = strdup(p);
return p;
}
n = read(fd, buffer, sizeof buffer - 1);
close(fd);
if (n > 0) {
buffer[n] = '\0';
if ((p = strtok(buffer, "\n\r")) != NULL)
return strdup(p);
}
return NULL;
}
@@ -186,7 +199,7 @@ static void generate_hash(char *in, char *challenge, char *out)
{
char buf[16];
sum_init();
sum_init(0);
sum_update(in, strlen(in));
sum_update(challenge, strlen(challenge));
sum_end(buf);
@@ -194,15 +207,12 @@ static void generate_hash(char *in, char *challenge, char *out)
base64_encode(buf, 16, out);
}
/* possible negotiate authentication with the client. Use "leader" to
start off the auth if necessary
return NULL if authentication failed
return "" if anonymous access
otherwise return username
*/
/* Possibly negotiate authentication with the client. Use "leader" to
* start off the auth if necessary.
*
* Return NULL if authentication failed. Return "" if anonymous access.
* Otherwise return username.
*/
char *auth_server(int f_in, int f_out, int module, char *addr, char *leader)
{
char *users = lp_auth_users(module);
@@ -216,46 +226,46 @@ char *auth_server(int f_in, int f_out, int module, char *addr, char *leader)
char *tok;
/* if no auth list then allow anyone in! */
if (!users || !*users) return "";
if (!users || !*users)
return "";
gen_challenge(addr, challenge);
base64_encode(challenge, 16, b64_challenge);
io_printf(f_out, "%s%s\n", leader, b64_challenge);
if (!read_line(f_in, line, sizeof(line)-1)) {
if (!read_line(f_in, line, sizeof line - 1))
return NULL;
}
memset(user, 0, sizeof(user));
memset(pass, 0, sizeof(pass));
memset(user, 0, sizeof user);
memset(pass, 0, sizeof pass);
if (sscanf(line,"%99s %29s", user, pass) != 2) {
if (sscanf(line,"%99s %29s", user, pass) != 2)
return NULL;
}
users = strdup(users);
if (!users) return NULL;
if (!users)
return NULL;
for (tok=strtok(users," ,\t"); tok; tok = strtok(NULL," ,\t")) {
if (wildmatch(tok, user)) break;
if (wildmatch(tok, user))
break;
}
free(users);
if (!tok) {
if (!tok)
return NULL;
}
memset(secret, 0, sizeof(secret));
if (!get_secret(module, user, secret, sizeof(secret)-1)) {
memset(secret, 0, sizeof(secret));
memset(secret, 0, sizeof secret);
if (!get_secret(module, user, secret, sizeof secret - 1)) {
memset(secret, 0, sizeof secret);
return NULL;
}
generate_hash(secret, b64_challenge, pass2);
memset(secret, 0, sizeof(secret));
memset(secret, 0, sizeof secret);
if (strcmp(pass, pass2) == 0)
return user;
@@ -267,12 +277,12 @@ void auth_client(int fd, char *user, char *challenge)
{
char *pass;
char pass2[30];
extern char *password_file;
if (!user || !*user)
user = "nobody";
if (!(pass=getpassf(password_file)) && !(pass=getenv("RSYNC_PASSWORD"))) {
if (!(pass = getpassf(password_file))
&& !(pass = getenv("RSYNC_PASSWORD"))) {
/* XXX: cyeoh says that getpass is deprecated, because
* it may return a truncated password on some systems,
* and it is not in the LSB.
@@ -285,9 +295,8 @@ void auth_client(int fd, char *user, char *challenge)
pass = getpass("Password: ");
}
if (!pass || !*pass) {
if (!pass)
pass = "";
}
generate_hash(pass, challenge, pass2);
io_printf(fd, "%s %s\n", user, pass2);

115
backup.c
View File

@@ -33,22 +33,38 @@ extern int preserve_devices;
extern int preserve_links;
extern int preserve_hard_links;
extern int orig_umask;
extern int safe_symlinks;
/* make a complete pathname for backup file */
char *get_backup_name(char *fname)
{
if (backup_dir) {
if (stringjoin(backup_dir_buf + backup_dir_len, backup_dir_remainder,
fname, backup_suffix, NULL) < backup_dir_remainder)
return backup_dir_buf;
} else {
if (stringjoin(backup_dir_buf, MAXPATHLEN,
fname, backup_suffix, NULL) < MAXPATHLEN)
return backup_dir_buf;
}
rprintf(FERROR, "backup filename too long\n");
return NULL;
}
/* simple backup creates a backup with a suffix in the same directory */
static int make_simple_backup(char *fname)
{
char fnamebak[MAXPATHLEN];
char *fnamebak = get_backup_name(fname);
if (stringjoin(fnamebak, sizeof fnamebak, fname, backup_suffix, NULL)
>= sizeof fnamebak) {
rprintf(FERROR, "backup filename too long\n");
if (!fnamebak)
return 0;
}
if (do_rename(fname, fnamebak) != 0) {
/* cygwin (at least version b19) reports EINVAL */
if (errno != ENOENT && errno != EINVAL) {
rsyserr(FERROR, errno, "rename %s to backup %s", fname, fnamebak);
rsyserr(FERROR, errno,
"rename %s to backup %s", fname, fnamebak);
return 0;
}
} else if (verbose > 1) {
@@ -83,9 +99,9 @@ static int make_bak_dir(char *fullpath)
if (do_mkdir(fullpath, 0777 & ~orig_umask) == 0)
break;
if (errno != ENOENT) {
rprintf(FERROR,
"make_bak_dir mkdir %s failed: %s\n",
full_fname(fullpath), strerror(errno));
rsyserr(FERROR, errno,
"make_bak_dir mkdir %s failed",
full_fname(fullpath));
goto failure;
}
}
@@ -96,12 +112,11 @@ static int make_bak_dir(char *fullpath)
if (p >= rel) {
/* Try to transfer the directory settings of the
* actual dir that the files are coming from. */
if (do_lstat(rel, &st) != 0) {
rprintf(FERROR,
"make_bak_dir stat %s failed: %s\n",
full_fname(rel), strerror(errno));
if (do_stat(rel, &st) < 0) {
rsyserr(FERROR, errno,
"make_bak_dir stat %s failed",
full_fname(rel));
} else {
set_modtime(fullpath, st.st_mtime);
do_lchown(fullpath, st.st_uid, st.st_gid);
do_chmod(fullpath, st.st_mode);
}
@@ -111,9 +126,8 @@ static int make_bak_dir(char *fullpath)
if (p == end)
break;
if (do_mkdir(fullpath, 0777 & ~orig_umask) < 0) {
rprintf(FERROR,
"make_bak_dir mkdir %s failed: %s\n",
full_fname(fullpath), strerror(errno));
rsyserr(FERROR, errno, "make_bak_dir mkdir %s failed",
full_fname(fullpath));
goto failure;
}
}
@@ -143,36 +157,34 @@ static int keep_backup(char *fname)
{
STRUCT_STAT st;
struct file_struct *file;
char *buf;
int kept = 0;
int ret_code;
/* return if no file to keep */
#if SUPPORT_LINKS
if (do_lstat(fname, &st)) return 1;
ret_code = do_lstat(fname, &st);
#else
if (do_stat(fname, &st)) return 1;
ret_code = do_stat(fname, &st);
#endif
if (ret_code < 0)
return 1;
file = make_file(fname, NULL, NO_EXCLUDES);
if (!(file = make_file(fname, NULL, NO_EXCLUDES)))
return 1; /* the file could have disappeared */
/* the file could have disappeared */
if (!file) return 1;
/* make a complete pathname for backup file */
if (stringjoin(backup_dir_buf + backup_dir_len, backup_dir_remainder,
fname, backup_suffix, NULL) >= backup_dir_remainder) {
rprintf(FERROR, "keep_backup filename too long\n");
if (!(buf = get_backup_name(fname)))
return 0;
}
#ifdef HAVE_MKNOD
/* Check to see if this is a device file, or link */
if (IS_DEVICE(file->mode)) {
if (am_root && preserve_devices) {
make_bak_dir(backup_dir_buf);
if (do_mknod(backup_dir_buf, file->mode, file->u.rdev) != 0) {
rprintf(FERROR, "mknod %s failed: %s\n",
full_fname(backup_dir_buf), strerror(errno));
if (do_mknod(buf, file->mode, file->u.rdev) < 0
&& (errno != ENOENT || make_bak_dir(buf) < 0
|| do_mknod(buf, file->mode, file->u.rdev) < 0)) {
rsyserr(FERROR, errno, "mknod %s failed",
full_fname(buf));
} else if (verbose > 2) {
rprintf(FINFO,
"make_backup: DEVICE %s successful.\n",
@@ -186,10 +198,14 @@ static int keep_backup(char *fname)
if (!kept && S_ISDIR(file->mode)) {
/* make an empty directory */
make_bak_dir(backup_dir_buf);
do_mkdir(backup_dir_buf, file->mode);
ret_code = do_rmdir(fname);
if (do_mkdir(buf, file->mode) < 0
&& (errno != ENOENT || make_bak_dir(buf) < 0
|| do_mkdir(buf, file->mode) < 0)) {
rsyserr(FINFO, errno, "mkdir %s failed",
full_fname(buf));
}
ret_code = do_rmdir(fname);
if (verbose > 2) {
rprintf(FINFO, "make_backup: RMDIR %s returns %i\n",
full_fname(fname), ret_code);
@@ -199,18 +215,18 @@ static int keep_backup(char *fname)
#if SUPPORT_LINKS
if (!kept && preserve_links && S_ISLNK(file->mode)) {
extern int safe_symlinks;
if (safe_symlinks && unsafe_symlink(file->u.link, backup_dir_buf)) {
if (safe_symlinks && unsafe_symlink(file->u.link, buf)) {
if (verbose) {
rprintf(FINFO, "ignoring unsafe symlink %s -> %s\n",
full_fname(backup_dir_buf), file->u.link);
full_fname(buf), file->u.link);
}
kept = 1;
}
make_bak_dir(backup_dir_buf);
if (do_symlink(file->u.link, backup_dir_buf) != 0) {
rprintf(FERROR, "link %s -> %s : %s\n",
full_fname(backup_dir_buf), file->u.link, strerror(errno));
if (do_symlink(file->u.link, buf) < 0
&& (errno != ENOENT || make_bak_dir(buf) < 0
|| do_symlink(file->u.link, buf) < 0)) {
rsyserr(FERROR, errno, "link %s -> \"%s\"",
full_fname(buf), file->u.link);
}
do_unlink(fname);
kept = 1;
@@ -220,20 +236,25 @@ static int keep_backup(char *fname)
if (!kept && !S_ISREG(file->mode)) {
rprintf(FINFO, "make_bak: skipping non-regular file %s\n",
fname);
return 1;
}
/* move to keep tree if a file */
if (!kept) {
if (robust_move(fname, backup_dir_buf) != 0) {
rprintf(FERROR, "keep_backup failed: %s -> \"%s\": %s\n",
full_fname(fname), backup_dir_buf, strerror(errno));
if (robust_move(fname, buf) != 0) {
rsyserr(FERROR, errno, "keep_backup failed: %s -> \"%s\"",
full_fname(fname), buf);
} else if (st.st_nlink > 1) {
/* If someone has hard-linked the file into the backup
* dir, rename() might return success but do nothing! */
robust_unlink(fname); /* Just in case... */
}
}
set_perms(backup_dir_buf, file, NULL, 0);
set_perms(buf, file, NULL, 0);
free(file);
if (verbose > 1)
rprintf(FINFO, "keep_backup %s -> %s\n", fname, backup_dir_buf);
rprintf(FINFO, "backed up %s to %s\n", fname, buf);
return 1;
}

448
batch.c
View File

@@ -8,329 +8,171 @@
#include "rsync.h"
#include <time.h>
extern char *batch_prefix;
extern int csum_length;
extern int protocol_version;
extern struct stats stats;
extern char *batch_name;
extern int eol_nulls;
extern int recurse;
extern int preserve_links;
extern int preserve_hard_links;
extern int preserve_devices;
extern int preserve_uid;
extern int preserve_gid;
extern int always_checksum;
struct file_list *batch_flist;
extern struct exclude_list_struct exclude_list;
static char rsync_flist_file[] = ".rsync_flist";
static char rsync_csums_file[] = ".rsync_csums";
static char rsync_delta_file[] = ".rsync_delta";
static char rsync_argvs_file[] = ".rsync_argvs";
static int *flag_ptr[] = {
&recurse,
&preserve_uid,
&preserve_gid,
&preserve_links,
&preserve_devices,
&preserve_hard_links,
&always_checksum,
NULL
};
static int f_csums = -1;
static int f_delta = -1;
static char *flag_name[] = {
"--recurse (-r)",
"--owner (-o)",
"--group (-g)",
"--links (-l)",
"--devices (-D)",
"--hard-links (-H)",
"--checksum (-c)",
NULL
};
void write_batch_flist_info(int flist_count, struct file_struct **files)
void write_stream_flags(int fd)
{
char filename[MAXPATHLEN];
int i, f, save_pv;
int64 save_written;
int i, flags;
stringjoin(filename, sizeof filename,
batch_prefix, rsync_flist_file, NULL);
f = do_open(filename, O_WRONLY | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR);
if (f < 0) {
rprintf(FERROR, "Batch file %s open error: %s\n",
filename, strerror(errno));
exit_cleanup(1);
/* Start the batch file with a bitmap of data-stream-affecting
* flags. */
for (i = 0, flags = 0; flag_ptr[i]; i++) {
if (*flag_ptr[i])
flags |= 1 << i;
}
save_written = stats.total_written;
save_pv = protocol_version;
protocol_version = PROTOCOL_VERSION;
write_int(f, protocol_version);
write_int(f, flist_count);
for (i = 0; i < flist_count; i++) {
send_file_entry(files[i], f,
files[i]->flags & FLAG_TOP_DIR ? XMIT_TOP_DIR : 0);
}
send_file_entry(NULL, f, 0);
protocol_version = save_pv;
stats.total_written = save_written;
close(f);
write_int(fd, flags);
}
void write_batch_argvs_file(int argc, char *argv[])
void read_stream_flags(int fd)
{
int f;
int i;
char buff[256]; /* XXX */
char buff2[MAXPATHLEN + 6];
char filename[MAXPATHLEN];
int i, flags;
for (i = 0, flags = read_int(fd); flag_ptr[i]; i++) {
int set = flags & (1 << i) ? 1 : 0;
if (*flag_ptr[i] != set) {
if (verbose) {
rprintf(FINFO,
"%sing the %s option to match the batchfile.\n",
set ? "Sett" : "Clear", flag_name[i]);
}
*flag_ptr[i] = set;
}
}
}
static void write_arg(int fd, char *arg)
{
char *x, *s;
if (*arg == '-' && (x = strchr(arg, '=')) != NULL) {
write(fd, arg, x - arg + 1);
arg += x - arg + 1;
}
if (strpbrk(arg, " \"'&;|[]()$#!*?^\\") != NULL) {
write(fd, "'", 1);
for (s = arg; (x = strchr(s, '\'')) != NULL; s = x + 1) {
write(fd, s, x - s + 1);
write(fd, "'", 1);
}
write(fd, s, strlen(s));
write(fd, "'", 1);
return;
}
write(fd, arg, strlen(arg));
}
static void write_excludes(int fd)
{
struct exclude_struct *ent;
write_sbuf(fd, " <<'#E#'\n");
for (ent = exclude_list.head; ent; ent = ent->next) {
char *p = ent->pattern;
if (ent->match_flags & MATCHFLG_INCLUDE)
write_buf(fd, "+ ", 2);
else if (((*p == '-' || *p == '+') && p[1] == ' ')
|| *p == '#' || *p == ';')
write_buf(fd, "- ", 2);
write_sbuf(fd, p);
if (ent->match_flags & MATCHFLG_DIRECTORY)
write_byte(fd, '/');
write_byte(fd, eol_nulls ? 0 : '\n');
}
if (eol_nulls)
write_sbuf(fd, ";\n");
write_sbuf(fd, "#E#");
}
/* This routine tries to write out an equivalent --read-batch command
* given the user's --write-batch args. However, it doesn't really
* understand most of the options, so it uses some overly simple
* heuristics to munge the command line into something that will
* (hopefully) work. */
void write_batch_shell_file(int argc, char *argv[], int file_arg_cnt)
{
int fd, i;
char *p, filename[MAXPATHLEN];
stringjoin(filename, sizeof filename,
batch_prefix, rsync_argvs_file, NULL);
f = do_open(filename, O_WRONLY | O_CREAT | O_TRUNC,
S_IRUSR | S_IWUSR | S_IEXEC);
if (f < 0) {
rprintf(FERROR, "Batch file %s open error: %s\n",
filename, strerror(errno));
batch_name, ".sh", NULL);
fd = do_open(filename, O_WRONLY | O_CREAT | O_TRUNC,
S_IRUSR | S_IWUSR | S_IEXEC);
if (fd < 0) {
rsyserr(FERROR, errno, "Batch file %s open error", filename);
exit_cleanup(1);
}
buff[0] = '\0';
/* Write argvs info to batch file */
for (i = 0; i < argc; ++i) {
if (i == argc - 2) /* Skip source directory on cmdline */
/* Write argvs info to BATCH.sh file */
write_arg(fd, argv[0]);
if (exclude_list.head)
write_sbuf(fd, " --exclude-from=-");
for (i = 1; i < argc - file_arg_cnt; i++) {
p = argv[i];
if (strncmp(p, "--files-from", 12) == 0
|| strncmp(p, "--include", 9) == 0
|| strncmp(p, "--exclude", 9) == 0) {
if (strchr(p, '=') == NULL)
i++;
continue;
/*
* FIXME:
* I think directly manipulating argv[] is probably bogus
*/
if (!strncmp(argv[i], "--write-batch",
strlen("--write-batch"))) {
/* Safer to change it here than script */
/*
* Change to --read-batch=prefix
* to get ready for remote
*/
strlcat(buff, "--read-batch=", sizeof buff);
strlcat(buff, batch_prefix, sizeof buff);
}
write(fd, " ", 1);
if (strncmp(p, "--write-batch", 13) == 0) {
write(fd, "--read-batch", 12);
if (p[13] == '=') {
write(fd, "=", 1);
write_arg(fd, p + 14);
}
} else
if (i == argc - 1) {
snprintf(buff2, sizeof buff2, "${1:-%s}", argv[i]);
strlcat(buff, buff2, sizeof buff);
}
else {
strlcat(buff, argv[i], sizeof buff);
}
if (i < (argc - 1)) {
strlcat(buff, " ", sizeof buff);
}
write_arg(fd, p);
}
strlcat(buff, "\n", sizeof buff);
if (!write(f, buff, strlen(buff))) {
rprintf(FERROR, "Batch file %s write error: %s\n",
filename, strerror(errno));
close(f);
if ((p = find_colon(argv[argc - 1])) != NULL) {
if (*++p == ':')
p++;
} else
p = argv[argc - 1];
write(fd, " ${1:-", 6);
write_arg(fd, p);
write_byte(fd, '}');
if (exclude_list.head)
write_excludes(fd);
if (write(fd, "\n", 1) != 1 || close(fd) < 0) {
rsyserr(FERROR, errno, "Batch file %s write error", filename);
exit_cleanup(1);
}
close(f);
}
struct file_list *create_flist_from_batch(void)
{
char filename[MAXPATHLEN];
unsigned short flags;
int i, f, save_pv;
int64 save_read;
stringjoin(filename, sizeof filename,
batch_prefix, rsync_flist_file, NULL);
f = do_open(filename, O_RDONLY, 0);
if (f < 0) {
rprintf(FERROR, "Batch file %s open error: %s\n",
filename, strerror(errno));
exit_cleanup(1);
}
batch_flist = flist_new(WITH_HLINK, "create_flist_from_batch");
save_read = stats.total_read;
save_pv = protocol_version;
protocol_version = read_int(f);
batch_flist->count = read_int(f);
flist_expand(batch_flist);
for (i = 0; (flags = read_byte(f)) != 0; i++) {
if (protocol_version >= 28 && (flags & XMIT_EXTENDED_FLAGS))
flags |= read_byte(f) << 8;
receive_file_entry(&batch_flist->files[i], flags, batch_flist, f);
}
receive_file_entry(NULL, 0, NULL, 0); /* Signal that we're done. */
protocol_version = save_pv;
stats.total_read = save_read;
return batch_flist;
}
void write_batch_csums_file(void *buff, int bytes_to_write)
{
if (write(f_csums, buff, bytes_to_write) < 0) {
rprintf(FERROR, "Batch file write error: %s\n",
strerror(errno));
close(f_csums);
exit_cleanup(1);
}
}
void close_batch_csums_file(void)
{
close(f_csums);
f_csums = -1;
}
/**
* Write csum info to batch file
*
* @todo This will break if s->count is ever larger than maxint. The
* batch code should probably be changed to consistently use the
* variable-length integer routines, which is probably a compatible
* change.
**/
void write_batch_csum_info(int *flist_entry, struct sum_struct *s)
{
size_t i;
int int_count;
char filename[MAXPATHLEN];
if (f_csums < 0) {
stringjoin(filename, sizeof filename,
batch_prefix, rsync_csums_file, NULL);
f_csums = do_open(filename, O_WRONLY | O_CREAT | O_TRUNC,
S_IRUSR | S_IWUSR);
if (f_csums < 0) {
rprintf(FERROR, "Batch file %s open error: %s\n",
filename, strerror(errno));
close(f_csums);
exit_cleanup(1);
}
}
write_batch_csums_file(flist_entry, sizeof (int));
int_count = s ? (int) s->count : 0;
write_batch_csums_file(&int_count, sizeof int_count);
if (s) {
for (i = 0; i < s->count; i++) {
write_batch_csums_file(&s->sums[i].sum1,
sizeof (uint32));
write_batch_csums_file(s->sums[i].sum2, csum_length);
}
}
}
int read_batch_csums_file(char *buff, int len)
{
int bytes_read;
if ((bytes_read = read(f_csums, buff, len)) < 0) {
rprintf(FERROR, "Batch file read error: %s\n", strerror(errno));
close(f_csums);
exit_cleanup(1);
}
return bytes_read;
}
void read_batch_csum_info(int flist_entry, struct sum_struct *s,
int *checksums_match)
{
int i;
int file_flist_entry;
int file_chunk_ct;
uint32 file_sum1;
char file_sum2[SUM_LENGTH];
char filename[MAXPATHLEN];
if (f_csums < 0) {
stringjoin(filename, sizeof filename,
batch_prefix, rsync_csums_file, NULL);
f_csums = do_open(filename, O_RDONLY, 0);
if (f_csums < 0) {
rprintf(FERROR, "Batch file %s open error: %s\n",
filename, strerror(errno));
close(f_csums);
exit_cleanup(1);
}
}
read_batch_csums_file((char *) &file_flist_entry, sizeof (int));
if (file_flist_entry != flist_entry) {
rprintf(FINFO, "file_flist_entry (%d) != flist_entry (%d)\n",
file_flist_entry, flist_entry);
close(f_csums);
exit_cleanup(1);
} else {
read_batch_csums_file((char *) &file_chunk_ct, sizeof (int));
*checksums_match = 1;
for (i = 0; i < file_chunk_ct; i++) {
read_batch_csums_file((char *) &file_sum1,
sizeof (uint32));
read_batch_csums_file(file_sum2, csum_length);
if ((s->sums[i].sum1 != file_sum1)
|| memcmp(s->sums[i].sum2, file_sum2, csum_length))
*checksums_match = 0;
} /* end for */
}
}
void write_batch_delta_file(char *buff, int bytes_to_write)
{
char filename[MAXPATHLEN];
if (f_delta < 0) {
stringjoin(filename, sizeof filename,
batch_prefix, rsync_delta_file, NULL);
f_delta = do_open(filename, O_WRONLY | O_CREAT | O_TRUNC,
S_IRUSR | S_IWUSR);
if (f_delta < 0) {
rprintf(FERROR, "Batch file %s open error: %s\n",
filename, strerror(errno));
exit_cleanup(1);
}
}
if (write(f_delta, buff, bytes_to_write) < 0) {
rprintf(FERROR, "Batch file %s write error: %s\n",
filename, strerror(errno));
close(f_delta);
exit_cleanup(1);
}
}
void close_batch_delta_file(void)
{
close(f_delta);
f_delta = -1;
}
int read_batch_delta_file(char *buff, int len)
{
int bytes_read;
char filename[MAXPATHLEN];
if (f_delta < 0) {
stringjoin(filename, sizeof filename,
batch_prefix, rsync_delta_file, NULL);
f_delta = do_open(filename, O_RDONLY, 0);
if (f_delta < 0) {
rprintf(FERROR, "Batch file %s open error: %s\n",
filename, strerror(errno));
close(f_delta);
exit_cleanup(1);
}
}
bytes_read = read(f_delta, buff, len);
if (bytes_read < 0) {
rprintf(FERROR, "Batch file %s read error: %s\n",
filename, strerror(errno));
close(f_delta);
exit_cleanup(1);
}
return bytes_read;
}
void show_flist(int index, struct file_struct **fptr)

View File

@@ -1,17 +1,17 @@
/*
/*
Copyright (C) Andrew Tridgell 1996
Copyright (C) Paul Mackerras 1996
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
@@ -38,9 +38,9 @@ uint32 get_checksum1(char *buf1,int len)
s1 = s2 = 0;
for (i = 0; i < (len-4); i+=4) {
s2 += 4*(s1 + buf[i]) + 3*buf[i+1] + 2*buf[i+2] + buf[i+3] +
s2 += 4*(s1 + buf[i]) + 3*buf[i+1] + 2*buf[i+2] + buf[i+3] +
10*CHAR_OFFSET;
s1 += (buf[i+0] + buf[i+1] + buf[i+2] + buf[i+3] + 4*CHAR_OFFSET);
s1 += (buf[i+0] + buf[i+1] + buf[i+2] + buf[i+3] + 4*CHAR_OFFSET);
}
for (; i < len; i++) {
s1 += (buf[i]+CHAR_OFFSET); s2 += s1;
@@ -62,15 +62,15 @@ void get_checksum2(char *buf,int len,char *sum)
len1 = len;
if (!buf1) out_of_memory("get_checksum2");
}
mdfour_begin(&m);
memcpy(buf1,buf,len);
if (checksum_seed) {
SIVAL(buf1,len,checksum_seed);
len += 4;
}
for(i = 0; i + CSUM_CHUNK <= len; i += CSUM_CHUNK) {
mdfour_update(&m, (uchar *)(buf1+i), CSUM_CHUNK);
}
@@ -83,7 +83,7 @@ void get_checksum2(char *buf,int len,char *sum)
if (len - i > 0 || protocol_version >= 27) {
mdfour_update(&m, (uchar *)(buf1+i), (len-i));
}
mdfour_result(&m, (uchar *)sum);
}
@@ -94,35 +94,29 @@ void file_checksum(char *fname,char *sum,OFF_T size)
struct map_struct *buf;
int fd;
OFF_T len = size;
char tmpchunk[CSUM_CHUNK];
struct mdfour m;
memset(sum,0,MD4_SUM_LENGTH);
fd = do_open(fname, O_RDONLY, 0);
if (fd == -1) return;
buf = map_file(fd,size);
if (fd == -1)
return;
buf = map_file(fd, size, MAX_MAP_SIZE, CSUM_CHUNK);
mdfour_begin(&m);
for(i = 0; i + CSUM_CHUNK <= len; i += CSUM_CHUNK) {
memcpy(tmpchunk, map_ptr(buf,i,CSUM_CHUNK), CSUM_CHUNK);
mdfour_update(&m, (uchar *)tmpchunk, CSUM_CHUNK);
mdfour_update(&m, (uchar *)map_ptr(buf, i, CSUM_CHUNK),
CSUM_CHUNK);
}
/*
* Prior to version 27 an incorrect MD4 checksum was computed
/* Prior to version 27 an incorrect MD4 checksum was computed
* by failing to call mdfour_tail() for block sizes that
* are multiples of 64. This is fixed by calling mdfour_update()
* even when there are no more bytes.
*/
if (len - i > 0) {
memcpy(tmpchunk, map_ptr(buf,i,len-i), len-i);
}
if (len - i > 0 || protocol_version >= 27) {
mdfour_update(&m, (uchar *)tmpchunk, (len-i));
}
* even when there are no more bytes. */
if (len - i > 0 || protocol_version >= 27)
mdfour_update(&m, (uchar *)map_ptr(buf, i, len-i), len-i);
mdfour_result(&m, (uchar *)sum);
@@ -135,13 +129,13 @@ static int sumresidue;
static char sumrbuf[CSUM_CHUNK];
static struct mdfour md;
void sum_init(void)
void sum_init(int seed)
{
char s[4];
mdfour_begin(&md);
sumresidue=0;
SIVAL(s,0,checksum_seed);
sum_update(s,4);
sumresidue = 0;
SIVAL(s, 0, seed);
sum_update(s, 4);
}
/**
@@ -178,7 +172,7 @@ void sum_update(char *p, int len)
sumresidue = len-i;
memcpy(sumrbuf,p+i,sumresidue);
} else {
sumresidue = 0;
sumresidue = 0;
}
}

View File

@@ -1,19 +1,19 @@
/* -*- c-file-style: "linux" -*-
Copyright (C) 1996-2000 by Andrew Tridgell
Copyright (C) Paul Mackerras 1996
Copyright (C) 2002 by Martin Pool
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
@@ -21,6 +21,10 @@
#include "rsync.h"
extern int io_error;
extern int keep_partial;
extern int log_got_error;
/**
* Close all open sockets and files, allowing a (somewhat) graceful
* shutdown() of socket connections. This eliminates the abortive
@@ -38,9 +42,8 @@ void close_all(void)
for (fd = max_fd; fd >= 0; fd--) {
ret = fstat(fd,&st);
if (fstat(fd,&st) == 0) {
if (is_a_socket(fd)) {
if (is_a_socket(fd))
ret = shutdown(fd, 2);
}
ret = close(fd);
}
}
@@ -65,15 +68,13 @@ void close_all(void)
* --partial is selected. We need to ensure that the partial file is
* kept if any real data has been transferred.
**/
int cleanup_got_literal=0;
int cleanup_got_literal = 0;
static char *cleanup_fname;
static char *cleanup_new_fname;
static struct file_struct *cleanup_file;
static int cleanup_fd1, cleanup_fd2;
static struct map_struct *cleanup_buf;
static int cleanup_fd_r, cleanup_fd_w;
static pid_t cleanup_pid = 0;
extern int io_error;
pid_t cleanup_child_pid = -1;
@@ -85,8 +86,6 @@ pid_t cleanup_child_pid = -1;
void _exit_cleanup(int code, const char *file, int line)
{
int ocode = code;
extern int keep_partial;
extern int log_got_error;
static int inside_cleanup = 0;
if (inside_cleanup > 10) {
@@ -98,37 +97,39 @@ void _exit_cleanup(int code, const char *file, int line)
signal(SIGUSR1, SIG_IGN);
signal(SIGUSR2, SIG_IGN);
if (verbose > 3)
rprintf(FINFO,"_exit_cleanup(code=%d, file=%s, line=%d): entered\n",
if (verbose > 3) {
rprintf(FINFO,"_exit_cleanup(code=%d, file=%s, line=%d): entered\n",
code, file, line);
}
if (cleanup_child_pid != -1) {
int status;
if (waitpid(cleanup_child_pid, &status, WNOHANG) == cleanup_child_pid) {
status = WEXITSTATUS(status);
if (status > code) code = status;
if (status > code)
code = status;
}
}
if (cleanup_got_literal && cleanup_fname && keep_partial) {
if (cleanup_got_literal && cleanup_fname && keep_partial
&& handle_partial_dir(cleanup_new_fname, PDIR_CREATE)) {
char *fname = cleanup_fname;
cleanup_fname = NULL;
if (cleanup_buf) unmap_file(cleanup_buf);
if (cleanup_fd1 != -1) close(cleanup_fd1);
if (cleanup_fd2 != -1) close(cleanup_fd2);
finish_transfer(cleanup_new_fname, fname, cleanup_file);
if (cleanup_fd_r != -1)
close(cleanup_fd_r);
if (cleanup_fd_w != -1)
close(cleanup_fd_w);
finish_transfer(cleanup_new_fname, fname, cleanup_file, 0);
}
io_flush(FULL_FLUSH);
if (cleanup_fname)
do_unlink(cleanup_fname);
if (code) {
if (code)
kill_all(SIGUSR1);
}
if (cleanup_pid && cleanup_pid == getpid()) {
char *pidf = lp_pid_file();
if (pidf && *pidf) {
if (pidf && *pidf)
unlink(lp_pid_file());
}
}
if (code == 0) {
@@ -138,11 +139,13 @@ void _exit_cleanup(int code, const char *file, int line)
code = RERR_VANISHED;
}
if (code) log_exit(code, file, line);
if (code)
log_exit(code, file, line);
if (verbose > 2)
rprintf(FINFO,"_exit_cleanup(code=%d, file=%s, line=%d): about to call exit(%d)\n",
if (verbose > 2) {
rprintf(FINFO,"_exit_cleanup(code=%d, file=%s, line=%d): about to call exit(%d)\n",
ocode, file, line, code);
}
close_all();
exit(code);
@@ -156,14 +159,13 @@ void cleanup_disable(void)
void cleanup_set(char *fnametmp, char *fname, struct file_struct *file,
struct map_struct *buf, int fd1, int fd2)
int fd_r, int fd_w)
{
cleanup_fname = fnametmp;
cleanup_new_fname = fname;
cleanup_file = file;
cleanup_buf = buf;
cleanup_fd1 = fd1;
cleanup_fd2 = fd2;
cleanup_fd_r = fd_r;
cleanup_fd_w = fd_w;
}
void cleanup_set_pid(pid_t pid)

View File

@@ -43,12 +43,11 @@ extern int am_server;
**/
char *client_addr(int fd)
{
struct sockaddr_storage ss;
socklen_t length = sizeof ss;
char *ssh_client, *p;
int len;
static char addr_buf[100];
static int initialised;
struct sockaddr_storage ss;
socklen_t length = sizeof ss;
char *ssh_info, *p;
if (initialised)
return addr_buf;
@@ -57,14 +56,13 @@ char *client_addr(int fd)
if (am_server) { /* daemon over --rsh mode */
strcpy(addr_buf, "0.0.0.0");
if ((ssh_client = getenv("SSH_CLIENT")) != NULL) {
/* truncate SSH_CLIENT to just IP address */
if ((p = strchr(ssh_client, ' ')) != NULL) {
len = MIN((unsigned int) (p - ssh_client),
sizeof addr_buf - 1);
strncpy(addr_buf, ssh_client, len);
*(addr_buf + len) = '\0';
}
if ((ssh_info = getenv("SSH_CONNECTION")) != NULL
|| (ssh_info = getenv("SSH_CLIENT")) != NULL
|| (ssh_info = getenv("SSH2_CLIENT")) != NULL) {
strlcpy(addr_buf, ssh_info, sizeof addr_buf);
/* Truncate the value to just the IP address. */
if ((p = strchr(addr_buf, ' ')) != NULL)
*p = '\0';
}
} else {
client_sockaddr(fd, &ss, &length);
@@ -118,11 +116,13 @@ char *client_name(int fd)
memset(&hint, 0, sizeof hint);
#ifdef AI_NUMERICHOST
hint.ai_flags = AI_NUMERICHOST;
#endif
hint.ai_socktype = SOCK_STREAM;
if ((err = getaddrinfo(addr, NULL, &hint, &answer)) != 0) {
rprintf(FERROR, RSYNC_NAME ": malformed address %s: %s\n",
rprintf(FLOG, "malformed address %s: %s\n",
addr, gai_strerror(err));
return name_buf;
}
@@ -145,8 +145,8 @@ char *client_name(int fd)
client_sockaddr(fd, &ss, &ss_len);
}
if (!lookup_name(fd, &ss, ss_len, name_buf, sizeof name_buf,
port_buf, sizeof port_buf))
if (lookup_name(fd, &ss, ss_len, name_buf, sizeof name_buf,
port_buf, sizeof port_buf) == 0)
check_name(fd, &ss, name_buf);
return name_buf;
@@ -168,8 +168,7 @@ void client_sockaddr(int fd,
if (getpeername(fd, (struct sockaddr *) ss, ss_len)) {
/* FIXME: Can we really not continue? */
rprintf(FERROR, RSYNC_NAME ": getpeername on fd%d failed: %s\n",
fd, strerror(errno));
rsyserr(FLOG, errno, "getpeername on fd%d failed", fd);
exit_cleanup(RERR_SOCKETIO);
}
@@ -224,9 +223,8 @@ int lookup_name(int fd, const struct sockaddr_storage *ss,
NI_NAMEREQD | NI_NUMERICSERV);
if (name_err != 0) {
strcpy(name_buf, default_name);
rprintf(FERROR, RSYNC_NAME ": name lookup failed for %s: %s\n",
client_addr(fd),
gai_strerror(name_err));
rprintf(FLOG, "name lookup failed for %s: %s\n",
client_addr(fd), gai_strerror(name_err));
return name_err;
}
@@ -247,8 +245,7 @@ int compare_addrinfo_sockaddr(const struct addrinfo *ai,
const char fn[] = "compare_addrinfo_sockaddr";
if (ai->ai_family != ss_family) {
rprintf(FERROR,
"%s: response family %d != %d\n",
rprintf(FLOG, "%s: response family %d != %d\n",
fn, ai->ai_family, ss_family);
return 1;
}
@@ -272,8 +269,7 @@ int compare_addrinfo_sockaddr(const struct addrinfo *ai,
sin2 = (const struct sockaddr_in6 *) ai->ai_addr;
if (ai->ai_addrlen < sizeof (struct sockaddr_in6)) {
rprintf(FERROR,
"%s: too short sockaddr_in6; length=%d\n",
rprintf(FLOG, "%s: too short sockaddr_in6; length=%d\n",
fn, ai->ai_addrlen);
return 1;
}
@@ -319,8 +315,7 @@ int check_name(int fd,
hints.ai_socktype = SOCK_STREAM;
error = getaddrinfo(name_buf, NULL, &hints, &res0);
if (error) {
rprintf(FERROR,
RSYNC_NAME ": forward name lookup for %s failed: %s\n",
rprintf(FLOG, "forward name lookup for %s failed: %s\n",
name_buf, gai_strerror(error));
strcpy(name_buf, default_name);
return error;
@@ -337,23 +332,17 @@ int check_name(int fd,
if (!res0) {
/* We hit the end of the list without finding an
* address that was the same as ss. */
rprintf(FERROR, RSYNC_NAME
": no known address for \"%s\": "
"spoofed address?\n",
name_buf);
rprintf(FLOG, "no known address for \"%s\": "
"spoofed address?\n", name_buf);
strcpy(name_buf, default_name);
} else if (res == NULL) {
/* We hit the end of the list without finding an
* address that was the same as ss. */
rprintf(FERROR, RSYNC_NAME
": %s is not a known address for \"%s\": "
"spoofed address?\n",
client_addr(fd),
name_buf);
rprintf(FLOG, "%s is not a known address for \"%s\": "
"spoofed address?\n", client_addr(fd), name_buf);
strcpy(name_buf, default_name);
}
freeaddrinfo(res0);
return 0;
}

View File

@@ -50,6 +50,7 @@ extern char *bind_address;
extern struct exclude_list_struct server_exclude_list;
extern char *exclude_path_prefix;
extern char *config_file;
extern char *files_from;
char *auth_user;
@@ -70,21 +71,21 @@ char *auth_user;
int start_socket_client(char *host, char *path, int argc, char *argv[])
{
int fd, ret;
char *p, *user=NULL;
char *p, *user = NULL;
/* this is redundant with code in start_inband_exchange(), but
* this short-circuits a problem before we open a socket, and
* the extra check won't hurt */
/* This is redundant with code in start_inband_exchange(), but this
* short-circuits a problem in the client before we open a socket,
* and the extra check won't hurt. */
if (*path == '/') {
rprintf(FERROR,"ERROR: The remote path must start with a module name not a /\n");
rprintf(FERROR,
"ERROR: The remote path must start with a module name not a /\n");
return -1;
}
p = strchr(host, '@');
if (p) {
if ((p = strchr(host, '@')) != NULL) {
user = host;
host = p+1;
*p = 0;
*p = '\0';
}
fd = open_socket_out_wrapped(host, rsync_port, bind_address,
@@ -97,7 +98,8 @@ int start_socket_client(char *host, char *path, int argc, char *argv[])
return ret < 0? ret : client_run(fd, fd, -1, argc, argv);
}
int start_inband_exchange(char *user, char *path, int f_in, int f_out, int argc)
int start_inband_exchange(char *user, char *path, int f_in, int f_out,
int argc)
{
int i;
char *sargs[MAX_ARGS];
@@ -109,12 +111,15 @@ int start_inband_exchange(char *user, char *path, int f_in, int f_out, int argc)
list_only = 1;
if (*path == '/') {
rprintf(FERROR, "ERROR: The remote path must start with a module name\n");
rprintf(FERROR,
"ERROR: The remote path must start with a module name\n");
return -1;
}
if (!user) user = getenv("USER");
if (!user) user = getenv("LOGNAME");
if (!user)
user = getenv("USER");
if (!user)
user = getenv("LOGNAME");
/* set daemon_over_rsh to false since we need to build the
* true set of args passed through the rsh/ssh connection;
@@ -131,7 +136,7 @@ int start_inband_exchange(char *user, char *path, int f_in, int f_out, int argc)
io_printf(f_out, "@RSYNCD: %d\n", protocol_version);
if (!read_line(f_in, line, sizeof(line)-1)) {
if (!read_line(f_in, line, sizeof line - 1)) {
rprintf(FERROR, "rsync: did not see server greeting\n");
return -1;
}
@@ -155,7 +160,7 @@ int start_inband_exchange(char *user, char *path, int f_in, int f_out, int argc)
kludge_around_eof = list_only && (protocol_version < 25);
while (1) {
if (!read_line(f_in, line, sizeof(line)-1)) {
if (!read_line(f_in, line, sizeof line - 1)) {
rprintf(FERROR, "rsync: didn't get server startup line\n");
return -1;
}
@@ -165,7 +170,8 @@ int start_inband_exchange(char *user, char *path, int f_in, int f_out, int argc)
continue;
}
if (strcmp(line,"@RSYNCD: OK") == 0) break;
if (strcmp(line,"@RSYNCD: OK") == 0)
break;
if (strcmp(line,"@RSYNCD: EXIT") == 0) {
/* This is sent by recent versions of the
@@ -176,7 +182,7 @@ int start_inband_exchange(char *user, char *path, int f_in, int f_out, int argc)
}
if (strncmp(line, "@ERROR", 6) == 0) {
rprintf(FERROR,"%s\n", line);
rprintf(FERROR, "%s\n", line);
/* This is always fatal; the server will now
* close the socket. */
return RERR_STARTCLIENT;
@@ -193,7 +199,7 @@ int start_inband_exchange(char *user, char *path, int f_in, int f_out, int argc)
if (protocol_version < 23) {
if (protocol_version == 22 || !am_sender)
io_start_multiplex_in(f_in);
io_start_multiplex_in();
}
return 0;
@@ -203,8 +209,9 @@ int start_inband_exchange(char *user, char *path, int f_in, int f_out, int argc)
static int rsync_module(int f_in, int f_out, int i)
{
int argc=0;
char *argv[MAX_ARGS];
int argc = 0;
int maxargs;
char **argv;
char **argp;
char line[MAXPATHLEN];
uid_t uid = (uid_t)-2; /* canonically "nobody" */
@@ -214,31 +221,36 @@ static int rsync_module(int f_in, int f_out, int i)
char *host = client_name(f_in);
char *name = lp_name(i);
int use_chroot = lp_use_chroot(i);
int start_glob=0;
int start_glob = 0;
int ret;
char *request=NULL;
char *request = NULL;
if (!allow_access(addr, host, lp_hosts_allow(i), lp_hosts_deny(i))) {
rprintf(FERROR,"rsync denied on module %s from %s (%s)\n",
rprintf(FLOG, "rsync denied on module %s from %s (%s)\n",
name, host, addr);
io_printf(f_out, "@ERROR: access denied to %s from %s (%s)\n",
name, host, addr);
if (!lp_list(i))
io_printf(f_out, "@ERROR: Unknown module '%s'\n", name);
else {
io_printf(f_out,
"@ERROR: access denied to %s from %s (%s)\n",
name, host, addr);
}
return -1;
}
if (am_daemon && am_server) {
rprintf(FINFO, "rsync allowed access on module %s from %s (%s)\n",
rprintf(FLOG, "rsync allowed access on module %s from %s (%s)\n",
name, host, addr);
}
if (!claim_connection(lp_lock_file(i), lp_max_connections(i))) {
if (errno) {
rprintf(FERROR,"failed to open lock file %s : %s\n",
lp_lock_file(i), strerror(errno));
io_printf(f_out, "@ERROR: failed to open lock file %s : %s\n",
lp_lock_file(i), strerror(errno));
rsyserr(FLOG, errno, "failed to open lock file %s",
lp_lock_file(i));
io_printf(f_out, "@ERROR: failed to open lock file %s\n",
lp_lock_file(i));
} else {
rprintf(FERROR,"max connections (%d) reached\n",
rprintf(FLOG, "max connections (%d) reached\n",
lp_max_connections(i));
io_printf(f_out, "@ERROR: max connections (%d) reached - try again later\n",
lp_max_connections(i));
@@ -246,11 +258,10 @@ static int rsync_module(int f_in, int f_out, int i)
return -1;
}
auth_user = auth_server(f_in, f_out, i, addr, "@RSYNCD: AUTHREQD ");
if (!auth_user) {
rprintf(FERROR,"auth failed on module %s from %s (%s)\n",
rprintf(FLOG, "auth failed on module %s from %s (%s)\n",
name, host, addr);
io_printf(f_out, "@ERROR: auth failed on module %s\n", name);
return -1;
@@ -263,8 +274,8 @@ static int rsync_module(int f_in, int f_out, int i)
if (am_root) {
p = lp_uid(i);
if (!name_to_uid(p, &uid)) {
if (!isdigit(* (unsigned char *) p)) {
rprintf(FERROR,"Invalid uid %s\n", p);
if (!isdigit(*(unsigned char *)p)) {
rprintf(FLOG, "Invalid uid %s\n", p);
io_printf(f_out, "@ERROR: invalid uid %s\n", p);
return -1;
}
@@ -273,8 +284,8 @@ static int rsync_module(int f_in, int f_out, int i)
p = lp_gid(i);
if (!name_to_gid(p, &gid)) {
if (!isdigit(* (unsigned char *) p)) {
rprintf(FERROR,"Invalid gid %s\n", p);
if (!isdigit(*(unsigned char *)p)) {
rprintf(FLOG, "Invalid gid %s\n", p);
io_printf(f_out, "@ERROR: invalid gid %s\n", p);
return -1;
}
@@ -326,20 +337,20 @@ static int rsync_module(int f_in, int f_out, int i)
* in which case we fail.
*/
if (chroot(lp_path(i))) {
rsyserr(FERROR, errno, "chroot %s failed", lp_path(i));
rsyserr(FLOG, errno, "chroot %s failed", lp_path(i));
io_printf(f_out, "@ERROR: chroot failed\n");
return -1;
}
if (!push_dir("/")) {
rsyserr(FERROR, errno, "chdir %s failed\n", lp_path(i));
rsyserr(FLOG, errno, "chdir %s failed\n", lp_path(i));
io_printf(f_out, "@ERROR: chdir failed\n");
return -1;
}
} else {
if (!push_dir(lp_path(i))) {
rsyserr(FERROR, errno, "chdir %s failed\n", lp_path(i));
rsyserr(FLOG, errno, "chdir %s failed\n", lp_path(i));
io_printf(f_out, "@ERROR: chdir failed\n");
return -1;
}
@@ -358,7 +369,7 @@ static int rsync_module(int f_in, int f_out, int i)
* all their supplementary groups. */
if (setgid(gid)) {
rsyserr(FERROR, errno, "setgid %d failed", (int) gid);
rsyserr(FLOG, errno, "setgid %d failed", (int)gid);
io_printf(f_out, "@ERROR: setgid failed\n");
return -1;
}
@@ -366,14 +377,14 @@ static int rsync_module(int f_in, int f_out, int i)
/* Get rid of any supplementary groups this process
* might have inheristed. */
if (setgroups(1, &gid)) {
rsyserr(FERROR, errno, "setgroups failed");
rsyserr(FLOG, errno, "setgroups failed");
io_printf(f_out, "@ERROR: setgroups failed\n");
return -1;
}
#endif
if (setuid(uid)) {
rsyserr(FERROR, errno, "setuid %d failed", (int) uid);
rsyserr(FLOG, errno, "setuid %d failed", (int)uid);
io_printf(f_out, "@ERROR: setuid failed\n");
return -1;
}
@@ -383,39 +394,39 @@ static int rsync_module(int f_in, int f_out, int i)
io_printf(f_out, "@RSYNCD: OK\n");
maxargs = MAX_ARGS;
if (!(argv = new_array(char *, maxargs)))
out_of_memory("rsync_module");
argv[argc++] = "rsyncd";
while (1) {
if (!read_line(f_in, line, sizeof(line)-1)) {
if (!read_line(f_in, line, sizeof line - 1))
return -1;
}
if (!*line) break;
if (!*line)
break;
p = line;
argv[argc] = strdup(p);
if (!argv[argc]) {
return -1;
if (argc == maxargs) {
maxargs += MAX_ARGS;
if (!(argv = realloc_array(argv, char *, maxargs)))
out_of_memory("rsync_module");
}
if (!(argv[argc] = strdup(p)))
out_of_memory("rsync_module");
if (start_glob) {
if (start_glob == 1) {
request = strdup(p);
start_glob++;
}
glob_expand(name, argv, &argc, MAX_ARGS);
} else {
glob_expand(name, &argv, &argc, &maxargs);
} else
argc++;
}
if (strcmp(line,".") == 0) {
if (strcmp(line, ".") == 0)
start_glob = 1;
}
if (argc == MAX_ARGS) {
return -1;
}
}
argp = argv;
@@ -426,12 +437,12 @@ static int rsync_module(int f_in, int f_out, int i)
if (request) {
if (*auth_user) {
rprintf(FINFO,"rsync %s %s from %s@%s (%s)\n",
am_sender?"on":"to",
rprintf(FLOG, "rsync %s %s from %s@%s (%s)\n",
am_sender ? "on" : "to",
request, auth_user, host, addr);
} else {
rprintf(FINFO,"rsync %s %s from %s (%s)\n",
am_sender?"on":"to",
rprintf(FLOG, "rsync %s %s from %s (%s)\n",
am_sender ? "on" : "to",
request, host, addr);
}
free(request);
@@ -443,27 +454,27 @@ static int rsync_module(int f_in, int f_out, int i)
verbose = lp_max_verbosity();
#endif
if (protocol_version < 23) {
if (protocol_version == 22 || am_sender)
io_start_multiplex_out(f_out);
if (protocol_version < 23
&& (protocol_version == 22 || am_sender))
io_start_multiplex_out();
else if (!ret) {
/* We have to get I/O multiplexing started so that we can
* get the error back to the client. This means getting
* the protocol setup finished first in later versions. */
setup_protocol(f_out, f_in);
if (files_from && !am_sender && strcmp(files_from, "-") != 0)
write_byte(f_out, 0);
io_start_multiplex_out();
}
/* For later protocol versions, we don't start multiplexing
* until we've configured nonblocking in start_server. That
* means we're in a sticky situation now: there's no way to
* convey errors to the client. */
/* FIXME: Hold off on reporting option processing errors until
* we've set up nonblocking and multiplexed IO and can get the
* message back to them. */
if (!ret) {
option_error();
msleep(400);
exit_cleanup(RERR_UNSUPPORTED);
}
if (lp_timeout(i)) {
if (lp_timeout(i))
io_timeout = lp_timeout(i);
}
start_server(f_in, f_out, argc, argp);
@@ -477,9 +488,10 @@ static void send_listing(int fd)
int n = lp_numservices();
int i;
for (i=0;i<n;i++)
for (i = 0; i < n; i++) {
if (lp_list(i))
io_printf(fd, "%-15s\t%s\n", lp_name(i), lp_comment(i));
}
if (protocol_version >= 25)
io_printf(fd,"@RSYNCD: EXIT\n");
@@ -492,11 +504,12 @@ int start_daemon(int f_in, int f_out)
{
char line[200];
char *motd;
int i = -1;
int i;
if (!lp_load(config_file, 0)) {
io_set_sock_fds(f_in, f_out);
if (!lp_load(config_file, 0))
exit_cleanup(RERR_SYNTAX);
}
log_init();
@@ -512,19 +525,19 @@ int start_daemon(int f_in, int f_out)
if (motd && *motd) {
FILE *f = fopen(motd,"r");
while (f && !feof(f)) {
int len = fread(line, 1, sizeof(line)-1, f);
int len = fread(line, 1, sizeof line - 1, f);
if (len > 0) {
line[len] = 0;
io_printf(f_out, "%s", line);
}
}
if (f) fclose(f);
if (f)
fclose(f);
io_printf(f_out, "\n");
}
if (!read_line(f_in, line, sizeof(line)-1)) {
if (!read_line(f_in, line, sizeof line - 1))
return -1;
}
if (sscanf(line,"@RSYNCD: %d", &remote_protocol) != 1) {
io_printf(f_out, "@ERROR: protocol startup error\n");
@@ -533,28 +546,28 @@ int start_daemon(int f_in, int f_out)
if (protocol_version > remote_protocol)
protocol_version = remote_protocol;
while (i == -1) {
line[0] = 0;
if (!read_line(f_in, line, sizeof(line)-1)) {
return -1;
}
line[0] = 0;
if (!read_line(f_in, line, sizeof line - 1))
return -1;
if (!*line || strcmp(line,"#list")==0) {
send_listing(f_out);
return -1;
}
if (!*line || strcmp(line, "#list") == 0) {
send_listing(f_out);
return -1;
}
if (*line == '#') {
/* it's some sort of command that I don't understand */
io_printf(f_out, "@ERROR: Unknown command '%s'\n", line);
return -1;
}
if (*line == '#') {
/* it's some sort of command that I don't understand */
io_printf(f_out, "@ERROR: Unknown command '%s'\n", line);
return -1;
}
i = lp_number(line);
if (i == -1) {
io_printf(f_out, "@ERROR: Unknown module '%s'\n", line);
return -1;
}
if ((i = lp_number(line)) < 0) {
char *addr = client_addr(f_in);
char *host = client_name(f_in);
rprintf(FLOG, "unknown module '%s' tried from %s (%s)\n",
line, host, addr);
io_printf(f_out, "@ERROR: Unknown module '%s'\n", line);
return -1;
}
return rsync_module(f_in, f_out, i);
@@ -571,7 +584,7 @@ int daemon_main(void)
/* we are running via inetd - close off stdout and
* stderr so that library functions (and getopt) don't
* try to use them. Redirect them to /dev/null */
for (i=1;i<3;i++) {
for (i = 1; i < 3; i++) {
close(i);
open("/dev/null", O_RDWR);
}
@@ -582,13 +595,12 @@ int daemon_main(void)
if (!no_detach)
become_daemon();
if (!lp_load(config_file, 1)) {
if (!lp_load(config_file, 1))
exit_cleanup(RERR_SYNTAX);
}
log_init();
rprintf(FINFO, "rsyncd version %s starting, listening on port %d\n",
rprintf(FLOG, "rsyncd version %s starting, listening on port %d\n",
RSYNC_VERSION, rsync_port);
/* TODO: If listening on a particular address, then show that
* address too. In fact, why not just do inet_ntop on the

View File

@@ -27,36 +27,27 @@
int remote_protocol = 0;
extern int am_server;
extern int preserve_links;
extern int preserve_perms;
extern int preserve_devices;
extern int preserve_uid;
extern int preserve_gid;
extern int preserve_times;
extern int always_checksum;
extern int checksum_seed;
extern int protocol_version;
extern int verbose;
extern int am_server;
extern int am_sender;
extern int read_batch;
extern int write_batch;
extern int checksum_seed;
extern int protocol_version;
void setup_protocol(int f_out,int f_in)
{
if (remote_protocol == 0) {
if (am_server) {
remote_protocol = read_int(f_in);
if (!read_batch)
write_int(f_out, protocol_version);
} else {
write_int(f_out, protocol_version);
remote_protocol = read_int(f_in);
}
remote_protocol = read_int(f_in);
if (protocol_version > remote_protocol)
protocol_version = remote_protocol;
}
if (read_batch && remote_protocol > protocol_version) {
rprintf(FERROR, "The protocol version in the batch file is too new (%d > %d).\n",
remote_protocol, protocol_version);
exit_cleanup(RERR_PROTOCOL);
}
if (verbose > 3) {
rprintf(FINFO, "(%s) Protocol versions: remote=%d, negotiated=%d\n",

View File

@@ -5,7 +5,7 @@ AC_CONFIG_SRCDIR([byteorder.h])
AC_CONFIG_HEADER(config.h)
AC_PREREQ(2.52)
RSYNC_VERSION=2.6.1
RSYNC_VERSION=2.6.3
AC_SUBST(RSYNC_VERSION)
AC_MSG_NOTICE([Configuring rsync $RSYNC_VERSION])
@@ -146,21 +146,26 @@ AC_TRY_RUN([
int main(void)
{
struct flock lock;
int status;
int fd = open("conftest.dat", O_CREAT|O_RDWR, 0600);
int status;
char tpl[32] = "/tmp/locktest.XXXXXX";
int fd = mkstemp(tpl);
if (fd < 0) {
strcpy(tpl, "conftest.dat");
fd = open(tpl, O_CREAT|O_RDWR, 0600);
}
lock.l_type = F_WRLCK;
lock.l_whence = SEEK_SET;
lock.l_start = 0;
lock.l_len = 1;
lock.l_pid = 0;
fcntl(fd,F_SETLK,&lock);
if (fork() == 0) {
lock.l_start = 1;
exit(fcntl(fd,F_SETLK,&lock) == 0);
}
wait(&status);
unlink("conftest.dat");
lock.l_start = 1;
_exit(fcntl(fd,F_SETLK,&lock) == 0);
}
wait(&status);
unlink(tpl);
exit(WEXITSTATUS(status));
}
],
@@ -282,7 +287,7 @@ AC_HEADER_SYS_WAIT
AC_CHECK_HEADERS(sys/fcntl.h sys/select.h fcntl.h sys/time.h sys/unistd.h \
unistd.h utime.h grp.h compat.h sys/param.h ctype.h sys/wait.h \
sys/ioctl.h sys/filio.h string.h stdlib.h sys/socket.h sys/mode.h \
sys/un.h glob.h mcheck.h sys/sysctl.h arpa/inet.h arpa/nameser.h \
sys/un.h glob.h mcheck.h arpa/inet.h arpa/nameser.h \
netdb.h malloc.h float.h)
AC_HEADER_MAJOR
@@ -437,9 +442,10 @@ dnl AC_FUNC_MEMCMP
AC_FUNC_UTIME_NULL
AC_FUNC_ALLOCA
AC_CHECK_FUNCS(waitpid wait4 getcwd strdup strerror chown chmod mknod mkfifo \
fchmod fstat strchr readlink link utime utimes strftime mtrace \
fchmod fstat strchr readlink link utime utimes strftime mtrace ftruncate \
memmove lchown vsnprintf snprintf asprintf setsid glob strpbrk \
strlcat strlcpy strtol mallinfo getgroups setgroups geteuid getegid)
strlcat strlcpy strtol mallinfo getgroups setgroups geteuid getegid \
open64 mkstemp64)
AC_CACHE_CHECK([for working socketpair],rsync_cv_HAVE_SOCKETPAIR,[
AC_TRY_RUN([
@@ -537,7 +543,7 @@ AC_TRY_RUN([
#include <unistd.h>
main() { struct timeval tv; exit(gettimeofday(&tv, NULL));}],
rsync_cv_HAVE_GETTIMEOFDAY_TZ=yes,rsync_cv_HAVE_GETTIMEOFDAY_TZ=no,rsync_cv_HAVE_GETTIMEOFDAY_TZ=cross)])
if test x"$rsync_cv_HAVE_GETTIMEOFDAY_TZ" = x"yes"; then
if test x"$rsync_cv_HAVE_GETTIMEOFDAY_TZ" != x"no"; then
AC_DEFINE(HAVE_GETTIMEOFDAY_TZ, 1, [ ])
fi

131
exclude.c
View File

@@ -38,24 +38,23 @@ struct exclude_list_struct local_exclude_list = { 0, 0, "per-dir .cvsignore " };
struct exclude_list_struct server_exclude_list = { 0, 0, "server " };
char *exclude_path_prefix = NULL;
/** Build an exclude structure given a exclude pattern */
static void make_exclude(struct exclude_list_struct *listp, const char *pattern,
int pat_len, int include)
/** Build an exclude structure given an exclude pattern. */
static void make_exclude(struct exclude_list_struct *listp, const char *pat,
unsigned int pat_len, unsigned int mflags)
{
struct exclude_struct *ret;
const char *cp;
int ex_len;
unsigned int ex_len;
ret = new(struct exclude_struct);
if (!ret)
out_of_memory("make_exclude");
memset(ret, 0, sizeof ret[0]);
ret->include = include;
if (exclude_path_prefix)
ret->match_flags |= MATCHFLG_ABS_PATH;
if (exclude_path_prefix && *pattern == '/')
mflags |= MATCHFLG_ABS_PATH;
if (exclude_path_prefix && *pat == '/')
ex_len = strlen(exclude_path_prefix);
else
ex_len = 0;
@@ -64,27 +63,29 @@ static void make_exclude(struct exclude_list_struct *listp, const char *pattern,
out_of_memory("make_exclude");
if (ex_len)
memcpy(ret->pattern, exclude_path_prefix, ex_len);
strlcpy(ret->pattern + ex_len, pattern, pat_len + 1);
strlcpy(ret->pattern + ex_len, pat, pat_len + 1);
pat_len += ex_len;
if (strpbrk(ret->pattern, "*[?")) {
ret->match_flags |= MATCHFLG_WILD;
mflags |= MATCHFLG_WILD;
if ((cp = strstr(ret->pattern, "**")) != NULL) {
ret->match_flags |= MATCHFLG_WILD2;
mflags |= MATCHFLG_WILD2;
/* If the pattern starts with **, note that. */
if (cp == ret->pattern)
ret->match_flags |= MATCHFLG_WILD2_PREFIX;
mflags |= MATCHFLG_WILD2_PREFIX;
}
}
if (pat_len > 1 && ret->pattern[pat_len-1] == '/') {
ret->pattern[pat_len-1] = 0;
ret->directory = 1;
mflags |= MATCHFLG_DIRECTORY;
}
for (cp = ret->pattern; (cp = strchr(cp, '/')) != NULL; cp++)
ret->slash_cnt++;
ret->match_flags = mflags;
if (!listp->tail)
listp->head = listp->tail = ret;
else {
@@ -99,15 +100,10 @@ static void free_exclude(struct exclude_struct *ex)
free(ex);
}
void free_exclude_list(struct exclude_list_struct *listp)
void clear_exclude_list(struct exclude_list_struct *listp)
{
struct exclude_struct *ent, *next;
if (verbose > 2) {
rprintf(FINFO, "[%s] clearing %sexclude list\n",
who_am_i(), listp->debug_type);
}
for (ent = listp->head; ent; ent = next) {
next = ent->next;
free_exclude(ent);
@@ -119,10 +115,13 @@ void free_exclude_list(struct exclude_list_struct *listp)
static int check_one_exclude(char *name, struct exclude_struct *ex,
int name_is_dir)
{
char *p;
char *p, full_name[MAXPATHLEN];
int match_start = 0;
char *pattern = ex->pattern;
if (!*name)
return 0;
/* If the pattern does not have any slashes AND it does not have
* a "**" (which could match a slash), then we just match the
* name portion of the path. */
@@ -130,16 +129,14 @@ static int check_one_exclude(char *name, struct exclude_struct *ex,
if ((p = strrchr(name,'/')) != NULL)
name = p+1;
}
else if ((ex->match_flags & MATCHFLG_ABS_PATH) && *name != '/') {
static char full_name[MAXPATHLEN];
int plus = curr_dir[1] == '\0'? 1 : 0;
pathjoin(full_name, sizeof full_name, curr_dir+plus, name);
else if (ex->match_flags & MATCHFLG_ABS_PATH && *name != '/'
&& curr_dir[1]) {
pathjoin(full_name, sizeof full_name, curr_dir + 1, name);
name = full_name;
}
if (!name[0]) return 0;
if (ex->directory && !name_is_dir) return 0;
if (ex->match_flags & MATCHFLG_DIRECTORY && !name_is_dir)
return 0;
if (*pattern == '/') {
match_start = 1;
@@ -151,8 +148,8 @@ static int check_one_exclude(char *name, struct exclude_struct *ex,
if (ex->match_flags & MATCHFLG_WILD) {
/* A non-anchored match with an infix slash and no "**"
* needs to match the last slash_cnt+1 name elements. */
if (!match_start && ex->slash_cnt &&
!(ex->match_flags & MATCHFLG_WILD2)) {
if (!match_start && ex->slash_cnt
&& !(ex->match_flags & MATCHFLG_WILD2)) {
int cnt = ex->slash_cnt + 1;
for (p = name + strlen(name) - 1; p >= name; p--) {
if (*p == '/' && !--cnt)
@@ -206,9 +203,11 @@ static void report_exclude_result(char const *name,
if (verbose >= 2) {
rprintf(FINFO, "[%s] %scluding %s %s because of %spattern %s%s\n",
who_am_i(), ent->include ? "in" : "ex",
who_am_i(),
ent->match_flags & MATCHFLG_INCLUDE ? "in" : "ex",
name_is_dir ? "directory" : "file", name, type,
ent->pattern, ent->directory ? "/" : "");
ent->pattern,
ent->match_flags & MATCHFLG_DIRECTORY ? "/" : "");
}
}
@@ -225,7 +224,7 @@ int check_exclude(struct exclude_list_struct *listp, char *name, int name_is_dir
if (check_one_exclude(name, ent, name_is_dir)) {
report_exclude_result(name, ent, name_is_dir,
listp->debug_type);
return ent->include ? 1 : -1;
return ent->match_flags & MATCHFLG_INCLUDE ? 1 : -1;
}
}
@@ -236,16 +235,15 @@ int check_exclude(struct exclude_list_struct *listp, char *name, int name_is_dir
/* Get the next include/exclude arg from the string. The token will not
* be '\0' terminated, so use the returned length to limit the string.
* Also, be sure to add this length to the returned pointer before passing
* it back to ask for the next token. This routine will not parse the +/-
* prefixes or the "!" token when xflags contains XFLG_WORDS_ONLY. The
* *incl_ptr value will be 1 for an include, 0 for an exclude, and -1 for
* the list-clearing "!" token.
* it back to ask for the next token. This routine parses the +/- prefixes
* and the "!" token unless xflags contains XFLG_WORDS_ONLY. The *flag_ptr
* value will also be set to the MATCHFLG_* bits for the current token.
*/
static const char *get_exclude_tok(const char *p, int *len_ptr, int *incl_ptr,
int xflags)
static const char *get_exclude_tok(const char *p, unsigned int *len_ptr,
unsigned int *flag_ptr, int xflags)
{
const unsigned char *s = (const unsigned char *)p;
int len;
unsigned int len, mflags = 0;
if (xflags & XFLG_WORD_SPLIT) {
/* Skip over any initial whitespace. */
@@ -258,10 +256,13 @@ static const char *get_exclude_tok(const char *p, int *len_ptr, int *incl_ptr,
/* Is this a '+' or '-' followed by a space (not whitespace)? */
if (!(xflags & XFLG_WORDS_ONLY)
&& (*s == '-' || *s == '+') && s[1] == ' ') {
*incl_ptr = *s == '+';
if (*s == '+')
mflags |= MATCHFLG_INCLUDE;
s += 2;
} else
*incl_ptr = xflags & XFLG_DEF_INCLUDE;
} else if (xflags & XFLG_DEF_INCLUDE)
mflags |= MATCHFLG_INCLUDE;
if (xflags & XFLG_DIRECTORY)
mflags |= MATCHFLG_DIRECTORY;
if (xflags & XFLG_WORD_SPLIT) {
const unsigned char *cp = s;
@@ -273,9 +274,10 @@ static const char *get_exclude_tok(const char *p, int *len_ptr, int *incl_ptr,
len = strlen(s);
if (*p == '!' && len == 1 && !(xflags & XFLG_WORDS_ONLY))
*incl_ptr = -1;
mflags |= MATCHFLG_CLEAR_LIST;
*len_ptr = len;
*flag_ptr = mflags;
return (const char *)s;
}
@@ -283,7 +285,7 @@ static const char *get_exclude_tok(const char *p, int *len_ptr, int *incl_ptr,
void add_exclude(struct exclude_list_struct *listp, const char *pattern,
int xflags)
{
int pat_len, incl;
unsigned int pat_len, mflags;
const char *cp;
if (!pattern)
@@ -292,21 +294,26 @@ void add_exclude(struct exclude_list_struct *listp, const char *pattern,
cp = pattern;
pat_len = 0;
while (1) {
cp = get_exclude_tok(cp + pat_len, &pat_len, &incl, xflags);
cp = get_exclude_tok(cp + pat_len, &pat_len, &mflags, xflags);
if (!pat_len)
break;
/* If we got the special "!" token, clear the list. */
if (incl < 0)
free_exclude_list(listp);
else {
make_exclude(listp, cp, pat_len, incl);
if (mflags & MATCHFLG_CLEAR_LIST) {
if (verbose > 2) {
rprintf(FINFO, "[%s] add_exclude(%.*s, %s%s)\n",
who_am_i(), pat_len, cp,
listp->debug_type,
incl ? "include" : "exclude");
rprintf(FINFO,
"[%s] clearing %sexclude list\n",
who_am_i(), listp->debug_type);
}
clear_exclude_list(listp);
continue;
}
make_exclude(listp, cp, pat_len, mflags);
if (verbose > 2) {
rprintf(FINFO, "[%s] add_exclude(%.*s, %s%sclude)\n",
who_am_i(), (int)pat_len, cp, listp->debug_type,
mflags & MATCHFLG_INCLUDE ? "in" : "ex");
}
}
}
@@ -316,8 +323,8 @@ void add_exclude_file(struct exclude_list_struct *listp, const char *fname,
int xflags)
{
FILE *fp;
char line[MAXPATHLEN];
char *eob = line + MAXPATHLEN - 1;
char line[MAXPATHLEN+3]; /* Room for "x " prefix and trailing slash. */
char *eob = line + sizeof line - 1;
int word_split = xflags & XFLG_WORD_SPLIT;
if (!fname || !*fname)
@@ -340,7 +347,7 @@ void add_exclude_file(struct exclude_list_struct *listp, const char *fname,
while (1) {
char *s = line;
int ch;
int ch, overflow = 0;
while (1) {
if ((ch = getc(fp)) == EOF) {
if (ferror(fp) && errno == EINTR)
@@ -353,6 +360,12 @@ void add_exclude_file(struct exclude_list_struct *listp, const char *fname,
break;
if (s < eob)
*s++ = ch;
else
overflow = 1;
}
if (overflow) {
rprintf(FERROR, "discarding over-long exclude: %s...\n", line);
s = line;
}
*s = '\0';
/* Skip an empty token and (when line parsing) comments. */
@@ -383,12 +396,12 @@ void send_exclude_list(int f)
l = strlcpy(p, ent->pattern, sizeof p);
if (l == 0 || l >= MAXPATHLEN)
continue;
if (ent->directory) {
if (ent->match_flags & MATCHFLG_DIRECTORY) {
p[l++] = '/';
p[l] = '\0';
}
if (ent->include) {
if (ent->match_flags & MATCHFLG_INCLUDE) {
write_int(f, l + 2);
write_buf(f, "+ ", 2);
} else if ((*p == '-' || *p == '+') && p[1] == ' ') {
@@ -405,7 +418,7 @@ void send_exclude_list(int f)
void recv_exclude_list(int f)
{
char line[MAXPATHLEN+1]; /* Allows a trailing slash on a max-len dir */
char line[MAXPATHLEN+3]; /* Room for "x " prefix and trailing slash. */
unsigned int l;
while ((l = read_int(f)) != 0) {

View File

@@ -22,9 +22,10 @@
*/
#include "rsync.h"
extern int sparse_files;
static char last_byte;
static int last_sparse;
extern int sparse_files;
int sparse_end(int f)
{
@@ -91,6 +92,7 @@ int flush_write_file(int f)
return ret;
}
/*
* write_file does not allow incomplete writes. It loops internally
* until len bytes are written or errno is set.
@@ -106,9 +108,9 @@ int write_file(int f,char *buf,size_t len)
r1 = write_sparse(f, buf, len1);
} else {
if (!wf_writeBuf) {
wf_writeBufSize = MAX_MAP_SIZE;
wf_writeBufSize = WRITE_SIZE * 8;
wf_writeBufCnt = 0;
wf_writeBuf = new_array(char, MAX_MAP_SIZE);
wf_writeBuf = new_array(char, wf_writeBufSize);
if (!wf_writeBuf)
out_of_memory("write_file");
}
@@ -125,7 +127,8 @@ int write_file(int f,char *buf,size_t len)
}
}
if (r1 <= 0) {
if (ret > 0) return ret;
if (ret > 0)
return ret;
return r1;
}
len -= r1;
@@ -136,29 +139,30 @@ int write_file(int f,char *buf,size_t len)
}
/* this provides functionality somewhat similar to mmap() but using
read(). It gives sliding window access to a file. mmap() is not
used because of the possibility of another program (such as a
mailer) truncating the file thus giving us a SIGBUS */
struct map_struct *map_file(int fd,OFF_T len)
/* This provides functionality somewhat similar to mmap() but using read().
* It gives sliding window access to a file. mmap() is not used because of
* the possibility of another program (such as a mailer) truncating the
* file thus giving us a SIGBUS. */
struct map_struct *map_file(int fd, OFF_T len, OFF_T map_size,
size_t block_size)
{
struct map_struct *map;
map = new(struct map_struct);
if (!map) out_of_memory("map_file");
if (!(map = new(struct map_struct)))
out_of_memory("map_file");
if (block_size && (map_size % block_size))
map_size += block_size - (map_size % block_size);
memset(map, 0, sizeof map[0]);
map->fd = fd;
map->file_size = len;
map->p = NULL;
map->p_size = 0;
map->p_offset = 0;
map->p_fd_offset = 0;
map->p_len = 0;
map->status = 0;
map->def_window_size = map_size;
return map;
}
/* slide the read window in the file */
char *map_ptr(struct map_struct *map,OFF_T offset,int len)
{
@@ -166,9 +170,8 @@ char *map_ptr(struct map_struct *map,OFF_T offset,int len)
OFF_T window_start, read_start;
int window_size, read_size, read_offset;
if (len == 0) {
if (len == 0)
return NULL;
}
/* can't go beyond the end of file */
if (len > (map->file_size - offset)) {
@@ -181,15 +184,9 @@ char *map_ptr(struct map_struct *map,OFF_T offset,int len)
return (map->p + (offset - map->p_offset));
}
/* nope, we are going to have to do a read. Work out our desired window */
if (offset > 2*CHUNK_SIZE) {
window_start = offset - 2*CHUNK_SIZE;
window_start &= ~((OFF_T)(CHUNK_SIZE-1)); /* assumes power of 2 */
} else {
window_start = 0;
}
window_size = MAX_MAP_SIZE;
window_start = offset;
window_size = map->def_window_size;
if (window_start + window_size > map->file_size) {
window_size = map->file_size - window_start;
}
@@ -200,7 +197,8 @@ char *map_ptr(struct map_struct *map,OFF_T offset,int len)
/* make sure we have allocated enough memory for the window */
if (window_size > map->p_size) {
map->p = realloc_array(map->p, char, window_size);
if (!map->p) out_of_memory("map_ptr");
if (!map->p)
out_of_memory("map_ptr");
map->p_size = window_size;
}
@@ -259,9 +257,8 @@ int unmap_file(struct map_struct *map)
map->p = NULL;
}
ret = map->status;
memset(map, 0, sizeof(*map));
memset(map, 0, sizeof map[0]);
free(map);
return ret;
}

220
flist.c
View File

@@ -34,6 +34,7 @@ extern int do_progress;
extern int am_root;
extern int am_server;
extern int am_daemon;
extern int am_sender;
extern int always_checksum;
extern int module_id;
extern int ignore_errors;
@@ -47,22 +48,22 @@ extern char *files_from;
extern int filesfrom_fd;
extern int one_file_system;
extern int keep_dirlinks;
extern int preserve_links;
extern int preserve_hard_links;
extern int preserve_perms;
extern int preserve_devices;
extern int preserve_uid;
extern int preserve_gid;
extern int preserve_times;
extern int relative_paths;
extern int implied_dirs;
extern int copy_links;
extern int copy_unsafe_links;
extern int protocol_version;
extern int sanitize_paths;
extern int read_batch;
extern int write_batch;
extern int delete_excluded;
extern int orig_umask;
extern int list_only;
extern struct exclude_list_struct exclude_list;
extern struct exclude_list_struct server_exclude_list;
@@ -72,6 +73,7 @@ int io_error;
static char empty_sum[MD4_SUM_LENGTH];
static unsigned int file_struct_len;
static struct file_list *received_flist;
static void clean_flist(struct file_list *flist, int strip_root, int no_dups);
static void output_flist(struct file_list *flist);
@@ -93,7 +95,7 @@ static int show_filelist_p(void)
static void start_filelist_progress(char *kind)
{
rprintf(FINFO, "%s ... ", kind);
if ((verbose > 1) || do_progress)
if (verbose > 1 || do_progress)
rprintf(FINFO, "\n");
rflush(FINFO);
}
@@ -107,7 +109,7 @@ static void emit_filelist_progress(const struct file_list *flist)
static void maybe_emit_filelist_progress(const struct file_list *flist)
{
if (do_progress && show_filelist_p() && ((flist->count % 100) == 0))
if (do_progress && show_filelist_p() && (flist->count % 100) == 0)
emit_filelist_progress(flist);
}
@@ -132,9 +134,10 @@ static void list_file_entry(struct file_struct *f)
{
char perms[11];
if (!f->basename)
if (!f->basename) {
/* this can happen if duplicate names were removed */
return;
}
permstring(perms, f->mode);
@@ -142,14 +145,16 @@ static void list_file_entry(struct file_struct *f)
if (preserve_links && S_ISLNK(f->mode)) {
rprintf(FINFO, "%s %11.0f %s %s -> %s\n",
perms,
(double) f->length, timestring(f->modtime),
(double)f->length, timestring(f->modtime),
f_name(f), f->u.link);
} else
#endif
{
rprintf(FINFO, "%s %11.0f %s %s\n",
perms,
(double) f->length, timestring(f->modtime),
(double)f->length, timestring(f->modtime),
f_name(f));
}
}
@@ -167,15 +172,15 @@ static void list_file_entry(struct file_struct *f)
* @post @p buffer contains information about the link or the
* referrent as appropriate, if they exist.
**/
int readlink_stat(const char *path, STRUCT_STAT *buffer, char *linkbuf)
static int readlink_stat(const char *path, STRUCT_STAT *buffer, char *linkbuf)
{
#if SUPPORT_LINKS
if (copy_links)
return do_stat(path, buffer);
if (do_lstat(path, buffer) == -1)
if (link_stat(path, buffer, 0) < 0)
return -1;
if (S_ISLNK(buffer->st_mode)) {
int l = readlink((char *) path, linkbuf, MAXPATHLEN - 1);
int l = readlink((char *)path, linkbuf, MAXPATHLEN - 1);
if (l == -1)
return -1;
linkbuf[l] = 0;
@@ -193,12 +198,19 @@ int readlink_stat(const char *path, STRUCT_STAT *buffer, char *linkbuf)
#endif
}
int link_stat(const char *path, STRUCT_STAT * buffer)
int link_stat(const char *path, STRUCT_STAT *buffer, int follow_dirlinks)
{
#if SUPPORT_LINKS
if (copy_links)
return do_stat(path, buffer);
return do_lstat(path, buffer);
if (do_lstat(path, buffer) < 0)
return -1;
if (follow_dirlinks && S_ISLNK(buffer->st_mode)) {
STRUCT_STAT st;
if (do_stat(path, &st) == 0 && S_ISDIR(st.st_mode))
*buffer = st;
}
return 0;
#else
return do_stat(path, buffer);
#endif
@@ -248,7 +260,7 @@ static dev_t filesystem_dev;
static void set_filesystem(char *fname)
{
STRUCT_STAT st;
if (link_stat(fname, &st) != 0)
if (do_stat(fname, &st) != 0)
return;
filesystem_dev = st.st_dev;
}
@@ -260,14 +272,14 @@ static int to_wire_mode(mode_t mode)
if (S_ISLNK(mode) && (_S_IFLNK != 0120000))
return (mode & ~(_S_IFMT)) | 0120000;
#endif
return (int) mode;
return (int)mode;
}
static mode_t from_wire_mode(int mode)
{
if ((mode & (_S_IFMT)) == 0120000 && (_S_IFLNK != 0120000))
return (mode & ~(_S_IFMT)) | _S_IFLNK;
return (mode_t) mode;
return (mode_t)mode;
}
@@ -283,7 +295,7 @@ static int flist_dir_len;
**/
void flist_expand(struct file_list *flist)
{
void *new_ptr;
struct file_struct **new_ptr;
if (flist->count < flist->malloced)
return;
@@ -302,21 +314,17 @@ void flist_expand(struct file_list *flist)
if (flist->malloced < flist->count)
flist->malloced = flist->count;
if (flist->files) {
new_ptr = realloc_array(flist->files,
struct file_struct *, flist->malloced);
} else {
new_ptr = new_array(struct file_struct *, flist->malloced);
}
new_ptr = realloc_array(flist->files, struct file_struct *,
flist->malloced);
if (verbose >= 2) {
rprintf(FINFO, "[%s] expand file_list to %.0f bytes, did%s move\n",
who_am_i(),
(double) sizeof flist->files[0] * flist->malloced,
(double)sizeof flist->files[0] * flist->malloced,
(new_ptr == flist->files) ? " not" : "");
}
flist->files = (struct file_struct **) new_ptr;
flist->files = new_ptr;
if (!flist->files)
out_of_memory("flist_expand");
@@ -333,7 +341,7 @@ void send_file_entry(struct file_struct *file, int f, unsigned short base_flags)
static uid_t uid;
static gid_t gid;
static char lastname[MAXPATHLEN];
char *fname, fbuf[MAXPATHLEN];
char fname[MAXPATHLEN];
int l1, l2;
if (f == -1)
@@ -351,7 +359,7 @@ void send_file_entry(struct file_struct *file, int f, unsigned short base_flags)
io_write_phase = "send_file_entry";
fname = f_name_to(file, fbuf);
f_name_to(file, fname);
flags = base_flags;
@@ -515,7 +523,7 @@ void send_file_entry(struct file_struct *file, int f, unsigned short base_flags)
void receive_file_entry(struct file_struct **fptr, unsigned short flags,
struct file_list *flist, int f)
struct file_list *flist, int f)
{
static time_t modtime;
static mode_t mode;
@@ -525,7 +533,7 @@ void receive_file_entry(struct file_struct **fptr, unsigned short flags,
static uid_t uid;
static gid_t gid;
static char lastname[MAXPATHLEN], *lastdir;
static int lastdir_len = -1;
static int lastdir_depth, lastdir_len = -1;
char thisname[MAXPATHLEN];
unsigned int l1 = 0, l2 = 0;
int alloc_len, basename_len, dirname_len, linkname_len, sum_len;
@@ -539,6 +547,7 @@ void receive_file_entry(struct file_struct **fptr, unsigned short flags,
rdev_major = 0;
uid = 0, gid = 0;
*lastname = '\0';
lastdir_len = -1;
return;
}
@@ -563,10 +572,10 @@ void receive_file_entry(struct file_struct **fptr, unsigned short flags,
strlcpy(lastname, thisname, MAXPATHLEN);
clean_fname(thisname);
clean_fname(thisname, 0);
if (sanitize_paths)
sanitize_path(thisname, NULL);
sanitize_path(thisname, thisname, "", 0);
if ((basename = strrchr(thisname, '/')) != NULL) {
dirname_len = ++basename - thisname; /* counts future '\0' */
@@ -649,6 +658,8 @@ void receive_file_entry(struct file_struct **fptr, unsigned short flags,
memcpy(bp, dirname, dirname_len - 1);
bp += dirname_len;
bp[-1] = '\0';
if (sanitize_paths)
lastdir_depth = count_dir_elements(lastdir);
} else if (dirname)
file->dirname = dirname;
@@ -664,7 +675,7 @@ void receive_file_entry(struct file_struct **fptr, unsigned short flags,
file->u.link = bp;
read_sbuf(f, bp, linkname_len - 1);
if (sanitize_paths)
sanitize_path(bp, lastdir);
sanitize_path(bp, bp, "", lastdir_depth);
bp += linkname_len;
}
#endif
@@ -708,7 +719,6 @@ void receive_file_entry(struct file_struct **fptr, unsigned short flags,
}
if (!preserve_perms) {
extern int orig_umask;
/* set an appropriate set of permissions based on original
* permissions and umask. This emulates what GNU cp does */
file->mode &= ~orig_umask;
@@ -731,8 +741,8 @@ void receive_file_entry(struct file_struct **fptr, unsigned short flags,
* statting directories if we're not recursing, but this is not a very
* important case. Some systems may not have d_type.
**/
struct file_struct *make_file(char *fname,
struct file_list *flist, int exclude_level)
struct file_struct *make_file(char *fname, struct file_list *flist,
int exclude_level)
{
static char *lastdir;
static int lastdir_len = -1;
@@ -745,7 +755,7 @@ struct file_struct *make_file(char *fname,
char *basename, *dirname, *bp;
unsigned short flags = 0;
if (!flist) /* lastdir isn't valid if flist is NULL */
if (!flist || !flist->count) /* Ignore lastdir when invalid. */
lastdir_len = -1;
if (strlcpy(thisname, fname, sizeof thisname)
@@ -753,33 +763,39 @@ struct file_struct *make_file(char *fname,
rprintf(FINFO, "skipping overly long name: %s\n", fname);
return NULL;
}
clean_fname(thisname);
clean_fname(thisname, 0);
if (sanitize_paths)
sanitize_path(thisname, NULL);
sanitize_path(thisname, thisname, "", 0);
memset(sum, 0, SUM_LENGTH);
if (readlink_stat(thisname, &st, linkname) != 0) {
int save_errno = errno;
if (errno == ENOENT) {
enum logcode c = am_daemon && protocol_version < 28
? FERROR : FINFO;
/* either symlink pointing nowhere or file that
* was removed during rsync run; see if excluded
* before reporting an error */
if (exclude_level != NO_EXCLUDES
&& check_exclude_file(thisname, 0, exclude_level)) {
/* file is excluded anyway, ignore silently */
return NULL;
/* See if file is excluded before reporting an error. */
if (exclude_level != NO_EXCLUDES
&& check_exclude_file(thisname, 0, exclude_level))
return NULL;
if (save_errno == ENOENT) {
#if SUPPORT_LINKS
/* Avoid "vanished" error if symlink points nowhere. */
if (copy_links && do_lstat(thisname, &st) == 0
&& S_ISLNK(st.st_mode)) {
io_error |= IOERR_GENERAL;
rprintf(FERROR, "symlink has no referent: %s\n",
full_fname(thisname));
} else
#endif
{
enum logcode c = am_daemon && protocol_version < 28
? FERROR : FINFO;
io_error |= IOERR_VANISHED;
rprintf(c, "file has vanished: %s\n",
full_fname(thisname));
}
io_error |= IOERR_VANISHED;
rprintf(c, "file has vanished: %s\n",
full_fname(thisname));
}
else {
} else {
io_error |= IOERR_GENERAL;
rprintf(FERROR, "readlink %s failed: %s\n",
full_fname(thisname), strerror(save_errno));
rsyserr(FERROR, save_errno, "readlink %s failed",
full_fname(thisname));
}
return NULL;
}
@@ -911,6 +927,26 @@ skip_excludes:
file->basedir = flist_dir;
/* This code is only used by the receiver when it is building
* a list of files for a delete pass. */
if (keep_dirlinks && linkname_len && flist) {
STRUCT_STAT st2;
int i = flist_find(received_flist, file);
if (i >= 0 && S_ISDIR(received_flist->files[i]->mode)
&& do_stat(thisname, &st2) == 0 && S_ISDIR(st2.st_mode)) {
file->modtime = st2.st_mtime;
file->length = st2.st_size;
file->mode = st2.st_mode;
file->uid = st2.st_uid;
file->gid = st2.st_gid;
file->u.link = NULL;
if (file->link_u.idev) {
pool_free(flist->hlink_pool, 0, file->link_u.idev);
file->link_u.idev = NULL;
}
}
}
if (!S_ISDIR(st.st_mode))
stats.total_size += st.st_size;
@@ -923,7 +959,6 @@ void send_file_name(int f, struct file_list *flist, char *fname,
{
struct file_struct *file;
char fbuf[MAXPATHLEN];
extern int delete_excluded;
/* f is set to -1 when calculating deletion file list */
file = make_file(fname, flist,
@@ -936,9 +971,6 @@ void send_file_name(int f, struct file_list *flist, char *fname,
flist_expand(flist);
if (write_batch)
file->flags |= FLAG_TOP_DIR;
if (file->basename[0]) {
flist->files[flist->count++] = file;
send_file_entry(file, f, base_flags);
@@ -949,7 +981,11 @@ void send_file_name(int f, struct file_list *flist, char *fname,
struct exclude_list_struct last_list = local_exclude_list;
local_exclude_list.head = local_exclude_list.tail = NULL;
send_directory(f, flist, f_name_to(file, fbuf));
free_exclude_list(&local_exclude_list);
if (verbose > 2) {
rprintf(FINFO, "[%s] popping %sexclude list\n",
who_am_i(), local_exclude_list.debug_type);
}
clear_exclude_list(&local_exclude_list);
local_exclude_list = last_list;
}
}
@@ -966,8 +1002,7 @@ static void send_directory(int f, struct file_list *flist, char *dir)
d = opendir(dir);
if (!d) {
io_error |= IOERR_GENERAL;
rprintf(FERROR, "opendir %s failed: %s\n",
full_fname(dir), strerror(errno));
rsyserr(FERROR, errno, "opendir %s failed", full_fname(dir));
return;
}
@@ -1014,8 +1049,7 @@ static void send_directory(int f, struct file_list *flist, char *dir)
}
if (errno) {
io_error |= IOERR_GENERAL;
rprintf(FERROR, "readdir(%s): (%d) %s\n",
dir, errno, strerror(errno));
rsyserr(FERROR, errno, "readdir(%s)", dir);
}
closedir(d);
@@ -1023,6 +1057,8 @@ static void send_directory(int f, struct file_list *flist, char *dir)
/**
* This function is normally called by the sender, but the receiver also
* uses it to construct its own file list if --delete has been specified.
* The delete_files() function in receiver.c sets f to -1 so that we just
* construct the file list in memory without sending it over the wire. It
* also has the side-effect of ignoring user-excludes if delete_excluded
@@ -1047,11 +1083,11 @@ struct file_list *send_file_list(int f, int argc, char *argv[])
"send_file_list");
if (f != -1) {
io_start_buffering_out(f);
io_start_buffering_out();
if (filesfrom_fd >= 0) {
if (argv[0] && !push_dir(argv[0])) {
rprintf(FERROR, "push_dir %s failed: %s\n",
full_fname(argv[0]), strerror(errno));
rsyserr(FERROR, errno, "push_dir %s failed",
full_fname(argv[0]));
exit_cleanup(RERR_FILESELECT);
}
use_ff_fd = 1;
@@ -1065,13 +1101,13 @@ struct file_list *send_file_list(int f, int argc, char *argv[])
if (use_ff_fd) {
if (read_filesfrom_line(filesfrom_fd, fname) == 0)
break;
sanitize_path(fname, NULL);
sanitize_path(fname, fname, "", 0);
} else {
if (argc-- == 0)
break;
strlcpy(fname, *argv++, MAXPATHLEN);
if (sanitize_paths)
sanitize_path(fname, NULL);
sanitize_path(fname, fname, "", 0);
}
l = strlen(fname);
@@ -1085,11 +1121,11 @@ struct file_list *send_file_list(int f, int argc, char *argv[])
}
}
if (link_stat(fname, &st) != 0) {
if (link_stat(fname, &st, keep_dirlinks) != 0) {
if (f != -1) {
io_error |= IOERR_GENERAL;
rprintf(FERROR, "link_stat %s failed: %s\n",
full_fname(fname), strerror(errno));
rsyserr(FERROR, errno, "link_stat %s failed",
full_fname(fname));
}
continue;
}
@@ -1158,8 +1194,8 @@ struct file_list *send_file_list(int f, int argc, char *argv[])
if (!push_dir(dir)) {
io_error |= IOERR_GENERAL;
rprintf(FERROR, "push_dir %s failed: %s\n",
full_fname(dir), strerror(errno));
rsyserr(FERROR, errno, "push_dir %s failed",
full_fname(dir));
continue;
}
@@ -1181,8 +1217,8 @@ struct file_list *send_file_list(int f, int argc, char *argv[])
flist_dir = NULL;
flist_dir_len = 0;
if (!pop_dir(olddir)) {
rprintf(FERROR, "pop_dir %s failed: %s\n",
full_fname(dir), strerror(errno));
rsyserr(FERROR, errno, "pop_dir %s failed",
full_fname(dir));
exit_cleanup(RERR_FILESELECT);
}
}
@@ -1213,8 +1249,6 @@ struct file_list *send_file_list(int f, int argc, char *argv[])
io_end_buffering();
stats.flist_size = stats.total_written - start_write;
stats.num_files = flist->count;
if (write_batch)
write_batch_flist_info(flist->count, flist->files);
}
if (verbose > 3)
@@ -1232,7 +1266,6 @@ struct file_list *recv_file_list(int f)
struct file_list *flist;
unsigned short flags;
int64 start_read;
extern int list_only;
if (show_filelist_p())
start_filelist_progress("receiving file list");
@@ -1240,6 +1273,7 @@ struct file_list *recv_file_list(int f)
start_read = stats.total_read;
flist = flist_new(WITH_HLINK, "recv_file_list");
received_flist = flist;
flist->count = 0;
flist->malloced = 1000;
@@ -1284,13 +1318,11 @@ struct file_list *recv_file_list(int f)
* protocol version 15 */
recv_uid_list(f, flist);
if (!read_batch) {
/* Recv the io_error flag */
if (lp_ignore_errors(module_id) || ignore_errors)
read_int(f);
else
io_error |= read_int(f);
}
/* Recv the io_error flag */
if (lp_ignore_errors(module_id) || ignore_errors)
read_int(f);
else
io_error |= read_int(f);
}
if (verbose > 3)
@@ -1422,7 +1454,7 @@ static void clean_flist(struct file_list *flist, int strip_root, int no_dups)
return;
qsort(flist->files, flist->count,
sizeof flist->files[0], (int (*)()) file_compare);
sizeof flist->files[0], (int (*)())file_compare);
for (i = no_dups? 0 : flist->count; i < flist->count; i++) {
if (flist->files[i]->basename) {
@@ -1478,7 +1510,7 @@ static void output_flist(struct file_list *flist)
for (i = 0; i < flist->count; i++) {
file = flist->files[i];
if (am_root && preserve_uid)
if ((am_root || am_sender) && preserve_uid)
sprintf(uidbuf, " uid=%ld", (long)file->uid);
else
*uidbuf = '\0';
@@ -1488,8 +1520,8 @@ static void output_flist(struct file_list *flist)
*gidbuf = '\0';
rprintf(FINFO, "[%s] i=%d %s %s %s mode=0%o len=%.0f%s%s\n",
who_am_i(), i, NS(file->basedir), NS(file->dirname),
NS(file->basename), (int) file->mode,
(double) file->length, uidbuf, gidbuf);
NS(file->basename), (int)file->mode,
(double)file->length, uidbuf, gidbuf);
}
}
@@ -1517,11 +1549,17 @@ int f_name_cmp(struct file_struct *f1, struct file_struct *f2)
if (!(c1 = (uchar*)f1->dirname)) {
state1 = fnc_BASE;
c1 = (uchar*)f1->basename;
} else if (!*c1) {
state1 = fnc_SLASH;
c1 = (uchar*)"/";
} else
state1 = fnc_DIR;
if (!(c2 = (uchar*)f2->dirname)) {
state2 = fnc_BASE;
c2 = (uchar*)f2->basename;
} else if (!*c2) {
state2 = fnc_SLASH;
c2 = (uchar*)"/";
} else
state2 = fnc_DIR;

View File

@@ -26,6 +26,7 @@
extern int verbose;
extern int dry_run;
extern int relative_paths;
extern int keep_dirlinks;
extern int preserve_links;
extern int am_root;
extern int preserve_devices;
@@ -35,29 +36,34 @@ extern int preserve_uid;
extern int preserve_gid;
extern int update_only;
extern int opt_ignore_existing;
extern int inplace;
extern int make_backups;
extern int csum_length;
extern int ignore_times;
extern int size_only;
extern int io_timeout;
extern int protocol_version;
extern int always_checksum;
extern char *partial_dir;
extern char *compare_dest;
extern int link_dest;
extern int whole_file;
extern int local_server;
extern int write_batch;
extern int list_only;
extern int read_batch;
extern int only_existing;
extern int orig_umask;
extern int safe_symlinks;
extern unsigned int block_size;
extern struct exclude_list_struct server_exclude_list;
/* choose whether to skip a particular file */
static int skip_file(char *fname, struct file_struct *file, STRUCT_STAT *st)
{
if (st->st_size != file->length) {
if (st->st_size != file->length)
return 0;
}
if (link_dest) {
if (preserve_perms
&& (st->st_mode & CHMOD_BITS) != (file->mode & CHMOD_BITS))
@@ -75,29 +81,18 @@ static int skip_file(char *fname, struct file_struct *file, STRUCT_STAT *st)
of the file time to determine whether to sync */
if (always_checksum && S_ISREG(st->st_mode)) {
char sum[MD4_SUM_LENGTH];
char fnamecmpdest[MAXPATHLEN];
if (compare_dest != NULL) {
if (access(fname, 0) != 0) {
pathjoin(fnamecmpdest, sizeof fnamecmpdest,
compare_dest, fname);
fname = fnamecmpdest;
}
}
file_checksum(fname,sum,st->st_size);
return memcmp(sum, file->u.sum, protocol_version < 21 ? 2
: MD4_SUM_LENGTH) == 0;
}
if (size_only) {
if (size_only)
return 1;
}
if (ignore_times) {
if (ignore_times)
return 0;
}
return (cmp_modtime(st->st_mtime,file->modtime) == 0);
return cmp_modtime(st->st_mtime, file->modtime) == 0;
}
@@ -118,11 +113,11 @@ void write_sum_head(int f, struct sum_struct *sum)
write_int(f, sum->remainder);
}
/*
/*
* set (initialize) the size entries in the per-file sum_struct
* calulating dynamic block ans checksum sizes.
* calculating dynamic block and checksum sizes.
*
* This is only called from generate_and_send_sums() but is a seperate
* This is only called from generate_and_send_sums() but is a separate
* function to encapsulate the logic.
*
* The block size is a rounded square root of file length.
@@ -138,7 +133,6 @@ void write_sum_head(int f, struct sum_struct *sum)
static void sum_sizes_sqroot(struct sum_struct *sum, uint64 len)
{
extern unsigned int block_size;
unsigned int blength;
int s2length;
uint32 c;
@@ -200,46 +194,37 @@ static void sum_sizes_sqroot(struct sum_struct *sum, uint64 len)
}
}
/**
* Perhaps we want to just send an empty checksum set for this file,
* which will force the whole thing to be literally transferred.
*
* When do we do this? If the user's explicitly said they
* want the whole thing, or if { they haven't explicitly
* requested a delta, and it's local but not batch mode.}
*
* Whew. */
static BOOL disable_deltas_p(void)
{
if (whole_file > 0)
return True;
if (whole_file == 0 || write_batch)
return False;
return local_server;
}
/*
* Generate and send a stream of signatures/checksums that describe a buffer
*
* Generate approximately one checksum every block_len bytes.
*/
static void generate_and_send_sums(struct map_struct *buf, size_t len, int f_out)
static void generate_and_send_sums(int fd, OFF_T len, int f_out, int f_copy)
{
size_t i;
struct map_struct *mapbuf;
struct sum_struct sum;
OFF_T offset = 0;
sum_sizes_sqroot(&sum, len);
if (len > 0)
mapbuf = map_file(fd, len, MAX_MAP_SIZE, sum.blength);
else
mapbuf = NULL;
write_sum_head(f_out, &sum);
for (i = 0; i < sum.count; i++) {
unsigned int n1 = MIN(len, sum.blength);
char *map = map_ptr(buf, offset, n1);
char *map = map_ptr(mapbuf, offset, n1);
uint32 sum1 = get_checksum1(map, n1);
char sum2[SUM_LENGTH];
if (f_copy >= 0)
full_write(f_copy, map, n1);
get_checksum2(map, n1, sum2);
if (verbose > 3) {
@@ -253,44 +238,67 @@ static void generate_and_send_sums(struct map_struct *buf, size_t len, int f_out
len -= n1;
offset += n1;
}
if (mapbuf)
unmap_file(mapbuf);
}
/**
/*
* Acts on file number @p i from @p flist, whose name is @p fname.
*
* First fixes up permissions, then generates checksums for the file.
*
* @note This comment was added later by mbp who was trying to work it
* out. It might be wrong.
**/
void recv_generator(char *fname, struct file_struct *file, int i, int f_out)
*/
static void recv_generator(char *fname, struct file_struct *file, int i,
int f_out)
{
int fd;
STRUCT_STAT st;
struct map_struct *mapbuf;
int statret;
char *fnamecmp;
int fd, f_copy;
STRUCT_STAT st, partial_st;
struct file_struct *back_file;
int statret, stat_errno;
char *fnamecmp, *partialptr, *backupptr;
char fnamecmpbuf[MAXPATHLEN];
if (list_only)
return;
if (verbose > 2)
rprintf(FINFO,"recv_generator(%s,%d)\n",fname,i);
rprintf(FINFO, "recv_generator(%s,%d)\n", safe_fname(fname), i);
statret = link_stat(fname,&st);
if (only_existing && statret == -1 && errno == ENOENT) {
/* we only want to update existing files */
if (verbose > 1) rprintf(FINFO, "not creating new file \"%s\"\n",fname);
if (server_exclude_list.head
&& check_exclude(&server_exclude_list, fname,
S_ISDIR(file->mode)) < 0) {
if (verbose) {
rprintf(FINFO, "skipping server-excluded file \"%s\"\n",
safe_fname(fname));
}
return;
}
if (statret == 0 &&
!preserve_perms &&
(S_ISDIR(st.st_mode) == S_ISDIR(file->mode))) {
if (dry_run > 1) {
statret = -1;
stat_errno = ENOENT;
} else {
statret = link_stat(fname, &st,
keep_dirlinks && S_ISDIR(file->mode));
stat_errno = errno;
}
if (only_existing && statret == -1 && stat_errno == ENOENT) {
/* we only want to update existing files */
if (verbose > 1) {
rprintf(FINFO, "not creating new file \"%s\"\n",
safe_fname(fname));
}
return;
}
if (statret == 0 && !preserve_perms
&& S_ISDIR(st.st_mode) == S_ISDIR(file->mode)) {
/* if the file exists already and we aren't perserving
* permissions then act as though the remote end sent
* us the file permissions we already have */
@@ -305,28 +313,31 @@ void recv_generator(char *fname, struct file_struct *file, int i, int f_out)
* we need to delete it. If it doesn't exist, then
* recursively create it. */
if (dry_run) return; /* XXXX -- might cause inaccuracies?? -- mbp */
if (dry_run)
return; /* TODO: causes inaccuracies -- fix */
if (statret == 0 && !S_ISDIR(st.st_mode)) {
if (robust_unlink(fname) != 0) {
rprintf(FERROR,
"recv_generator: unlink %s to make room for directory: %s\n",
full_fname(fname), strerror(errno));
rsyserr(FERROR, errno,
"recv_generator: unlink %s to make room for directory",
full_fname(fname));
return;
}
statret = -1;
}
if (statret != 0 && do_mkdir(fname,file->mode) != 0 && errno != EEXIST) {
if (!(relative_paths && errno==ENOENT &&
create_directory_path(fname, orig_umask)==0 &&
do_mkdir(fname,file->mode)==0)) {
rprintf(FERROR, "recv_generator: mkdir %s failed: %s\n",
full_fname(fname), strerror(errno));
if (!(relative_paths && errno == ENOENT
&& create_directory_path(fname, orig_umask) == 0
&& do_mkdir(fname, file->mode) == 0)) {
rsyserr(FERROR, errno,
"recv_generator: mkdir %s failed",
full_fname(fname));
}
}
/* f_out is set to -1 when doing final directory
permission and modification time repair */
if (set_perms(fname,file,NULL,0) && verbose && (f_out != -1))
rprintf(FINFO,"%s/\n",fname);
/* f_out is set to -1 when doing final directory-permission
* and modification-time repair. */
if (set_perms(fname, file, statret ? NULL : &st, 0)
&& verbose && f_out != -1)
rprintf(FINFO, "%s/\n", safe_fname(fname));
return;
}
@@ -350,7 +361,8 @@ void recv_generator(char *fname, struct file_struct *file, int i, int f_out)
* right place -- no further action
* required. */
if (strcmp(lnk,file->u.link) == 0) {
set_perms(fname,file,&st,1);
set_perms(fname, file, &st,
PERMS_REPORT);
return;
}
}
@@ -360,12 +372,13 @@ void recv_generator(char *fname, struct file_struct *file, int i, int f_out)
delete_file(fname);
}
if (do_symlink(file->u.link,fname) != 0) {
rprintf(FERROR, "symlink %s -> \"%s\" failed: %s\n",
full_fname(fname), file->u.link, strerror(errno));
rsyserr(FERROR, errno, "symlink %s -> \"%s\" failed",
full_fname(fname), safe_fname(file->u.link));
} else {
set_perms(fname,file,NULL,0);
if (verbose) {
rprintf(FINFO,"%s -> %s\n", fname,file->u.link);
rprintf(FINFO, "%s -> %s\n", safe_fname(fname),
safe_fname(file->u.link));
}
}
#endif
@@ -378,19 +391,23 @@ void recv_generator(char *fname, struct file_struct *file, int i, int f_out)
st.st_mode != file->mode ||
st.st_rdev != file->u.rdev) {
delete_file(fname);
if (verbose > 2)
if (verbose > 2) {
rprintf(FINFO,"mknod(%s,0%o,0x%x)\n",
fname,(int)file->mode,(int)file->u.rdev);
safe_fname(fname),
(int)file->mode, (int)file->u.rdev);
}
if (do_mknod(fname,file->mode,file->u.rdev) != 0) {
rprintf(FERROR, "mknod %s failed: %s\n",
full_fname(fname), strerror(errno));
rsyserr(FERROR, errno, "mknod %s failed",
full_fname(fname));
} else {
set_perms(fname,file,NULL,0);
if (verbose)
rprintf(FINFO,"%s\n",fname);
if (verbose) {
rprintf(FINFO, "%s\n",
safe_fname(fname));
}
}
} else {
set_perms(fname,file,&st,1);
set_perms(fname, file, &st, PERMS_REPORT);
}
return;
}
@@ -400,7 +417,8 @@ void recv_generator(char *fname, struct file_struct *file, int i, int f_out)
return;
if (!S_ISREG(file->mode)) {
rprintf(FINFO, "skipping non-regular file \"%s\"\n",fname);
rprintf(FINFO, "skipping non-regular file \"%s\"\n",
safe_fname(fname));
return;
}
@@ -408,91 +426,100 @@ void recv_generator(char *fname, struct file_struct *file, int i, int f_out)
if (statret == -1 && compare_dest != NULL) {
/* try the file at compare_dest instead */
int saveerrno = errno;
pathjoin(fnamecmpbuf, sizeof fnamecmpbuf, compare_dest, fname);
statret = link_stat(fnamecmpbuf,&st);
if (!S_ISREG(st.st_mode))
statret = -1;
if (statret == -1)
errno = saveerrno;
if (link_stat(fnamecmpbuf, &st, 0) == 0
&& S_ISREG(st.st_mode)) {
#if HAVE_LINK
else if (link_dest && !dry_run) {
if (do_link(fnamecmpbuf, fname) != 0) {
if (verbose > 0) {
rprintf(FINFO,"link %s => %s : %s\n",
fnamecmpbuf, fname,
strerror(errno));
if (link_dest && !dry_run) {
if (do_link(fnamecmpbuf, fname) < 0) {
if (verbose) {
rsyserr(FINFO, errno,
"link %s => %s",
fnamecmpbuf,
safe_fname(fname));
}
fnamecmp = fnamecmpbuf;
}
}
fnamecmp = fnamecmpbuf;
}
} else
#endif
else
fnamecmp = fnamecmpbuf;
fnamecmp = fnamecmpbuf;
statret = 0;
}
}
if (statret == 0 && !S_ISREG(st.st_mode)) {
if (delete_file(fname) != 0)
return;
statret = -1;
stat_errno = ENOENT;
}
if (partial_dir && (partialptr = partial_dir_fname(fname))
&& link_stat(partialptr, &partial_st, 0) == 0
&& S_ISREG(partial_st.st_mode)) {
if (statret == -1)
goto prepare_to_open;
} else
partialptr = NULL;
if (statret == -1) {
if (preserve_hard_links && hard_link_check(file, HL_SKIP))
return;
if (errno == ENOENT) {
if (stat_errno == ENOENT) {
write_int(f_out,i);
if (!dry_run) write_sum_head(f_out, NULL);
if (!dry_run && !read_batch)
write_sum_head(f_out, NULL);
} else if (verbose > 1) {
rprintf(FERROR,
"recv_generator: failed to open %s: %s\n",
full_fname(fname), strerror(errno));
rsyserr(FERROR, stat_errno,
"recv_generator: failed to stat %s",
full_fname(fname));
}
return;
}
if (!S_ISREG(st.st_mode)) {
if (delete_file(fname) != 0) {
return;
}
/* now pretend the file didn't exist */
if (preserve_hard_links && hard_link_check(file, HL_SKIP))
return;
write_int(f_out,i);
if (!dry_run) write_sum_head(f_out, NULL);
return;
}
if (opt_ignore_existing && fnamecmp == fname) {
if (verbose > 1)
rprintf(FINFO,"%s exists\n",fname);
rprintf(FINFO, "%s exists\n", safe_fname(fname));
return;
}
if (update_only && cmp_modtime(st.st_mtime,file->modtime)>0 && fnamecmp == fname) {
if (update_only && fnamecmp == fname
&& cmp_modtime(st.st_mtime, file->modtime) > 0) {
if (verbose > 1)
rprintf(FINFO,"%s is newer\n",fname);
rprintf(FINFO, "%s is newer\n", safe_fname(fname));
return;
}
if (skip_file(fname, file, &st)) {
if (skip_file(fnamecmp, file, &st)) {
if (fnamecmp == fname)
set_perms(fname,file,&st,1);
set_perms(fname, file, &st, PERMS_REPORT);
return;
}
if (dry_run) {
prepare_to_open:
if (dry_run || read_batch) {
write_int(f_out,i);
return;
}
if (disable_deltas_p()) {
if (whole_file > 0) {
write_int(f_out,i);
write_sum_head(f_out, NULL);
return;
}
if (partialptr) {
st = partial_st;
fnamecmp = partialptr;
}
/* open the file */
fd = do_open(fnamecmp, O_RDONLY, 0);
if (fd == -1) {
rprintf(FERROR, "failed to open %s, continuing: %s\n",
full_fname(fnamecmp), strerror(errno));
rsyserr(FERROR, errno, "failed to open %s, continuing",
full_fname(fnamecmp));
pretend_missing:
/* pretend the file didn't exist */
if (preserve_hard_links && hard_link_check(file, HL_SKIP))
return;
@@ -501,31 +528,63 @@ void recv_generator(char *fname, struct file_struct *file, int i, int f_out)
return;
}
if (st.st_size > 0)
mapbuf = map_file(fd,st.st_size);
else
mapbuf = NULL;
if (inplace && make_backups) {
if (!(backupptr = get_backup_name(fname))) {
close(fd);
return;
}
if (!(back_file = make_file(fname, NULL, NO_EXCLUDES))) {
close(fd);
goto pretend_missing;
}
if (robust_unlink(backupptr) && errno != ENOENT) {
rsyserr(FERROR, errno, "unlink %s",
full_fname(backupptr));
free(back_file);
close(fd);
return;
}
if ((f_copy = do_open(backupptr,
O_WRONLY | O_CREAT | O_TRUNC | O_EXCL, 0600)) < 0) {
rsyserr(FERROR, errno, "open %s",
full_fname(backupptr));
free(back_file);
close(fd);
return;
}
} else {
backupptr = NULL;
back_file = NULL;
f_copy = -1;
}
if (verbose > 3) {
rprintf(FINFO,"gen mapped %s of size %.0f\n", fnamecmp,
(double)st.st_size);
rprintf(FINFO, "gen mapped %s of size %.0f\n",
safe_fname(fnamecmp), (double)st.st_size);
}
if (verbose > 2)
rprintf(FINFO, "generating and sending sums for %d\n", i);
write_int(f_out,i);
generate_and_send_sums(mapbuf, st.st_size, f_out);
generate_and_send_sums(fd, st.st_size, f_out, f_copy);
if (f_copy >= 0) {
close(f_copy);
set_perms(backupptr, back_file, NULL, 0);
if (verbose > 1)
rprintf(FINFO, "backed up %s to %s\n", fname, backupptr);
free(back_file);
}
close(fd);
if (mapbuf) unmap_file(mapbuf);
}
void generate_files(int f, struct file_list *flist, char *local_name)
void generate_files(int f_out, struct file_list *flist, char *local_name)
{
int i;
int phase=0;
int phase = 0;
char fbuf[MAXPATHLEN];
if (verbose > 2) {
@@ -535,7 +594,7 @@ void generate_files(int f, struct file_list *flist, char *local_name)
if (verbose >= 2) {
rprintf(FINFO,
disable_deltas_p()
whole_file > 0
? "delta-transmission disabled for local transfer or --whole-file\n"
: "delta transmission enabled\n");
}
@@ -563,31 +622,31 @@ void generate_files(int f, struct file_list *flist, char *local_name)
}
recv_generator(local_name ? local_name : f_name_to(file, fbuf),
file, i, f);
file, i, f_out);
}
phase++;
csum_length = SUM_LENGTH;
ignore_times=1;
ignore_times = 1;
if (verbose > 2)
rprintf(FINFO,"generate_files phase=%d\n",phase);
write_int(f,-1);
write_int(f_out, -1);
/* files can cycle through the system more than once
* to catch initial checksum errors */
while ((i = get_redo_num()) != -1) {
struct file_struct *file = flist->files[i];
recv_generator(local_name ? local_name : f_name_to(file, fbuf),
file, i, f);
file, i, f_out);
}
phase++;
if (verbose > 2)
rprintf(FINFO,"generate_files phase=%d\n",phase);
write_int(f,-1);
write_int(f_out, -1);
if (preserve_hard_links)
do_hard_links();
@@ -596,7 +655,8 @@ void generate_files(int f, struct file_list *flist, char *local_name)
* modified during the transfer */
for (i = 0; i < flist->count; i++) {
struct file_struct *file = flist->files[i];
if (!file->basename || !S_ISDIR(file->mode)) continue;
if (!file->basename || !S_ISDIR(file->mode))
continue;
recv_generator(local_name ? local_name : f_name(file),
file, i, -1);
}

17
getfsdev.c Normal file
View File

@@ -0,0 +1,17 @@
#include "rsync.h"
int main(int argc, char *argv[])
{
STRUCT_STAT st;
while (--argc > 0) {
if (stat(*++argv, &st) < 0) {
fprintf(stderr, "Unable to stat `%s'\n", *argv);
exit(1);
}
printf("%ld/%ld\n", (long)major(st.st_dev),
(long)minor(st.st_dev));
}
return 0;
}

17
hlink.c
View File

@@ -135,6 +135,7 @@ void init_hard_links(struct file_list *flist)
int hard_link_check(struct file_struct *file, int skip)
{
#if SUPPORT_HARD_LINKS
if (!hlink_list || !file->link_u.links)
return 0;
if (skip && !(file->flags & FLAG_HLINK_EOL))
@@ -146,6 +147,7 @@ int hard_link_check(struct file_struct *file, int skip)
}
return 1;
}
#endif
return 0;
}
@@ -154,8 +156,8 @@ static void hard_link_one(char *hlink1, char *hlink2)
{
if (do_link(hlink1, hlink2)) {
if (verbose) {
rprintf(FINFO, "link %s => %s failed: %s\n",
hlink2, hlink1, strerror(errno));
rsyserr(FINFO, errno, "link %s => %s failed",
hlink2, hlink1);
}
}
else if (verbose)
@@ -183,11 +185,11 @@ void do_hard_links(void)
for (i = 0; i < hlink_count; i++) {
first = file = hlink_list[i];
if (link_stat(f_name_to(first, hlink1), &st1) != 0)
if (link_stat(f_name_to(first, hlink1), &st1, 0) < 0)
continue;
while ((file = file->F_NEXT) != first) {
hlink2 = f_name(file);
if (link_stat(hlink2, &st2) == 0) {
if (link_stat(hlink2, &st2, 0) == 0) {
if (st2.st_dev == st1.st_dev
&& st2.st_ino == st1.st_ino)
continue;
@@ -196,10 +198,9 @@ void do_hard_links(void)
continue;
} else if (robust_unlink(hlink2)) {
if (verbose > 0) {
rprintf(FINFO,
"unlink %s failed: %s\n",
full_fname(hlink2),
strerror(errno));
rsyserr(FINFO, errno,
"unlink %s failed",
full_fname(hlink2));
}
continue;
}

549
io.c
View File

@@ -1,19 +1,19 @@
/* -*- c-file-style: "linux" -*-
*
* Copyright (C) 1996-2001 by Andrew Tridgell
*
* Copyright (C) 1996-2001 by Andrew Tridgell
* Copyright (C) Paul Mackerras 1996
* Copyright (C) 2001, 2002 by Martin Pool <mbp@samba.org>
*
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
@@ -22,7 +22,7 @@
/**
* @file io.c
*
* Socket and pipe IO utilities used in rsync.
* Socket and pipe I/O utilities used in rsync.
*
* rsync provides its own multiplexing system, which is used to send
* stderr and stdout over a single socket. We need this because
@@ -39,23 +39,23 @@
/** If no timeout is specified then use a 60 second select timeout */
#define SELECT_TIMEOUT 60
static int io_multiplexing_out;
static int io_multiplexing_in;
static int multiplex_in_fd = -1;
static int multiplex_out_fd = -1;
static time_t last_io;
static int no_flush;
extern int bwlimit;
extern size_t bwlimit_writemax;
extern int verbose;
extern int io_timeout;
extern int am_server;
extern int am_daemon;
extern int am_sender;
extern int eol_nulls;
extern int checksum_seed;
extern int protocol_version;
extern char *remote_filesfrom_file;
extern struct stats stats;
const char phase_unknown[] = "unknown";
int select_timeout = SELECT_TIMEOUT;
int batch_fd = -1;
int batch_gen_fd = -1;
/**
* The connection might be dropped at some point; perhaps because the
@@ -63,9 +63,9 @@ const char phase_unknown[] = "unknown";
* not very helpful. So instead we try to make io_phase_name point to
* something useful.
*
* For buffered/multiplexed IO these names will be somewhat
* For buffered/multiplexed I/O these names will be somewhat
* approximate; perhaps for ease of support we would rather make the
* buffer always flush when a single application-level IO finishes.
* buffer always flush when a single application-level I/O finishes.
*
* @todo Perhaps we want some simple stack functionality, but there's
* no need to overdo it.
@@ -80,6 +80,16 @@ int kludge_around_eof = False;
int msg_fd_in = -1;
int msg_fd_out = -1;
static int io_multiplexing_out;
static int io_multiplexing_in;
static int sock_f_in = -1;
static int sock_f_out = -1;
static time_t last_io;
static int no_flush;
static int write_batch_monitor_in = -1;
static int write_batch_monitor_out = -1;
static int io_filesfrom_f_in = -1;
static int io_filesfrom_f_out = -1;
static char io_filesfrom_buf[2048];
@@ -135,18 +145,26 @@ static void check_timeout(void)
t = time(NULL);
if (last_io && io_timeout && (t-last_io) >= io_timeout) {
if (t - last_io >= io_timeout) {
if (!am_server && !am_daemon) {
rprintf(FERROR,"io timeout after %d seconds - exiting\n",
rprintf(FERROR, "io timeout after %d seconds - exiting\n",
(int)(t-last_io));
}
exit_cleanup(RERR_TIMEOUT);
}
}
/* Note the fds used for the main socket (which might really be a pipe
* for a local transfer, but we can ignore that). */
void io_set_sock_fds(int f_in, int f_out)
{
sock_f_in = f_in;
sock_f_out = f_out;
}
/** Setup the fd used to receive MSG_* messages. Only needed when
* we're the generator because the sender and receiver both use the
* multiplexed IO setup. */
* multiplexed I/O setup. */
void set_msg_fd_in(int fd)
{
msg_fd_in = fd;
@@ -154,7 +172,7 @@ void set_msg_fd_in(int fd)
/** Setup the fd used to send our MSG_* messages. Only needed when
* we're the receiver because the generator and the sender both use
* the multiplexed IO setup. */
* the multiplexed I/O setup. */
void set_msg_fd_out(int fd)
{
msg_fd_out = fd;
@@ -191,13 +209,13 @@ void send_msg(enum msgcode code, char *buf, int len)
* called by the generator. */
static void read_msg_fd(void)
{
char buf[200];
char buf[2048];
size_t n;
int fd = msg_fd_in;
int tag, len;
/* Temporarily disable msg_fd_in. This is needed because we
* may call a write routine that could try to call us back. */
/* Temporarily disable msg_fd_in. This is needed to avoid looping back
* to this routine from read_timeout() and writefd_unbuffered(). */
msg_fd_in = -1;
read_loop(fd, buf, 4);
@@ -244,7 +262,7 @@ static void read_msg_fd(void)
/* Try to push messages off the list onto the wire. If we leave with more
* to do, return 0. On error, return -1. If everything flushed, return 1.
* This is only called by the receiver. */
* This is only active in the receiver. */
int msg_list_push(int flush_it_all)
{
static int written = 0;
@@ -266,7 +284,7 @@ int msg_list_push(int flush_it_all)
return 0;
FD_ZERO(&fds);
FD_SET(msg_fd_out, &fds);
tv.tv_sec = io_timeout ? io_timeout : SELECT_TIMEOUT;
tv.tv_sec = select_timeout;
tv.tv_usec = 0;
if (!select(msg_fd_out+1, NULL, &fds, NULL, &tv))
check_timeout();
@@ -329,34 +347,21 @@ void io_set_filesfrom_fds(int f_in, int f_out)
* program where that is a problem (start_socket_client),
* kludge_around_eof is True and we just exit.
*/
static void whine_about_eof(void)
static void whine_about_eof(int fd)
{
if (kludge_around_eof)
if (kludge_around_eof && fd == sock_f_in)
exit_cleanup(0);
else {
rprintf(FERROR,
"%s: connection unexpectedly closed "
"(%.0f bytes read so far)\n",
RSYNC_NAME, (double)stats.total_read);
exit_cleanup(RERR_STREAMIO);
}
}
rprintf(FERROR, RSYNC_NAME ": connection unexpectedly closed "
"(%.0f bytes received so far) [%s]\n",
(double)stats.total_read, who_am_i());
static void die_from_readerr(int err)
{
/* this prevents us trying to write errors on a dead socket */
io_multiplexing_close();
rprintf(FERROR, "%s: read error: %s\n",
RSYNC_NAME, strerror(err));
exit_cleanup(RERR_STREAMIO);
}
/**
* Read from a socket with IO timeout. return the number of bytes
* Read from a socket with I/O timeout. return the number of bytes
* read. If no bytes can be read then exit, never return a number <= 0.
*
* TODO: If the remote shell connection fails, then current versions
@@ -368,7 +373,7 @@ static void die_from_readerr(int err)
*/
static int read_timeout(int fd, char *buf, size_t len)
{
int n, ret=0;
int n, ret = 0;
io_flush(NORMAL_FLUSH);
@@ -376,15 +381,20 @@ static int read_timeout(int fd, char *buf, size_t len)
/* until we manage to read *something* */
fd_set r_fds, w_fds;
struct timeval tv;
int fd_count = fd+1;
int maxfd = fd;
int count;
FD_ZERO(&r_fds);
FD_ZERO(&w_fds);
FD_SET(fd, &r_fds);
if (msg_fd_in >= 0) {
FD_SET(msg_fd_in, &r_fds);
if (msg_fd_in >= fd_count)
fd_count = msg_fd_in+1;
if (msg_fd_in > maxfd)
maxfd = msg_fd_in;
} else if (msg_list_head) {
FD_SET(msg_fd_out, &w_fds);
if (msg_fd_out > maxfd)
maxfd = msg_fd_out;
}
if (io_filesfrom_f_out >= 0) {
int new_fd;
@@ -397,37 +407,31 @@ static int read_timeout(int fd, char *buf, size_t len)
new_fd = -1;
}
} else {
FD_ZERO(&w_fds);
FD_SET(io_filesfrom_f_out, &w_fds);
new_fd = io_filesfrom_f_out;
}
if (new_fd >= fd_count)
fd_count = new_fd+1;
if (new_fd > maxfd)
maxfd = new_fd;
}
tv.tv_sec = io_timeout?io_timeout:SELECT_TIMEOUT;
tv.tv_sec = select_timeout;
tv.tv_usec = 0;
errno = 0;
count = select(fd_count, &r_fds,
io_filesfrom_buflen? &w_fds : NULL,
NULL, &tv);
if (count == 0) {
msg_list_push(NORMAL_FLUSH);
check_timeout();
}
count = select(maxfd + 1, &r_fds, &w_fds, NULL, &tv);
if (count <= 0) {
if (errno == EBADF) {
if (errno == EBADF)
exit_cleanup(RERR_SOCKETIO);
}
check_timeout();
continue;
}
if (msg_fd_in >= 0 && FD_ISSET(msg_fd_in, &r_fds))
read_msg_fd();
else if (msg_list_head && FD_ISSET(msg_fd_out, &w_fds))
msg_list_push(NORMAL_FLUSH);
if (io_filesfrom_f_out >= 0) {
if (io_filesfrom_buflen) {
@@ -457,7 +461,6 @@ static int read_timeout(int fd, char *buf, size_t len)
io_filesfrom_buflen = io_filesfrom_lastchar? 2 : 1;
io_filesfrom_f_in = -1;
} else {
extern int eol_nulls;
if (!eol_nulls) {
char *s = io_filesfrom_buf + l;
/* Transform CR and/or LF into '\0' */
@@ -493,26 +496,31 @@ static int read_timeout(int fd, char *buf, size_t len)
}
}
if (!FD_ISSET(fd, &r_fds)) continue;
if (!FD_ISSET(fd, &r_fds))
continue;
n = read(fd, buf, len);
if (n > 0) {
buf += n;
len -= n;
ret += n;
if (io_timeout)
last_io = time(NULL);
continue;
} else if (n == 0) {
whine_about_eof();
return -1; /* doesn't return */
} else if (n < 0) {
if (errno == EINTR || errno == EWOULDBLOCK ||
errno == EAGAIN)
if (n <= 0) {
if (n == 0)
whine_about_eof(fd); /* Doesn't return. */
if (errno == EINTR || errno == EWOULDBLOCK
|| errno == EAGAIN)
continue;
die_from_readerr(errno);
/* Don't write errors on a dead socket. */
if (fd == sock_f_in)
close_multiplexing_out();
rsyserr(FERROR, errno, "read error");
exit_cleanup(RERR_STREAMIO);
}
buf += n;
len -= n;
ret += n;
if (io_timeout && fd == sock_f_in)
last_io = time(NULL);
}
return ret;
@@ -526,9 +534,6 @@ int read_filesfrom_line(int fd, char *fname)
{
char ch, *s, *eob = fname + MAXPATHLEN - 1;
int cnt;
extern int io_timeout;
extern int eol_nulls;
extern char *remote_filesfrom_file;
int reading_remotely = remote_filesfrom_file != NULL;
int nulls = eol_nulls || reading_remotely;
@@ -542,7 +547,7 @@ int read_filesfrom_line(int fd, char *fname)
fd_set fds;
FD_ZERO(&fds);
FD_SET(fd, &fds);
tv.tv_sec = io_timeout? io_timeout : SELECT_TIMEOUT;
tv.tv_sec = select_timeout;
tv.tv_usec = 0;
if (!select(fd+1, &fds, NULL, NULL, &tv))
check_timeout();
@@ -569,6 +574,42 @@ int read_filesfrom_line(int fd, char *fname)
}
static char *iobuf_out;
static int iobuf_out_cnt;
void io_start_buffering_out(void)
{
if (iobuf_out)
return;
if (!(iobuf_out = new_array(char, IO_BUFFER_SIZE)))
out_of_memory("io_start_buffering_out");
iobuf_out_cnt = 0;
}
static char *iobuf_in;
static size_t iobuf_in_siz;
void io_start_buffering_in(void)
{
if (iobuf_in)
return;
iobuf_in_siz = 2 * IO_BUFFER_SIZE;
if (!(iobuf_in = new_array(char, iobuf_in_siz)))
out_of_memory("io_start_buffering_in");
}
void io_end_buffering(void)
{
io_flush(NORMAL_FLUSH);
if (!io_multiplexing_out) {
free(iobuf_out);
iobuf_out = NULL;
}
}
/**
* Continue trying to read len bytes - don't return until len has been
* read.
@@ -587,36 +628,29 @@ static void read_loop(int fd, char *buf, size_t len)
/**
* Read from the file descriptor handling multiplexing - return number
* of bytes read.
*
* Never returns <= 0.
*
* Never returns <= 0.
*/
static int read_unbuffered(int fd, char *buf, size_t len)
static int readfd_unbuffered(int fd, char *buf, size_t len)
{
static size_t remaining;
static size_t iobuf_in_ndx;
int tag, ret = 0;
char line[1024];
static char *buffer;
static size_t bufferIdx = 0;
static size_t bufferSz;
if (fd != multiplex_in_fd)
if (!iobuf_in || fd != sock_f_in)
return read_timeout(fd, buf, len);
if (!io_multiplexing_in && remaining == 0) {
if (!buffer) {
bufferSz = 2 * IO_BUFFER_SIZE;
buffer = new_array(char, bufferSz);
if (!buffer) out_of_memory("read_unbuffered");
}
remaining = read_timeout(fd, buffer, bufferSz);
bufferIdx = 0;
remaining = read_timeout(fd, iobuf_in, iobuf_in_siz);
iobuf_in_ndx = 0;
}
while (ret == 0) {
if (remaining) {
len = MIN(len, remaining);
memcpy(buf, buffer + bufferIdx, len);
bufferIdx += len;
memcpy(buf, iobuf_in + iobuf_in_ndx, len);
iobuf_in_ndx += len;
remaining -= len;
ret = len;
break;
@@ -630,13 +664,14 @@ static int read_unbuffered(int fd, char *buf, size_t len)
switch (tag) {
case MSG_DATA:
if (!buffer || remaining > bufferSz) {
buffer = realloc_array(buffer, char, remaining);
if (!buffer) out_of_memory("read_unbuffered");
bufferSz = remaining;
if (remaining > iobuf_in_siz) {
if (!(iobuf_in = realloc_array(iobuf_in, char,
remaining)))
out_of_memory("readfd_unbuffered");
iobuf_in_siz = remaining;
}
read_loop(fd, buffer, remaining);
bufferIdx = 0;
read_loop(fd, iobuf_in, remaining);
iobuf_in_ndx = 0;
break;
case MSG_INFO:
case MSG_ERROR:
@@ -671,14 +706,20 @@ static int read_unbuffered(int fd, char *buf, size_t len)
static void readfd(int fd, char *buffer, size_t N)
{
int ret;
size_t total=0;
size_t total = 0;
while (total < N) {
ret = read_unbuffered(fd, buffer + total, N-total);
ret = readfd_unbuffered(fd, buffer + total, N-total);
total += ret;
}
stats.total_read += total;
if (fd == write_batch_monitor_in) {
if ((size_t)write(batch_fd, buffer, total) != total)
exit_cleanup(RERR_FILEIO);
}
if (fd == sock_f_in)
stats.total_read += total;
}
@@ -689,7 +730,8 @@ int32 read_int(int f)
readfd(f,b,4);
ret = IVAL(b,0);
if (ret == (int32)0xffffffff) return -1;
if (ret == (int32)0xffffffff)
return -1;
return ret;
}
@@ -699,17 +741,17 @@ int64 read_longint(int f)
char b[8];
ret = read_int(f);
if ((int32)ret != (int32)0xffffffff) {
if ((int32)ret != (int32)0xffffffff)
return ret;
}
#ifdef NO_INT64
rprintf(FERROR,"Integer overflow - attempted 64 bit offset\n");
exit_cleanup(RERR_UNSUPPORTED);
#else
#ifdef INT64_IS_OFF_T
if (sizeof (int64) < 8) {
rprintf(FERROR, "Integer overflow: attempted 64-bit offset\n");
exit_cleanup(RERR_UNSUPPORTED);
}
#endif
readfd(f,b,8);
ret = IVAL(b,0) | (((int64)IVAL(b,4))<<32);
#endif
return ret;
}
@@ -721,14 +763,14 @@ void read_buf(int f,char *buf,size_t len)
void read_sbuf(int f,char *buf,size_t len)
{
read_buf(f,buf,len);
readfd(f, buf, len);
buf[len] = 0;
}
unsigned char read_byte(int f)
{
unsigned char c;
read_buf(f, (char *)&c, 1);
readfd(f, (char *)&c, 1);
return c;
}
@@ -741,81 +783,107 @@ unsigned char read_byte(int f)
* use a bit less bandwidth than specified, because it doesn't make up
* for slow periods. But arguably this is a feature. In addition, we
* ought to take the time used to write the data into account.
*
* During some phases of big transfers (file FOO is uptodate) this is
* called with a small bytes_written every time. As the kernel has to
* round small waits up to guarantee that we actually wait at least the
* requested number of microseconds, this can become grossly inaccurate.
* We therefore keep track of the bytes we've written over time and only
* sleep when the accumulated delay is at least 1 tenth of a second.
**/
static void sleep_for_bwlimit(int bytes_written)
{
struct timeval tv;
static struct timeval prior_tv;
static long total_written = 0;
struct timeval tv, start_tv;
long elapsed_usec, sleep_usec;
#define ONE_SEC 1000000L /* # of microseconds in a second */
if (!bwlimit)
return;
assert(bytes_written > 0);
assert(bwlimit > 0);
total_written += bytes_written;
tv.tv_usec = bytes_written * 1000 / bwlimit;
tv.tv_sec = tv.tv_usec / 1000000;
tv.tv_usec = tv.tv_usec % 1000000;
gettimeofday(&start_tv, NULL);
if (prior_tv.tv_sec) {
elapsed_usec = (start_tv.tv_sec - prior_tv.tv_sec) * ONE_SEC
+ (start_tv.tv_usec - prior_tv.tv_usec);
total_written -= elapsed_usec * bwlimit / (ONE_SEC/1024);
if (total_written < 0)
total_written = 0;
}
sleep_usec = total_written * (ONE_SEC/1024) / bwlimit;
if (sleep_usec < ONE_SEC / 10) {
prior_tv = start_tv;
return;
}
tv.tv_sec = sleep_usec / ONE_SEC;
tv.tv_usec = sleep_usec % ONE_SEC;
select(0, NULL, NULL, NULL, &tv);
gettimeofday(&prior_tv, NULL);
elapsed_usec = (prior_tv.tv_sec - start_tv.tv_sec) * ONE_SEC
+ (prior_tv.tv_usec - start_tv.tv_usec);
total_written = (sleep_usec - elapsed_usec) * bwlimit / (ONE_SEC/1024);
}
/**
* Write len bytes to the file descriptor @p fd.
/* Write len bytes to the file descriptor fd, looping as necessary to get
* the job done and also (in the generator) reading any data on msg_fd_in
* (to avoid deadlock).
*
* This function underlies the multiplexing system. The body of the
* application never calls this function directly.
**/
* application never calls this function directly. */
static void writefd_unbuffered(int fd,char *buf,size_t len)
{
size_t total = 0;
size_t n, total = 0;
fd_set w_fds, r_fds;
int fd_count, count;
int maxfd, count, ret;
struct timeval tv;
msg_list_push(NORMAL_FLUSH);
no_flush++;
while (total < len) {
FD_ZERO(&w_fds);
FD_SET(fd,&w_fds);
fd_count = fd;
maxfd = fd;
if (msg_fd_in >= 0) {
FD_ZERO(&r_fds);
FD_SET(msg_fd_in,&r_fds);
if (msg_fd_in > fd_count)
fd_count = msg_fd_in;
if (msg_fd_in > maxfd)
maxfd = msg_fd_in;
}
tv.tv_sec = io_timeout?io_timeout:SELECT_TIMEOUT;
tv.tv_sec = select_timeout;
tv.tv_usec = 0;
errno = 0;
count = select(fd_count+1, msg_fd_in >= 0 ? &r_fds : NULL,
count = select(maxfd + 1, msg_fd_in >= 0 ? &r_fds : NULL,
&w_fds, NULL, &tv);
if (count == 0) {
msg_list_push(NORMAL_FLUSH);
check_timeout();
}
if (count <= 0) {
if (errno == EBADF) {
if (count < 0 && errno == EBADF)
exit_cleanup(RERR_SOCKETIO);
}
check_timeout();
continue;
}
if (msg_fd_in >= 0 && FD_ISSET(msg_fd_in, &r_fds))
read_msg_fd();
if (FD_ISSET(fd, &w_fds)) {
int ret;
size_t n = len-total;
ret = write(fd,buf+total,n);
if (!FD_ISSET(fd, &w_fds))
continue;
n = len - total;
if (bwlimit && n > bwlimit_writemax)
n = bwlimit_writemax;
ret = write(fd, buf + total, n);
if (ret <= 0) {
if (ret < 0) {
if (errno == EINTR)
continue;
@@ -825,23 +893,28 @@ static void writefd_unbuffered(int fd,char *buf,size_t len)
}
}
if (ret <= 0) {
/* Don't try to write errors back
* across the stream */
io_multiplexing_close();
rprintf(FERROR, RSYNC_NAME
": writefd_unbuffered failed to write %ld bytes: phase \"%s\": %s\n",
(long) len, io_write_phase,
strerror(errno));
exit_cleanup(RERR_STREAMIO);
/* Don't try to write errors back across the stream. */
if (fd == sock_f_out)
close_multiplexing_out();
rsyserr(FERROR, errno,
"writefd_unbuffered failed to write %ld bytes: phase \"%s\" [%s]",
(long)len, io_write_phase, who_am_i());
/* If the other side is sending us error messages, try
* to grab any messages they sent before they died. */
while (fd == sock_f_out && io_multiplexing_in) {
io_timeout = 30;
readfd_unbuffered(sock_f_in, io_filesfrom_buf,
sizeof io_filesfrom_buf);
}
exit_cleanup(RERR_STREAMIO);
}
sleep_for_bwlimit(ret);
total += ret;
total += ret;
if (fd == sock_f_out) {
if (io_timeout)
last_io = time(NULL);
sleep_for_bwlimit(ret);
}
}
@@ -849,97 +922,76 @@ static void writefd_unbuffered(int fd,char *buf,size_t len)
}
static char *io_buffer;
static int io_buffer_count;
void io_start_buffering_out(int fd)
{
if (io_buffer) return;
multiplex_out_fd = fd;
io_buffer = new_array(char, IO_BUFFER_SIZE);
if (!io_buffer) out_of_memory("writefd");
io_buffer_count = 0;
}
void io_start_buffering_in(int fd)
{
multiplex_in_fd = fd;
}
/**
* Write an message to a multiplexed stream. If this fails then rsync
* exits.
**/
static void mplex_write(int fd, enum msgcode code, char *buf, size_t len)
static void mplex_write(enum msgcode code, char *buf, size_t len)
{
char buffer[4096];
size_t n = len;
SIVAL(buffer, 0, ((MPLEX_BASE + (int)code)<<24) + len);
if (n > (sizeof buffer - 4)) {
if (n > sizeof buffer - 4)
n = sizeof buffer - 4;
}
memcpy(&buffer[4], buf, n);
writefd_unbuffered(fd, buffer, n+4);
writefd_unbuffered(sock_f_out, buffer, n+4);
len -= n;
buf += n;
if (len) {
writefd_unbuffered(fd, buf, len);
}
if (len)
writefd_unbuffered(sock_f_out, buf, len);
}
void io_flush(int flush_it_all)
{
int fd = multiplex_out_fd;
msg_list_push(flush_it_all);
if (!io_buffer_count || no_flush)
if (!iobuf_out_cnt || no_flush)
return;
if (io_multiplexing_out)
mplex_write(fd, MSG_DATA, io_buffer, io_buffer_count);
mplex_write(MSG_DATA, iobuf_out, iobuf_out_cnt);
else
writefd_unbuffered(fd, io_buffer, io_buffer_count);
io_buffer_count = 0;
writefd_unbuffered(sock_f_out, iobuf_out, iobuf_out_cnt);
iobuf_out_cnt = 0;
}
void io_end_buffering(void)
{
io_flush(NORMAL_FLUSH);
if (!io_multiplexing_out) {
free(io_buffer);
io_buffer = NULL;
}
}
static void writefd(int fd,char *buf,size_t len)
{
stats.total_written += len;
if (fd == msg_fd_out) {
rprintf(FERROR, "Internal error: wrong write used in receiver.\n");
exit_cleanup(RERR_PROTOCOL);
}
msg_list_push(NORMAL_FLUSH);
if (fd == sock_f_out)
stats.total_written += len;
if (!io_buffer || fd != multiplex_out_fd) {
if (fd == write_batch_monitor_out) {
if ((size_t)write(batch_fd, buf, len) != len)
exit_cleanup(RERR_FILEIO);
}
if (!iobuf_out || fd != sock_f_out) {
writefd_unbuffered(fd, buf, len);
return;
}
while (len) {
int n = MIN((int) len, IO_BUFFER_SIZE-io_buffer_count);
int n = MIN((int)len, IO_BUFFER_SIZE - iobuf_out_cnt);
if (n > 0) {
memcpy(io_buffer+io_buffer_count, buf, n);
memcpy(iobuf_out+iobuf_out_cnt, buf, n);
buf += n;
len -= n;
io_buffer_count += n;
iobuf_out_cnt += n;
}
if (io_buffer_count == IO_BUFFER_SIZE)
if (iobuf_out_cnt == IO_BUFFER_SIZE)
io_flush(NORMAL_FLUSH);
}
}
@@ -974,16 +1026,18 @@ void write_longint(int f, int64 x)
return;
}
#ifdef NO_INT64
rprintf(FERROR,"Integer overflow - attempted 64 bit offset\n");
exit_cleanup(RERR_UNSUPPORTED);
#else
#ifdef INT64_IS_OFF_T
if (sizeof (int64) < 8) {
rprintf(FERROR, "Integer overflow: attempted 64-bit offset\n");
exit_cleanup(RERR_UNSUPPORTED);
}
#endif
write_int(f, (int32)0xFFFFFFFF);
SIVAL(b,0,(x&0xFFFFFFFF));
SIVAL(b,4,((x>>32)&0xFFFFFFFF));
writefd(f,b,8);
#endif
}
void write_buf(int f,char *buf,size_t len)
@@ -992,24 +1046,24 @@ void write_buf(int f,char *buf,size_t len)
}
/** Write a string to the connection */
static void write_sbuf(int f,char *buf)
void write_sbuf(int f, char *buf)
{
write_buf(f, buf, strlen(buf));
writefd(f, buf, strlen(buf));
}
void write_byte(int f,unsigned char c)
{
write_buf(f,(char *)&c,1);
writefd(f, (char *)&c, 1);
}
/**
* Read a line of up to @p maxlen characters into @p buf. Does not
* contain a trailing newline or carriage return.
* Read a line of up to @p maxlen characters into @p buf (not counting
* the trailing null). Strips the (required) trailing newline and all
* carriage returns.
*
* @return 1 for success; 0 for io error or truncation.
* @return 1 for success; 0 for I/O error or truncation.
**/
int read_line(int f, char *buf, size_t maxlen)
{
@@ -1018,27 +1072,21 @@ int read_line(int f, char *buf, size_t maxlen)
read_buf(f, buf, 1);
if (buf[0] == 0)
return 0;
if (buf[0] == '\n') {
buf[0] = 0;
if (buf[0] == '\n')
break;
}
if (buf[0] != '\r') {
buf++;
maxlen--;
}
}
if (maxlen == 0) {
*buf = 0;
return 0;
}
return 1;
*buf = '\0';
return maxlen > 0;
}
void io_printf(int fd, const char *format, ...)
{
va_list ap;
va_list ap;
char buf[1024];
int len;
@@ -1046,43 +1094,72 @@ void io_printf(int fd, const char *format, ...)
len = vsnprintf(buf, sizeof buf, format, ap);
va_end(ap);
if (len < 0) exit_cleanup(RERR_STREAMIO);
if (len < 0)
exit_cleanup(RERR_STREAMIO);
write_sbuf(fd, buf);
}
/** Setup for multiplexing a MSG_* stream with the data stream. */
void io_start_multiplex_out(int fd)
void io_start_multiplex_out(void)
{
multiplex_out_fd = fd;
io_flush(NORMAL_FLUSH);
io_start_buffering_out(fd);
io_start_buffering_out();
io_multiplexing_out = 1;
}
/** Setup for multiplexing a MSG_* stream with the data stream. */
void io_start_multiplex_in(int fd)
void io_start_multiplex_in(void)
{
multiplex_in_fd = fd;
io_flush(NORMAL_FLUSH);
io_start_buffering_in();
io_multiplexing_in = 1;
}
/** Write an message to the multiplexed data stream. */
int io_multiplex_write(enum msgcode code, char *buf, size_t len)
{
if (!io_multiplexing_out) return 0;
if (!io_multiplexing_out)
return 0;
io_flush(NORMAL_FLUSH);
stats.total_written += (len+4);
mplex_write(multiplex_out_fd, code, buf, len);
mplex_write(code, buf, len);
return 1;
}
void close_multiplexing_in(void)
{
io_multiplexing_in = 0;
}
/** Stop output multiplexing. */
void io_multiplexing_close(void)
void close_multiplexing_out(void)
{
io_multiplexing_out = 0;
}
void start_write_batch(int fd)
{
write_stream_flags(batch_fd);
/* Some communication has already taken place, but we don't
* enable batch writing until here so that we can write a
* canonical record of the communication even though the
* actual communication so far depends on whether a daemon
* is involved. */
write_int(batch_fd, protocol_version);
write_int(batch_fd, checksum_seed);
if (am_sender)
write_batch_monitor_out = fd;
else
write_batch_monitor_in = fd;
}
void stop_write_batch(void)
{
write_batch_monitor_out = -1;
write_batch_monitor_in = -1;
}

View File

@@ -119,6 +119,7 @@ typedef struct
char *comment;
char *lock_file;
BOOL read_only;
BOOL write_only;
BOOL list;
BOOL use_chroot;
BOOL transfer_logging;
@@ -151,6 +152,7 @@ static service sDefault =
NULL, /* comment */
DEFAULT_LOCK_FILE, /* lock file */
True, /* read only */
False, /* write only */
True, /* list */
True, /* use chroot */
False, /* transfer logging */
@@ -277,6 +279,7 @@ static struct parm_struct parm_table[] =
{"lock file", P_STRING, P_LOCAL, &sDefault.lock_file, NULL, 0},
{"path", P_PATH, P_LOCAL, &sDefault.path, NULL, 0},
{"read only", P_BOOL, P_LOCAL, &sDefault.read_only, NULL, 0},
{"write only", P_BOOL, P_LOCAL, &sDefault.write_only, NULL, 0},
{"list", P_BOOL, P_LOCAL, &sDefault.list, NULL, 0},
{"use chroot", P_BOOL, P_LOCAL, &sDefault.use_chroot, NULL, 0},
{"ignore nonreadable",P_BOOL, P_LOCAL, &sDefault.ignore_nonreadable, NULL, 0},
@@ -356,6 +359,7 @@ FN_LOCAL_STRING(lp_comment, comment)
FN_LOCAL_STRING(lp_path, path)
FN_LOCAL_STRING(lp_lock_file, lock_file)
FN_LOCAL_BOOL(lp_read_only, read_only)
FN_LOCAL_BOOL(lp_write_only, write_only)
FN_LOCAL_BOOL(lp_list, list)
FN_LOCAL_BOOL(lp_use_chroot, use_chroot)
FN_LOCAL_BOOL(lp_transfer_logging, transfer_logging)
@@ -807,7 +811,7 @@ int lp_number(char *name)
int iService;
for (iService = iNumServices - 1; iService >= 0; iService--)
if (strequal(lp_name(iService), name))
if (strcmp(lp_name(iService), name) == 0)
break;
return (iService);

135
log.c
View File

@@ -41,7 +41,7 @@ static char *logfname;
static FILE *logfile;
struct stats stats;
int log_got_error=0;
int log_got_error = 0;
struct {
int code;
@@ -61,7 +61,7 @@ struct {
{ RERR_WAITCHILD , "some error returned by waitpid()" },
{ RERR_MALLOC , "error allocating core memory buffers" },
{ RERR_PARTIAL , "some files could not be transferred" },
{ RERR_VANISHED , "some files vanished before they could be transfered" },
{ RERR_VANISHED , "some files vanished before they could be transferred" },
{ RERR_TIMEOUT , "timeout in data send/receive" },
{ RERR_CMD_FAILED , "remote shell failed" },
{ RERR_CMD_KILLED , "remote shell killed" },
@@ -104,7 +104,8 @@ void log_init(void)
int options = LOG_PID;
time_t t;
if (log_initialised) return;
if (log_initialised)
return;
log_initialised = 1;
/* this looks pointless, but it is needed in order for the
@@ -160,7 +161,7 @@ void log_close(void)
* it with FINFO, FERROR or FLOG */
void rwrite(enum logcode code, char *buf, int len)
{
FILE *f=NULL;
FILE *f = NULL;
/* recursion can happen with certain fatal conditions */
if (quiet && code == FINFO)
@@ -171,44 +172,39 @@ void rwrite(enum logcode code, char *buf, int len)
buf[len] = 0;
if (code == FLOG) {
if (am_daemon) logit(LOG_INFO, buf);
if (am_server && msg_fd_out >= 0) {
/* Pass the message to our sibling. */
send_msg((enum msgcode)code, buf, len);
return;
}
if (am_daemon) {
static int in_block;
char msg[2048];
int priority = code == FERROR ? LOG_WARNING : LOG_INFO;
if (in_block)
return;
in_block = 1;
if (!log_initialised)
log_init();
strlcpy(msg, buf, MIN((int)sizeof msg, len + 1));
logit(priority, msg);
in_block = 0;
if (code == FLOG || !am_server)
return;
} else if (code == FLOG)
return;
if (am_server) {
/* Pass it to non-server side, perhaps through our sibling. */
if (msg_fd_out >= 0) {
send_msg((enum msgcode)code, buf, len);
return;
}
/* Pass the message to the non-server side. */
if (io_multiplex_write((enum msgcode)code, buf, len))
return;
}
/* otherwise, if in daemon mode and either we are not a server
* (that is, we are not running --daemon over a remote shell) or
* the log has already been initialised, log the message on this
* side because we don't want the client to see most errors for
* security reasons. We do want early messages when running daemon
* mode over a remote shell to go to the remote side; those will
* fall through to the next case.
* Note that this is only for the time before multiplexing is enabled.
*/
if (am_daemon && (!am_server || log_initialised)) {
static int depth;
int priority = LOG_INFO;
if (code == FERROR) priority = LOG_WARNING;
if (depth) return;
depth++;
log_init();
logit(priority, buf);
depth--;
return;
if (am_daemon) {
/* TODO: can we send the error to the user somehow? */
return;
}
}
if (code == FERROR) {
@@ -216,18 +212,17 @@ void rwrite(enum logcode code, char *buf, int len)
f = stderr;
}
if (code == FINFO) {
if (am_server)
f = stderr;
else
f = stdout;
}
if (code == FINFO)
f = am_server ? stderr : stdout;
if (!f) exit_cleanup(RERR_MESSAGEIO);
if (!f)
exit_cleanup(RERR_MESSAGEIO);
if (fwrite(buf, len, 1, f) != 1) exit_cleanup(RERR_MESSAGEIO);
if (fwrite(buf, len, 1, f) != 1)
exit_cleanup(RERR_MESSAGEIO);
if (buf[len-1] == '\r' || buf[len-1] == '\n') fflush(f);
if (buf[len-1] == '\r' || buf[len-1] == '\n')
fflush(f);
}
@@ -236,18 +231,17 @@ void rwrite(enum logcode code, char *buf, int len)
void rprintf(enum logcode code, const char *format, ...)
{
va_list ap;
char buf[1024];
int len;
char buf[MAXPATHLEN+512];
size_t len;
va_start(ap, format);
/* Note: might return -1 */
len = vsnprintf(buf, sizeof(buf), format, ap);
va_end(ap);
/* Deal with buffer overruns. Instead of panicking, just
* truncate the resulting string. Note that some vsnprintf()s
* return -1 on truncation, e.g., glibc 2.0.6 and earlier. */
if ((size_t) len > sizeof(buf)-1 || len < 0) {
* truncate the resulting string. (Note that configure ensures
* that we have a vsnprintf() that doesn't ever return -1.) */
if (len > sizeof buf - 1) {
const char ellipsis[] = "[...]";
/* Reset length, and zero-terminate the end of our buffer */
@@ -285,33 +279,23 @@ void rprintf(enum logcode code, const char *format, ...)
void rsyserr(enum logcode code, int errcode, const char *format, ...)
{
va_list ap;
char buf[1024];
int len;
size_t sys_len;
char *sysmsg;
char buf[MAXPATHLEN+512];
size_t len;
strcpy(buf, RSYNC_NAME ": ");
len = (sizeof RSYNC_NAME ": ") - 1;
va_start(ap, format);
/* Note: might return <0 */
len = vsnprintf(buf, sizeof(buf), format, ap);
len += vsnprintf(buf + len, sizeof buf - len, format, ap);
va_end(ap);
/* TODO: Put in RSYNC_NAME at the start. */
if ((size_t) len > sizeof(buf)-1)
if (len < sizeof buf) {
len += snprintf(buf + len, sizeof buf - len,
": %s (%d)\n", strerror(errcode), errcode);
}
if (len >= sizeof buf)
exit_cleanup(RERR_MESSAGEIO);
sysmsg = strerror(errcode);
sys_len = strlen(sysmsg);
if ((size_t) len + 3 + sys_len > sizeof(buf) - 1)
exit_cleanup(RERR_MESSAGEIO);
strcpy(buf + len, ": ");
len += 2;
strcpy(buf + len, sysmsg);
len += sys_len;
strcpy(buf + len, "\n");
len++;
rwrite(code, buf, len);
}
@@ -363,8 +347,9 @@ static void log_formatted(enum logcode code,
* rather keep going until we reach the nul of the format.
* Just to make sure we don't clobber that nul and therefore
* accidentally keep going, we zero the buffer now. */
memset(buf, 0, sizeof buf);
strlcpy(buf, format, sizeof(buf));
l = strlcpy(buf, format, sizeof buf);
if (l < sizeof buf)
memset(buf + l, 0, sizeof buf - l);
for (s = &buf[0]; s && (p = strchr(s,'%')); ) {
n = NULL;
@@ -388,7 +373,7 @@ static void log_formatted(enum logcode code,
pathjoin(buf2, sizeof buf2,
file->basedir ? file->basedir : "",
f_name(file));
clean_fname(buf2);
clean_fname(buf2, 0);
n = buf2;
if (*n == '/') n++;
break;

342
main.c
View File

@@ -43,20 +43,25 @@ extern int local_server;
extern int log_got_error;
extern int module_id;
extern int orig_umask;
extern int copy_links;
extern int keep_dirlinks;
extern int preserve_hard_links;
extern int protocol_version;
extern int recurse;
extern int relative_paths;
extern int rsync_port;
extern int whole_file;
extern int read_batch;
extern int write_batch;
extern int batch_fd;
extern int batch_gen_fd;
extern int filesfrom_fd;
extern pid_t cleanup_child_pid;
extern char *files_from;
extern char *remote_filesfrom_file;
extern char *rsync_path;
extern char *shell_cmd;
extern struct file_list *batch_flist;
extern char *batch_name;
/* there's probably never more than at most 2 outstanding child processes,
@@ -84,7 +89,7 @@ void wait_process(pid_t pid, int *status)
io_flush(FULL_FLUSH);
}
if ((waited_pid == -1) && (errno == ECHILD)) {
if (waited_pid == -1 && errno == ECHILD) {
/* status of requested child no longer available.
* check to see if it was processed by the sigchld_handler.
*/
@@ -105,8 +110,19 @@ void wait_process(pid_t pid, int *status)
*status = WEXITSTATUS(*status);
}
/* This function gets called from all 3 processes. We want the client side
* to actually output the text, but the sender is the only process that has
* all the stats we need. So, if we're a client sender, we do the report.
* If we're a server sender, we write the stats on the supplied fd. If
* we're the client receiver we read the stats from the supplied fd and do
* the report. All processes might also generate a set of debug stats, if
* the verbose level is high enough (this is the only thing that the
* generator process and the server receiver ever do here). */
static void report(int f)
{
/* Cache two stats because the read/write code can change it. */
int64 total_read = stats.total_read;
int64 total_written = stats.total_written;
time_t t = time(NULL);
if (do_stats && verbose > 1) {
@@ -120,18 +136,15 @@ static void report(int f)
if (am_daemon) {
log_exit(0, __FILE__, __LINE__);
if (f == -1 || !am_sender) return;
if (f == -1 || !am_sender)
return;
}
if (am_server) {
if (am_sender) {
int64 w;
/* store total_written in a temporary
* because write_longint changes it */
w = stats.total_written;
write_longint(f,stats.total_read);
write_longint(f,w);
write_longint(f,stats.total_size);
write_longint(f, total_read);
write_longint(f, total_written);
write_longint(f, stats.total_size);
}
return;
}
@@ -139,12 +152,17 @@ static void report(int f)
/* this is the client */
if (!am_sender) {
int64 r;
stats.total_written = read_longint(f);
/* store total_read in a temporary, read_longint changes it */
r = read_longint(f);
/* Read the first two in opposite order because the meaning of
* read/write swaps when switching from sender to receiver. */
total_written = read_longint(f);
total_read = read_longint(f);
stats.total_size = read_longint(f);
stats.total_read = r;
} else if (write_batch) {
/* The --read-batch process is going to be a client
* receiver, so we need to give it the stats. */
write_longint(batch_fd, total_read);
write_longint(batch_fd, total_written);
write_longint(batch_fd, stats.total_size);
}
if (do_stats) {
@@ -160,20 +178,20 @@ static void report(int f)
rprintf(FINFO,"Matched data: %.0f bytes\n",
(double)stats.matched_data);
rprintf(FINFO,"File list size: %d\n", stats.flist_size);
rprintf(FINFO,"Total bytes written: %.0f\n",
(double)stats.total_written);
rprintf(FINFO,"Total bytes read: %.0f\n",
(double)stats.total_read);
rprintf(FINFO,"Total bytes sent: %.0f\n",
(double)total_written);
rprintf(FINFO,"Total bytes received: %.0f\n",
(double)total_read);
}
if (verbose || do_stats) {
rprintf(FINFO,"\nwrote %.0f bytes read %.0f bytes %.2f bytes/sec\n",
(double)stats.total_written,
(double)stats.total_read,
(stats.total_written+stats.total_read)/(0.5 + (t-starttime)));
rprintf(FINFO,"total size is %.0f speedup is %.2f\n",
rprintf(FINFO,
"\nsent %.0f bytes received %.0f bytes %.2f bytes/sec\n",
(double)total_written, (double)total_read,
(total_written + total_read)/(0.5 + (t - starttime)));
rprintf(FINFO, "total size is %.0f speedup is %.2f\n",
(double)stats.total_size,
(1.0*stats.total_size)/(stats.total_written+stats.total_read));
(double)stats.total_size / (total_written+total_read));
}
fflush(stdout);
@@ -217,7 +235,7 @@ static pid_t do_cmd(char *cmd, char *machine, char *user, char *path,
int *f_in, int *f_out)
{
int i, argc = 0;
char *args[100];
char *args[MAX_ARGS];
pid_t ret;
char *tok, *dir = NULL;
int dash_l_set = 0;
@@ -232,8 +250,14 @@ static pid_t do_cmd(char *cmd, char *machine, char *user, char *path,
if (!cmd)
goto oom;
for (tok = strtok(cmd, " "); tok; tok = strtok(NULL, " "))
for (tok = strtok(cmd, " "); tok; tok = strtok(NULL, " ")) {
/* Comparison leaves rooms for server_options(). */
if (argc >= MAX_ARGS - 100) {
rprintf(FERROR, "internal: args[] overflowed in do_cmd()\n");
exit_cleanup(RERR_SYNTAX);
}
args[argc++] = tok;
}
/* check to see if we've already been given '-l user' in
* the remote-shell command */
@@ -270,6 +294,11 @@ static pid_t do_cmd(char *cmd, char *machine, char *user, char *path,
}
server_options(args,&argc);
if (argc >= MAX_ARGS - 2) {
rprintf(FERROR, "internal: args[] overflowed in do_cmd()\n");
exit_cleanup(RERR_SYNTAX);
}
}
args[argc++] = ".";
@@ -277,29 +306,36 @@ static pid_t do_cmd(char *cmd, char *machine, char *user, char *path,
if (!daemon_over_rsh && path && *path)
args[argc++] = path;
if (argc >= (int)(sizeof args / sizeof args[0])) {
rprintf(FERROR, "internal: args[] overflowed in do_cmd()\n");
exit_cleanup(RERR_MALLOC); /* XXX Need better RERR? */
}
args[argc] = NULL;
if (verbose > 3) {
rprintf(FINFO,"cmd=");
for (i=0;i<argc;i++)
for (i = 0; i < argc; i++)
rprintf(FINFO,"%s ",args[i]);
rprintf(FINFO,"\n");
}
if (local_server) {
if (read_batch)
create_flist_from_batch(); /* sets batch_flist */
if (read_batch) {
int from_gen_pipe[2];
if (fd_pair(from_gen_pipe) < 0) {
rsyserr(FERROR, errno, "pipe");
exit_cleanup(RERR_IPC);
}
batch_gen_fd = from_gen_pipe[0];
*f_out = from_gen_pipe[1];
*f_in = batch_fd;
ret = -1; /* no child pid */
} else if (local_server) {
/* If the user didn't request --[no-]whole-file, force
* it on, but only if we're not batch processing. */
if (whole_file < 0 && !write_batch)
whole_file = 1;
ret = local_child(argc, args, f_in, f_out, child_main);
} else {
} else
ret = piped_child(args,f_in,f_out);
}
if (dir) free(dir);
if (dir)
free(dir);
return ret;
@@ -324,8 +360,8 @@ static char *get_local_name(struct file_list *flist,char *name)
if (do_stat(name,&st) == 0) {
if (S_ISDIR(st.st_mode)) {
if (!push_dir(name)) {
rprintf(FERROR, "push_dir %s failed: %s (1)\n",
full_fname(name), strerror(errno));
rsyserr(FERROR, errno, "push_dir#1 %s failed",
full_fname(name));
exit_cleanup(RERR_FILESELECT);
}
return NULL;
@@ -341,17 +377,20 @@ static char *get_local_name(struct file_list *flist,char *name)
return name;
if (do_mkdir(name,0777 & ~orig_umask) != 0) {
rprintf(FERROR, "mkdir %s failed: %s\n",
full_fname(name), strerror(errno));
rsyserr(FERROR, errno, "mkdir %s failed", full_fname(name));
exit_cleanup(RERR_FILEIO);
} else {
if (verbose > 0)
rprintf(FINFO,"created directory %s\n",name);
}
if (verbose > 0)
rprintf(FINFO, "created directory %s\n", name);
if (dry_run) {
dry_run++;
return NULL;
}
if (!push_dir(name)) {
rprintf(FERROR, "push_dir %s failed: %s (2)\n",
full_fname(name), strerror(errno));
rsyserr(FERROR, errno, "push_dir#2 %s failed",
full_fname(name));
exit_cleanup(RERR_FILESELECT);
}
@@ -370,9 +409,15 @@ static void do_server_sender(int f_in, int f_out, int argc,char *argv[])
(long)getpid());
}
if (am_daemon && lp_write_only(module_id)) {
rprintf(FERROR, "ERROR: module is write only\n");
exit_cleanup(RERR_SYNTAX);
return;
}
if (!relative_paths && !push_dir(dir)) {
rprintf(FERROR, "push_dir %s failed: %s (3)\n",
full_fname(dir), strerror(errno));
rsyserr(FERROR, errno, "push_dir#3 %s failed",
full_fname(dir));
exit_cleanup(RERR_FILESELECT);
}
argc--;
@@ -382,12 +427,12 @@ static void do_server_sender(int f_in, int f_out, int argc,char *argv[])
int l = strlen(dir);
if (strcmp(dir,"/") == 0)
l = 0;
for (i=0;i<argc;i++)
for (i = 0; i < argc; i++)
argv[i] += l+1;
}
if (argc == 0 && recurse) {
argc=1;
argc = 1;
argv--;
argv[0] = ".";
}
@@ -397,8 +442,9 @@ static void do_server_sender(int f_in, int f_out, int argc,char *argv[])
exit_cleanup(0);
}
io_start_buffering_in(f_in);
io_start_buffering_out(f_out);
io_start_buffering_in();
io_start_buffering_out();
send_files(flist,f_out,f_in);
io_flush(FULL_FLUSH);
report(f_out);
@@ -414,17 +460,20 @@ static void do_server_sender(int f_in, int f_out, int argc,char *argv[])
static int do_recv(int f_in,int f_out,struct file_list *flist,char *local_name)
{
int pid;
int status=0;
int status = 0;
int error_pipe[2];
/* The receiving side mustn't obey this, or an existing symlink that
* points to an identical file won't be replaced by the referent. */
copy_links = 0;
if (preserve_hard_links)
init_hard_links(flist);
if (!delete_after) {
/* I moved this here from recv_files() to prevent a race condition */
if (recurse && delete_mode && !local_name && flist->count>0) {
if (recurse && delete_mode && !local_name && flist->count > 0)
delete_files(flist);
}
}
if (fd_pair(error_pipe) < 0) {
@@ -434,12 +483,13 @@ static int do_recv(int f_in,int f_out,struct file_list *flist,char *local_name)
io_flush(NORMAL_FLUSH);
if ((pid=do_fork()) == 0) {
if ((pid = do_fork()) == 0) {
close(error_pipe[0]);
if (f_in != f_out) close(f_out);
if (f_in != f_out)
close(f_out);
/* we can't let two processes write to the socket at one time */
io_multiplexing_close();
close_multiplexing_out();
/* set place to send errors */
set_msg_fd_out(error_pipe[1]);
@@ -458,11 +508,15 @@ static int do_recv(int f_in,int f_out,struct file_list *flist,char *local_name)
}
am_generator = 1;
close_multiplexing_in();
if (write_batch)
stop_write_batch();
close(error_pipe[1]);
if (f_in != f_out) close(f_in);
if (f_in != f_out)
close(f_in);
io_start_buffering_out(f_out);
io_start_buffering_out();
set_msg_fd_in(error_pipe[0]);
@@ -496,7 +550,7 @@ static void do_server_recv(int f_in, int f_out, int argc,char *argv[])
argc, (long)getpid());
}
if (am_daemon && lp_read_only(module_id) && !am_sender) {
if (am_daemon && lp_read_only(module_id)) {
rprintf(FERROR,"ERROR: module is read only\n");
exit_cleanup(RERR_SYNTAX);
return;
@@ -508,13 +562,13 @@ static void do_server_recv(int f_in, int f_out, int argc,char *argv[])
argc--;
argv++;
if (!am_daemon && !push_dir(dir)) {
rprintf(FERROR, "push_dir %s failed: %s (4)\n",
full_fname(dir), strerror(errno));
rsyserr(FERROR, errno, "push_dir#4 %s failed",
full_fname(dir));
exit_cleanup(RERR_FILESELECT);
}
}
io_start_buffering_in(f_in);
io_start_buffering_in();
if (delete_mode && !delete_excluded)
recv_exclude_list(f_in);
@@ -527,10 +581,7 @@ static void do_server_recv(int f_in, int f_out, int argc,char *argv[])
filesfrom_fd = -1;
}
if (read_batch)
flist = batch_flist;
else
flist = recv_file_list(f_in);
flist = recv_file_list(f_in);
if (!flist) {
rprintf(FERROR,"server_recv: recv_file_list error\n");
exit_cleanup(RERR_FILESELECT);
@@ -539,7 +590,8 @@ static void do_server_recv(int f_in, int f_out, int argc,char *argv[])
if (argc > 0) {
if (strcmp(dir,".")) {
argv[0] += strlen(dir);
if (argv[0][0] == '/') argv[0]++;
if (argv[0][0] == '/')
argv[0]++;
}
local_name = get_local_name(flist,argv[0]);
}
@@ -558,20 +610,21 @@ int child_main(int argc, char *argv[])
void start_server(int f_in, int f_out, int argc, char *argv[])
{
setup_protocol(f_out, f_in);
set_nonblocking(f_in);
set_nonblocking(f_out);
io_set_sock_fds(f_in, f_out);
setup_protocol(f_out, f_in);
if (protocol_version >= 23)
io_start_multiplex_out(f_out);
io_start_multiplex_out();
if (am_sender) {
if (!read_batch) {
recv_exclude_list(f_in);
if (cvs_exclude)
add_cvs_excludes();
}
keep_dirlinks = 0; /* Must be disabled on the sender. */
recv_exclude_list(f_in);
if (cvs_exclude)
add_cvs_excludes();
do_server_sender(f_in, f_out, argc, argv);
} else {
do_server_recv(f_in, f_out, argc, argv);
@@ -591,25 +644,41 @@ int client_run(int f_in, int f_out, pid_t pid, int argc, char *argv[])
char *local_name = NULL;
cleanup_child_pid = pid;
if (read_batch)
flist = batch_flist;
set_nonblocking(f_in);
set_nonblocking(f_out);
if (read_batch) {
assert(am_sender == 0);
} else {
set_nonblocking(f_in);
set_nonblocking(f_out);
}
io_set_sock_fds(f_in, f_out);
setup_protocol(f_out,f_in);
if (protocol_version >= 23)
io_start_multiplex_in(f_in);
if (protocol_version >= 23 && !read_batch)
io_start_multiplex_in();
/* We set our stderr file handle to blocking because ssh might have
* set it to non-blocking. This can be particularly troublesome if
* stderr is a clone of stdout, because ssh would have set our stdout
* to non-blocking at the same time (which can easily cause us to lose
* output from our print statements). This kluge shouldn't cause ssh
* any problems for how we use it. Note also that we delayed setting
* this until after the above protocol setup so that we know for sure
* that ssh is done twiddling its file descriptors. */
set_blocking(STDERR_FILENO);
if (am_sender) {
io_start_buffering_out(f_out);
keep_dirlinks = 0; /* Must be disabled on the sender. */
io_start_buffering_out();
if (cvs_exclude)
add_cvs_excludes();
if (delete_mode && !delete_excluded)
send_exclude_list(f_out);
if (remote_filesfrom_file)
filesfrom_fd = f_in;
if (write_batch)
start_write_batch(f_out);
if (!read_batch) /* don't write to pipe */
flist = send_file_list(f_out,argc,argv);
if (verbose > 3)
@@ -633,11 +702,10 @@ int client_run(int f_in, int f_out, pid_t pid, int argc, char *argv[])
exit_cleanup(status);
}
if (argc == 0) {
if (argc == 0)
list_only = 1;
}
if (!write_batch)
if (!read_batch)
send_exclude_list(f_out);
if (filesfrom_fd >= 0) {
@@ -645,6 +713,8 @@ int client_run(int f_in, int f_out, pid_t pid, int argc, char *argv[])
filesfrom_fd = -1;
}
if (write_batch)
start_write_batch(f_in);
flist = recv_file_list(f_in);
if (!flist || flist->count == 0) {
rprintf(FINFO, "client: nothing to do: "
@@ -708,33 +778,39 @@ static int start_client(int argc, char *argv[])
return rc;
/* rsync:// always uses rsync server over direct socket connection */
if (strncasecmp(URL_PREFIX, argv[0], strlen(URL_PREFIX)) == 0) {
if (strncasecmp(URL_PREFIX, argv[0], strlen(URL_PREFIX)) == 0
&& !read_batch) {
char *host, *path;
host = argv[0] + strlen(URL_PREFIX);
p = strchr(host,'/');
if (p) {
*p = 0;
*p = '\0';
path = p+1;
} else {
} else
path = "";
}
p = strchr(host,':');
if (*host == '[' && (p = strchr(host, ']')) != NULL) {
host++;
*p++ = '\0';
if (*p != ':')
p = NULL;
} else
p = strchr(host, ':');
if (p) {
rsync_port = atoi(p+1);
*p = 0;
*p = '\0';
}
return start_socket_client(host, path, argc-1, argv+1);
}
if (!read_batch) {
if (!read_batch) { /* for read_batch, NO source is specified */
p = find_colon(argv[0]);
if (p) {
if (p) { /* source is remote */
if (remote_filesfrom_file
&& remote_filesfrom_file != files_from + 1
&& strncmp(files_from, argv[0], p-argv[0]+1) != 0) {
rprintf(FERROR,
"--files-from hostname is not transfer hostname\n");
"--files-from hostname is not the same as the transfer hostname\n");
exit_cleanup(RERR_SYNTAX);
}
if (p[1] == ':') { /* double colon */
@@ -747,7 +823,7 @@ static int start_client(int argc, char *argv[])
daemon_over_rsh = 1;
}
if (argc < 1) {
if (argc < 1) { /* destination required */
usage(FERROR);
exit_cleanup(RERR_SYNTAX);
}
@@ -756,9 +832,8 @@ static int start_client(int argc, char *argv[])
*p = 0;
shell_machine = argv[0];
shell_path = p+1;
argc--;
argv++;
} else {
} else { /* source is local */
am_sender = 1;
/* rsync:// destination uses rsync server over direct socket */
@@ -768,32 +843,37 @@ static int start_client(int argc, char *argv[])
host = argv[argc-1] + strlen(URL_PREFIX);
p = strchr(host,'/');
if (p) {
*p = 0;
*p = '\0';
path = p+1;
} else {
} else
path = "";
}
p = strchr(host,':');
if (*host == '[' && (p = strchr(host, ']')) != NULL) {
host++;
*p++ = '\0';
if (*p != ':')
p = NULL;
} else
p = strchr(host, ':');
if (p) {
rsync_port = atoi(p+1);
*p = 0;
*p = '\0';
}
return start_socket_client(host, path, argc-1, argv);
}
p = find_colon(argv[argc-1]);
p = find_colon(argv[argc-1]); /* look in dest arg */
if (p && remote_filesfrom_file
&& remote_filesfrom_file != files_from + 1
&& strncmp(files_from, argv[argc-1], p-argv[argc-1]+1) != 0) {
rprintf(FERROR,
"--files-from hostname is not transfer hostname\n");
"--files-from hostname is not the same as the transfer hostname\n");
exit_cleanup(RERR_SYNTAX);
}
if (!p) {
if (!p) { /* no colon found, so src & dest are local */
local_server = 1;
if (remote_filesfrom_file) {
rprintf(FERROR,
"--files-from is remote but transfer is local\n");
"--files-from cannot be remote when the transfer is local\n");
exit_cleanup(RERR_SYNTAX);
}
} else if (p[1] == ':') { /* double colon */
@@ -819,12 +899,15 @@ static int start_client(int argc, char *argv[])
shell_machine = argv[argc-1];
shell_path = p+1;
}
argc--;
}
} else {
am_sender = 1;
argc--;
} else { /* read_batch */
local_server = 1;
shell_path = argv[argc-1];
if (find_colon(shell_path)) {
rprintf(FERROR, "remote destination is not allowed with --read-batch\n");
exit_cleanup(RERR_SYNTAX);
}
}
if (shell_machine) {
@@ -844,12 +927,14 @@ static int start_client(int argc, char *argv[])
shell_path?shell_path:"");
}
/* for remote source, only single dest arg can remain ... */
if (!am_sender && argc > 1) {
usage(FERROR);
exit_cleanup(RERR_SYNTAX);
}
if (argc == 0 && !am_sender) {
/* ... or no dest at all */
if (!am_sender && argc == 0) {
list_only = 1;
}
@@ -965,11 +1050,8 @@ static RETSIGTYPE rsync_panic_handler(UNUSED(int whatsig))
int main(int argc,char *argv[])
{
int ret;
int orig_argc;
char **orig_argv;
orig_argc = argc;
orig_argv = argv;
int orig_argc = argc;
char **orig_argv = argv;
signal(SIGUSR1, sigusr1_handler);
signal(SIGUSR2, sigusr2_handler);
@@ -1018,8 +1100,24 @@ int main(int argc,char *argv[])
init_flist();
if (write_batch && !am_server) {
write_batch_argvs_file(orig_argc, orig_argv);
if (write_batch || read_batch) {
if (write_batch)
write_batch_shell_file(orig_argc, orig_argv, argc);
if (read_batch && strcmp(batch_name, "-") == 0)
batch_fd = STDIN_FILENO;
else {
batch_fd = do_open(batch_name,
write_batch ? O_WRONLY | O_CREAT | O_TRUNC
: O_RDONLY, S_IRUSR | S_IWUSR);
}
if (batch_fd < 0) {
rsyserr(FERROR, errno, "Batch file %s open error",
batch_name);
exit_cleanup(RERR_FILEIO);
}
if (read_batch)
read_stream_flags(batch_fd);
}
if (am_daemon && !am_server)

99
match.c
View File

@@ -22,6 +22,9 @@
extern int verbose;
extern int am_server;
extern int do_progress;
extern int checksum_seed;
extern int inplace;
extern int make_backups;
typedef unsigned short tag;
@@ -139,16 +142,17 @@ static void matched(int f,struct sum_struct *s,struct map_struct *buf,
static void hash_search(int f,struct sum_struct *s,
struct map_struct *buf, OFF_T len)
{
OFF_T offset, end;
OFF_T offset, end, backup;
unsigned int k;
size_t last_i;
size_t want_i;
char sum2[SUM_LENGTH];
uint32 s1, s2, sum;
int more;
schar *map;
/* last_i is used to encourage adjacent matches, allowing the RLL coding of the
output to work more efficiently */
last_i = (size_t)-1;
/* want_i is used to encourage adjacent matches, allowing the RLL
* coding of the output to work more efficiently. */
want_i = 0;
if (verbose > 2) {
rprintf(FINFO,"hash search b=%u len=%.0f\n",
@@ -187,7 +191,7 @@ static void hash_search(int f,struct sum_struct *s,
sum = (s1 & 0xffff) | (s2 << 16);
tag_hits++;
for (; j < s->count && targets[j].t == t; j++) {
do {
unsigned int l;
size_t i = targets[j].i;
@@ -199,6 +203,12 @@ static void hash_search(int f,struct sum_struct *s,
if (l != s->sums[i].len)
continue;
/* inplace: ensure chunk's offset is either >= our
* offset or that the data didn't move. */
if (inplace && !make_backups && s->sums[i].offset < offset
&& !(s->sums[i].flags & SUMFLG_SAME_OFFSET))
continue;
if (verbose > 3)
rprintf(FINFO,"potential match at %.0f target=%.0f %.0f sum=%08x\n",
(double)offset,(double)j,(double)i,sum);
@@ -214,23 +224,42 @@ static void hash_search(int f,struct sum_struct *s,
continue;
}
/* we've found a match, but now check to see
* if last_i can hint at a better match */
for (j++; j < s->count && targets[j].t == t; j++) {
size_t i2 = targets[j].i;
if (i2 == last_i + 1) {
if (sum != s->sums[i2].sum1)
break;
if (memcmp(sum2,s->sums[i2].sum2,s->s2length) != 0)
break;
/* we've found an adjacent match - the RLL coder
* will be happy */
i = i2;
break;
}
/* If inplace is enabled, the best possible match is
* one with an identical offset, so we prefer that over
* the following want_i optimization. */
if (inplace && !make_backups) {
do {
size_t i2 = targets[j].i;
if (s->sums[i2].offset != offset)
continue;
if (i2 != i) {
if (sum != s->sums[i2].sum1)
break;
if (memcmp(sum2, s->sums[i2].sum2,
s->s2length) != 0)
break;
i = i2;
}
/* This chunk was at the same offset on
* both the sender and the receiver. */
s->sums[i].flags |= SUMFLG_SAME_OFFSET;
goto set_want_i;
} while (++j < s->count && targets[j].t == t);
}
last_i = i;
/* we've found a match, but now check to see
* if want_i can hint at a better match. */
if (i != want_i && want_i < s->count
&& (!inplace || make_backups || s->sums[want_i].offset >= offset
|| s->sums[want_i].flags & SUMFLG_SAME_OFFSET)
&& sum == s->sums[want_i].sum1
&& memcmp(sum2, s->sums[want_i].sum2, s->s2length) == 0) {
/* we've found an adjacent match - the RLL coder
* will be happy */
i = want_i;
}
set_want_i:
want_i = i + 1;
matched(f,s,buf,offset,i);
offset += s->sums[i].len - 1;
@@ -241,17 +270,24 @@ static void hash_search(int f,struct sum_struct *s,
s2 = sum >> 16;
matches++;
break;
}
} while (++j < s->count && targets[j].t == t);
null_tag:
backup = offset - last_match;
/* We sometimes read 1 byte prior to last_match... */
if (backup < 0)
backup = 0;
/* Trim off the first byte from the checksum */
map = (schar *)map_ptr(buf, offset, k+1);
more = offset + k < len;
map = (schar *)map_ptr(buf, offset - backup, k + more + backup)
+ backup;
s1 -= map[0] + CHAR_OFFSET;
s2 -= k * (map[0]+CHAR_OFFSET);
/* Add on the next byte (if there is one) to the checksum */
if (k < (len-offset)) {
s1 += (map[k]+CHAR_OFFSET);
if (more) {
s1 += map[k] + CHAR_OFFSET;
s2 += s1;
} else
--k;
@@ -262,9 +298,8 @@ static void hash_search(int f,struct sum_struct *s,
match. The 3 reads are caused by the
running match, the checksum update and the
literal send. */
if (offset > last_match
&& offset-last_match >= CHUNK_SIZE+s->blength
&& end-offset > CHUNK_SIZE) {
if (backup >= CHUNK_SIZE + s->blength
&& end - offset > CHUNK_SIZE) {
matched(f,s,buf,offset - s->blength, -2);
}
} while (++offset < end);
@@ -291,7 +326,6 @@ static void hash_search(int f,struct sum_struct *s,
void match_sums(int f, struct sum_struct *s, struct map_struct *buf, OFF_T len)
{
char file_sum[MD4_SUM_LENGTH];
extern int write_batch;
last_match = 0;
false_alarms = 0;
@@ -299,7 +333,7 @@ void match_sums(int f, struct sum_struct *s, struct map_struct *buf, OFF_T len)
matches = 0;
data_transfer = 0;
sum_init();
sum_init(checksum_seed);
if (len > 0 && s->count>0) {
build_hash_table(s);
@@ -322,12 +356,13 @@ void match_sums(int f, struct sum_struct *s, struct map_struct *buf, OFF_T len)
}
sum_end(file_sum);
/* If we had a read error, send a bad checksum. */
if (buf && buf->status != 0)
file_sum[0]++;
if (verbose > 2)
rprintf(FINFO,"sending file_sum\n");
write_buf(f,file_sum,MD4_SUM_LENGTH);
if (write_batch)
write_batch_delta_file(file_sum, MD4_SUM_LENGTH);
if (targets) {
free(targets);

360
options.c
View File

@@ -22,8 +22,9 @@
#include "popt.h"
extern int sanitize_paths;
extern char curr_dir[MAXPATHLEN];
extern int select_timeout;
extern struct exclude_list_struct exclude_list;
extern struct exclude_list_struct server_exclude_list;
int make_backups = 0;
@@ -38,6 +39,7 @@ int make_backups = 0;
int whole_file = -1;
int archive_mode = 0;
int keep_dirlinks = 0;
int copy_links = 0;
int preserve_links = 0;
int preserve_hard_links = 0;
@@ -83,6 +85,7 @@ int safe_symlinks = 0;
int copy_unsafe_links = 0;
int size_only = 0;
int bwlimit = 0;
size_t bwlimit_writemax = 0;
int delete_after = 0;
int only_existing = 0;
int opt_ignore_existing = 0;
@@ -91,6 +94,7 @@ int ignore_errors = 0;
int modify_window = 0;
int blocking_io = -1;
int checksum_seed = 0;
int inplace = 0;
unsigned int block_size = 0;
@@ -114,6 +118,7 @@ unsigned int backup_dir_remainder;
char *backup_suffix = NULL;
char *tmpdir = NULL;
char *partial_dir = NULL;
char *compare_dest = NULL;
char *config_file = NULL;
char *shell_cmd = NULL;
@@ -130,15 +135,14 @@ int quiet = 0;
int always_checksum = 0;
int list_only = 0;
#define FIXED_CHECKSUM_SEED 32761
#define MAX_BATCH_PREFIX_LEN 256 /* Must be less than MAXPATHLEN-13 */
char *batch_prefix = NULL;
#define MAX_BATCH_NAME_LEN 256 /* Must be less than MAXPATHLEN-13 */
char *batch_name = NULL;
static int daemon_opt; /* sets am_daemon after option error-reporting */
static int modify_window_set;
/** Local address to bind. As a character string because it's
* interpreted by the IPv6 layer: should be a numeric IP4 or ip6
* interpreted by the IPv6 layer: should be a numeric IP4 or IP6
* address, or a hostname. **/
char *bind_address;
@@ -146,6 +150,7 @@ char *bind_address;
static void print_rsync_version(enum logcode f)
{
char const *got_socketpair = "no ";
char const *have_inplace = "no ";
char const *hardlinks = "no ";
char const *links = "no ";
char const *ipv6 = "no ";
@@ -155,6 +160,10 @@ static void print_rsync_version(enum logcode f)
got_socketpair = "";
#endif
#if HAVE_FTRUNCATE
have_inplace = "";
#endif
#if SUPPORT_HARD_LINKS
hardlinks = "";
#endif
@@ -180,8 +189,8 @@ static void print_rsync_version(enum logcode f)
/* Note that this field may not have type ino_t. It depends
* on the complicated interaction between largefile feature
* macros. */
rprintf(f, " %sIPv6, %d-bit system inums, %d-bit internal inums\n",
ipv6,
rprintf(f, " %sinplace, %sIPv6, %d-bit system inums, %d-bit internal inums\n",
have_inplace, ipv6,
(int) (sizeof dumstat->st_ino * 8),
(int) (sizeof (uint64) * 8));
#ifdef MAINTAINER_MODE
@@ -189,8 +198,9 @@ static void print_rsync_version(enum logcode f)
get_panic_action());
#endif
#ifdef NO_INT64
rprintf(f, "WARNING: no 64-bit integers on this platform!\n");
#ifdef INT64_IS_OFF_T
if (sizeof (int64) < 8)
rprintf(f, "WARNING: no 64-bit integers on this platform!\n");
#endif
rprintf(f,
@@ -231,6 +241,8 @@ void usage(enum logcode F)
rprintf(F," --backup-dir make backups into this directory\n");
rprintf(F," --suffix=SUFFIX backup suffix (default %s w/o --backup-dir)\n",BACKUP_SUFFIX);
rprintf(F," -u, --update update only (don't overwrite newer files)\n");
rprintf(F," --inplace update destination files inplace (SEE MAN PAGE)\n");
rprintf(F," -K, --keep-dirlinks treat symlinked dir on receiver as dir\n");
rprintf(F," -l, --links copy symlinks as symlinks\n");
rprintf(F," -L, --copy-links copy the referent of all symlinks\n");
rprintf(F," --copy-unsafe-links copy the referent of \"unsafe\" symlinks\n");
@@ -246,7 +258,7 @@ void usage(enum logcode F)
rprintf(F," -W, --whole-file copy whole files, no incremental checks\n");
rprintf(F," --no-whole-file turn off --whole-file\n");
rprintf(F," -x, --one-file-system don't cross filesystem boundaries\n");
rprintf(F," -B, --block-size=SIZE checksum blocking size (default %d)\n",BLOCK_SIZE);
rprintf(F," -B, --block-size=SIZE force a fixed checksum block-size\n");
rprintf(F," -e, --rsh=COMMAND specify the remote shell\n");
rprintf(F," --rsync-path=PATH specify path to rsync on the remote machine\n");
rprintf(F," --existing only update files that already exist\n");
@@ -257,13 +269,14 @@ void usage(enum logcode F)
rprintf(F," --ignore-errors delete even if there are I/O errors\n");
rprintf(F," --max-delete=NUM don't delete more than NUM files\n");
rprintf(F," --partial keep partially transferred files\n");
rprintf(F," --partial-dir=DIR put a partially transferred file into DIR\n");
rprintf(F," --force force deletion of directories even if not empty\n");
rprintf(F," --numeric-ids don't map uid/gid values by user/group name\n");
rprintf(F," --timeout=TIME set I/O timeout in seconds\n");
rprintf(F," -I, --ignore-times turn off mod time & file size quick check\n");
rprintf(F," --size-only ignore mod time for quick check (use size)\n");
rprintf(F," --modify-window=NUM compare mod times with reduced accuracy\n");
rprintf(F," -T --temp-dir=DIR create temporary files in directory DIR\n");
rprintf(F," -T, --temp-dir=DIR create temporary files in directory DIR\n");
rprintf(F," --compare-dest=DIR also compare destination files relative to DIR\n");
rprintf(F," --link-dest=DIR create hardlinks to DIR for unchanged files\n");
rprintf(F," -P equivalent to --partial --progress\n");
@@ -274,7 +287,7 @@ void usage(enum logcode F)
rprintf(F," --include=PATTERN don't exclude files matching PATTERN\n");
rprintf(F," --include-from=FILE don't exclude patterns listed in FILE\n");
rprintf(F," --files-from=FILE read FILE for list of source-file names\n");
rprintf(F," -0 --from0 all *-from file lists are delimited by nulls\n");
rprintf(F," -0, --from0 all *-from file lists are delimited by nulls\n");
rprintf(F," --version print version number\n");
rprintf(F," --daemon run as an rsync daemon\n");
rprintf(F," --no-detach do not detach from the parent\n");
@@ -288,13 +301,14 @@ void usage(enum logcode F)
rprintf(F," --log-format=FORMAT log file transfers using specified format\n");
rprintf(F," --password-file=FILE get password from FILE\n");
rprintf(F," --bwlimit=KBPS limit I/O bandwidth, KBytes per second\n");
rprintf(F," --write-batch=PREFIX write batch fileset starting with PREFIX\n");
rprintf(F," --read-batch=PREFIX read batch fileset starting with PREFIX\n");
rprintf(F," -h, --help show this help screen\n");
rprintf(F," --write-batch=FILE write a batch to FILE\n");
rprintf(F," --read-batch=FILE read a batch from FILE\n");
rprintf(F," --checksum-seed=NUM set block/file checksum seed\n");
#ifdef INET6
rprintf(F," -4 prefer IPv4\n");
rprintf(F," -6 prefer IPv6\n");
rprintf(F," -4, --ipv4 prefer IPv4\n");
rprintf(F," -6, --ipv6 prefer IPv6\n");
#endif
rprintf(F," -h, --help show this help screen\n");
rprintf(F,"\n");
@@ -305,15 +319,15 @@ void usage(enum logcode F)
enum {OPT_VERSION = 1000, OPT_SENDER, OPT_EXCLUDE, OPT_EXCLUDE_FROM,
OPT_DELETE_AFTER, OPT_DELETE_EXCLUDED, OPT_LINK_DEST,
OPT_INCLUDE, OPT_INCLUDE_FROM, OPT_MODIFY_WINDOW,
OPT_READ_BATCH, OPT_WRITE_BATCH,
OPT_READ_BATCH, OPT_WRITE_BATCH, OPT_TIMEOUT,
OPT_REFUSED_BASE = 9000};
static struct poptOption long_options[] = {
/* longName, shortName, argInfo, argPtr, value, descrip, argDesc */
{"version", 0, POPT_ARG_NONE, 0, OPT_VERSION, 0, 0},
{"suffix", 0, POPT_ARG_STRING, &backup_suffix, 0, 0, 0 },
{"rsync-path", 0, POPT_ARG_STRING, &rsync_path, 0, 0, 0 },
{"password-file", 0, POPT_ARG_STRING, &password_file, 0, 0, 0 },
{"rsync-path", 0, POPT_ARG_STRING, &rsync_path, 0, 0, 0 },
{"password-file", 0, POPT_ARG_STRING, &password_file, 0, 0, 0 },
{"ignore-times", 'I', POPT_ARG_NONE, &ignore_times, 0, 0, 0 },
{"size-only", 0, POPT_ARG_NONE, &size_only, 0, 0, 0 },
{"modify-window", 0, POPT_ARG_INT, &modify_window, OPT_MODIFY_WINDOW, 0, 0 },
@@ -336,6 +350,8 @@ static struct poptOption long_options[] = {
{"sparse", 'S', POPT_ARG_NONE, &sparse_files, 0, 0, 0 },
{"cvs-exclude", 'C', POPT_ARG_NONE, &cvs_exclude, 0, 0, 0 },
{"update", 'u', POPT_ARG_NONE, &update_only, 0, 0, 0 },
{"inplace", 0, POPT_ARG_NONE, &inplace, 0, 0, 0 },
{"keep-dirlinks", 'K', POPT_ARG_NONE, &keep_dirlinks, 0, 0, 0 },
{"links", 'l', POPT_ARG_NONE, &preserve_links, 0, 0, 0 },
{"copy-links", 'L', POPT_ARG_NONE, &copy_links, 0, 0, 0 },
{"whole-file", 'W', POPT_ARG_VAL, &whole_file, 1, 0, 0 },
@@ -358,7 +374,7 @@ static struct poptOption long_options[] = {
{"rsh", 'e', POPT_ARG_STRING, &shell_cmd, 0, 0, 0 },
{"block-size", 'B', POPT_ARG_INT, &block_size, 0, 0, 0 },
{"max-delete", 0, POPT_ARG_INT, &max_delete, 0, 0, 0 },
{"timeout", 0, POPT_ARG_INT, &io_timeout, 0, 0, 0 },
{"timeout", 0, POPT_ARG_INT, &io_timeout, OPT_TIMEOUT, 0, 0 },
{"temp-dir", 'T', POPT_ARG_STRING, &tmpdir, 0, 0, 0 },
{"compare-dest", 0, POPT_ARG_STRING, &compare_dest, 0, 0, 0 },
{"link-dest", 0, POPT_ARG_STRING, &compare_dest, OPT_LINK_DEST, 0, 0 },
@@ -369,6 +385,7 @@ static struct poptOption long_options[] = {
{"stats", 0, POPT_ARG_NONE, &do_stats, 0, 0, 0 },
{"progress", 0, POPT_ARG_NONE, &do_progress, 0, 0, 0 },
{"partial", 0, POPT_ARG_NONE, &keep_partial, 0, 0, 0 },
{"partial-dir", 0, POPT_ARG_STRING, &partial_dir, 0, 0, 0 },
{"ignore-errors", 0, POPT_ARG_NONE, &ignore_errors, 0, 0, 0 },
{"blocking-io", 0, POPT_ARG_VAL, &blocking_io, 1, 0, 0 },
{"no-blocking-io", 0, POPT_ARG_VAL, &blocking_io, 0, 0, 0 },
@@ -380,21 +397,22 @@ static struct poptOption long_options[] = {
{"address", 0, POPT_ARG_STRING, &bind_address, 0, 0, 0 },
{"backup-dir", 0, POPT_ARG_STRING, &backup_dir, 0, 0, 0 },
{"hard-links", 'H', POPT_ARG_NONE, &preserve_hard_links, 0, 0, 0 },
{"read-batch", 0, POPT_ARG_STRING, &batch_prefix, OPT_READ_BATCH, 0, 0 },
{"write-batch", 0, POPT_ARG_STRING, &batch_prefix, OPT_WRITE_BATCH, 0, 0 },
{"read-batch", 0, POPT_ARG_STRING, &batch_name, OPT_READ_BATCH, 0, 0 },
{"write-batch", 0, POPT_ARG_STRING, &batch_name, OPT_WRITE_BATCH, 0, 0 },
{"files-from", 0, POPT_ARG_STRING, &files_from, 0, 0, 0 },
{"from0", '0', POPT_ARG_NONE, &eol_nulls, 0, 0, 0},
{"no-implied-dirs", 0, POPT_ARG_VAL, &implied_dirs, 0, 0, 0 },
{"protocol", 0, POPT_ARG_INT, &protocol_version, 0, 0, 0 },
{"checksum-seed", 0, POPT_ARG_INT, &checksum_seed, 0, 0, 0 },
#ifdef INET6
{0, '4', POPT_ARG_VAL, &default_af_hint, AF_INET, 0, 0 },
{0, '6', POPT_ARG_VAL, &default_af_hint, AF_INET6, 0, 0 },
{"ipv4", '4', POPT_ARG_VAL, &default_af_hint, AF_INET, 0, 0 },
{"ipv6", '6', POPT_ARG_VAL, &default_af_hint, AF_INET6, 0, 0 },
#endif
{0,0,0,0, 0, 0, 0}
};
static char err_buf[100];
static char err_buf[200];
/**
@@ -404,15 +422,12 @@ static char err_buf[100];
**/
void option_error(void)
{
if (err_buf[0]) {
rprintf(FLOG, "%s", err_buf);
rprintf(FERROR, RSYNC_NAME ": %s", err_buf);
} else {
rprintf (FERROR, "Error parsing options: "
"option may be supported on client but not on server?\n");
rprintf (FERROR, RSYNC_NAME ": Error parsing options: "
"option may be supported on client but not on server?\n");
if (!err_buf[0]) {
strcpy(err_buf, "Error parsing options: "
"option may be supported on client but not on server?\n");
}
rprintf(FERROR, RSYNC_NAME ": %s", err_buf);
}
@@ -423,23 +438,38 @@ void option_error(void)
static void set_refuse_options(char *bp)
{
struct poptOption *op;
char *cp;
char *cp, shortname[2];
int is_wild, found_match;
shortname[1] = '\0';
while (1) {
while (*bp == ' ') bp++;
if (!*bp)
break;
if ((cp = strchr(bp, ' ')) != NULL)
*cp= '\0';
/* If they specify "delete", reject all delete options. */
if (strcmp(bp, "delete") == 0)
bp = "delete*";
is_wild = strpbrk(bp, "*?[") != NULL;
found_match = 0;
for (op = long_options; ; op++) {
if (!op->longName) {
rprintf(FLOG,
"Unknown option %s in \"refuse options\" setting\n",
bp);
break;
}
if (strcmp(bp, op->longName) == 0) {
op->val = (op - long_options)+OPT_REFUSED_BASE;
*shortname = op->shortName;
if (!op->longName && !*shortname)
break;
if ((op->longName && wildmatch(bp, op->longName))
|| (*shortname && wildmatch(bp, shortname))) {
op->val = (op - long_options) + OPT_REFUSED_BASE;
found_match = 1;
if (!is_wild)
break;
}
}
if (!found_match) {
rprintf(FLOG, "No match for refuse-options string \"%s\"\n",
bp);
}
if (!cp)
break;
*cp = ' ';
@@ -519,19 +549,19 @@ int parse_arguments(int *argc, const char ***argv, int frommain)
break;
case OPT_EXCLUDE_FROM:
arg = poptGetOptArg(pc);
if (sanitize_paths)
arg = alloc_sanitize_path(arg, curr_dir);
add_exclude_file(&exclude_list, arg,
XFLG_FATAL_ERRORS);
break;
case OPT_INCLUDE_FROM:
arg = poptGetOptArg(pc);
if (sanitize_paths)
arg = alloc_sanitize_path(arg, curr_dir);
add_exclude_file(&exclude_list, arg,
XFLG_FATAL_ERRORS | XFLG_DEF_INCLUDE);
arg = sanitize_path(NULL, arg, NULL, 0);
if (server_exclude_list.head) {
char *cp = (char *)arg;
clean_fname(cp, 1);
if (check_exclude(&server_exclude_list, cp, 0) < 0)
goto options_rejected;
}
add_exclude_file(&exclude_list, arg, XFLG_FATAL_ERRORS
| (opt == OPT_INCLUDE_FROM
? XFLG_DEF_INCLUDE : 0));
break;
case 'h':
@@ -561,15 +591,18 @@ int parse_arguments(int *argc, const char ***argv, int frommain)
break;
case OPT_WRITE_BATCH:
/* popt stores the filename in batch_prefix for us */
/* batch_name is already set */
write_batch = 1;
checksum_seed = FIXED_CHECKSUM_SEED;
break;
case OPT_READ_BATCH:
/* popt stores the filename in batch_prefix for us */
/* batch_name is already set */
read_batch = 1;
checksum_seed = FIXED_CHECKSUM_SEED;
break;
case OPT_TIMEOUT:
if (io_timeout && io_timeout < select_timeout)
select_timeout = io_timeout;
break;
case OPT_LINK_DEST:
@@ -580,7 +613,6 @@ int parse_arguments(int *argc, const char ***argv, int frommain)
snprintf(err_buf, sizeof err_buf,
"hard links are not supported on this %s\n",
am_server ? "server" : "client");
rprintf(FERROR, "ERROR: %s", err_buf);
return 0;
#endif
@@ -591,7 +623,7 @@ int parse_arguments(int *argc, const char ***argv, int frommain)
struct poptOption *op =
&long_options[opt-OPT_REFUSED_BASE];
int n = snprintf(err_buf, sizeof err_buf,
"This server does not support --%s\n",
"The server is configured to refuse --%s\n",
op->longName) - 1;
if (op->shortName) {
snprintf(err_buf+n, sizeof err_buf-n,
@@ -613,7 +645,6 @@ int parse_arguments(int *argc, const char ***argv, int frommain)
snprintf(err_buf, sizeof err_buf,
"symlinks are not supported on this %s\n",
am_server ? "server" : "client");
rprintf(FERROR, "ERROR: %s", err_buf);
return 0;
}
#endif
@@ -623,32 +654,49 @@ int parse_arguments(int *argc, const char ***argv, int frommain)
snprintf(err_buf, sizeof err_buf,
"hard links are not supported on this %s\n",
am_server ? "server" : "client");
rprintf(FERROR, "ERROR: %s", err_buf);
return 0;
}
#endif
if (write_batch && read_batch) {
rprintf(FERROR,
"write-batch and read-batch can not be used together\n");
exit_cleanup(RERR_SYNTAX);
snprintf(err_buf, sizeof err_buf,
"--write-batch and --read-batch can not be used together\n");
return 0;
}
if (batch_prefix && strlen(batch_prefix) > MAX_BATCH_PREFIX_LEN) {
rprintf(FERROR,
"the batch-file prefix must be %d characters or less.\n",
MAX_BATCH_PREFIX_LEN);
exit_cleanup(RERR_SYNTAX);
if (write_batch || read_batch) {
if (dry_run) {
snprintf(err_buf, sizeof err_buf,
"--%s-batch cannot be used with --dry_run (-n)\n",
write_batch ? "write" : "read");
return 0;
}
if (am_server) {
rprintf(FINFO,
"ignoring --%s-batch option sent to server\n",
write_batch ? "write" : "read");
/* We don't actually exit_cleanup(), so that we can
* still service older version clients that still send
* batch args to server. */
read_batch = write_batch = 0;
batch_name = NULL;
}
}
if (read_batch && files_from) {
snprintf(err_buf, sizeof err_buf,
"--read-batch cannot be used with --files-from\n");
return 0;
}
if (batch_name && strlen(batch_name) > MAX_BATCH_NAME_LEN) {
snprintf(err_buf, sizeof err_buf,
"the batch-file name must be %d characters or less.\n",
MAX_BATCH_NAME_LEN);
return 0;
}
if (tmpdir && strlen(tmpdir) >= MAXPATHLEN - 10) {
rprintf(FERROR, "the --temp-dir path is WAY too long.\n");
exit_cleanup(RERR_SYNTAX);
}
if (do_compression && (write_batch || read_batch)) {
rprintf(FERROR,
"compress can not be used with write-batch or read-batch\n");
exit_cleanup(RERR_SYNTAX);
snprintf(err_buf, sizeof err_buf,
"the --temp-dir path is WAY too long.\n");
return 0;
}
if (archive_mode) {
@@ -676,15 +724,49 @@ int parse_arguments(int *argc, const char ***argv, int frommain)
if (sanitize_paths) {
int i;
for (i = *argc; i-- > 0; )
(*argv)[i] = alloc_sanitize_path((*argv)[i], NULL);
(*argv)[i] = sanitize_path(NULL, (*argv)[i], "", 0);
if (tmpdir)
tmpdir = alloc_sanitize_path(tmpdir, curr_dir);
tmpdir = sanitize_path(NULL, tmpdir, NULL, 0);
if (partial_dir)
partial_dir = sanitize_path(NULL, partial_dir, NULL, 0);
if (compare_dest)
compare_dest = alloc_sanitize_path(compare_dest, curr_dir);
compare_dest = sanitize_path(NULL, compare_dest, NULL, 0);
if (backup_dir)
backup_dir = alloc_sanitize_path(backup_dir, curr_dir);
backup_dir = sanitize_path(NULL, backup_dir, NULL, 0);
if (files_from)
files_from = alloc_sanitize_path(files_from, curr_dir);
files_from = sanitize_path(NULL, files_from, NULL, 0);
}
if (server_exclude_list.head && !am_sender) {
struct exclude_list_struct *elp = &server_exclude_list;
if (tmpdir) {
clean_fname(tmpdir, 1);
if (check_exclude(elp, tmpdir, 1) < 0)
goto options_rejected;
}
if (partial_dir) {
clean_fname(partial_dir, 1);
if (check_exclude(elp, partial_dir, 1) < 0)
goto options_rejected;
}
if (compare_dest) {
clean_fname(compare_dest, 1);
if (check_exclude(elp, compare_dest, 1) < 0)
goto options_rejected;
}
if (backup_dir) {
clean_fname(backup_dir, 1);
if (check_exclude(elp, backup_dir, 1) < 0)
goto options_rejected;
}
}
if (server_exclude_list.head && files_from) {
clean_fname(files_from, 1);
if (check_exclude(&server_exclude_list, files_from, 0) < 0) {
options_rejected:
snprintf(err_buf, sizeof err_buf,
"Your options have been rejected by the server.\n");
return 0;
}
}
if (daemon_opt) {
@@ -697,16 +779,18 @@ int parse_arguments(int *argc, const char ***argv, int frommain)
backup_suffix = backup_dir ? "" : BACKUP_SUFFIX;
backup_suffix_len = strlen(backup_suffix);
if (strchr(backup_suffix, '/') != NULL) {
rprintf(FERROR, "--suffix cannot contain slashes: %s\n",
snprintf(err_buf, sizeof err_buf,
"--suffix cannot contain slashes: %s\n",
backup_suffix);
exit_cleanup(RERR_SYNTAX);
return 0;
}
if (backup_dir) {
backup_dir_len = strlcpy(backup_dir_buf, backup_dir, sizeof backup_dir_buf);
backup_dir_remainder = sizeof backup_dir_buf - backup_dir_len;
if (backup_dir_remainder < 32) {
rprintf(FERROR, "the --backup-dir path is WAY too long.\n");
exit_cleanup(RERR_SYNTAX);
snprintf(err_buf, sizeof err_buf,
"the --backup-dir path is WAY too long.\n");
return 0;
}
if (backup_dir_buf[backup_dir_len - 1] != '/') {
backup_dir_buf[backup_dir_len++] = '/';
@@ -715,17 +799,57 @@ int parse_arguments(int *argc, const char ***argv, int frommain)
if (verbose > 1 && !am_sender)
rprintf(FINFO, "backup_dir is %s\n", backup_dir_buf);
} else if (!backup_suffix_len && (!am_server || !am_sender)) {
rprintf(FERROR,
snprintf(err_buf, sizeof err_buf,
"--suffix cannot be a null string without --backup-dir\n");
exit_cleanup(RERR_SYNTAX);
return 0;
}
if (do_progress && !verbose)
verbose = 1;
if (bwlimit) {
bwlimit_writemax = (size_t)bwlimit * 128;
if (bwlimit_writemax < 512)
bwlimit_writemax = 512;
}
if (inplace) {
#if HAVE_FTRUNCATE
if (partial_dir) {
snprintf(err_buf, sizeof err_buf,
"--inplace cannot be used with --partial-dir\n");
return 0;
}
keep_partial = 0;
#else
snprintf(err_buf, sizeof err_buf,
"--inplace is not supported on this %s\n",
am_server ? "server" : "client");
return 0;
#endif
if (compare_dest) {
snprintf(err_buf, sizeof err_buf,
"--inplace does not yet work with %s\n",
link_dest ? "--link-dest" : "--compare-dest");
return 0;
}
} else {
if (keep_partial && !partial_dir)
partial_dir = getenv("RSYNC_PARTIAL_DIR");
if (partial_dir) {
if (!*partial_dir || strcmp(partial_dir, ".") == 0)
partial_dir = NULL;
else if (*partial_dir != '/') {
add_exclude(&exclude_list, partial_dir,
XFLG_DIRECTORY);
}
keep_partial = 1;
}
}
if (files_from) {
char *colon;
if (*argc != 2 && !(am_server && am_sender && *argc == 1)) {
if (*argc > 2 || (!am_daemon && *argc == 1)) {
usage(FERROR);
exit_cleanup(RERR_SYNTAX);
}
@@ -741,16 +865,17 @@ int parse_arguments(int *argc, const char ***argv, int frommain)
}
remote_filesfrom_file = colon+1 + (colon[1] == ':');
if (strcmp(remote_filesfrom_file, "-") == 0) {
rprintf(FERROR, "Invalid --files-from remote filename\n");
exit_cleanup(RERR_SYNTAX);
snprintf(err_buf, sizeof err_buf,
"Invalid --files-from remote filename\n");
return 0;
}
} else {
filesfrom_fd = open(files_from, O_RDONLY|O_BINARY);
if (filesfrom_fd < 0) {
rsyserr(FERROR, errno,
"failed to open files-from file %s",
files_from);
exit_cleanup(RERR_FILEIO);
snprintf(err_buf, sizeof err_buf,
"failed to open files-from file %s: %s\n",
files_from, strerror(errno));
return 0;
}
}
}
@@ -806,6 +931,8 @@ void server_options(char **args,int *argc)
argstr[x++] = 'l';
if (copy_links)
argstr[x++] = 'L';
if (keep_dirlinks && am_sender)
argstr[x++] = 'K';
if (whole_file > 0)
argstr[x++] = 'W';
@@ -866,13 +993,6 @@ void server_options(char **args,int *argc)
args[ac++] = arg;
}
if (batch_prefix) {
char *r_or_w = write_batch ? "write" : "read";
if (asprintf(&arg, "--%s-batch=%s", r_or_w, batch_prefix) < 0)
goto oom;
args[ac++] = arg;
}
if (io_timeout) {
if (asprintf(&arg, "--timeout=%d", io_timeout) < 0)
goto oom;
@@ -898,10 +1018,18 @@ void server_options(char **args,int *argc)
args[ac++] = arg;
}
if (delete_excluded)
args[ac++] = "--delete-excluded";
else if (delete_mode)
args[ac++] = "--delete";
if (am_sender) {
if (delete_excluded)
args[ac++] = "--delete-excluded";
else if (delete_mode)
args[ac++] = "--delete";
if (delete_after)
args[ac++] = "--delete-after";
if (force_delete)
args[ac++] = "--force";
}
if (size_only)
args[ac++] = "--size-only";
@@ -912,15 +1040,18 @@ void server_options(char **args,int *argc)
args[ac++] = arg;
}
if (keep_partial)
if (checksum_seed) {
if (asprintf(&arg, "--checksum-seed=%d", checksum_seed) < 0)
goto oom;
args[ac++] = arg;
}
if (partial_dir && am_sender) {
args[ac++] = "--partial-dir";
args[ac++] = partial_dir;
} else if (keep_partial)
args[ac++] = "--partial";
if (force_delete)
args[ac++] = "--force";
if (delete_after)
args[ac++] = "--delete-after";
if (ignore_errors)
args[ac++] = "--ignore-errors";
@@ -939,6 +1070,9 @@ void server_options(char **args,int *argc)
if (opt_ignore_existing && am_sender)
args[ac++] = "--ignore-existing";
if (inplace)
args[ac++] = "--inplace";
if (tmpdir) {
args[ac++] = "--temp-dir";
args[ac++] = tmpdir;

View File

@@ -1,6 +1,6 @@
Summary: Program for efficient remote updates of files.
Name: rsync
Version: 2.6.1
Version: 2.6.3
Release: 1
Copyright: GPL
Group: Applications/Networking

View File

@@ -491,8 +491,8 @@ static FILE *OpenConfFile( char *FileName )
OpenedFile = fopen( FileName, "r" );
if( NULL == OpenedFile )
{
rprintf(FERROR,"rsync: unable to open configuration file \"%s\": %s\n",
FileName, strerror(errno));
rsyserr(FERROR, errno, "rsync: unable to open configuration file \"%s\"",
FileName);
}
return( OpenedFile );

68
pipe.c
View File

@@ -1,19 +1,19 @@
/* -*- c-file-style: "linux" -*-
*
* Copyright (C) 1996-2000 by Andrew Tridgell
*
* Copyright (C) 1996-2000 by Andrew Tridgell
* Copyright (C) Paul Mackerras 1996
* Copyright (C) 2001, 2002 by Martin Pool <mbp@samba.org>
*
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
@@ -25,14 +25,14 @@ extern int am_sender;
extern int am_server;
extern int blocking_io;
extern int orig_umask;
extern int read_batch;
extern int write_batch;
extern int filesfrom_fd;
/**
* Create a child connected to use on stdin/stdout.
*
* This is derived from CVS code
*
* This is derived from CVS code
*
* Note that in the child STDIN is set to blocking and STDOUT
* is set to non-blocking. This is necessary as rsh relies on stdin being blocking
* and ssh relies on stdout being non-blocking
@@ -46,20 +46,19 @@ pid_t piped_child(char **command, int *f_in, int *f_out)
pid_t pid;
int to_child_pipe[2];
int from_child_pipe[2];
if (verbose >= 2) {
print_child_argv(command);
}
if (fd_pair(to_child_pipe) < 0 || fd_pair(from_child_pipe) < 0) {
rprintf(FERROR, "pipe: %s\n", strerror(errno));
rsyserr(FERROR, errno, "pipe");
exit_cleanup(RERR_IPC);
}
pid = do_fork();
if (pid == -1) {
rprintf(FERROR, "fork: %s\n", strerror(errno));
rsyserr(FERROR, errno, "fork");
exit_cleanup(RERR_IPC);
}
@@ -68,8 +67,7 @@ pid_t piped_child(char **command, int *f_in, int *f_out)
close(to_child_pipe[1]) < 0 ||
close(from_child_pipe[0]) < 0 ||
dup2(from_child_pipe[1], STDOUT_FILENO) < 0) {
rprintf(FERROR, "Failed to dup/close : %s\n",
strerror(errno));
rsyserr(FERROR, errno, "Failed to dup/close");
exit_cleanup(RERR_IPC);
}
if (to_child_pipe[0] != STDIN_FILENO)
@@ -81,13 +79,12 @@ pid_t piped_child(char **command, int *f_in, int *f_out)
if (blocking_io > 0)
set_blocking(STDOUT_FILENO);
execvp(command[0], command);
rprintf(FERROR, "Failed to exec %s : %s\n",
command[0], strerror(errno));
rsyserr(FERROR, errno, "Failed to exec %s", command[0]);
exit_cleanup(RERR_IPC);
}
if (close(from_child_pipe[1]) < 0 || close(to_child_pipe[0]) < 0) {
rprintf(FERROR, "Failed to close : %s\n", strerror(errno));
rsyserr(FERROR, errno, "Failed to close");
exit_cleanup(RERR_IPC);
}
@@ -97,7 +94,17 @@ pid_t piped_child(char **command, int *f_in, int *f_out)
return pid;
}
pid_t local_child(int argc, char **argv,int *f_in,int *f_out,
/* This function forks a child which calls child_main(). First,
* however, it has to establish communication paths to and from the
* newborn child. It creates two socket pairs -- one for writing to
* the child (from the parent) and one for reading from the child
* (writing to the parent). Since that's four socket ends, each
* process has to close the two ends it doesn't need. The remaining
* two socket ends are retained for reading and writing. In the
* child, the STDIN and STDOUT file descriptors refer to these
* sockets. In the parent, the function arguments f_in and f_out are
* set to refer to these sockets. */
pid_t local_child(int argc, char **argv, int *f_in, int *f_out,
int (*child_main)(int, char*[]))
{
pid_t pid;
@@ -106,20 +113,23 @@ pid_t local_child(int argc, char **argv,int *f_in,int *f_out,
if (fd_pair(to_child_pipe) < 0 ||
fd_pair(from_child_pipe) < 0) {
rprintf(FERROR,"pipe: %s\n",strerror(errno));
rsyserr(FERROR, errno, "pipe");
exit_cleanup(RERR_IPC);
}
pid = do_fork();
if (pid == -1) {
rprintf(FERROR,"fork: %s\n",strerror(errno));
rsyserr(FERROR, errno, "fork");
exit_cleanup(RERR_IPC);
}
if (pid == 0) {
am_sender = read_batch ? 0 : !am_sender;
am_server = 1;
am_sender = !am_sender;
am_server = 1;
/* The server side never writes the batch, even if it
* is local (it makes the logic easier elsewhere). */
write_batch = 0;
if (!am_sender)
filesfrom_fd = -1;
@@ -128,11 +138,13 @@ pid_t local_child(int argc, char **argv,int *f_in,int *f_out,
close(to_child_pipe[1]) < 0 ||
close(from_child_pipe[0]) < 0 ||
dup2(from_child_pipe[1], STDOUT_FILENO) < 0) {
rprintf(FERROR,"Failed to dup/close : %s\n",strerror(errno));
rsyserr(FERROR, errno, "Failed to dup/close");
exit_cleanup(RERR_IPC);
}
if (to_child_pipe[0] != STDIN_FILENO) close(to_child_pipe[0]);
if (from_child_pipe[1] != STDOUT_FILENO) close(from_child_pipe[1]);
if (to_child_pipe[0] != STDIN_FILENO)
close(to_child_pipe[0]);
if (from_child_pipe[1] != STDOUT_FILENO)
close(from_child_pipe[1]);
child_main(argc, argv);
}
@@ -141,12 +153,12 @@ pid_t local_child(int argc, char **argv,int *f_in,int *f_out,
if (close(from_child_pipe[1]) < 0 ||
close(to_child_pipe[0]) < 0) {
rprintf(FERROR,"Failed to close : %s\n",strerror(errno));
rsyserr(FERROR, errno, "Failed to close");
exit_cleanup(RERR_IPC);
}
*f_in = from_child_pipe[0];
*f_out = to_child_pipe[1];
return pid;
}

View File

@@ -63,7 +63,7 @@ struct poptOption poptHelpOptions[] = {
/**
* @param table option(s)
*/
/*@observer@*/ /*@null@*/ static const char *const
/*@observer@*/ /*@null@*/ static const char *
getTableTranslationDomain(/*@null@*/ const struct poptOption *table)
/*@*/
{
@@ -81,10 +81,10 @@ getTableTranslationDomain(/*@null@*/ const struct poptOption *table)
* @param opt option(s)
* @param translation_domain translation domain
*/
/*@observer@*/ /*@null@*/ static const char *const
/*@observer@*/ /*@null@*/ static const char *
getArgDescrip(const struct poptOption * opt,
/*@-paramuse@*/ /* FIX: wazzup? */
/*@null@*/ UNUSED(const char * translation_domain))
/*@null@*/ const char * translation_domain)
/*@=paramuse@*/
/*@*/
{
@@ -115,7 +115,7 @@ static /*@only@*/ /*@null@*/ char *
singleOptionDefaultValue(int lineLength,
const struct poptOption * opt,
/*@-paramuse@*/ /* FIX: i18n macros disable with lclint */
/*@null@*/ UNUSED(const char * translation_domain))
/*@null@*/ const char * translation_domain)
/*@=paramuse@*/
/*@*/
{

View File

@@ -19,6 +19,14 @@
#include <unistd.h>
#endif
#if !defined(__GNUC__) || defined(APPLE)
/* Apparently the OS X port of gcc gags on __attribute__.
*
* <http://www.opensource.apple.com/bugs/X/gcc/2512150.html> */
#define __attribute__(x)
#endif
#ifdef __NeXT
/* access macros are not declared in non posix mode in unistd.h -
don't try to use posix on NeXTstep 3.3 ! */

View File

@@ -22,19 +22,22 @@
extern int verbose;
extern int recurse;
extern int delete_mode;
extern int delete_after;
extern int max_delete;
extern int csum_length;
extern struct stats stats;
extern int dry_run;
extern int read_batch;
extern int batch_gen_fd;
extern int am_server;
extern int relative_paths;
extern int keep_dirlinks;
extern int preserve_hard_links;
extern int preserve_perms;
extern int cvs_exclude;
extern int io_error;
extern char *tmpdir;
extern char *partial_dir;
extern char *compare_dest;
extern int make_backups;
extern int do_progress;
@@ -45,24 +48,31 @@ extern int cleanup_got_literal;
extern int module_id;
extern int ignore_errors;
extern int orig_umask;
extern int keep_partial;
extern int checksum_seed;
extern int inplace;
extern struct exclude_list_struct server_exclude_list;
static void delete_one(char *fn, int is_dir)
{
if (!is_dir) {
if (robust_unlink(fn) != 0) {
rprintf(FERROR, "delete_one: unlink %s failed: %s\n",
full_fname(fn), strerror(errno));
} else if (verbose) {
rprintf(FINFO, "deleting %s\n", fn);
}
rsyserr(FERROR, errno, "delete_one: unlink %s failed",
full_fname(fn));
} else if (verbose)
rprintf(FINFO, "deleting %s\n", safe_fname(fn));
} else {
if (do_rmdir(fn) != 0) {
if (errno != ENOTEMPTY && errno != EEXIST) {
rprintf(FERROR, "delete_one: rmdir %s failed: %s\n",
full_fname(fn), strerror(errno));
rsyserr(FERROR, errno,
"delete_one: rmdir %s failed",
full_fname(fn));
}
} else if (verbose) {
rprintf(FINFO, "deleting directory %s\n", fn);
rprintf(FINFO, "deleting directory %s\n",
safe_fname(fn));
}
}
}
@@ -103,7 +113,7 @@ void delete_files(struct file_list *flist)
continue;
if (verbose > 1)
rprintf(FINFO, "deleting in %s\n", fbuf);
rprintf(FINFO, "deleting in %s\n", safe_fname(fbuf));
for (i = local_file_list->count-1; i >= 0; i--) {
if (max_delete && deletion_count > max_delete)
@@ -113,9 +123,11 @@ void delete_files(struct file_list *flist)
if (flist_find(flist,local_file_list->files[i]) < 0) {
char *f = f_name(local_file_list->files[i]);
if (make_backups && (backup_dir || !is_backup_file(f))) {
(void) make_backup(f);
if (verbose)
rprintf(FINFO, "deleting %s\n", f);
make_backup(f);
if (verbose) {
rprintf(FINFO, "deleting %s\n",
safe_fname(f));
}
} else {
int mode = local_file_list->files[i]->mode;
delete_one(f, S_ISDIR(mode) != 0);
@@ -189,22 +201,33 @@ static int get_tmpname(char *fnametmp, char *fname)
}
static int receive_data(int f_in,struct map_struct *mapbuf,int fd,char *fname,
OFF_T total_size)
static int receive_data(int f_in, char *fname_r, int fd_r, OFF_T size_r,
char *fname, int fd, OFF_T total_size)
{
int i;
static char file_sum1[MD4_SUM_LENGTH];
static char file_sum2[MD4_SUM_LENGTH];
struct map_struct *mapbuf;
struct sum_struct sum;
unsigned int len;
OFF_T offset = 0;
OFF_T offset2;
char *data;
static char file_sum1[MD4_SUM_LENGTH];
static char file_sum2[MD4_SUM_LENGTH];
char *map=NULL;
int i;
char *map = NULL;
read_sum_head(f_in, &sum);
sum_init();
if (fd_r >= 0 && size_r > 0) {
OFF_T map_size = MAX(sum.blength * 2, 16*1024);
mapbuf = map_file(fd_r, size_r, map_size, sum.blength);
if (verbose > 2) {
rprintf(FINFO, "recv mapped %s of size %.0f\n",
safe_fname(fname_r), (double)size_r);
}
} else
mapbuf = NULL;
sum_init(checksum_seed);
while ((i = recv_token(f_in, &data)) != 0) {
if (do_progress)
@@ -221,11 +244,8 @@ static int receive_data(int f_in,struct map_struct *mapbuf,int fd,char *fname,
sum_update(data,i);
if (fd != -1 && write_file(fd,data,i) != i) {
rprintf(FERROR, "write failed on %s: %s\n",
full_fname(fname), strerror(errno));
exit_cleanup(RERR_FILEIO);
}
if (fd != -1 && write_file(fd,data,i) != i)
goto report_write_error;
offset += i;
continue;
}
@@ -233,7 +253,7 @@ static int receive_data(int f_in,struct map_struct *mapbuf,int fd,char *fname,
i = -(i+1);
offset2 = i*(OFF_T)sum.blength;
len = sum.blength;
if (i == (int) sum.count-1 && sum.remainder != 0)
if (i == (int)sum.count-1 && sum.remainder != 0)
len = sum.remainder;
stats.matched_data += len;
@@ -249,61 +269,83 @@ static int receive_data(int f_in,struct map_struct *mapbuf,int fd,char *fname,
sum_update(map,len);
}
if (fd != -1 && write_file(fd,map,len) != (int) len) {
rprintf(FERROR, "write failed on %s: %s\n",
full_fname(fname), strerror(errno));
exit_cleanup(RERR_FILEIO);
if (inplace) {
if (offset == offset2 && fd != -1) {
if (flush_write_file(fd) < 0)
goto report_write_error;
offset += len;
if (do_lseek(fd, len, SEEK_CUR) != offset) {
rsyserr(FERROR, errno,
"lseek failed on %s",
full_fname(fname));
exit_cleanup(RERR_FILEIO);
}
continue;
}
}
if (fd != -1 && write_file(fd, map, len) != (int)len)
goto report_write_error;
offset += len;
}
flush_write_file(fd);
#ifdef HAVE_FTRUNCATE
if (inplace && fd != -1)
ftruncate(fd, offset);
#endif
if (do_progress)
end_progress(total_size);
if (fd != -1 && offset > 0 && sparse_end(fd) != 0) {
rprintf(FERROR, "write failed on %s: %s\n",
full_fname(fname), strerror(errno));
report_write_error:
rsyserr(FERROR, errno, "write failed on %s",
full_fname(fname));
exit_cleanup(RERR_FILEIO);
}
sum_end(file_sum1);
if (mapbuf)
unmap_file(mapbuf);
read_buf(f_in,file_sum2,MD4_SUM_LENGTH);
if (verbose > 2) {
if (verbose > 2)
rprintf(FINFO,"got file_sum\n");
}
if (fd != -1 && memcmp(file_sum1,file_sum2,MD4_SUM_LENGTH) != 0) {
if (fd != -1 && memcmp(file_sum1, file_sum2, MD4_SUM_LENGTH) != 0)
return 0;
}
return 1;
}
static void discard_receive_data(int f_in, OFF_T length)
{
receive_data(f_in, NULL, -1, 0, NULL, -1, length);
}
/**
* main routine for receiver process.
*
* Receiver process runs on the same host as the generator process. */
int recv_files(int f_in,struct file_list *flist,char *local_name)
int recv_files(int f_in, struct file_list *flist, char *local_name)
{
int next_gen_i = -1;
int fd1,fd2;
STRUCT_STAT st;
char *fname, fbuf[MAXPATHLEN];
char template[MAXPATHLEN];
char fnametmp[MAXPATHLEN];
char *fnamecmp;
char *fnamecmp, *partialptr;
char fnamecmpbuf[MAXPATHLEN];
struct map_struct *mapbuf;
int i;
struct file_struct *file;
int phase=0;
int recv_ok;
struct stats initial_stats;
int save_make_backups = make_backups;
int i, recv_ok, phase = 0;
if (verbose > 2) {
if (verbose > 2)
rprintf(FINFO,"recv_files(%d) starting\n",flist->count);
}
if (flist->hlink_pool) {
pool_destroy(flist->hlink_pool);
@@ -315,15 +357,23 @@ int recv_files(int f_in,struct file_list *flist,char *local_name)
i = read_int(f_in);
if (i == -1) {
if (phase == 0) {
phase++;
csum_length = SUM_LENGTH;
if (verbose > 2)
rprintf(FINFO,"recv_files phase=%d\n",phase);
send_msg(MSG_DONE, "", 0);
continue;
if (read_batch) {
if (next_gen_i != flist->count)
while (read_int(batch_gen_fd) != -1) {}
next_gen_i = -1;
}
break;
if (phase)
break;
phase = 1;
csum_length = SUM_LENGTH;
if (verbose > 2)
rprintf(FINFO, "recv_files phase=%d\n", phase);
send_msg(MSG_DONE, "", 0);
if (keep_partial)
make_backups = 0; /* prevents double backup */
continue;
}
if (i < 0 || i >= flist->count) {
@@ -345,22 +395,58 @@ int recv_files(int f_in,struct file_list *flist,char *local_name)
fname = f_name_to(file, fbuf);
if (dry_run) {
if (!am_server && verbose) { /* log transfer */
rprintf(FINFO, "%s\n", fname);
}
if (!am_server && verbose) /* log the transfer */
rprintf(FINFO, "%s\n", safe_fname(fname));
continue;
}
initial_stats = stats;
if (verbose > 2)
rprintf(FINFO,"recv_files(%s)\n",fname);
rprintf(FINFO, "recv_files(%s)\n", safe_fname(fname));
fnamecmp = fname;
if (read_batch) {
while (i > next_gen_i) {
next_gen_i = read_int(batch_gen_fd);
if (next_gen_i == -1)
next_gen_i = flist->count;
}
if (i < next_gen_i) {
rprintf(FINFO, "skipping update for \"%s\"\n",
safe_fname(fname));
discard_receive_data(f_in, file->length);
continue;
}
}
if (server_exclude_list.head
&& check_exclude(&server_exclude_list, fname,
S_ISDIR(file->mode)) < 0) {
rprintf(FERROR, "attempt to hack rsync failed.\n");
exit_cleanup(RERR_PROTOCOL);
}
if (partial_dir) {
if ((partialptr = partial_dir_fname(fname)) != NULL)
fnamecmp = partialptr;
else
fnamecmp = fname;
} else
fnamecmp = partialptr = fname;
if (inplace && make_backups) {
if (!(fnamecmp = get_backup_name(fname)))
fnamecmp = partialptr;
}
/* open the file */
fd1 = do_open(fnamecmp, O_RDONLY, 0);
if (fd1 == -1 && fnamecmp != fname) {
fnamecmp = fname;
fd1 = do_open(fnamecmp, O_RDONLY, 0);
}
if (fd1 == -1 && compare_dest != NULL) {
/* try the file at compare_dest instead */
pathjoin(fnamecmpbuf, sizeof fnamecmpbuf,
@@ -370,9 +456,9 @@ int recv_files(int f_in,struct file_list *flist,char *local_name)
}
if (fd1 != -1 && do_fstat(fd1,&st) != 0) {
rprintf(FERROR, "fstat %s failed: %s\n",
full_fname(fnamecmp), strerror(errno));
receive_data(f_in,NULL,-1,NULL,file->length);
rsyserr(FERROR, errno, "fstat %s failed",
full_fname(fnamecmp));
discard_receive_data(f_in, file->length);
close(fd1);
continue;
}
@@ -385,7 +471,7 @@ int recv_files(int f_in,struct file_list *flist,char *local_name)
*/
rprintf(FERROR,"recv_files: %s is a directory\n",
full_fname(fnamecmp));
receive_data(f_in, NULL, -1, NULL, file->length);
discard_receive_data(f_in, file->length);
close(fd1);
continue;
}
@@ -393,7 +479,6 @@ int recv_files(int f_in,struct file_list *flist,char *local_name)
if (fd1 != -1 && !S_ISREG(st.st_mode)) {
close(fd1);
fd1 = -1;
mapbuf = NULL;
}
if (fd1 != -1 && !preserve_perms) {
@@ -403,86 +488,123 @@ int recv_files(int f_in,struct file_list *flist,char *local_name)
file->mode = st.st_mode;
}
if (fd1 != -1 && st.st_size > 0) {
mapbuf = map_file(fd1,st.st_size);
if (verbose > 2)
rprintf(FINFO,"recv mapped %s of size %.0f\n",fnamecmp,(double)st.st_size);
} else
mapbuf = NULL;
/* We now check to see if we are writing file "inplace" */
if (inplace) {
fd2 = do_open(fname, O_WRONLY|O_CREAT, 0);
if (fd2 == -1) {
rsyserr(FERROR, errno, "open %s failed",
full_fname(fname));
discard_receive_data(f_in, file->length);
if (fd1 != -1)
close(fd1);
continue;
}
} else {
if (!get_tmpname(fnametmp,fname)) {
discard_receive_data(f_in, file->length);
if (fd1 != -1)
close(fd1);
continue;
}
if (!get_tmpname(fnametmp,fname)) {
if (mapbuf) unmap_file(mapbuf);
if (fd1 != -1) close(fd1);
continue;
}
strlcpy(template, fnametmp, sizeof template);
strlcpy(template, fnametmp, sizeof template);
/* we initially set the perms without the
* setuid/setgid bits to ensure that there is no race
* condition. They are then correctly updated after
* the lchown. Thanks to snabb@epipe.fi for pointing
* this out. We also set it initially without group
* access because of a similar race condition. */
fd2 = do_mkstemp(fnametmp, file->mode & INITACCESSPERMS);
/* in most cases parent directories will already exist
* because their information should have been previously
* transferred, but that may not be the case with -R */
if (fd2 == -1 && relative_paths && errno == ENOENT &&
create_directory_path(fnametmp, orig_umask) == 0) {
strlcpy(fnametmp, template, sizeof fnametmp);
/* we initially set the perms without the
* setuid/setgid bits to ensure that there is no race
* condition. They are then correctly updated after
* the lchown. Thanks to snabb@epipe.fi for pointing
* this out. We also set it initially without group
* access because of a similar race condition. */
fd2 = do_mkstemp(fnametmp, file->mode & INITACCESSPERMS);
}
if (fd2 == -1) {
rprintf(FERROR, "mkstemp %s failed: %s\n",
full_fname(fnametmp), strerror(errno));
receive_data(f_in,mapbuf,-1,NULL,file->length);
if (mapbuf) unmap_file(mapbuf);
if (fd1 != -1) close(fd1);
continue;
/* in most cases parent directories will already exist
* because their information should have been previously
* transferred, but that may not be the case with -R */
if (fd2 == -1 && relative_paths && errno == ENOENT
&& create_directory_path(fnametmp, orig_umask) == 0) {
strlcpy(fnametmp, template, sizeof fnametmp);
fd2 = do_mkstemp(fnametmp, file->mode & INITACCESSPERMS);
}
if (fd2 == -1) {
rsyserr(FERROR, errno, "mkstemp %s failed",
full_fname(fnametmp));
discard_receive_data(f_in, file->length);
if (fd1 != -1)
close(fd1);
continue;
}
if (partialptr)
cleanup_set(fnametmp, partialptr, file, fd1, fd2);
}
cleanup_set(fnametmp, fname, file, mapbuf, fd1, fd2);
if (!am_server && verbose) { /* log transfer */
rprintf(FINFO, "%s\n", fname);
}
if (!am_server && verbose) /* log the transfer */
rprintf(FINFO, "%s\n", safe_fname(fname));
/* recv file data */
recv_ok = receive_data(f_in,mapbuf,fd2,fname,file->length);
recv_ok = receive_data(f_in, fnamecmp, fd1, st.st_size,
fname, fd2, file->length);
log_recv(file, &initial_stats);
if (mapbuf) unmap_file(mapbuf);
if (fd1 != -1) {
if (fd1 != -1)
close(fd1);
if (close(fd2) < 0) {
rsyserr(FERROR, errno, "close failed on %s",
full_fname(fnametmp));
exit_cleanup(RERR_FILEIO);
}
close(fd2);
if (verbose > 2)
rprintf(FINFO,"renaming %s to %s\n",fnametmp,fname);
if (recv_ok || inplace)
finish_transfer(fname, fnametmp, file, recv_ok);
else if (keep_partial && partialptr
&& handle_partial_dir(partialptr, PDIR_CREATE))
finish_transfer(partialptr, fnametmp, file, 0);
else {
partialptr = NULL;
do_unlink(fnametmp);
}
finish_transfer(fname, fnametmp, file);
if (partialptr != fname && fnamecmp == partialptr && recv_ok) {
do_unlink(partialptr);
handle_partial_dir(partialptr, PDIR_DELETE);
}
cleanup_disable();
if (!recv_ok) {
if (csum_length == SUM_LENGTH) {
rprintf(FERROR,"ERROR: file corruption in %s. File changed during transfer?\n",
full_fname(fname));
} else {
int msgtype = csum_length == SUM_LENGTH || read_batch ?
FERROR : FINFO;
if (msgtype == FERROR || verbose) {
char *errstr, *redostr, *keptstr;
if (!(keep_partial && partialptr) && !inplace)
keptstr = "discarded";
else if (partial_dir)
keptstr = "put into partial-dir";
else
keptstr = "retained";
if (msgtype == FERROR) {
errstr = "ERROR";
redostr = "";
} else {
errstr = "WARNING";
redostr = " (will try again)";
}
rprintf(msgtype,
"%s: %s failed verification -- update %s%s.\n",
errstr, safe_fname(fname),
keptstr, redostr);
}
if (csum_length != SUM_LENGTH) {
char buf[4];
if (verbose > 1)
rprintf(FINFO,"redoing %s(%d)\n",fname,i);
SIVAL(buf, 0, i);
send_msg(MSG_REDO, buf, 4);
}
}
}
make_backups = save_make_backups;
if (delete_after && recurse && delete_mode && !local_name
&& flist->count > 0)
if (delete_after && recurse && !local_name && flist->count > 0)
delete_files(flist);
if (verbose > 2)

95
rsync.c
View File

@@ -26,13 +26,16 @@ extern int verbose;
extern int dry_run;
extern int preserve_times;
extern int am_root;
extern int am_server;
extern int am_sender;
extern int am_generator;
extern int preserve_uid;
extern int preserve_gid;
extern int preserve_perms;
extern int force_delete;
extern int recurse;
extern int keep_dirlinks;
extern int make_backups;
extern char *backup_dir;
extern int inplace;
/*
@@ -54,10 +57,8 @@ int delete_file(char *fname)
DIR *d;
struct dirent *di;
char buf[MAXPATHLEN];
extern int force_delete;
STRUCT_STAT st;
int ret;
extern int recurse;
#if SUPPORT_LINKS
ret = do_lstat(fname, &st);
@@ -70,8 +71,8 @@ int delete_file(char *fname)
if (!S_ISDIR(st.st_mode)) {
if (robust_unlink(fname) == 0 || errno == ENOENT)
return 0;
rprintf(FERROR, "delete_file: unlink %s failed: %s\n",
full_fname(fname), strerror(errno));
rsyserr(FERROR, errno, "delete_file: unlink %s failed",
full_fname(fname));
return -1;
}
@@ -79,15 +80,15 @@ int delete_file(char *fname)
return 0;
if (!force_delete || !recurse
|| (errno != ENOTEMPTY && errno != EEXIST)) {
rprintf(FERROR, "delete_file: rmdir %s failed: %s\n",
full_fname(fname), strerror(errno));
rsyserr(FERROR, errno, "delete_file: rmdir %s failed",
full_fname(fname));
return -1;
}
/* now we do a recsursive delete on the directory ... */
if (!(d = opendir(fname))) {
rprintf(FERROR, "delete_file: opendir %s failed: %s\n",
full_fname(fname), strerror(errno));
rsyserr(FERROR, errno, "delete_file: opendir %s failed",
full_fname(fname));
return -1;
}
@@ -98,15 +99,15 @@ int delete_file(char *fname)
continue;
pathjoin(buf, sizeof buf, fname, dname);
if (verbose > 0)
rprintf(FINFO, "deleting %s\n", buf);
rprintf(FINFO, "deleting %s\n", safe_fname(buf));
if (delete_file(buf) != 0) {
closedir(d);
return -1;
}
}
if (errno) {
rprintf(FERROR, "delete_file: readdir %s failed: %s\n",
full_fname(fname), strerror(errno));
rsyserr(FERROR, errno, "delete_file: readdir %s failed",
full_fname(fname));
closedir(d);
return -1;
}
@@ -114,8 +115,8 @@ int delete_file(char *fname)
closedir(d);
if (do_rmdir(fname) != 0) {
rprintf(FERROR, "delete_file: rmdir %s failed: %s\n",
full_fname(fname), strerror(errno));
rsyserr(FERROR, errno, "delete_file: rmdir %s failed",
full_fname(fname));
return -1;
}
@@ -123,31 +124,35 @@ int delete_file(char *fname)
}
int set_perms(char *fname,struct file_struct *file,STRUCT_STAT *st,
int report)
int flags)
{
int updated = 0;
STRUCT_STAT st2;
int change_uid, change_gid;
if (dry_run) return 0;
if (dry_run)
return 0;
if (!st) {
if (link_stat(fname,&st2) != 0) {
rprintf(FERROR, "stat %s failed: %s\n",
full_fname(fname), strerror(errno));
if (link_stat(fname, &st2, 0) < 0) {
rsyserr(FERROR, errno, "stat %s failed",
full_fname(fname));
return 0;
}
st = &st2;
}
if (preserve_times && !S_ISLNK(st->st_mode) &&
cmp_modtime(st->st_mtime, file->modtime) != 0) {
if (!preserve_times || S_ISLNK(st->st_mode)
|| (make_backups && !backup_dir && S_ISDIR(st->st_mode)))
flags |= PERMS_SKIP_MTIME;
if (!(flags & PERMS_SKIP_MTIME)
&& cmp_modtime(st->st_mtime, file->modtime) != 0) {
/* don't complain about not setting times on directories
* because some filesystems can't do it */
if (set_modtime(fname,file->modtime) != 0 &&
!S_ISDIR(st->st_mode)) {
rprintf(FERROR, "failed to set times on %s: %s\n",
full_fname(fname), strerror(errno));
rsyserr(FERROR, errno, "failed to set times on %s",
full_fname(fname));
return 0;
}
updated = 1;
@@ -174,16 +179,17 @@ int set_perms(char *fname,struct file_struct *file,STRUCT_STAT *st,
change_gid ? file->gid : st->st_gid) != 0) {
/* shouldn't have attempted to change uid or gid
* unless have the privilege */
rprintf(FERROR, "%s %s failed: %s\n",
rsyserr(FERROR, errno, "%s %s failed",
change_uid ? "chown" : "chgrp",
full_fname(fname), strerror(errno));
full_fname(fname));
return 0;
}
/* a lchown had been done - we have to re-stat if the
* destination had the setuid or setgid bits set due
* to the side effect of the chown call */
if (st->st_mode & (S_ISUID | S_ISGID)) {
link_stat(fname, st);
link_stat(fname, st,
keep_dirlinks && S_ISDIR(st->st_mode));
}
updated = 1;
}
@@ -193,15 +199,15 @@ int set_perms(char *fname,struct file_struct *file,STRUCT_STAT *st,
if ((st->st_mode & CHMOD_BITS) != (file->mode & CHMOD_BITS)) {
updated = 1;
if (do_chmod(fname,(file->mode & CHMOD_BITS)) != 0) {
rprintf(FERROR, "failed to set permissions on %s: %s\n",
full_fname(fname), strerror(errno));
rsyserr(FERROR, errno, "failed to set permissions on %s",
full_fname(fname));
return 0;
}
}
}
#endif
if (verbose > 1 && report) {
if (verbose > 1 && flags & PERMS_REPORT) {
if (updated)
rprintf(FINFO,"%s\n",fname);
else
@@ -228,26 +234,43 @@ void sig_int(void)
/* finish off a file transfer, renaming the file and setting the permissions
and ownership */
void finish_transfer(char *fname, char *fnametmp, struct file_struct *file)
void finish_transfer(char *fname, char *fnametmp, struct file_struct *file,
int ok_to_set_time)
{
int ret;
if (inplace) {
if (verbose > 2)
rprintf(FINFO, "finishing %s\n", fname);
goto do_set_perms;
}
if (make_backups && !make_backup(fname))
return;
/* Change permissions before putting the file into place. */
set_perms(fnametmp, file, NULL, ok_to_set_time ? 0 : PERMS_SKIP_MTIME);
/* move tmp file over real file */
if (verbose > 2)
rprintf(FINFO, "renaming %s to %s\n", fnametmp, fname);
ret = robust_rename(fnametmp, fname, file->mode & INITACCESSPERMS);
if (ret < 0) {
rprintf(FERROR, "%s %s -> \"%s\": %s\n",
rsyserr(FERROR, errno, "%s %s -> \"%s\"",
ret == -2 ? "copy" : "rename",
full_fname(fnametmp), fname, strerror(errno));
full_fname(fnametmp), fname);
do_unlink(fnametmp);
} else {
set_perms(fname,file,NULL,0);
return;
}
if (ret == 0) {
/* The file was moved into place (not copied), so it's done. */
return;
}
do_set_perms:
set_perms(fname, file, NULL, ok_to_set_time ? 0 : PERMS_SKIP_MTIME);
}
const char *who_am_i(void)
{
return am_sender ? "sender" : am_generator ? "generator" : "receiver";
return am_sender ? "sender" : am_generator ? "generator" : "receiver";
}

36
rsync.h
View File

@@ -108,10 +108,17 @@
#define XFLG_DEF_INCLUDE (1<<1)
#define XFLG_WORDS_ONLY (1<<2)
#define XFLG_WORD_SPLIT (1<<3)
#define XFLG_DIRECTORY (1<<4)
#define PERMS_REPORT (1<<0)
#define PERMS_SKIP_MTIME (1<<1)
#define FULL_FLUSH 1
#define NORMAL_FLUSH 0
#define PDIR_CREATE 1
#define PDIR_DELETE 0
/* Log-message categories. FLOG is only used on the daemon side to
* output messages to the log file. */
@@ -120,10 +127,10 @@ enum logcode { FERROR=1, FINFO=2, FLOG=3 };
/* Messages types that are sent over the message channel. The logcode
* values must all be present here with identical numbers. */
enum msgcode {
MSG_DATA=0, /* raw data on the multiplexed stream */
MSG_ERROR=FERROR, MSG_INFO=FINFO, MSG_LOG=FLOG, /* remote logging */
MSG_REDO=4, /* reprocess indicated flist index */
MSG_DONE=5, /* current phase is done */
MSG_REDO=4, /* reprocess indicated flist index */
MSG_ERROR=FERROR, MSG_INFO=FINFO, MSG_LOG=FLOG, /* remote logging */
MSG_DATA=0 /* raw data on the multiplexed stream */
};
#include "errcode.h"
@@ -309,7 +316,7 @@ enum msgcode {
#else
/* As long as it gets... */
#define int64 off_t
#define NO_INT64
#define INT64_IS_OFF_T
#endif
#if (SIZEOF_LONG == 8)
@@ -388,7 +395,7 @@ struct idev {
#define IN_LOOPBACKNET 127
#endif
#define GID_NONE (gid_t) -1
#define GID_NONE ((gid_t)-1)
#define HL_CHECK_MASTER 0
#define HL_SKIP 1
@@ -455,11 +462,13 @@ struct file_list {
struct file_struct **files;
};
#define SUMFLG_SAME_OFFSET (1<<0)
struct sum_buf {
OFF_T offset; /**< offset in file of this chunk */
unsigned int len; /**< length of chunk of file */
int i; /**< index of this chunk */
uint32 sum1; /**< simple checksum */
short flags; /**< flag bits */
char sum2[SUM_LENGTH]; /**< checksum */
};
@@ -475,11 +484,9 @@ struct sum_struct {
struct map_struct {
char *p; /* Window pointer */
int fd; /* File Descriptor */
int p_size; /* Window size at allocation */
int p_len; /* Window size after fill */
/* p_size and p_len could be
* consolodated by using a local
* variable in map_ptr() */
int p_size; /* Largest window size we allocated */
int p_len; /* Latest (rounded) window size */
int def_window_size; /* Default window size */
int status; /* first errno from read errors */
OFF_T file_size; /* File size (from stat) */
OFF_T p_offset; /* Window start */
@@ -490,12 +497,13 @@ struct map_struct {
#define MATCHFLG_WILD2 (1<<1) /* pattern has '**' */
#define MATCHFLG_WILD2_PREFIX (1<<2) /* pattern starts with '**' */
#define MATCHFLG_ABS_PATH (1<<3) /* path-match on absolute path */
#define MATCHFLG_INCLUDE (1<<4) /* this is an include, not an exclude */
#define MATCHFLG_DIRECTORY (1<<5) /* this matches only directories */
#define MATCHFLG_CLEAR_LIST (1<<6) /* this item is the "!" token */
struct exclude_struct {
struct exclude_struct *next;
char *pattern;
int match_flags;
int include;
int directory;
unsigned int match_flags;
int slash_cnt;
};

341
rsync.yo
View File

@@ -1,5 +1,5 @@
mailto(rsync-bugs@samba.org)
manpage(rsync)(1)(26 Apr 2004)()()
manpage(rsync)(1)(30 Sep 2004)()()
manpagename(rsync)(faster, flexible replacement for rcp)
manpagesynopsis()
@@ -21,8 +21,8 @@ manpagedescription()
rsync is a program that behaves in much the same way that rcp does,
but has many more options and uses the rsync remote-update protocol to
greatly speed up file transfers when the destination file already
exists.
greatly speed up file transfers when the destination file is being
updated.
The rsync remote-update protocol allows rsync to transfer just the
differences between two sets of files across the network connection, using
@@ -32,7 +32,7 @@ report that accompanies this package.
Some of the additional features of rsync are:
itemize(
it() support for copying links, devices, owners, groups and permissions
it() support for copying links, devices, owners, groups, and permissions
it() exclude and exclude-from options similar to GNU tar
it() a CVS exclude mode for ignoring the same files that CVS would ignore
it() can use any transparent remote shell, including ssh or rsh
@@ -113,7 +113,7 @@ and a destination, one of which may be remote.
Perhaps the best way to explain the syntax is with some examples:
quote(rsync *.c foo:src/)
quote(rsync -t *.c foo:src/)
This would transfer all files matching the pattern *.c from the
current directory to the directory src on the machine foo. If any of
@@ -141,8 +141,8 @@ destination. In other words, each of the following commands copies the
files in the same way, including their setting of the attributes of
/dest/foo:
quote(rsync -avz /src/foo /dest)
quote(rsync -avz /src/foo/ /dest/foo)
quote(rsync -av /src/foo /dest)
quote(rsync -av /src/foo/ /dest/foo)
You can also use rsync in local-only mode, where both the source and
destination don't have a ':' in the name. In this case it behaves like
@@ -154,6 +154,35 @@ This would list all the anonymous rsync modules available on the host
somehost.mydomain.com. (See the following section for more details.)
manpagesection(ADVANCED USAGE)
The syntax for requesting multiple files from a remote host involves using
quoted spaces in the SRC. Some examples:
quote(rsync host::'modname/dir1/file1 modname/dir2/file2' /dest)
This would copy file1 and file2 into /dest from an rsync daemon. Each
additional arg must include the same "modname/" prefix as the first one,
and must be preceded by a single space. All other spaces are assumed
to be a part of the filenames.
quote(rsync -av host:'dir1/file1 dir2/file2' /dest)
This would copy file1 and file2 into /dest using a remote shell. This
word-splitting is done by the remote shell, so if it doesn't work it means
that the remote shell isn't configured to split its args based on
whitespace (a very rare setting, but not unknown). If you need to transfer
a filename that contains whitespace, you'll need to either escape the
whitespace in a way that the remote shell will understand, or use wildcards
in place of the spaces. Two examples of this are:
quote(rsync -av host:'file\ name\ with\ spaces' /dest)
quote(rsync -av host:file?name?with?spaces /dest)
This latter example assumes that your shell passes through unmatched
wildcards. If it complains about "no match", put the name in quotes.
manpagesection(CONNECTING TO AN RSYNC SERVER)
It is also possible to use rsync without a remote shell as the
@@ -289,6 +318,8 @@ verb(
--backup-dir make backups into this directory
--suffix=SUFFIX backup suffix (default ~ w/o --backup-dir)
-u, --update update only (don't overwrite newer files)
--inplace update the destination files inplace
-K, --keep-dirlinks treat symlinked dir on receiver as dir
-l, --links copy symlinks as symlinks
-L, --copy-links copy the referent of all symlinks
--copy-unsafe-links copy the referent of "unsafe" symlinks
@@ -304,7 +335,7 @@ verb(
-W, --whole-file copy whole files, no incremental checks
--no-whole-file turn off --whole-file
-x, --one-file-system don't cross filesystem boundaries
-B, --block-size=SIZE checksum blocking size (default 700)
-B, --block-size=SIZE force a fixed checksum block-size
-e, --rsh=COMMAND specify the remote shell
--rsync-path=PATH specify path to rsync on the remote machine
--existing only update files that already exist
@@ -315,6 +346,7 @@ verb(
--ignore-errors delete even if there are I/O errors
--max-delete=NUM don't delete more than NUM files
--partial keep partially transferred files
--partial-dir=DIR put a partially transferred file into DIR
--force force deletion of dirs even if not empty
--numeric-ids don't map uid/gid values by user/group name
--timeout=TIME set I/O timeout in seconds
@@ -346,8 +378,11 @@ verb(
--log-format=FORMAT log file transfers using specified format
--password-file=FILE get password from FILE
--bwlimit=KBPS limit I/O bandwidth, KBytes per second
--write-batch=PREFIX write batch fileset starting with PREFIX
--read-batch=PREFIX read batch fileset starting with PREFIX
--write-batch=FILE write a batch to FILE
--read-batch=FILE read a batch from FILE
--checksum-seed=NUM set block/file checksum seed
-4 --ipv4 prefer IPv4
-6 --ipv6 prefer IPv6
-h, --help show this help screen
@@ -476,11 +511,42 @@ symlink where the destination has a file, the transfer would occur
regardless of the timestamps. This might change in the future (feel
free to comment on this on the mailing list if you have an opinion).
dit(bf(-K, --keep-dirlinks)) On the receiving side, if a symlink is
pointing to a directory, it will be treated as matching a directory
from the sender.
dit(bf(--inplace)) This causes rsync not to create a new copy of the file
and then move it into place. Instead rsync will overwrite the existing
file, meaning that the rsync algorithm can't extract the full amount of
network reduction it might otherwise (since it does not yet try to sort
data matches -- a future version may improve this).
This option is useful for transfer of large files with block-based changes
or appended data, and also on systems that are disk bound, not network
bound.
The option implies --partial (since an interrupted transfer does not delete
the file), but conflicts with --partial-dir, --compare-dest, and
--link-dest (a future rsync version will hopefully update the protocol to
remove these restrictions).
WARNING: The file's data will be in an inconsistent state during the
transfer (and possibly afterward if the transfer gets interrupted), so you
should not use this option to update files that are in use. Also note that
rsync will be unable to update a file inplace that is not writable by the
receiving user.
dit(bf(-l, --links)) When symlinks are encountered, recreate the
symlink on the destination.
dit(bf(-L, --copy-links)) When symlinks are encountered, the file that
they point to (the referent) is copied, rather than the symlink.
they point to (the referent) is copied, rather than the symlink. In older
versions of rsync, this option also had the side-effect of telling the
receiving side to follow symlinks, such as symlinks to directories. In a
modern rsync such as this one, you'll need to specify --keep-dirlinks (-K)
to get this extra behavior. The only exception is when sending files to
an rsync that is too old to understand -K -- in that case, the -L option
will still have the side-effect of -K on that older receiving rsync.
dit(bf(--copy-unsafe-links)) This tells rsync to copy the referent of
symbolic links that point outside the copied tree. Absolute symlinks
@@ -504,9 +570,9 @@ This option can be quite slow, so only use it if you need it.
dit(bf(-W, --whole-file)) With this option the incremental rsync algorithm
is not used and the whole file is sent as-is instead. The transfer may be
faster if this option is used when the bandwidth between the source and
target machines is higher than the bandwidth to disk (especially when the
destination machines is higher than the bandwidth to disk (especially when the
"disk" is actually a networked filesystem). This is the default when both
the source and target are on the local machine.
the source and destination are specified as local paths.
dit(bf(--no-whole-file)) Turn off --whole-file, for use when it is the
default.
@@ -540,9 +606,9 @@ dit(bf(-t, --times)) This tells rsync to transfer modification times along
with the files and update them on the remote system. Note that if this
option is not used, the optimization that excludes files that have not been
modified cannot be effective; in other words, a missing -t or -a will
cause the next transfer to behave as if it used -I, and all files will have
their checksums compared and show up in log messages even if they haven't
changed.
cause the next transfer to behave as if it used -I, causing all files to be
updated (though the rsync algorithm will make the update fairly efficient
if the files haven't actually changed, you're much better off using -t).
dit(bf(-n, --dry-run)) This tells rsync to not do any file transfers,
instead it will just report the actions it would have taken.
@@ -603,8 +669,9 @@ they are not empty when they are to be replaced by non-directories. This
is only relevant without --delete because deletions are now done depth-first.
Requires the --recursive option (which is implied by -a) to have any effect.
dit(bf(-B , --block-size=BLOCKSIZE)) This controls the block size used in
the rsync algorithm. See the technical report for details.
dit(bf(-B, --block-size=BLOCKSIZE)) This forces the block size used in
the rsync algorithm to a fixed value. It is normally selected based on
the size of each file being updated. See the technical report for details.
dit(bf(-e, --rsh=COMMAND)) This option allows you to choose an alternative
remote shell program to use for communication between the local and
@@ -678,11 +745,11 @@ See the EXCLUDE PATTERNS section for detailed information on this option.
dit(bf(--include-from=FILE)) This specifies a list of include patterns
from a file.
If em(FILE) is bf(-) the list will be read from standard input.
If em(FILE) is "-" the list will be read from standard input.
dit(bf(--files-from=FILE)) Using this option allows you to specify the
exact list of files to transfer (as read from the specified FILE or "-"
for stdin). It also tweaks the default behavior of rsync to make
for standard input). It also tweaks the default behavior of rsync to make
transferring just the specified files and directories easier. For
instance, the --relative option is enabled by default when this option
is used (use --no-relative if you want to turn that off), all
@@ -739,20 +806,25 @@ although this skips files that haven't changed; see also --link-dest).
This option increases the usefulness of --partial because partially
transferred files will remain in the new temporary destination until they
have a chance to be completed. If DIR is a relative path, it is relative
to the destination directory (which changes in a recursive transfer).
to the destination directory.
dit(bf(--link-dest=DIR)) This option behaves like bf(--compare-dest) but
also will create hard links from em(DIR) to the destination directory for
unchanged files. Files with changed ownership or permissions will not be
linked.
Like bf(--compare-dest) if DIR is a relative path, it is relative
to the destination directory (which changes in a recursive transfer).
An example:
verb(
rsync -av --link-dest=$PWD/prior_dir host:src_dir/ new_dir/
)
Like bf(--compare-dest) if DIR is a relative path, it is relative to the
destination directory.
Note that rsync versions prior to 2.6.1 had a bug that could prevent
--link-dest from working properly for a non-root user when -o was specified
(or implied by -a). If the receiving rsync is not new enough, you can work
around this bug by avoiding the -o option.
dit(bf(-z, --compress)) With this option, rsync compresses any data from
the files that it sends to the destination machine. This
option is useful on slow connections. The compression method used is the
@@ -842,6 +914,46 @@ it is more desirable to keep partially transferred files. Using the
--partial option tells rsync to keep the partial file which should
make a subsequent transfer of the rest of the file much faster.
dit(bf(--partial-dir=DIR)) Turns on --partial mode, but tells rsync to
put a partially transferred file into DIR instead of writing out the
file to the destination dir. Rsync will also use a file found in this
dir as data to speed up the transfer (i.e. when you redo the send after
rsync creates a partial file) and delete such a file after it has served
its purpose. Note that if --whole-file is specified (or implied) that an
existing partial-dir file will not be used to speedup the transfer (since
rsync is sending files without using the incremental rsync algorithm).
Rsync will create the dir if it is missing (just the last dir -- not the
whole path). This makes it easy to use a relative path (such as
"--partial-dir=.rsync-partial") to have rsync create the partial-directory
in the destination file's directory (rsync will also try to remove the DIR
if a partial file was found to exist at the start of the transfer and the
DIR was specified as a relative path).
If the partial-dir value is not an absolute path, rsync will also add an
--exclude of this value at the end of all your existing excludes. This
will prevent partial-dir files from being transferred and also prevent the
untimely deletion of partial-dir items on the receiving side. An example:
the above --partial-dir option would add an "--exclude=.rsync-partial/"
rule at the end of any other include/exclude rules. Note that if you are
supplying your own include/exclude rules, you may need to manually insert a
rule for this directory exclusion somewhere higher up in the list so that
it has a high enough priority to be effective (e.g., if your rules specify
a trailing --exclude=* rule, the auto-added rule will be ineffective).
IMPORTANT: the --partial-dir should not be writable by other users or it
is a security risk. E.g. AVOID "/tmp".
You can also set the partial-dir value the RSYNC_PARTIAL_DIR environment
variable. Setting this in the environment does not force --partial to be
enabled, but rather it effects where partial files go when --partial (or
-P) is used. For instance, instead of specifying --partial-dir=.rsync-tmp
along with --progress, you could set RSYNC_PARTIAL_DIR=.rsync-tmp in your
environment and then just use the -P option to turn on the use of the
.rsync-tmp dir for partial transfers. The only time the --partial option
does not look for this environment value is when --inplace was also
specified (since --inplace conflicts with --partial-dir).
dit(bf(--progress)) This option tells rsync to print information
showing the progress of the transfer. This gives a bored user
something to watch.
@@ -870,9 +982,9 @@ the file, and the addition of a total-transfer summary in parentheses.
These additional numbers tell you how many files have been updated, and
what percent of the total number of files has been scanned.
dit(bf(-P)) The -P option is equivalent to --partial --progress. I
found myself typing that combination quite often so I created an
option to make it easier.
dit(bf(-P)) The -P option is equivalent to --partial --progress. Its
purpose is to make it much easier to specify these two options for a long
transfer that may be interrupted.
dit(bf(--password-file)) This option allows you to provide a password
in a file for accessing a remote rsync server. Note that this option
@@ -889,13 +1001,33 @@ transfer was too fast, it will wait before sending the next data block. The
result is an average transfer rate equaling the specified limit. A value
of zero specifies no limit.
dit(bf(--write-batch=PREFIX)) Generate a set of files that can be
transferred as a batch update. Each filename in the set starts with
PREFIX. See the "BATCH MODE" section for details.
dit(bf(--write-batch=FILE)) Record a file that can later be applied to
another identical destination with --read-batch. See the "BATCH MODE"
section for details.
dit(bf(--read-batch=PREFIX)) Apply a previously generated change batch,
using the fileset whose filenames start with PREFIX. See the "BATCH
MODE" section for details.
dit(bf(--read-batch=FILE)) Apply all of the changes stored in FILE, a
file previously generated by --write-batch.
If em(FILE) is "-" the batch data will be read from standard input.
See the "BATCH MODE" section for details.
dit(bf(-4, --ipv4) or bf(-6, --ipv6)) Tells rsync to prefer IPv4/IPv6
when creating sockets. This only affects sockets that rsync has direct
control over, such as the outgoing socket when directly contacting an
rsync daemon, or the incoming sockets that an rsync daemon uses to
listen for connections. One of these options may be required in older
versions of Linux to work around an IPv6 bug in the kernel (if you see
an "address already in use" error when nothing else is using the port,
try specifying --ipv6 or --ipv4 when starting the daemon).
dit(bf(--checksum-seed=NUM)) Set the MD4 checksum seed to the integer
NUM. This 4 byte checksum seed is included in each block and file
MD4 checksum calculation. By default the checksum seed is generated
by the server and defaults to the current time(). This option
is used to set a specific checksum seed, which is useful for
applications that want repeatable block and file checksums, or
in the case where the user wants a more random checksum seed.
Note that setting NUM to 0 causes rsync to use the default of time()
for checksum seed.
enddit()
@@ -1035,7 +1167,7 @@ This fails because the parent directory "some" is excluded by the '*' rule,
so rsync never visits any of the files in the "some" or "some/path"
directories. One solution is to ask for all directories in the hierarchy
to be included by using a single rule: --include='*/' (put it somewhere
before the --excludde='*' rule). Another solution is to add specific
before the --exclude='*' rule). Another solution is to add specific
include rules for all the parent dirs that need to be visited. For
instance, this set of rules works fine:
@@ -1067,7 +1199,8 @@ itemize(
manpagesection(BATCH MODE)
bf(Note:) Batch mode should be considered experimental in this version
of rsync. The interface or behaviour may change before it stabilizes.
of rsync. The interface and behavior have now stabilized, though, so
feel free to try this out.
Batch mode can be used to apply the same set of updates to many
identical systems. Suppose one has a tree which is replicated on a
@@ -1076,80 +1209,112 @@ source tree and those changes need to be propagated to the other
hosts. In order to do this using batch mode, rsync is run with the
write-batch option to apply the changes made to the source tree to one
of the destination trees. The write-batch option causes the rsync
client to store the information needed to repeat this operation against
other destination trees in a batch update fileset (see below). The
filename of each file in the fileset starts with a prefix specified by
the user as an argument to the write-batch option. This fileset is
then copied to each remote host, where rsync is run with the read-batch
option, again specifying the same prefix, and the destination tree.
Rsync updates the destination tree using the information stored in the
batch update fileset.
client to store in a "batch file" all the information needed to repeat
this operation against other, identical destination trees.
The fileset consists of 4 files:
To apply the recorded changes to another destination tree, run rsync
with the read-batch option, specifying the name of the same batch
file, and the destination tree. Rsync updates the destination tree
using the information stored in the batch file.
itemize(
it() bf(<prefix>.rsync_argvs) command-line arguments
it() bf(<prefix>.rsync_flist) rsync internal file metadata
it() bf(<prefix>.rsync_csums) rsync checksums
it() bf(<prefix>.rsync_delta) data blocks for file update & change
)
For convenience, one additional file is creating when the write-batch
option is used. This file's name is created by appending
".sh" to the batch filename. The .sh file contains
a command-line suitable for updating a destination tree using that
batch file. It can be executed using a Bourne(-like) shell, optionally
passing in an alternate destination tree pathname which is then used
instead of the original path. This is useful when the destination tree
path differs from the original destination tree path.
The .rsync_argvs file contains a command-line suitable for updating a
destination tree using that batch update fileset. It can be executed
using a Bourne(-like) shell, optionally passing in an alternate
destination tree pathname which is then used instead of the original
path. This is useful when the destination tree path differs from the
original destination tree path.
Generating the batch update fileset once saves having to perform the
file status, checksum and data block generation more than once when
Generating the batch file once saves having to perform the file
status, checksum, and data block generation more than once when
updating multiple destination trees. Multicast transport protocols can
be used to transfer the batch update files in parallel to many hosts at
once, instead of sending the same data to every host individually.
be used to transfer the batch update files in parallel to many hosts
at once, instead of sending the same data to every host individually.
Example:
Examples:
verb(
$ rsync --write-batch=pfx -a /source/dir/ /adest/dir/
$ rcp pfx.rsync_* remote:
$ ssh remote rsync --read-batch=pfx -a /bdest/dir/
# or alternatively
$ ssh remote ./pfx.rsync_argvs /bdest/dir/
$ rsync --write-batch=foo -a host:/source/dir/ /adest/dir/
$ scp foo* remote:
$ ssh remote ./foo.sh /bdest/dir/
)
In this example, rsync is used to update /adest/dir/ with /source/dir/
and the information to repeat this operation is stored in the files
pfx.rsync_*. These files are then copied to the machine named "remote".
Rsync is then invoked on "remote" to update /bdest/dir/ the same way as
/adest/dir/. The last line shows the rsync_argvs file being used to
invoke rsync.
verb(
$ rsync --write-batch=foo -a /source/dir/ /adest/dir/
$ ssh remote rsync --read-batch=- -a /bdest/dir/ <foo
)
In these examples, rsync is used to update /adest/dir/ from /source/dir/
and the information to repeat this operation is stored in "foo" and
"foo.sh". The host "remote" is then updated with the batched data going
into the directory /bdest/dir. The differences between the two examples
reveals some of the flexibility you have in how you deal with batches:
itemize(
it() The first example shows that the initial copy doesn't have to be
local -- you can push or pull data to/from a remote host using either the
remote-shell syntax or rsync daemon syntax, as desired.
it() The first example uses the created "foo.sh" file to get the right
rsync options when running the read-batch command on the remote host.
it() The second example reads the batch data via standard input so that
the batch file doesn't need to be copied to the remote machine first.
This example avoids the foo.sh script because it needed to use a modified
--read-batch option, but you could edit the script file if you wished to
make use of it (just be sure that no other option is trying to use
standard input, such as the "--exclude-from=-" option).
)
Caveats:
The read-batch option expects the destination tree it is meant to update
The read-batch option expects the destination tree that it is updating
to be identical to the destination tree that was used to create the
batch update fileset. When a difference between the destination trees
is encountered the update will fail at that point, leaving the
destination tree in a partially updated state. In that case, rsync can
is encountered the update might be discarded with no error (if the file
appears to be up-to-date already) or the file-update may be attempted
and then, if the file fails to verify, the update discarded with an
error. This means that it should be safe to re-run a read-batch operation
if the command got interrupted. If you wish to force the batched-update to
always be attempted regardless of the file's size and date, use the -I
option (when reading the batch).
If an error occurs, the destination tree will probably be in a
partially updated state. In that case, rsync can
be used in its regular (non-batch) mode of operation to fix up the
destination tree.
The rsync version used on all destinations should be identical to the
one used on the original destination.
The rsync version used on all destinations must be at least as new as the
one used to generate the batch file. Rsync will die with an error if the
protocol version in the batch file is too new for the batch-reading rsync
to handle.
The -z/--compress option does not work in batch mode and yields a usage
error. A separate compression tool can be used instead to reduce the
size of the batch update files for transport to the destination.
The -n/--dryrun option does not work in batch mode and yields a runtime
The --dry-run (-n) option does not work in batch mode and yields a runtime
error.
See bf(http://www.ils.unc.edu/i2dsi/unc_rsync+.html) for papers and technical
reports.
When reading a batch file, rsync will force the value of certain options
to match the data in the batch file if you didn't set them to the same
as the batch-writing command. Other options can (and should) be changed.
For instance
--write-batch changes to --read-batch, --files-from is dropped, and the
--include/--exclude options are not needed unless --delete is specified
without --delete-excluded.
The code that creates the BATCH.sh file transforms any include/exclude
options into a single list that is appended as a "here" document to the
shell script file. An advanced user can use this to modify the exclude
list if a change in what gets deleted by --delete is desired. A normal
user can ignore this detail and just use the shell script as an easy way
to run the appropriate --read-batch command for the batched data.
The original batch mode in rsync was based on "rsync+", but the latest
version uses a new implementation.
manpagesection(SYMBOLIC LINKS)
Three basic behaviours are possible when rsync encounters a symbolic
Three basic behaviors are possible when rsync encounters a symbolic
link in the source directory.
By default, symbolic links are not transferred at all. A message
@@ -1210,7 +1375,7 @@ dit(bf(2)) Protocol incompatibility
dit(bf(3)) Errors selecting input/output files, dirs
dit(bf(4)) Requested action not supported: an attempt
was made to manipulate 64-bit files on a platform that cannot support
them; or an option was specifed that is supported by the client and
them; or an option was specified that is supported by the client and
not by the server.
dit(bf(5)) Error starting client-server protocol
dit(bf(10)) Error in socket I/O
@@ -1270,7 +1435,7 @@ manpagebugs()
times are transferred as unix time_t values
When transferring to FAT filesystems rsync may resync
When transferring to FAT filesystems rsync may re-sync
unmodified files.
See the comments on the --modify-window option.
@@ -1307,7 +1472,7 @@ and David Bell for helpful suggestions, patches and testing of rsync.
I've probably missed some people, my apologies if I have.
Especial thanks also to: David Dykstra, Jos Backus, Sebastian Krahmer,
Martin Pool, Wayne Davison.
Martin Pool, Wayne Davison, J.W. Schultz.
manpageauthor()

View File

@@ -1,5 +1,5 @@
mailto(rsync-bugs@samba.org)
manpage(rsyncd.conf)(5)(26 Apr 2004)()()
manpage(rsyncd.conf)(5)(30 Sep 2004)()()
manpagename(rsyncd.conf)(configuration file for rsync server)
manpagesynopsis()
@@ -134,8 +134,8 @@ dit(bf(use chroot)) If "use chroot" is true, the rsync server will chroot
to the "path" before starting the file transfer with the client. This has
the advantage of extra protection against possible implementation security
holes, but it has the disadvantages of requiring super-user privileges,
of not being able to follow symbolic links outside of the new root path
when reading, and of complicating the preservation of usernames and groups
of not being able to follow symbolic links that are either absolute or outside
of the new root path, and of complicating the preservation of usernames and groups
(see below). When "use chroot" is false, for security reasons,
symlinks may only be relative paths pointing to other files within the root
path, and leading slashes are removed from most absolute paths (options
@@ -154,12 +154,11 @@ specified.
Note that you are free to setup user/group information in the chroot area
differently from your normal system. For example, you could abbreviate
the list of users and groups. Also, you can protect this information
from being downloaded by adding an exclude rule to the rsync.conf file
(e.g. "exclude = /etc/"). To protect it from being changed by an upload
(if the module is not read only), be sure to set the permissions (or
owner) on the files and/or parent directories so that they cannot be
written by the daemon.
the list of users and groups. Also, you can protect this information from
being downloaded/uploaded by adding an exclude rule to the rsync.conf file
(e.g. "exclude = /etc/"). Note that having the exclusion affect uploads
is a relatively new feature in rsync, so make sure your server is running
at least 2.6.3 to effect this.
dit(bf(max connections)) The "max connections" option allows you to
specify the maximum number of simultaneous connections you will allow.
@@ -179,6 +178,12 @@ attempted uploads will fail. If "read only" is false then uploads will
be possible if file permissions on the server allow them. The default
is for all modules to be read only.
dit(bf(write only)) The "write only" option determines whether clients
will be able to download files or not. If "write only" is true then any
attempted downloads will fail. If "write only" is false then downloads
will be possible if file permissions on the server allow them. The
default is for this option to be disabled.
dit(bf(list)) The "list" option determines if this module should be
listed when the client asks for a listing of available modules. By
setting this to false you can create hidden modules. The default is
@@ -195,24 +200,18 @@ file transfers to and from that module should take place as when the daemon
was run as root. This complements the "uid" option. The default is gid -2,
which is normally the group "nobody".
dit(bf(exclude)) The "exclude" option allows you to specify a space
separated list of patterns to add to the exclude list.
This is only superficially equivalent
to the client specifying these patterns with the --exclude option.
Only one "exclude" option may be specified, but
you can use "-" and "+" before patterns to specify exclude/include.
dit(bf(exclude)) The "exclude" option allows you to specify a
space-separated list of patterns that the server will not allow to be read
or written. This is only superficially equivalent to the client
specifying these patterns with the --exclude option. Only one "exclude"
option may be specified, but you can use "-" and "+" before patterns to
specify exclude/include.
Because this exclude list is not passed to the client it only applies on
the server: that is, it excludes files received by a client when receiving
from a server and files deleted on a server when sending to a server, but
it doesn't exclude files sent from a client when sending to a server or
files deleted on a client when receiving from a server.
Note that this option is not designed with strong security in
mind, it is quite possible that a client may find a way to bypass this
exclude list. If you want to absolutely ensure that certain files
cannot be accessed then use the uid/gid options in combination with
file permissions.
it doesn't exclude files from being deleted on a client when receiving
from a server.
dit(bf(exclude from)) The "exclude from" option specifies a filename
on the server that contains exclude patterns, one per line.
@@ -220,14 +219,14 @@ This is only superficially equivalent
to the client specifying the --exclude-from option with an equivalent file.
See the "exclude" option above.
dit(bf(include)) The "include" option allows you to specify a space
separated list of patterns which rsync should not exclude. This is
only superficially equivalent to the client specifying these patterns
with the --include option because it applies only on the server.
This is useful as it
allows you to build up quite complex exclude/include rules. Only one
"include" option may be specified, but you can use "+" and "-" before
patterns to switch include/exclude. See the "exclude" option above.
dit(bf(include)) The "include" option allows you to specify a
space-separated list of patterns which rsync should not exclude. This is
only superficially equivalent to the client specifying these patterns with
the --include option because it applies only on the server. This is
useful as it allows you to build up quite complex exclude/include rules.
Only one "include" option may be specified, but you can use "+" and "-"
before patterns to switch include/exclude. See the "exclude" option
above.
dit(bf(include from)) The "include from" option specifies a filename
on the server that contains include patterns, one per line. This is
@@ -236,7 +235,7 @@ only superficially equivalent to the client specifying the
See the "exclude" option above.
dit(bf(auth users)) The "auth users" option specifies a comma and
space separated list of usernames that will be allowed to connect to
space-separated list of usernames that will be allowed to connect to
this module. The usernames do not need to exist on the local
system. The usernames may also contain shell wildcard characters. If
"auth users" is set then the client will be challenged to supply a
@@ -380,9 +379,15 @@ default. A good choice for anonymous rsync servers may be 600 (giving
a 10 minute timeout).
dit(bf(refuse options)) The "refuse options" option allows you to
specify a space separated list of rsync command line options that will
be refused by your rsync server. The full names of the options must be
used (i.e., you must use "checksum" not "c" to disable checksumming).
specify a space-separated list of rsync command line options that will
be refused by your rsync server.
You may specify the full option name, its one-letter abbreviation, or a
wild-card string that matches multiple options.
For example, this would refuse --checksum (-c) and all the options that
start with "delete":
quote(refuse options = c delete*)
When an option is refused, the server prints an error message and exits.
To prevent all compression, you can use "dont compress = *" (see below)
instead of "refuse options = compress" to avoid returning an error to a
@@ -394,7 +399,7 @@ during transfer. Compression is expensive in terms of CPU usage so it
is usually good to not try to compress files that won't compress well,
such as already compressed files.
The "dont compress" option takes a space separated list of
The "dont compress" option takes a space-separated list of
case-insensitive wildcard patterns. Any source filename matching one
of the patterns will not be compressed during transfer.

224
sender.c
View File

@@ -27,6 +27,8 @@ extern int dry_run;
extern int am_server;
extern int am_daemon;
extern int protocol_version;
extern int make_backups;
extern struct stats stats;
/**
@@ -62,8 +64,8 @@ static struct sum_struct *receive_sums(int f)
int i;
OFF_T offset = 0;
s = new(struct sum_struct);
if (!s) out_of_memory("receive_sums");
if (!(s = new(struct sum_struct)))
out_of_memory("receive_sums");
read_sum_head(f, s);
@@ -77,26 +79,28 @@ static struct sum_struct *receive_sums(int f)
if (s->count == 0)
return(s);
s->sums = new_array(struct sum_buf, s->count);
if (!s->sums) out_of_memory("receive_sums");
if (!(s->sums = new_array(struct sum_buf, s->count)))
out_of_memory("receive_sums");
for (i = 0; i < (int) s->count; i++) {
for (i = 0; i < (int)s->count; i++) {
s->sums[i].sum1 = read_int(f);
read_buf(f, s->sums[i].sum2, s->s2length);
s->sums[i].offset = offset;
s->sums[i].i = i;
s->sums[i].flags = 0;
if (i == (int) s->count-1 && s->remainder != 0) {
if (i == (int)s->count-1 && s->remainder != 0)
s->sums[i].len = s->remainder;
} else {
else
s->sums[i].len = s->blength;
}
offset += s->sums[i].len;
if (verbose > 3)
rprintf(FINFO, "chunk[%d] len=%d offset=%.0f sum1=%08x\n",
i, s->sums[i].len, (double)s->sums[i].offset, s->sums[i].sum1);
if (verbose > 3) {
rprintf(FINFO,
"chunk[%d] len=%d offset=%.0f sum1=%08x\n",
i, s->sums[i].len, (double)s->sums[i].offset,
s->sums[i].sum1);
}
}
s->flength = offset;
@@ -110,21 +114,15 @@ void send_files(struct file_list *flist, int f_out, int f_in)
{
int fd = -1;
struct sum_struct *s;
struct map_struct *buf = NULL;
struct map_struct *mbuf = NULL;
STRUCT_STAT st;
char fname[MAXPATHLEN];
char *fname2, fname[MAXPATHLEN];
int i;
struct file_struct *file;
int phase = 0;
extern struct stats stats;
struct stats initial_stats;
extern int write_batch;
extern int read_batch;
int checksums_match;
int buff_len;
char buff[CHUNK_SIZE];
int save_make_backups = make_backups;
int j;
int done;
if (verbose > 2)
rprintf(FINFO, "send_files starting\n");
@@ -140,6 +138,9 @@ void send_files(struct file_list *flist, int f_out, int f_in)
write_int(f_out, -1);
if (verbose > 2)
rprintf(FINFO, "send_files phase=%d\n", phase);
/* For inplace: redo phase turns off the backup
* flag so that we do a regular inplace send. */
make_backups = 0;
continue;
}
break;
@@ -164,145 +165,100 @@ void send_files(struct file_list *flist, int f_out, int f_in)
fname[offset++] = '/';
} else
offset = 0;
f_name_to(file, fname + offset);
fname2 = f_name_to(file, fname + offset);
if (verbose > 2)
rprintf(FINFO, "send_files(%d, %s)\n", i, fname);
if (dry_run) {
if (!am_server && verbose) { /* log transfer */
rprintf(FINFO, "%s\n", fname+offset);
}
if (!am_server && verbose) /* log the transfer */
rprintf(FINFO, "%s\n", safe_fname(fname2));
write_int(f_out, i);
continue;
}
initial_stats = stats;
s = receive_sums(f_in);
if (!s) {
if (!(s = receive_sums(f_in))) {
io_error |= IOERR_GENERAL;
rprintf(FERROR, "receive_sums failed\n");
return;
}
if (write_batch)
write_batch_csum_info(&i, s);
if (!read_batch) {
fd = do_open(fname, O_RDONLY, 0);
if (fd == -1) {
if (errno == ENOENT) {
enum logcode c = am_daemon
&& protocol_version < 28 ? FERROR
: FINFO;
io_error |= IOERR_VANISHED;
rprintf(c, "file has vanished: %s\n",
full_fname(fname));
} else {
io_error |= IOERR_GENERAL;
rprintf(FERROR, "send_files failed to open %s: %s\n",
full_fname(fname), strerror(errno));
}
free_sums(s);
continue;
}
/* map the local file */
if (do_fstat(fd, &st) != 0) {
io_error |= IOERR_GENERAL;
rprintf(FERROR, "fstat failed: %s\n", strerror(errno));
free_sums(s);
close(fd);
return;
}
if (st.st_size > 0) {
buf = map_file(fd, st.st_size);
fd = do_open(fname, O_RDONLY, 0);
if (fd == -1) {
if (errno == ENOENT) {
enum logcode c = am_daemon
&& protocol_version < 28 ? FERROR
: FINFO;
io_error |= IOERR_VANISHED;
rprintf(c, "file has vanished: %s\n",
full_fname(fname));
} else {
buf = NULL;
io_error |= IOERR_GENERAL;
rsyserr(FERROR, errno,
"send_files failed to open %s",
full_fname(fname));
}
if (verbose > 2)
rprintf(FINFO, "send_files mapped %s of size %.0f\n",
fname, (double)st.st_size);
write_int(f_out, i);
if (write_batch)
write_batch_delta_file((char *)&i, sizeof i);
write_sum_head(f_out, s);
free_sums(s);
continue;
}
if (verbose > 2 && !read_batch)
rprintf(FINFO, "calling match_sums %s\n", fname);
if (!am_server && verbose) { /* log transfer */
rprintf(FINFO, "%s\n", fname+offset);
/* map the local file */
if (do_fstat(fd, &st) != 0) {
io_error |= IOERR_GENERAL;
rsyserr(FERROR, errno, "fstat failed");
free_sums(s);
close(fd);
return;
}
if (st.st_size) {
OFF_T map_size = MAX(s->blength * 3, MAX_MAP_SIZE);
mbuf = map_file(fd, st.st_size, map_size, s->blength);
} else
mbuf = NULL;
if (verbose > 2) {
rprintf(FINFO, "send_files mapped %s of size %.0f\n",
safe_fname(fname), (double)st.st_size);
}
write_int(f_out, i);
write_sum_head(f_out, s);
if (verbose > 2) {
rprintf(FINFO, "calling match_sums %s\n",
safe_fname(fname));
}
if (!am_server && verbose) /* log the transfer */
rprintf(FINFO, "%s\n", safe_fname(fname2));
set_compression(fname);
if (read_batch) {
/* read checksums originally computed on sender side */
read_batch_csum_info(i, s, &checksums_match);
if (checksums_match) {
read_batch_delta_file((char*)&j, sizeof (int));
if (j != i) { /* if flist index entries don't match*/
rprintf(FINFO, "index mismatch in send_files\n");
rprintf(FINFO, "read index = %d flist ndx = %d\n", j, i);
close_batch_delta_file();
close_batch_csums_file();
exit_cleanup(1);
} else {
write_int(f_out, j);
write_sum_head(f_out, s);
done = 0;
while (!done) {
read_batch_delta_file((char*)&buff_len, sizeof (int));
write_int(f_out, buff_len);
if (buff_len == 0) {
done = 1;
} else {
if (buff_len > 0) {
read_batch_delta_file(buff, buff_len);
write_buf(f_out, buff, buff_len);
}
}
} /* end while */
read_batch_delta_file( buff, MD4_SUM_LENGTH);
write_buf(f_out, buff, MD4_SUM_LENGTH);
match_sums(f_out, s, mbuf, st.st_size);
log_send(file, &initial_stats);
} /* j=i */
} else { /* not checksum match */
rprintf (FINFO, "readbatch & checksums don't match\n");
rprintf (FINFO, "filename=%s is being skipped\n", fname);
continue;
if (mbuf) {
j = unmap_file(mbuf);
if (j) {
io_error |= IOERR_GENERAL;
rsyserr(FERROR, j,
"read errors mapping %s",
full_fname(fname));
}
} else {
match_sums(f_out, s, buf, st.st_size);
log_send(file, &initial_stats);
}
if (!read_batch) {
if (buf) {
j = unmap_file(buf);
if (j) {
io_error |= IOERR_GENERAL;
rprintf(FERROR,
"read errors mapping %s: (%d) %s\n",
full_fname(fname), j, strerror(j));
}
}
close(fd);
}
close(fd);
free_sums(s);
if (verbose > 2)
rprintf(FINFO, "sender finished %s\n", fname);
if (verbose > 2) {
rprintf(FINFO, "sender finished %s\n",
safe_fname(fname));
}
}
make_backups = save_make_backups;
if (verbose > 2)
rprintf(FINFO, "send files finished\n");
@@ -310,14 +266,4 @@ void send_files(struct file_list *flist, int f_out, int f_in)
match_report();
write_int(f_out, -1);
if (write_batch || read_batch) {
close_batch_csums_file();
close_batch_delta_file();
}
}

113
socket.c
View File

@@ -33,6 +33,8 @@
#include "rsync.h"
extern char *bind_address;
extern int default_af_hint;
/**
* Establish a proxy connection on an open socket to a web proxy by
@@ -69,15 +71,13 @@ static int establish_proxy_connection(int fd, char *host, int port,
host, port, authhdr, authbuf);
len = strlen(buffer);
if (write(fd, buffer, len) != len) {
rprintf(FERROR, "failed to write to proxy: %s\n",
strerror(errno));
rsyserr(FERROR, errno, "failed to write to proxy");
return -1;
}
for (cp = buffer; cp < &buffer[sizeof buffer - 1]; cp++) {
if (read(fd, cp, 1) != 1) {
rprintf(FERROR, "failed to read from proxy: %s\n",
strerror(errno));
rsyserr(FERROR, errno, "failed to read from proxy");
return -1;
}
if (*cp == '\n')
@@ -106,8 +106,8 @@ static int establish_proxy_connection(int fd, char *host, int port,
while (1) {
for (cp = buffer; cp < &buffer[sizeof buffer - 1]; cp++) {
if (read(fd, cp, 1) != 1) {
rprintf(FERROR, "failed to read from proxy: %s\n",
strerror(errno));
rsyserr(FERROR, errno,
"failed to read from proxy");
return -1;
}
if (*cp == '\n')
@@ -276,8 +276,7 @@ int open_socket_out(char *host, int port, const char *bind_address,
}
freeaddrinfo(res0);
if (s < 0) {
rprintf(FERROR, RSYNC_NAME ": failed to connect to %s: %s\n",
h, strerror(errno));
rsyserr(FERROR, errno, "failed to connect to %s", h);
return -1;
}
return s;
@@ -314,19 +313,14 @@ int open_socket_out_wrapped(char *host, int port, const char *bind_address,
/**
* Open a socket of the specified type, port and address for incoming data
* Open one or more sockets for incoming data using the specified type,
* port, and address.
*
* Try to be better about handling the results of getaddrinfo(): when
* opening an inbound socket, we might get several address results,
* e.g. for the machine's ipv4 and ipv6 name.
* The getaddrinfo() call may return several address results, e.g. for
* the machine's IPv4 and IPv6 name.
*
* If binding a wildcard, then any one of them should do. If an address
* was specified but it's insufficiently specific then that's not our
* fault.
*
* However, some of the advertized addresses may not work because e.g. we
* don't have IPv6 support in the kernel. In that case go on and try all
* addresses until one succeeds.
* We return an array of file-descriptors to the sockets, with a trailing
* -1 value to indicate the end of the list.
*
* @param bind_address Local address to bind, or NULL to allow it to
* default.
@@ -334,8 +328,8 @@ int open_socket_out_wrapped(char *host, int port, const char *bind_address,
static int *open_socket_in(int type, int port, const char *bind_address,
int af_hint)
{
int one=1;
int s, *sp, *socks, maxs;
int one = 1;
int s, *socks, maxs, i;
struct addrinfo hints, *all_ai, *resp;
char portbuf[10];
int error;
@@ -354,18 +348,14 @@ static int *open_socket_in(int type, int port, const char *bind_address,
/* Count max number of sockets we might open. */
for (maxs = 0, resp = all_ai; resp; resp = resp->ai_next, maxs++) {}
socks = new_array(int, maxs + 1);
if (!socks) {
rprintf(FERROR,
RSYNC_NAME "couldn't allocate memory for sockets");
return NULL;
}
if (!(socks = new_array(int, maxs + 1)))
out_of_memory("open_socket_in");
/* We may not be able to create the socket, if for example the
* machine knows about IPv6 in the C library, but not in the
* kernel. */
sp = socks + 1; /* Leave room for count at start of array. */
for (resp = all_ai; resp; resp = resp->ai_next) {
for (resp = all_ai, i = 0; resp; resp = resp->ai_next) {
s = socket(resp->ai_family, resp->ai_socktype,
resp->ai_protocol);
@@ -379,8 +369,12 @@ static int *open_socket_in(int type, int port, const char *bind_address,
#ifdef IPV6_V6ONLY
if (resp->ai_family == AF_INET6) {
setsockopt(s, IPPROTO_IPV6, IPV6_V6ONLY,
(char *)&one, sizeof one);
if (setsockopt(s, IPPROTO_IPV6, IPV6_V6ONLY,
(char *)&one, sizeof one) < 0
&& default_af_hint != AF_INET6) {
close(s);
continue;
}
}
#endif
@@ -391,17 +385,17 @@ static int *open_socket_in(int type, int port, const char *bind_address,
continue;
}
*sp++ = s;
socks[i++] = s;
}
*socks = sp - socks - 1; /* Save count. */
socks[i] = -1;
if (all_ai)
freeaddrinfo(all_ai);
if (*socks == 0) {
if (!i) {
rprintf(FERROR,
RSYNC_NAME ": open inbound socket on port %d failed: "
"%s\n", port, strerror(errno));
"unable to bind any inbound sockets on port %d\n",
port);
free(socks);
return NULL;
}
@@ -446,9 +440,7 @@ static RETSIGTYPE sigchld_handler(UNUSED(int val))
void start_accept_loop(int port, int (*fn)(int, int))
{
fd_set deffds;
int *sp, maxfd, i, j;
extern char *bind_address;
extern int default_af_hint;
int *sp, maxfd, i;
/* open an incoming socket */
sp = open_socket_in(SOCK_STREAM, port, bind_address, default_af_hint);
@@ -457,12 +449,15 @@ void start_accept_loop(int port, int (*fn)(int, int))
/* ready to listen */
FD_ZERO(&deffds);
maxfd = -1;
for (i = 1; i <= *sp; i++) {
if (listen(sp[i], 5) == -1) {
for (j = 1; j <= i; j++)
close(sp[j]);
free(sp);
for (i = 0, maxfd = -1; sp[i] >= 0; i++) {
if (listen(sp[i], 5) < 0) {
rsyserr(FERROR, errno, "listen() on socket failed");
#ifdef INET6
if (errno == EADDRINUSE && i > 0) {
rprintf(FINFO,
"Try using --ipv4 or --ipv6 to avoid this listen() error.");
}
#endif
exit_cleanup(RERR_SOCKETIO);
}
FD_SET(sp[i], &deffds);
@@ -494,8 +489,7 @@ void start_accept_loop(int port, int (*fn)(int, int))
if (select(maxfd + 1, &fds, NULL, NULL, NULL) != 1)
continue;
fd = -1;
for (i = 1; i <= *sp; i++) {
for (i = 0, fd = -1; sp[i] >= 0; i++) {
if (FD_ISSET(sp[i], &fds)) {
fd = accept(sp[i], (struct sockaddr *)&addr,
&addrlen);
@@ -510,7 +504,8 @@ void start_accept_loop(int port, int (*fn)(int, int))
if ((pid = fork()) == 0) {
int ret;
close(sp[i]);
for (i = 0; sp[i] >= 0; i++)
close(sp[i]);
/* open log file in child before possibly giving
* up privileges */
log_open();
@@ -518,10 +513,8 @@ void start_accept_loop(int port, int (*fn)(int, int))
close_all();
_exit(ret);
} else if (pid < 0) {
rprintf(FERROR,
RSYNC_NAME
": could not create child server process: %s\n",
strerror(errno));
rsyserr(FERROR, errno,
"could not create child server process");
close(fd);
/* This might have happened because we're
* overloaded. Sleep briefly before trying to
@@ -638,9 +631,10 @@ void set_socket_options(int fd, char *options)
break;
}
if (ret != 0)
rprintf(FERROR, "failed to set socket option %s: %s\n", tok,
strerror(errno));
if (ret != 0) {
rsyserr(FERROR, errno,
"failed to set socket option %s", tok);
}
}
free(options);
@@ -733,14 +727,16 @@ static int socketpair_tcp(int fd[2])
goto failed;
close(listener);
listener = -1;
set_blocking(fd[1]);
if (connect_done == 0) {
if (connect(fd[1], (struct sockaddr *)&sock, sizeof sock) != 0
&& errno != EISCONN)
goto failed;
}
set_blocking(fd[1]);
/* all OK! */
return 0;
@@ -770,8 +766,7 @@ int sock_exec(const char *prog)
int fd[2];
if (socketpair_tcp(fd) != 0) {
rprintf(FERROR, RSYNC_NAME ": socketpair_tcp failed (%s)\n",
strerror(errno));
rsyserr(FERROR, errno, "socketpair_tcp failed");
return -1;
}
if (verbose >= 2)

View File

@@ -152,7 +152,7 @@ int do_mkstemp(char *template, mode_t perms)
RETURN_ERROR_IF(dry_run, 0);
RETURN_ERROR_IF(read_only, EROFS);
#if defined(HAVE_SECURE_MKSTEMP) && defined(HAVE_FCHMOD)
#if HAVE_SECURE_MKSTEMP && HAVE_FCHMOD && (!HAVE_OPEN64 || HAVE_MKSTEMP64)
{
int fd = mkstemp(template);
if (fd == -1)

View File

@@ -28,6 +28,7 @@
int modify_window = 0;
int module_id = -1;
char *partial_dir;
struct exclude_list_struct server_exclude_list;
void rprintf(UNUSED(enum logcode code), const char *format, ...)
@@ -38,6 +39,16 @@ struct exclude_list_struct server_exclude_list;
va_end(ap);
}
void rsyserr(UNUSED(enum logcode code), int errcode, const char *format, ...)
{
va_list ap;
fputs(RSYNC_NAME ": ", stderr);
va_start(ap, format);
vfprintf(stderr, format, ap);
va_end(ap);
fprintf(stderr, ": %s (%d)\n", strerror(errcode), errcode);
}
void _exit_cleanup(int code, const char *file, int line)
{
fprintf(stderr, "exit(%d): %s(%d)\n",

173
test.sh
View File

@@ -1,173 +0,0 @@
#!/bin/sh
# Copyright (C) 1998,1999 Philip Hands <phil@hands.com>
#
# This program is distributable under the terms of the GNU GPL (see COPYING)
#
# This is a simple test script that tests a few rsync
# features to make sure I haven't broken them before a release.
#
#
# check if we are running under debian-test, and change behaviour to suit
if test -n "${DEBIANTEST_LIB}" ; then
# make sure rsync is installed
test -e /usr/bin/rsync || exit 0
. ${DEBIANTEST_LIB}/functions.sh
Debian=1
else
cat <<EOF
This set of tests is not completely portable. It is intended for developers
not for end users. You may experience failures on some platforms that
do not indicate a problem with rsync.
EOF
RSYNC=`pwd`/rsync
runtest() {
echo -n "Test $1: "
eval "$2"
}
printmsg() {
echo ""
echo "**** ${1}^G ****"
echo ""
}
fi
TMP=/tmp/rsync-test.$$
FROM=${TMP}/from
TO=${TMP}/to
F1=text1
LOG=${TMP}/log
mkdir $TMP
mkdir $FROM
mkdir $TO
# set up test data
touch ${FROM}/empty
mkdir ${FROM}/emptydir
ps ax > ${FROM}/pslist
echo -n "This file has no trailing lf" > ${FROM}/nolf
ln -s nolf ${FROM}/nolf-symlink
# Gather some random text. We need files that will exist and be
# publicly readable on all platforms: hopefully this will work.
cat /etc/*tab /etc/services /etc/*.conf /etc/*rc > ${FROM}/${F1}
mkdir ${FROM}/dir
cp ${FROM}/${F1} ${FROM}/dir/
mkdir ${FROM}/dir/subdir
mkdir ${FROM}/dir/subdir/subsubdir
ls -ltr /etc > ${FROM}/dir/subdir/subsubdir/etc-ltr-list
mkdir ${FROM}/dir/subdir/subsubdir2
ls -lt /bin > ${FROM}/dir/subdir/subsubdir2/bin-lt-list
checkit() {
testnum=`expr 0${testnum} + 1`
log=${LOG}.${testnum}
failed=
echo "Running: \"$1\"" >${log}
echo "">>${log}
eval "$1" >>${log} 2>&1
status=$?
if [ $status != 0 ]; then
failed="YES";
fi
echo "-------------">>${log}
echo "check how the files compare with diff:">>${log}
echo "">>${log}
diff -ur $2 $3 >>${log} 2>&1 || failed=YES
echo "-------------">>${log}
echo "check how the directory listings compare with diff:">>${log}
echo "">>${log}
( cd $2 ; ls -laR ) > ${TMP}/ls-from 2>>${log}
( cd $3 ; ls -laR ) > ${TMP}/ls-to 2>>${log}
diff -u ${TMP}/ls-from ${TMP}/ls-to >>${log} 2>&1 || failed=YES
if [ -z "${failed}" ] ; then
test -z "${Debian}" && echo " done."
rm $log
return 0
else
if test -n "${Debian}" ; then
cat ${log}
rm ${log}
else
echo " FAILED (test # ${testnum} status=$status)."
fi
return 1
fi
}
checkforlogs() {
# skip it if we're under debian-test
if test -n "${Debian}" ; then return 0 ; fi
if [ -f $1 ] ; then
cat <<EOF
Failures have occured.
You can find the output of the tests in these files:
$@
Please hit <RETURN>
EOF
read input
else
rm -rf ${TMP}
echo ""
echo "Tests Completed Successfully :-)"
fi
}
# Main script starts here
runtest "basic operation" 'checkit "$RSYNC -av ${FROM}/ ${TO}" ${FROM}/ ${TO}'
ln ${FROM}/pslist ${FROM}/dir
runtest "hard links" 'checkit "$RSYNC -avH ${FROM}/ ${TO}" ${FROM}/ ${TO}'
rm ${TO}/${F1}
runtest "one file" 'checkit "$RSYNC -avH ${FROM}/ ${TO}" ${FROM}/ ${TO}'
echo "extra line" >> ${TO}/${F1}
runtest "extra data" 'checkit "$RSYNC -avH ${FROM}/ ${TO}" ${FROM}/ ${TO}'
cp ${FROM}/${F1} ${TO}/ThisShouldGo
runtest " --delete" 'checkit "$RSYNC --delete -avH ${FROM}/ ${TO}" ${FROM}/ ${TO}'
LONGDIR=${FROM}/This-is-a-directory-with-a-stupidly-long-name-created-in-an-attempt-to-provoke-an-error-found-in-2.0.11-that-should-hopefully-never-appear-again-if-this-test-does-its-job/This-is-a-directory-with-a-stupidly-long-name-created-in-an-attempt-to-provoke-an-error-found-in-2.0.11-that-should-hopefully-never-appear-again-if-this-test-does-its-job/This-is-a-directory-with-a-stupidly-long-name-created-in-an-attempt-to-provoke-an-error-found-in-2.0.11-that-should-hopefully-never-appear-again-if-this-test-does-its-job
mkdir -p ${LONGDIR}
date > ${LONGDIR}/1
ls -la / > ${LONGDIR}/2
runtest "long paths" 'checkit "$RSYNC --delete -avH ${FROM}/ ${TO}" ${FROM}/ ${TO}'
if type ssh >/dev/null 2>&1; then
if [ "`ssh -o'BatchMode yes' localhost echo yes 2>/dev/null`" = "yes" ]; then
rm -rf ${TO}
runtest "ssh: basic test" 'checkit "$RSYNC -avH -e ssh --rsync-path=$RSYNC ${FROM}/ localhost:${TO}" ${FROM}/ ${TO}'
mv ${TO}/${F1} ${TO}/ThisShouldGo
runtest "ssh: renamed file" 'checkit "$RSYNC --delete -avH -e ssh --rsync-path=$RSYNC ${FROM}/ localhost:${TO}" ${FROM}/ ${TO}'
else
printmsg "Skipping SSH tests because ssh conection to localhost not authorised"
fi
else
printmsg "Skipping SSH tests because ssh is not in the path"
fi
rm -rf ${TO}
mkdir -p ${FROM}2/dir/subdir
cp -a ${FROM}/dir/subdir/subsubdir ${FROM}2/dir/subdir
cp ${FROM}/dir/* ${FROM}2/dir 2>/dev/null
runtest "excludes" 'checkit "$RSYNC -vv -Hlrt --delete --include /dir/ --include /dir/\* --include /dir/\*/subsubdir --include /dir/\*/subsubdir/\*\* --exclude \*\* ${FROM}/dir ${TO}" ${FROM}2/ ${TO}'
rm -r ${FROM}2
checkforlogs ${LOG}.?

View File

@@ -17,8 +17,8 @@ with the GNU Standards, installcheck does not look for rsync on the
path.
If the tests pass, you should see a report to that effect. Some tests
require being root or some other precondition, and so will normally be
checked -- look at the test scripts for more information.
require being root or some other precondition, and so will normally not
be checked -- look at the test scripts for more information.
If the tests fail, you will see rather more output. The scratch
directory will remain in the build directory. It would be useful if

61
testsuite/backup.test Normal file
View File

@@ -0,0 +1,61 @@
#! /bin/sh
# Copyright (C) 2004 by Wayne Davison <wayned@samba.org>
# This program is distributable under the terms of the GNU GPL (see
# COPYING).
# Test that the --backup option works right.
. "$suitedir/rsync.fns"
bakdir="$tmpdir/bak"
mkdir "$fromdir" "$bakdir"
name1="$fromdir/name1"
name2="$fromdir/name2"
outfile="$scratchdir/rsync.out"
cat $srcdir/[gr]*.[ch] > "$name1"
cat $srcdir/[et]*.[ch] > "$name2"
checkit "$RSYNC -avv \"$fromdir/\" \"$todir/\"" "$fromdir" "$todir"
checkit "$RSYNC -avv \"$fromdir/\" \"$chkdir/\"" "$fromdir" "$chkdir"
cat $srcdir/[fgpr]*.[ch] > "$name1"
cat $srcdir/[etw]*.[ch] > "$name2"
$RSYNC -avv --no-whole-file --backup "$fromdir/" "$todir/" \
| tee "$outfile"
for fn in name1 name2; do
grep "backed up $fn to $fn~" "$outfile" >/dev/null || test_fail "no backup message output for $fn"
diff $diffopt "$fromdir/$fn" "$todir" || test_fail "copy of $fn failed"
diff $diffopt "$chkdir/$fn" "$todir/$fn~" || test_fail "backup of $fn to $fn~ failed"
mv "$todir/$fn~" "$todir/$fn"
done
checkit "$RSYNC -avv --no-whole-file --backup --backup-dir=\"$bakdir\" \"$fromdir/\" \"$todir/\"" "$fromdir" "$todir" \
| tee "$outfile"
for fn in name1 name2; do
grep "backed up $fn to .*/$fn$" "$outfile" >/dev/null || test_fail "no backup message output for $fn"
done
diff -r $diffopt "$chkdir" "$bakdir" || test_fail "backup dir contents are bogus"
checkit "$RSYNC -avv \"$fromdir/\" \"$chkdir/\"" "$fromdir" "$chkdir"
cat $srcdir/[efgr]*.[ch] > "$name1"
cat $srcdir/[ew]*.[ch] > "$name2"
checkit "$RSYNC -avv --inplace --no-whole-file --backup --backup-dir=\"$bakdir\" \"$fromdir/\" \"$todir/\"" "$fromdir" "$todir" \
| tee "$outfile"
for fn in name1 name2; do
grep "backed up $fn to .*/$fn$" "$outfile" >/dev/null || test_fail "no backup message output for $fn"
done
diff -r $diffopt "$chkdir" "$bakdir" || test_fail "backup dir contents are bogus"
checkit "$RSYNC -avv --inplace --no-whole-file \"$fromdir/\" \"$bakdir/\"" "$fromdir" "$bakdir"
# The script would have aborted on error, so getting here means we've won.
exit 0

45
testsuite/batch-mode.test Normal file
View File

@@ -0,0 +1,45 @@
#! /bin/sh
# Copyright (C) 2004 by Chris Shoemaker <c.shoemaker@cox.net>
# This program is distributable under the terms of the GNU GPL (see
# COPYING).
# Test rsync's --write-batch and --read-batch options
. "$suitedir/rsync.fns"
set -x
hands_setup
cd "$tmpdir"
# Build chkdir for the daemon tests using a normal rsync and an --exclude.
$RSYNC -av --exclude=foobar.baz "$fromdir/" "$chkdir/"
runtest "local --write-batch" 'checkit "$RSYNC -av --write-batch=BATCH \"$fromdir/\" \"$todir\"" "$fromdir" "$todir"'
rm -rf "$todir"
runtest "--read-batch" 'checkit "$RSYNC -av --read-batch=BATCH \"$todir\"" "$fromdir" "$todir"'
build_rsyncd_conf
RSYNC_CONNECT_PROG="$RSYNC --config=$conf --daemon"
export RSYNC_CONNECT_PROG
rm -rf "$todir"
runtest "daemon sender --write-batch" 'checkit "$RSYNC -av --write-batch=BATCH rsync://localhost/test-from/ \"$todir\"" "$chkdir" "$todir"'
rm -rf "$todir"
runtest "--read-batch from daemon" 'checkit "$RSYNC -av --read-batch=BATCH \"$todir\"" "$chkdir" "$todir"'
rm -rf "$todir"
runtest "BATCH.sh use of --read-batch" 'checkit "./BATCH.sh" "$chkdir" "$todir"'
rm -rf "$todir"
mkdir "$todir" || test_fail "failed to restore empty destination directory"
runtest "daemon recv --write-batch" 'checkit "$RSYNC -av --write-batch=BATCH \"$fromdir/\" rsync://localhost/test-to" "$chkdir" "$todir"'
# The script would have aborted on error, so getting here means we pass.
exit 0

View File

@@ -9,15 +9,12 @@
# the test is a member of them. Hopefully they're in at least one
# test.
. $srcdir/testsuite/rsync.fns
. "$suitedir/rsync.fns"
set -x
# Build some hardlinks
fromdir="$scratchdir/from"
todir="$scratchdir/to"
mygrps="`rsync_getgroups`" || fail "Can't get groups"
mkdir "$fromdir"
@@ -29,7 +26,7 @@ do
done
sleep 2
checkit "$RSYNC -rtgvvv \"$fromdir/\" \"$todir/\"" "$fromdir" "$todir"
checkit "$RSYNC -rtgpvvv \"$fromdir/\" \"$todir/\"" "$fromdir" "$todir"
# The script would have aborted on error, so getting here means we've won.
exit 0

View File

@@ -0,0 +1,41 @@
#! /bin/sh
# Copyright (C) 2004 by Wayne Davison <wayned@samba.org>
# This program is distributable under the terms of the GNU GPL see
# COPYING).
# Test that various read-only and set[ug]id permissions work properly,
# even when using a --temp-dir option (which we try to point at a
# different filesystem than the destination dir).
. "$suitedir/rsync.fns"
set -x
hands_setup
tmpdir2=/tmp
sdev=`$TOOLDIR/getfsdev $scratchdir`
tdev=`$TOOLDIR/getfsdev $tmpdir2`
if [ x$sdev = x$tdev ]; then
tmpdir2=/var/tmp
tdev=`$TOOLDIR/getfsdev $tmpdir2`
[ x$sdev = x$tdev ] && test_skipped "Can't find a tmp dir on a different file system"
fi
chmod 440 "$fromdir/text"
chmod 500 "$fromdir/dir/text"
e="$fromdir/dir/subdir/foobar.baz"
chmod 6450 "$e" || chmod 2450 "$e" || chmod 1450 "$e" || chmod 450 "$e"
e="$fromdir/dir/subdir/subsubdir/etc-ltr-list"
chmod 2670 "$e" || chmod 1670 "$e" || chmod 670 "$e"
# First a normal copy.
runtest "normal copy" 'checkit "$RSYNC -avv --temp-dir=\"$tmpdir2\" \"$fromdir/\" \"$todir\"" "$fromdir" "$todir"'
# Then we update all the files.
runtest "update copy" 'checkit "$RSYNC -avvI --no-whole-file --temp-dir=\"$tmpdir2\" \"$fromdir/\" \"$todir\"" "$fromdir" "$todir"'
# The script would have aborted on error, so getting here means we've won.
exit 0

32
testsuite/chmod.test Normal file
View File

@@ -0,0 +1,32 @@
#! /bin/sh
# Copyright (C) 2004 by Wayne Davison <wayned@samba.org>
# This program is distributable under the terms of the GNU GPL see
# COPYING).
# Test that various read-only and set[ug]id permissions work properly,
# even when using a --temp-dir option (which we try to point at a
# different filesystem than the destination dir).
. "$suitedir/rsync.fns"
set -x
hands_setup
chmod 440 "$fromdir/text"
chmod 500 "$fromdir/dir/text"
e="$fromdir/dir/subdir/foobar.baz"
chmod 6450 "$e" || chmod 2450 "$e" || chmod 1450 "$e" || chmod 450 "$e"
e="$fromdir/dir/subdir/subsubdir/etc-ltr-list"
chmod 2670 "$e" || chmod 1670 "$e" || chmod 670 "$e"
# First a normal copy.
runtest "normal copy" 'checkit "$RSYNC -avv \"$fromdir/\" \"$todir\"" "$fromdir" "$todir"'
# Then we update all the files.
runtest "update copy" 'checkit "$RSYNC -avvI --no-whole-file \"$fromdir/\" \"$todir\"" "$fromdir" "$todir"'
# The script would have aborted on error, so getting here means we've won.
exit 0

View File

@@ -11,15 +11,12 @@
# We don't know what users will be present on this system, so we just
# use random numeric uids and gids.
. $srcdir/testsuite/rsync.fns
. "$suitedir/rsync.fns"
set -x
# Build some hardlinks
fromdir="$scratchdir/from"
todir="$scratchdir/to"
mkdir "$fromdir"
name1="$fromdir/name1"
name2="$fromdir/name2"

View File

@@ -0,0 +1,33 @@
#! /bin/sh
# Copyright (C) 2004 by Wayne Davison <wayned@samba.org>
# This program is distributable under the terms of the GNU GPL see
# COPYING).
# Test rsync handling of the --compare-dest option.
. "$suitedir/rsync.fns"
set -x
altdir="$tmpdir/alt"
# Build some files/dirs/links to copy
hands_setup
# Setup the alt and chk dirs
$RSYNC -av --include=text --include='*/' --exclude='*' "$fromdir/" "$altdir/"
sleep 1
touch "$fromdir/dir/text"
$RSYNC -av --exclude=/text "$fromdir/" "$chkdir/"
# Let's do it!
checkit "$RSYNC -avv --no-whole-file --compare-dest=\"$altdir\" \
\"$fromdir/\" \"$todir/\"" "$chkdir" "$todir"
# The script would have aborted on error, so getting here means we've won.
exit 0

View File

@@ -27,7 +27,11 @@ RSYNC_CONNECT_PROG="$RSYNC --config=$conf --daemon"
export RSYNC_CONNECT_PROG
hands_setup
checkit "$RSYNC -avvvvz localhost::test-from/ \"$TO/\"" "$FROM" "$TO"
# Build chkdir with a normal rsync and an --exclude.
$RSYNC -av --exclude=foobar.baz "$fromdir/" "$chkdir/"
checkit "$RSYNC -avvvvz localhost::test-from/ \"$todir/\"" "$chkdir" "$todir"
# The script would have aborted on error, so getting here means we've won.
exit 0

View File

@@ -21,7 +21,11 @@ RSYNC_CONNECT_PROG="$RSYNC --config=$conf --daemon"
export RSYNC_CONNECT_PROG
hands_setup
checkit "$RSYNC -avvvvz \"$FROM/\" localhost::test-to/" "$FROM" "$TO"
# Build chkdir with a normal rsync and an --exclude.
$RSYNC -av --exclude=foobar.baz "$fromdir/" "$chkdir/"
checkit "$RSYNC -avvvvz \"$fromdir/\" localhost::test-to/" "$chkdir" "$todir"
# The script would have aborted on error, so getting here means we've won.
exit 0

View File

@@ -7,15 +7,12 @@
# Test rsync handling of devices. This can only run if you're root.
. $srcdir/testsuite/rsync.fns
. "$suitedir/rsync.fns"
set -x
# Build some hardlinks
fromdir="$scratchdir/from"
todir="$scratchdir/to"
case `id -u` in
'') ;; # If "id" failed, try to continue...
0) ;;
@@ -31,6 +28,7 @@ mknod "$fromdir/char3" c 42 69 || test_skipped "Can't create char device node u
mknod "$fromdir/block" b 42 69 || test_skipped "Can't create block device node unless root"
mknod "$fromdir/block2" b 42 73 || test_skipped "Can't create block device node unless root"
mknod "$fromdir/block3" b 105 73 || test_skipped "Can't create block device node unless root"
mkfifo "$fromdir/fifo" || test_skipped "Can't run mkfifo"
checkit "$RSYNC -aHvv \"$fromdir/\" \"$todir/\"" "$fromdir" "$todir"

View File

@@ -19,15 +19,12 @@
# This test is not great, because it is a timing-dependent bug.
. $srcdir/testsuite/rsync.fns
. "$suitedir/rsync.fns"
set -x
# Build some hardlinks
fromdir="$scratchdir/from"
todir="$scratchdir/to"
mkdir "$fromdir"
name1="$fromdir/name1"
name2="$fromdir/name2"

View File

@@ -10,7 +10,7 @@
# Test some of the more obscure wildcard handling of exclude/include
# processing.
. $srcdir/testsuite/rsync.fns
. "$suitedir/rsync.fns"
set -x
@@ -20,33 +20,28 @@ export HOME CVSIGNORE
# Build some files/dirs/links to copy
fromdir="$scratchdir/from"
todir="$scratchdir/to"
chkdir="$scratchdir/chk"
echo home-cvs-exclude >"$scratchdir"/.cvsignore
makepath "$fromdir/foo/down/to/you"
makepath "$fromdir/bar/down/to/foo/too"
makepath "$fromdir/mid/for/foo/and/that/is/who"
echo kept >"$fromdir/foo/file1"
echo removed >"$fromdir/foo/file2"
echo cvsout >"$fromdir/foo/file2.old"
echo cvsout >"$fromdir/bar/down/to/home-cvs-exclude"
echo keeper >"$fromdir/bar/down/to/foo/file1"
echo cvsout >"$fromdir/bar/down/to/foo/file1.bak"
echo gone >"$fromdir/bar/down/to/foo/file3"
echo lost >"$fromdir/bar/down/to/foo/file4"
echo cvsout >"$fromdir/bar/down/to/foo/file4.junk"
echo smashed >"$fromdir/bar/down/to/foo/to"
echo cvsout >"$fromdir/bar/down/to/home-cvs-exclude"
echo cvsout >"$fromdir/mid/one-in-one-out"
echo one-in-one-out >"$fromdir/mid/.cvsignore"
echo cvsin >"$fromdir/mid/one-for-all"
echo cvsin >"$fromdir/mid/for/one-in-one-out"
echo expunged >"$fromdir/mid/for/foo/extra"
echo retained >"$fromdir/mid/for/foo/keep"
echo cvsin >"$fromdir/mid/for/one-in-one-out"
ln -s too "$fromdir/bar/down/to/foo/sym"
# Setup our test exclude/include file.
# Setup our test exclude/include files.
excl="$scratchdir/exclude-from"
cat >"$excl" <<EOF
@@ -65,6 +60,10 @@ cat >"$excl" <<EOF
- /mid/for/foo/extra
EOF
cat >"$scratchdir/.cvsignore" <<EOF
home-cvs-exclude
EOF
# Create the chk dir with what we expect to be excluded
checkit "$RSYNC -avv \"$fromdir/\" \"$chkdir/\"" "$fromdir" "$chkdir"
@@ -83,7 +82,7 @@ $RSYNC -av --existing --include='*/' --exclude='*' "$fromdir/" "$chkdir/"
# Now, test if rsync excludes the same files.
checkit "$RSYNC -avv --exclude-from=$excl \"$fromdir/\" \"$todir/\"" "$chkdir" "$todir"
checkit "$RSYNC -avv --exclude-from=\"$excl\" \"$fromdir/\" \"$todir/\"" "$chkdir" "$todir"
# Modify the chk dir by removing cvs-ignored files and then tweaking the dir times.
@@ -98,8 +97,8 @@ $RSYNC -av --existing --include='*/' --exclude='*' "$fromdir/" "$chkdir/"
# Now, test if rsync excludes the same files, this time with --cvs-exclude
# and --delete-excluded.
checkit "$RSYNC -avvC --delete-excluded --exclude-from=$excl \
\"$fromdir/\" \"$todir/\"" "$chkdir" "$todir"
checkit "$RSYNC -avvC --exclude-from=\"$excl\" \
--delete-excluded \"$fromdir/\" \"$todir/\"" "$chkdir" "$todir"
# The script would have aborted on error, so getting here means we've won.
exit 0

View File

@@ -11,19 +11,19 @@ hands_setup
# Main script starts here
runtest "basic operation" 'checkit "$RSYNC -av ${FROM}/ ${TO}" ${FROM}/ ${TO}'
runtest "basic operation" 'checkit "$RSYNC -av \"$fromdir/\" \"$todir\"" "$fromdir/" "$todir"'
ln ${FROM}/filelist ${FROM}/dir
runtest "hard links" 'checkit "$RSYNC -avH ${FROM}/ ${TO}" ${FROM}/ ${TO}'
ln "$fromdir/filelist" "$fromdir/dir"
runtest "hard links" 'checkit "$RSYNC -avH \"$fromdir/\" \"$todir\"" "$fromdir/" "$todir"'
rm ${TO}/text
runtest "one file" 'checkit "$RSYNC -avH ${FROM}/ ${TO}" ${FROM}/ ${TO}'
rm "$todir/text"
runtest "one file" 'checkit "$RSYNC -avH \"$fromdir/\" \"$todir\"" "$fromdir/" "$todir"'
echo "extra line" >> ${TO}/text
runtest "extra data" 'checkit "$RSYNC -avH ${FROM}/ ${TO}" ${FROM}/ ${TO}'
echo "extra line" >> "$todir/text"
runtest "extra data" 'checkit "$RSYNC -avH \"$fromdir/\" \"$todir\"" "$fromdir/" "$todir"'
cp ${FROM}/text ${TO}/ThisShouldGo
runtest " --delete" 'checkit "$RSYNC --delete -avH ${FROM}/ ${TO}" ${FROM}/ ${TO}'
cp "$fromdir/text" "$todir/ThisShouldGo"
runtest " --delete" 'checkit "$RSYNC --delete -avH \"$fromdir/\" \"$todir\"" "$fromdir/" "$todir"'
# The script would have aborted on error, so getting here means we've won.
exit 0

View File

@@ -10,7 +10,7 @@
# specify -H, then hard links are detected and recreated as hardlinks
# on the other end.
. $srcdir/testsuite/rsync.fns
. "$suitedir/rsync.fns"
set -x

View File

@@ -11,14 +11,14 @@
hands_setup
LONGNAME=This-is-a-directory-with-a-stupidly-long-name-created-in-an-attempt-to-provoke-an-error-found-in-2.0.11-that-should-hopefully-never-appear-again-if-this-test-does-its-job
LONGDIR=$FROM/$LONGNAME/$LONGNAME/$LONGNAME
longname=This-is-a-directory-with-a-stupidly-long-name-created-in-an-attempt-to-provoke-an-error-found-in-2.0.11-that-should-hopefully-never-appear-again-if-this-test-does-its-job
longdir="$fromdir/$longname/$longname/$longname"
makepath $LONGDIR || test_skipped "unable to create long directory"
touch $LONGDIR/1 || test_skipped "unable to create files in long directory"
date > ${LONGDIR}/1
ls -la / > ${LONGDIR}/2
checkit "$RSYNC --delete -avH ${FROM}/ ${TO}" ${FROM}/ ${TO}
makepath "$longdir" || test_skipped "unable to create long directory"
touch "$longdir/1" || test_skipped "unable to create files in long directory"
date > "$longdir/1"
ls -la / > "$longdir/2"
checkit "$RSYNC --delete -avH \"$fromdir/\" \"$todir\"" "$fromdir/" "$todir"
# The script would have aborted on error, so getting here means we've won.
exit 0

View File

@@ -7,18 +7,15 @@
# Make sure we can merge files from multiple directories into one.
. $srcdir/testsuite/rsync.fns
. "$suitedir/rsync.fns"
set -x
# Build some files/dirs/links to copy
fromdir="$scratchdir/from"
from1dir="${fromdir}1"
from2dir="${fromdir}2"
from3dir="${fromdir}3"
todir="$scratchdir/to"
chkdir="$scratchdir/chk"
mkdir "$from1dir" "$from2dir" "$from3dir"
mkdir "$from2dir"/sub1 "$from3dir"/sub1
@@ -43,9 +40,9 @@ cp -p "$from2dir"/sub1/uno "$from3dir"/sub1/dos "$from2dir"/sub1/tres "$chkdir"/
cp -p "$from3dir"/sub2/subby "$chkdir"/sub2
# Get rid of any directory-time differences
touch "$fromdir"? "$chkdir" "$fromdir"?/sub? "$chkdir"/sub?
$RSYNC -av --existing --include='*/' --exclude='*' "$from1dir/" "$from2dir/" "$from3dir/" "$chkdir/"
checkit "$RSYNC -aHvv \"$fromdir\"?/ \"$todir/\"" "$chkdir" "$todir"
checkit "$RSYNC -aHvv \"$from1dir/\" \"$from2dir/\" \"$from3dir/\" \"$todir/\"" "$chkdir" "$todir"
# The script would have aborted on error, so getting here means we've won.
exit 0

View File

@@ -18,16 +18,15 @@
# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
TMP="$scratchdir"
FROM=${TMP}/from
TO=${TMP}/to
LOG=${TMP}/log
RSYNC="$rsync_bin"
tmpdir="$scratchdir"
fromdir="$tmpdir/from"
todir="$tmpdir/to"
chkdir="$tmpdir/chk"
# Berkley's nice.
PATH="$PATH:/usr/ucb"
if diff -u $srcdir/testsuite/rsync.fns $srcdir/testsuite/rsync.fns >/dev/null 2>&1; then
if diff -u "$srcdir/testsuite/rsync.fns" "$srcdir/testsuite/rsync.fns" >/dev/null 2>&1; then
diffopt="-u"
else
diffopt="-c"
@@ -37,10 +36,10 @@ runtest() {
echo $ECHO_N "Test $1: $ECHO_C"
if eval "$2"
then
echo "${ECHO_T} done."
echo "$ECHO_T done."
return 0
else
echo "${ECHO_T} failed!"
echo "$ECHO_T failed!"
return 1
fi
}
@@ -60,16 +59,16 @@ rsync_getgroups() {
####################
# Build test directories TO and FROM, with FROM full of files.
# Build test directories $todir and $fromdir, with $fromdir full of files.
hands_setup() {
# Clean before creation
rm -rf $FROM
rm -rf $TO
rm -rf "$fromdir"
rm -rf "$todir"
[ -d $TMP ] || mkdir $TMP
[ -d $FROM ] || mkdir $FROM
[ -d $TO ] || mkdir $TO
[ -d "$tmpdir" ] || mkdir "$tmpdir"
[ -d "$fromdir" ] || mkdir "$fromdir"
[ -d "$todir" ] || mkdir "$todir"
# On some BSD systems, the umask affects the mode of created
# symlinks, even though the mode apparently has no effect on how
@@ -82,29 +81,37 @@ hands_setup() {
# the same. So, we need to set our umask before doing any creations.
# set up test data
touch ${FROM}/empty
mkdir ${FROM}/emptydir
touch "$fromdir/empty"
mkdir "$fromdir/emptydir"
# a hundred lines of text or so
rsync_ls_lR "${srcdir}" > ${FROM}/filelist
rsync_ls_lR "$srcdir" > "$fromdir/filelist"
# This might fail on systems that don't have -n
echo $ECHO_N "This file has no trailing lf$ECHO_C" > ${FROM}/nolf
echo $ECHO_N "This file has no trailing lf$ECHO_C" > "$fromdir/nolf"
umask 0
ln -s nolf ${FROM}/nolf-symlink
ln -s nolf "$fromdir/nolf-symlink"
umask 022
cat $srcdir/*.c > ${FROM}/text
mkdir ${FROM}/dir
cp ${FROM}/text ${FROM}/dir
mkdir ${FROM}/dir/subdir
mkdir ${FROM}/dir/subdir/subsubdir
ls -ltr /etc > ${FROM}/dir/subdir/subsubdir/etc-ltr-list
mkdir ${FROM}/dir/subdir/subsubdir2
ls -lt /bin > ${FROM}/dir/subdir/subsubdir2/bin-lt-list
cat $srcdir/*.c > "$fromdir/text"
mkdir "$fromdir/dir"
cp "$fromdir/text" "$fromdir/dir"
mkdir "$fromdir/dir/subdir"
echo some data > "$fromdir/dir/subdir/foobar.baz"
mkdir "$fromdir/dir/subdir/subsubdir"
if [ -r /etc ]; then
ls -ltr /etc > "$fromdir/dir/subdir/subsubdir/etc-ltr-list"
else
ls -ltr / > "$fromdir/dir/subdir/subsubdir/etc-ltr-list"
fi
mkdir "$fromdir/dir/subdir/subsubdir2"
if [ -r /bin ]; then
ls -lt /bin > "$fromdir/dir/subdir/subsubdir2/bin-lt-list"
else
ls -lt / > "$fromdir/dir/subdir/subsubdir2/bin-lt-list"
fi
# echo testing head:
# ls -lR ${srcdir} | head -10 || echo failed
# ls -lR "$srcdir" | head -10 || echo failed
}
@@ -169,10 +176,10 @@ checkit() {
echo "-------------"
echo "check how the directory listings compare with diff:"
echo ""
( cd "$2" && rsync_ls_lR . ) > ${TMP}/ls-from
( cd "$3" && rsync_ls_lR . ) > ${TMP}/ls-to
diff $diffopt ${TMP}/ls-from ${TMP}/ls-to || failed=YES
if [ -z "${failed}" ] ; then
( cd "$2" && rsync_ls_lR . ) > "$tmpdir/ls-from"
( cd "$3" && rsync_ls_lR . ) > "$tmpdir/ls-to"
diff $diffopt "$tmpdir/ls-from" "$tmpdir/ls-to" || failed=YES
if [ -z "$failed" ] ; then
return 0
else
return 1
@@ -189,32 +196,31 @@ build_rsyncd_conf() {
pidfile="$scratchdir/rsyncd.pid"
logfile="$scratchdir/rsyncd.log"
cat >$conf <<EOF
cat >"$conf" <<EOF
# rsyncd configuration file autogenerated by $0
pid file = $pidfile
use chroot = no
hosts allow = localhost, 127.0.0.1
log file = $logfile
exclude = foobar.baz
max verbosity = 9
uid = 0
gid = 0
[test-from]
path = $FROM
path = $fromdir
read only = yes
[test-to]
path = $TO
path = $todir
read only = no
EOF
}
build_symlinks() {
fromdir="$scratchdir/from"
todir="$scratchdir/to"
mkdir "$fromdir"
date >"$fromdir/referent"
ln -s referent "$fromdir/relative"
@@ -230,7 +236,7 @@ test_fail() {
test_skipped() {
echo "$@" >&2
echo "$@" > "$TMP/whyskipped"
echo "$@" > "$tmpdir/whyskipped"
exit 77
}

View File

@@ -24,11 +24,11 @@ if ! [ "`ssh -o'BatchMode yes' localhost echo yes`" = "yes" ]; then
fi
# Added by Steve Bonds Feb 2 2003
# Without this, there are no files in the ${FROM} directory, so rsync has
# Without this, there are no files in the $fromdir directory, so rsync has
# nothing to do.
hands_setup
runtest "ssh: basic test" 'checkit "$RSYNC -avH -e ssh --rsync-path=$RSYNC ${FROM}/ localhost:${TO}" ${FROM}/ ${TO}'
runtest "ssh: basic test" 'checkit "$RSYNC -avH -e ssh --rsync-path=$RSYNC \"$fromdir/\" \"localhost:$todir\"" "$fromdir/" "$todir"'
# Added by Steve Bonds Feb 2 2003
# I assumed that "F1" was intended to hold a single file for testing if
@@ -36,8 +36,8 @@ runtest "ssh: basic test" 'checkit "$RSYNC -avH -e ssh --rsync-path=$RSYNC ${FRO
# it was unset so the "mv" tried to move a parent directory into a
# subdirectory of itself. There is probably a better way of pulling out
# a sample file to rename.
F1=`ls ${TO} | head -5 | tail -1`
F1=`ls "$todir" | head -5 | tail -1`
mv ${TO}/${F1} ${TO}/ThisShouldGo
mv "$todir/$F1" "$todir/ThisShouldGo"
runtest "ssh: renamed file" 'checkit "$RSYNC --delete -avH -e ssh --rsync-path=$RSYNC ${FROM}/ localhost:${TO}" ${FROM}/ ${TO}'
runtest "ssh: renamed file" 'checkit "$RSYNC --delete -avH -e ssh --rsync-path=$RSYNC \"$fromdir/\" \"localhost:$todir\"" "$fromdir/" "$todir"'

View File

@@ -8,7 +8,7 @@
# Test rsync's somewhat over-featured symlink control: the default
# behaviour is that symlinks should not be copied at all.
. $srcdir/testsuite/rsync.fns
. "$suitedir/rsync.fns"
set -x
@@ -18,19 +18,19 @@ build_symlinks || test_fail "failed to build symlinks"
# should be missing.
$RSYNC -r "$fromdir/" "$todir" || test_fail "$RSYNC returned $?"
[ -f "${todir}/referent" ] || test_fail "referent was not copied"
[ -d "${todir}/from" ] && test_fail "extra level of directories"
if is_a_link "${todir}/dangling"
[ -f "$todir/referent" ] || test_fail "referent was not copied"
[ -d "$todir/from" ] && test_fail "extra level of directories"
if is_a_link "$todir/dangling"
then
test_fail "dangling symlink was copied"
fi
if is_a_link "${todir}/relative"
if is_a_link "$todir/relative"
then
test_fail "relative symlink was copied"
fi
if is_a_link "${todir}/absolute"
if is_a_link "$todir/absolute"
then
test_fail "absolute symlink was copied"
fi

View File

@@ -7,7 +7,7 @@
# Test tiny function to trim trailing slashes.
. $srcdir/testsuite/rsync.fns
. "$suitedir/rsync.fns"
set -x

View File

@@ -4,7 +4,7 @@
# Call directly into unsafe_symlink and test its handling of various filenames
. $srcdir/testsuite/rsync.fns
. "$suitedir/rsync.fns"
test_unsafe() {
# $1 is the target of a symlink

View File

@@ -2,7 +2,7 @@
# Originally by Vladim<69>r Michl <Vladimir.Michl@hlubocky.del.cz>
. $srcdir/testsuite/rsync.fns
. "$suitedir/rsync.fns"
test_symlink() {
is_a_link "$1" || test_fail "File $1 is not a symlink"
@@ -14,7 +14,7 @@ test_regular() {
fi;
};
cd "$TMP"
cd "$tmpdir"
mkdir from

View File

@@ -7,7 +7,7 @@
# Test the wildmatch functionality
. $srcdir/testsuite/rsync.fns
. "$suitedir/rsync.fns"
set -x

21
tls.c
View File

@@ -49,17 +49,16 @@ int list_only = 0;
int preserve_perms = 0;
static void failed (char const *what,
char const *where)
static void failed(char const *what, char const *where)
{
fprintf (stderr, PROGRAM ": %s %s: %s\n",
what, where, strerror (errno));
exit (1);
fprintf(stderr, PROGRAM ": %s %s: %s\n",
what, where, strerror(errno));
exit(1);
}
static void list_file (const char *fname)
static void list_file(const char *fname)
{
STRUCT_STAT buf;
char permbuf[PERMSTRING_SIZE];
@@ -68,7 +67,7 @@ static void list_file (const char *fname)
char linkbuf[4096];
if (do_lstat(fname, &buf) == -1)
failed ("stat", fname);
failed("stat", fname);
/* The size of anything but a regular file is probably not
* worth thinking about. */
@@ -114,7 +113,7 @@ static void list_file (const char *fname)
/* TODO: Perhaps escape special characters in fname? */
printf("%s ", permbuf);
if (IS_DEVICE(buf.st_mode)) {
if (S_ISCHR(buf.st_mode) || S_ISBLK(buf.st_mode)) {
printf("%5ld,%6ld",
(long)major(buf.st_rdev),
(long)minor(buf.st_rdev));
@@ -130,13 +129,13 @@ int
main(int argc, char *argv[])
{
if (argc < 2) {
fprintf (stderr, "usage: " PROGRAM " DIR ...\n"
"Trivial file listing program for portably checking rsync\n");
fprintf(stderr, "usage: " PROGRAM " DIR ...\n"
"Trivial file listing program for portably checking rsync\n");
return 1;
}
for (argv++; *argv; argv++) {
list_file (*argv);
list_file(*argv);
}
return 0;

67
token.c
View File

@@ -1,17 +1,17 @@
/*
/*
Copyright (C) Andrew Tridgell 1996
Copyright (C) Paul Mackerras 1996
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
@@ -21,23 +21,26 @@
#include "zlib/zlib.h"
extern int do_compression;
extern int module_id;
static int compression_level = Z_DEFAULT_COMPRESSION;
/* determine the compression level based on a wildcard filename list */
void set_compression(char *fname)
{
extern int module_id;
char *dont;
char *tok;
if (!do_compression) return;
if (!do_compression)
return;
compression_level = Z_DEFAULT_COMPRESSION;
dont = lp_dont_compress(module_id);
if (!dont || !*dont) return;
if (!dont || !*dont)
return;
if ((dont[0] == '*') && (!dont[1])) {
if (dont[0] == '*' && !dont[1]) {
/* an optimization to skip the rest of this routine */
compression_level = 0;
return;
@@ -45,12 +48,13 @@ void set_compression(char *fname)
dont = strdup(dont);
fname = strdup(fname);
if (!dont || !fname) return;
if (!dont || !fname)
return;
strlower(dont);
strlower(fname);
for (tok=strtok(dont," ");tok;tok=strtok(NULL," ")) {
for (tok = strtok(dont, " "); tok; tok = strtok(NULL, " ")) {
if (wildmatch(tok, fname)) {
compression_level = 0;
break;
@@ -69,12 +73,14 @@ static int simple_recv_token(int f,char **data)
if (!buf) {
buf = new_array(char, CHUNK_SIZE);
if (!buf) out_of_memory("simple_recv_token");
if (!buf)
out_of_memory("simple_recv_token");
}
if (residue == 0) {
int i = read_int(f);
if (i <= 0) return i;
if (i <= 0)
return i;
residue = i;
}
@@ -90,29 +96,18 @@ static int simple_recv_token(int f,char **data)
static void simple_send_token(int f,int token,
struct map_struct *buf,OFF_T offset,int n)
{
extern int write_batch;
int hold_int;
if (n > 0) {
int l = 0;
while (l < n) {
int n1 = MIN(CHUNK_SIZE,n-l);
write_int(f,n1);
write_buf(f,map_ptr(buf,offset+l,n1),n1);
if (write_batch) {
write_batch_delta_file( (char *) &n1, sizeof(int) );
write_batch_delta_file(map_ptr(buf,offset+l,n1),n1);
}
l += n1;
}
}
/* a -2 token means to send data only and no token */
if (token != -2) {
write_int(f,-(token+1));
if (write_batch) {
hold_int = -(token+1);
write_batch_delta_file( (char *) &hold_int, sizeof(int) );
}
}
}
@@ -159,8 +154,6 @@ send_deflated_token(int f, int token,
{
int n, r;
static int init_done, flush_pending;
extern int write_batch;
char temp_byte;
if (last_token == -1) {
/* initialization */
@@ -193,28 +186,13 @@ send_deflated_token(int f, int token,
n = last_token - run_start;
if (r >= 0 && r <= 63) {
write_byte(f, (n==0? TOKEN_REL: TOKENRUN_REL) + r);
if (write_batch) {
temp_byte = (char)( (n==0? TOKEN_REL: TOKENRUN_REL) + r);
write_batch_delta_file(&temp_byte,sizeof(char));
}
} else {
write_byte(f, (n==0? TOKEN_LONG: TOKENRUN_LONG));
write_int(f, run_start);
if (write_batch) {
temp_byte = (char)(n==0? TOKEN_LONG: TOKENRUN_LONG);
write_batch_delta_file(&temp_byte,sizeof(char));
write_batch_delta_file((char *)&run_start,sizeof(run_start));
}
}
if (n != 0) {
write_byte(f, n);
write_byte(f, n >> 8);
if (write_batch) {
temp_byte = (char)n;
write_batch_delta_file(&temp_byte,sizeof(char));
temp_byte = (char)(n >> 8);
write_batch_delta_file(&temp_byte,sizeof(char));
}
}
last_run_end = last_token;
run_start = token;
@@ -273,8 +251,6 @@ send_deflated_token(int f, int token,
obuf[0] = DEFLATED_DATA + (n >> 8);
obuf[1] = n;
write_buf(f, obuf, n+2);
if (write_batch)
write_batch_delta_file(obuf,n+2);
}
}
} while (nb != 0 || tx_strm.avail_out == 0);
@@ -284,11 +260,6 @@ send_deflated_token(int f, int token,
if (token == -1) {
/* end of file - clean up */
write_byte(f, END_FLAG);
if (write_batch) {
temp_byte = END_FLAG;
write_batch_delta_file(&temp_byte,sizeof(char));
}
} else if (token != -2) {
/* add the data in the current block to the compressor's
history and hash table */
@@ -491,7 +462,7 @@ static void see_deflate_token(char *buf, int len)
/**
* Transmit a verbatim buffer of length @p n followed by a token.
* If token == -1 then we have reached EOF
* If token == -1 then we have reached EOF
* If n == 0 then don't send a buffer
*/
void send_token(int f,int token,struct map_struct *buf,OFF_T offset,

View File

@@ -81,7 +81,7 @@ static char *gid_to_name(gid_t gid)
static int map_uid(int id, char *name)
{
uid_t uid;
if (uid != 0 && name_to_uid(name, &uid))
if (id != 0 && name_to_uid(name, &uid))
return uid;
return id;
}
@@ -89,7 +89,7 @@ static int map_uid(int id, char *name)
static int map_gid(int id, char *name)
{
gid_t gid;
if (gid != 0 && name_to_gid(name, &gid))
if (id != 0 && name_to_gid(name, &gid))
return gid;
return id;
}
@@ -161,7 +161,7 @@ static struct idlist *recv_add_uid(int id, char *name)
int id2 = name ? map_uid(id, name) : id;
struct idlist *node;
node = add_to_list(&uidlist, id, name, map_uid(id, name));
node = add_to_list(&uidlist, id, name, id2);
if (verbose > 3) {
rprintf(FINFO, "uid %d(%s) maps to %d\n",

516
util.c
View File

@@ -28,6 +28,10 @@
#include "rsync.h"
extern int verbose;
extern int dry_run;
extern int module_id;
extern int modify_window;
extern char *partial_dir;
extern struct exclude_list_struct server_exclude_list;
int sanitize_paths = 0;
@@ -126,13 +130,12 @@ void overflow(char *str)
int set_modtime(char *fname, time_t modtime)
{
extern int dry_run;
if (dry_run)
return 0;
if (verbose > 2) {
rprintf(FINFO, "set modtime of %s to (%ld) %s",
fname, (long) modtime,
fname, (long)modtime,
asctime(localtime(&modtime)));
}
@@ -194,7 +197,7 @@ int create_directory_path(char *fname, int base_umask)
*
* Derived from GNU C's cccp.c.
*/
static int full_write(int desc, char *ptr, size_t len)
int full_write(int desc, char *ptr, size_t len)
{
int total_written;
@@ -242,7 +245,7 @@ static int safe_read(int desc, char *ptr, size_t len)
/** Copy a file.
*
* This is used in conjunction with the --temp-dir option */
* This is used in conjunction with the --temp-dir and --backup options */
int copy_file(char *source, char *dest, mode_t mode)
{
int ifd;
@@ -252,41 +255,46 @@ int copy_file(char *source, char *dest, mode_t mode)
ifd = do_open(source, O_RDONLY, 0);
if (ifd == -1) {
rprintf(FERROR,"open %s: %s\n",
source,strerror(errno));
rsyserr(FERROR, errno, "open %s", full_fname(source));
return -1;
}
if (robust_unlink(dest) && errno != ENOENT) {
rprintf(FERROR,"unlink %s: %s\n",
dest,strerror(errno));
rsyserr(FERROR, errno, "unlink %s", full_fname(dest));
return -1;
}
ofd = do_open(dest, O_WRONLY | O_CREAT | O_TRUNC | O_EXCL, mode);
if (ofd == -1) {
rprintf(FERROR,"open %s: %s\n",
dest,strerror(errno));
rsyserr(FERROR, errno, "open %s", full_fname(dest));
close(ifd);
return -1;
}
while ((len = safe_read(ifd, buf, sizeof buf)) > 0) {
if (full_write(ofd, buf, len) < 0) {
rprintf(FERROR,"write %s: %s\n",
dest,strerror(errno));
rsyserr(FERROR, errno, "write %s", full_fname(dest));
close(ifd);
close(ofd);
return -1;
}
}
close(ifd);
close(ofd);
if (len < 0) {
rprintf(FERROR,"read %s: %s\n",
source,strerror(errno));
rsyserr(FERROR, errno, "read %s", full_fname(source));
close(ifd);
close(ofd);
return -1;
}
if (close(ifd) < 0) {
rsyserr(FINFO, errno, "close failed on %s",
full_fname(source));
}
if (close(ofd) < 0) {
rsyserr(FERROR, errno, "close failed on %s",
full_fname(dest));
return -1;
}
@@ -354,8 +362,8 @@ int robust_unlink(char *fname)
#endif
}
/* Returns 0 on success, -1 on most errors, and -2 if we got an error
* trying to copy the file across file systems. */
/* Returns 0 on successful rename, 1 if we successfully copied the file
* across filesystems, -2 if copy_file() failed, and -1 on other errors. */
int robust_rename(char *from, char *to, int mode)
{
int tries = 4;
@@ -375,7 +383,7 @@ int robust_rename(char *from, char *to, int mode)
if (copy_file(from, to, mode) != 0)
return -2;
do_unlink(from);
return 0;
return 1;
default:
return -1;
}
@@ -432,7 +440,8 @@ void kill_all(int sig)
int name_to_uid(char *name, uid_t *uid)
{
struct passwd *pass;
if (!name || !*name) return 0;
if (!name || !*name)
return 0;
pass = getpwnam(name);
if (pass) {
*uid = pass->pw_uid;
@@ -445,7 +454,8 @@ int name_to_uid(char *name, uid_t *uid)
int name_to_gid(char *name, gid_t *gid)
{
struct group *grp;
if (!name || !*name) return 0;
if (!name || !*name)
return 0;
grp = getgrnam(name);
if (grp) {
*gid = grp->gr_gid;
@@ -486,75 +496,92 @@ static int exclude_server_path(char *arg)
return 0;
}
static void glob_expand_one(char *s, char **argv, int *argc, int maxargs)
static void glob_expand_one(char *s, char ***argv_ptr, int *argc_ptr,
int *maxargs_ptr)
{
char **argv = *argv_ptr;
int argc = *argc_ptr;
int maxargs = *maxargs_ptr;
#if !(defined(HAVE_GLOB) && defined(HAVE_GLOB_H))
if (!*s) s = ".";
s = argv[*argc] = strdup(s);
if (argc == maxargs) {
maxargs += MAX_ARGS;
if (!(argv = realloc_array(argv, char *, maxargs)))
out_of_memory("glob_expand_one");
*argv_ptr = argv;
*maxargs_ptr = maxargs;
}
if (!*s)
s = ".";
s = argv[argc++] = strdup(s);
exclude_server_path(s);
(*argc)++;
#else
extern int sanitize_paths;
glob_t globbuf;
int i;
if (!*s) s = ".";
if (maxargs <= argc)
return;
if (!*s)
s = ".";
s = argv[*argc] = strdup(s);
if (sanitize_paths) {
sanitize_path(s, NULL);
}
if (sanitize_paths)
s = sanitize_path(NULL, s, "", 0);
else
s = strdup(s);
memset(&globbuf, 0, sizeof globbuf);
if (!exclude_server_path(s))
glob(s, 0, NULL, &globbuf);
if (globbuf.gl_pathc == 0) {
(*argc)++;
globfree(&globbuf);
return;
if (MAX((int)globbuf.gl_pathc, 1) > maxargs - argc) {
maxargs += globbuf.gl_pathc + MAX_ARGS;
if (!(argv = realloc_array(argv, char *, maxargs)))
out_of_memory("glob_expand_one");
*argv_ptr = argv;
*maxargs_ptr = maxargs;
}
for (i = 0; i < maxargs - *argc && i < (int)globbuf.gl_pathc; i++) {
if (i == 0)
free(s);
argv[*argc + i] = strdup(globbuf.gl_pathv[i]);
if (!argv[*argc + i])
out_of_memory("glob_expand");
if (globbuf.gl_pathc == 0)
argv[argc++] = s;
else {
int j = globbuf.gl_pathc;
free(s);
for (i = 0; i < j; i++) {
if (!(argv[argc++] = strdup(globbuf.gl_pathv[i])))
out_of_memory("glob_expand_one");
}
}
globfree(&globbuf);
*argc += i;
#endif
*argc_ptr = argc;
}
/* This routine is only used in daemon mode. */
void glob_expand(char *base1, char **argv, int *argc, int maxargs)
void glob_expand(char *base1, char ***argv_ptr, int *argc_ptr, int *maxargs_ptr)
{
char *s = argv[*argc];
char *s = (*argv_ptr)[*argc_ptr];
char *p, *q;
char *base = base1;
int base_len = strlen(base);
if (!s || !*s) return;
if (!s || !*s)
return;
if (strncmp(s, base, base_len) == 0)
s += base_len;
s = strdup(s);
if (!s) out_of_memory("glob_expand");
if (!(s = strdup(s)))
out_of_memory("glob_expand");
if (asprintf(&base," %s/", base1) <= 0) out_of_memory("glob_expand");
if (asprintf(&base," %s/", base1) <= 0)
out_of_memory("glob_expand");
base_len++;
q = s;
while ((p = strstr(q,base)) != NULL && *argc < maxargs) {
/* split it at this point */
*p = 0;
glob_expand_one(q, argv, argc, maxargs);
q = p + base_len;
for (q = s; *q; q = p + base_len) {
if ((p = strstr(q, base)) != NULL)
*p = '\0'; /* split it at this point */
glob_expand_one(q, argv_ptr, argc_ptr, maxargs_ptr);
if (!p)
break;
}
if (*q && *argc < maxargs)
glob_expand_one(q, argv, argc, maxargs);
free(s);
free(base);
}
@@ -565,8 +592,8 @@ void glob_expand(char *base1, char **argv, int *argc, int maxargs)
void strlower(char *s)
{
while (*s) {
if (isupper(* (unsigned char *) s))
*s = tolower(* (unsigned char *) s);
if (isupper(*(unsigned char *)s))
*s = tolower(*(unsigned char *)s);
s++;
}
}
@@ -623,118 +650,143 @@ size_t stringjoin(char *dest, size_t destsize, ...)
return ret;
}
void clean_fname(char *name)
int count_dir_elements(const char *p)
{
char *p;
int l;
int modified = 1;
if (!name) return;
while (modified) {
modified = 0;
if ((p = strstr(name,"/./")) != NULL) {
modified = 1;
while (*p) {
p[0] = p[2];
p++;
}
}
if ((p = strstr(name,"//")) != NULL) {
modified = 1;
while (*p) {
p[0] = p[1];
p++;
}
}
if (strncmp(p = name, "./", 2) == 0) {
modified = 1;
do {
p[0] = p[2];
} while (*p++);
}
l = strlen(p = name);
if (l > 1 && p[l-1] == '/') {
modified = 1;
p[l-1] = 0;
int cnt = 0, new_component = 1;
while (*p) {
if (*p++ == '/')
new_component = 1;
else if (new_component) {
new_component = 0;
cnt++;
}
}
return cnt;
}
/**
* Make path appear as if a chroot had occurred:
*
* @li 1. remove leading "/" (or replace with "." if at end)
*
* @li 2. remove leading ".." components (except those allowed by @p reldir)
*
* @li 3. delete any other "<dir>/.." (recursively)
*
* Can only shrink paths, so sanitizes in place.
*
* While we're at it, remove double slashes and "." components like
* clean_fname() does, but DON'T remove a trailing slash because that
* is sometimes significant on command line arguments.
*
* If @p reldir is non-null, it is a sanitized directory that the path will be
* relative to, so allow as many ".." at the beginning of the path as
* there are components in reldir. This is used for symbolic link targets.
* If reldir is non-null and the path began with "/", to be completely like
* a chroot we should add in depth levels of ".." at the beginning of the
* path, but that would blow the assumption that the path doesn't grow and
* it is not likely to end up being a valid symlink anyway, so just do
* the normal removal of the leading "/" instead.
*
* Contributed by Dave Dykstra <dwd@bell-labs.com>
*/
void sanitize_path(char *p, char *reldir)
/* Turns multiple adjacent slashes into a single slash, gets rid of "./"
* elements (but not a trailing dot dir), removes a trailing slash, and
* optionally collapses ".." elements (except for those at the start of the
* string). If the resulting name would be empty, change it into a ".". */
unsigned int clean_fname(char *name, BOOL collapse_dot_dot)
{
char *start, *sanp;
int depth = 0;
int allowdotdot = 0;
char *limit = name - 1, *t = name, *f = name;
int anchored;
if (reldir) {
depth++;
while (*reldir) {
if (*reldir++ == '/') {
depth++;
if (!name)
return 0;
if ((anchored = *f == '/') != 0)
*t++ = *f++;
while (*f) {
/* discard extra slashes */
if (*f == '/') {
f++;
continue;
}
if (*f == '.') {
/* discard "." dirs (but NOT a trailing '.'!) */
if (f[1] == '/') {
f += 2;
continue;
}
/* collapse ".." dirs */
if (collapse_dot_dot
&& f[1] == '.' && (f[2] == '/' || !f[2])) {
char *s = t - 1;
if (s == name && anchored) {
f += 2;
continue;
}
while (s > limit && *--s != '/') {}
if (s != t - 1 && (s < name || *s == '/')) {
t = s + 1;
f += 2;
continue;
}
limit = t + 2;
}
}
while (*f && (*t++ = *f++) != '/') {}
}
start = p;
sanp = p;
while (*p == '/') {
/* remove leading slashes */
p++;
if (t > name+anchored && t[-1] == '/')
t--;
if (t == name)
*t++ = '.';
*t = '\0';
return t - name;
}
/* Make path appear as if a chroot had occurred. This handles a leading
* "/" (either removing it or expanding it) and any leading or embedded
* ".." components that attempt to escape past the module's top dir.
*
* If dest is NULL, a buffer is allocated to hold the result. It is legal
* to call with the dest and the path (p) pointing to the same buffer, but
* rootdir will be ignored to avoid expansion of the string.
*
* The rootdir string contains a value to use in place of a leading slash.
* Specify NULL to get the default of lp_path(module_id).
*
* If depth is >= 0, it is a count of how many '..'s to allow at the start
* of the path. Use -1 to allow unlimited depth.
*
* We also clean the path in a manner similar to clean_fname() but with a
* few differences:
*
* Turns multiple adjacent slashes into a single slash, gets rid of "." dir
* elements (INCLUDING a trailing dot dir), PRESERVES a trailing slash, and
* ALWAYS collapses ".." elements (except for those at the start of the
* string up to "depth" deep). If the resulting name would be empty,
* change it into a ".". */
char *sanitize_path(char *dest, const char *p, const char *rootdir, int depth)
{
char *start, *sanp;
int rlen = 0;
if (dest != p) {
int plen = strlen(p);
if (*p == '/') {
if (!rootdir)
rootdir = lp_path(module_id);
rlen = strlen(rootdir);
depth = 0;
p++;
}
if (dest) {
if (rlen + plen + 1 >= MAXPATHLEN)
return NULL;
} else if (!(dest = new_array(char, rlen + plen + 1)))
out_of_memory("sanitize_path");
if (rlen) {
memcpy(dest, rootdir, rlen);
if (rlen > 1)
dest[rlen++] = '/';
}
}
start = sanp = dest + rlen;
while (*p != '\0') {
/* discard leading or extra slashes */
if (*p == '/') {
p++;
continue;
}
/* this loop iterates once per filename component in p.
* both p (and sanp if the original had a slash) should
* always be left pointing after a slash
*/
if (*p == '.' && (p[1] == '/' || p[1] == '\0')) {
/* skip "." component */
while (*++p == '/') {
/* skip following slashes */
;
}
p++;
continue;
}
allowdotdot = 0;
if (*p == '.' && p[1] == '.' && (p[2] == '/' || p[2] == '\0')) {
/* ".." component followed by slash or end */
if (depth > 0 && sanp == start) {
/* allow depth levels of .. at the beginning */
--depth;
allowdotdot = 1;
} else {
if (depth <= 0 || sanp != start) {
p += 2;
if (*p == '/')
p++;
if (sanp != start) {
/* back up sanp one level */
--sanp; /* now pointing at slash */
@@ -745,68 +797,21 @@ void sanitize_path(char *p, char *reldir)
}
continue;
}
}
while (1) {
/* copy one component through next slash */
*sanp++ = *p++;
if (*p == '\0' || p[-1] == '/') {
while (*p == '/') {
/* skip multiple slashes */
p++;
}
break;
}
}
if (allowdotdot) {
/* allow depth levels of .. at the beginning */
depth--;
/* move the virtual beginning to leave the .. alone */
start = sanp;
start = sanp + 3;
}
/* copy one component through next slash */
while (*p && (*sanp++ = *p++) != '/') {}
}
if (sanp == start && !allowdotdot) {
if (sanp == dest) {
/* ended up with nothing, so put in "." component */
/*
* note that the !allowdotdot doesn't prevent this from
* happening in all allowed ".." situations, but I didn't
* think it was worth putting in an extra variable to ensure
* it since an extra "." won't hurt in those situations.
*/
*sanp++ = '.';
}
*sanp = '\0';
}
/* Works much like sanitize_path(), with these differences: (1) a new buffer
* is allocated for the sanitized path rather than modifying it in-place; (2)
* a leading slash gets transformed into the rootdir value (which can be empty
* or NULL if you just want the slash to get dropped); (3) no "reldir" can be
* specified. */
char *alloc_sanitize_path(const char *path, const char *rootdir)
{
char *buf;
int rlen, plen = strlen(path);
if (*path == '/' && rootdir) {
rlen = strlen(rootdir);
if (rlen == 1)
path++;
} else
rlen = 0;
if (!(buf = new_array(char, rlen + plen + 1)))
out_of_memory("alloc_sanitize_path");
if (rlen)
memcpy(buf, rootdir, rlen);
memcpy(buf + rlen, path, plen + 1);
if (rlen > 1)
rlen++;
sanitize_path(buf + rlen, NULL);
if (rlen && buf[rlen] == '.' && buf[rlen+1] == '\0') {
if (rlen > 1)
rlen--;
buf[rlen] = '\0';
}
return buf;
return dest;
}
char curr_dir[MAXPATHLEN];
@@ -850,7 +855,7 @@ int push_dir(char *dir)
curr_dir_len += len;
}
clean_fname(curr_dir);
curr_dir_len = clean_fname(curr_dir, 1);
return 1;
}
@@ -871,14 +876,37 @@ int pop_dir(char *dir)
return 1;
}
/**
* Return the filename, turning any newlines into '?'s. This ensures that
* outputting it on a line of its own cannot generate an empty line. This
* function can handle only 2 names at a time!
**/
const char *safe_fname(const char *fname)
{
static char fbuf1[MAXPATHLEN], fbuf2[MAXPATHLEN];
static char *fbuf = fbuf2;
char *nl = strchr(fname, '\n');
if (!nl)
return fname;
fbuf = fbuf == fbuf1 ? fbuf2 : fbuf1;
strlcpy(fbuf, fname, MAXPATHLEN);
nl = fbuf + (nl - (char *)fname);
do {
*nl = '?';
} while ((nl = strchr(nl+1, '\n')) != NULL);
return fbuf;
}
/**
* Return a quoted string with the full pathname of the indicated filename.
* The string " (in MODNAME)" may also be appended. The returned pointer
* remains valid until the next time full_fname() is called.
**/
char *full_fname(char *fn)
char *full_fname(const char *fn)
{
extern int module_id;
static char *result = NULL;
char *m1, *m2, *m3;
char *p1, *p2;
@@ -886,6 +914,7 @@ char *full_fname(char *fn)
if (result)
free(result);
fn = safe_fname(fn);
if (*fn == '/')
p1 = p2 = "";
else {
@@ -917,6 +946,69 @@ char *full_fname(char *fn)
return result;
}
static char partial_fname[MAXPATHLEN];
char *partial_dir_fname(const char *fname)
{
char *t = partial_fname;
int sz = sizeof partial_fname;
const char *fn;
if ((fn = strrchr(fname, '/')) != NULL) {
fn++;
if (*partial_dir != '/') {
int len = fn - fname;
strncpy(t, fname, len); /* safe */
t += len;
sz -= len;
}
} else
fn = fname;
if ((int)pathjoin(t, sz, partial_dir, fn) >= sz)
return NULL;
if (server_exclude_list.head
&& check_exclude(&server_exclude_list, partial_fname, 0) < 0)
return NULL;
return partial_fname;
}
/* If no --partial-dir option was specified, we don't need to do anything
* (the partial-dir is essentially '.'), so just return success. */
int handle_partial_dir(const char *fname, int create)
{
char *fn, *dir;
if (fname != partial_fname)
return 1;
if (!create && *partial_dir == '/')
return 1;
if (!(fn = strrchr(partial_fname, '/')))
return 1;
*fn = '\0';
dir = partial_fname;
if (create) {
STRUCT_STAT st;
#if SUPPORT_LINKS
int statret = do_lstat(dir, &st);
#else
int statret = do_stat(dir, &st);
#endif
if (statret == 0 && !S_ISDIR(st.st_mode)) {
if (do_unlink(dir) < 0)
return 0;
statret = -1;
}
if (statret < 0 && do_mkdir(dir, 0700) < 0)
return 0;
} else
do_rmdir(dir);
*fn = '/';
return 1;
}
/** We need to supply our own strcmp function for file list comparisons
to ensure that signed/unsigned usage is consistent between machines. */
int u_strcmp(const char *cs1, const char *cs2)
@@ -963,7 +1055,8 @@ int unsafe_symlink(const char *dest, const char *src)
int depth = 0;
/* all absolute and null symlinks are unsafe */
if (!dest || !*dest || *dest == '/') return 1;
if (!dest || !*dest || *dest == '/')
return 1;
/* find out what our safety margin is */
for (name = src; (slash = strchr(name, '/')) != 0; name = slash+1) {
@@ -1031,7 +1124,6 @@ int msleep(int t)
struct timeval tval, t1, t2;
gettimeofday(&t1, NULL);
gettimeofday(&t2, NULL);
while (tdiff < t) {
tval.tv_sec = (t-tdiff)/1000;
@@ -1062,13 +1154,13 @@ int msleep(int t)
**/
int cmp_modtime(time_t file1, time_t file2)
{
extern int modify_window;
if (file2 > file1) {
if (file2 - file1 <= modify_window) return 0;
if (file2 - file1 <= modify_window)
return 0;
return -1;
}
if (file1 - file2 <= modify_window) return 0;
if (file1 - file2 <= modify_window)
return 0;
return 1;
}